Skip to content

Commit

Permalink
Expanded exploitable function detouring
Browse files Browse the repository at this point in the history
A number of functions have been detoured when used on entities with IsACFEntity set to true on it. Most of these will also call ACF.CheckLegal at the time of use, and will block function use
- SetMass
- SetModel
- SetNoDraw
- SetNotSolid - Still allowed (fading door)
- PhysicsInitSphere
- SetCollisionBounds
- SetCollisionGroup - Still allows entities to be made not collideable (context menu)

Makespherical has also been blocked from use on ACF entities, and ProperClipping will be blocked on ACF entities except for procedural armor

Two new convenience functions have been added for development use, ACF.Contraption.SetMass and ACF.Contraption.SetModel; these will set the appropriate variable in the entity's ACF table, and then set the mass normally. As long as Entity.ACF.Mass/Model has been set on an entity PRIOR to mass/model change, the original functions will still call the above functions
Also got rid of LegalMass being set on most entities as it is not used

There is also a new name-and-shame message which is disabled by default on both server and client. When enabled on the server, any time an entity is marked disabled by a legal check, a message is sent out to all players which, depending on their setting, will have a message in the console saying who, what entity, and what happened to make it disabled.
  • Loading branch information
LiddulBOFH committed Feb 8, 2024
1 parent 06d5cf3 commit 6e6cd27
Show file tree
Hide file tree
Showing 22 changed files with 251 additions and 177 deletions.
160 changes: 127 additions & 33 deletions lua/acf/contraption/contraption_sv.lua
Original file line number Diff line number Diff line change
Expand Up @@ -278,52 +278,146 @@ do -- ACF Parent Detouring
end

do -- ASSUMING DIRECT CONTROL
local ENT = FindMetaTable("Entity")
local OBJ = FindMetaTable("PhysObj")

do -- SetMass
-- Reject any changes to mass on ACF entities
-- Mass can only be set to whatever Ent.ACF.LegalMass is
local SetMass = SetMass or OBJ.SetMass
local BlockedTools = {
proper_clipping = true,
makespherical = true
}

local BlockedGroups = {
[COLLISION_GROUP_DEBRIS] = true,
[COLLISION_GROUP_IN_VEHICLE] = true,
[COLLISION_GROUP_VEHICLE_CLIP] = true,
[COLLISION_GROUP_DOOR_BLOCKER] = true
}

-- If allowed, will remove existing makespherical dupe modifiers on ACF entities
hook.Add("OnEntityCreated", "ACF Exploitables Stubbing", function(Entity)
if not ACF.LegalChecks then return end
if not IsValid(Entity) then return end
if not Entity.IsACFEntity then return end

duplicator.ClearEntityModifier(Entity, "sphere")
duplicator.ClearEntityModifier(Entity, "MakeSphericalCollisions")
end)

-- This, if allowed, will prevent physical clips from happening on ACF entities, except for procedural armor
hook.Add("ProperClippingCanPhysicsClip", "ACF Block PhysicsClip", function(Entity)
if not ACF.LegalChecks then return true end
if Entity.IsACFArmor then return true end
if Entity.IsACFEntity then return false end
end)

-- This, if allowed, will block ProperClipping from putting clips on any ACF entities, except for procedural armor
hook.Add("CanTool", "ACF Block ProperClipping", function(_, Trace, Tool)
if not ACF.LegalChecks then return end

if not BlockedTools[Tool] then return end

function OBJ:SetMass(Number)
local Ent = self:GetEntity()
-- Special case, allow this but block on everything else
if Trace.Entity.IsACFArmor and Tool == "proper_clipping" then return true end

if Trace.Entity.IsACFEntity then return false end
end)

hook.Add("Initialize", "ACF Meta Detour",function()
timer.Simple(1,function()
Contraption.Detours = Contraption.Detours or {
ENT = {},
OBJ = {},
}

local ENT = FindMetaTable("Entity")
local OBJ = FindMetaTable("PhysObj")

local EntDetours = Contraption.Detours.ENT
local ObjDetours = Contraption.Detours.OBJ

local SetMass = OBJ.SetMass
ObjDetours.SetMass = SetMass

local SetNoDraw = ENT.SetNoDraw
local SetModel = ENT.SetModel
local PhysicsInitSphere = ENT.PhysicsInitSphere
local SetCollisionBounds = ENT.SetCollisionBounds
local SetCollisionGroup = ENT.SetCollisionGroup
local SetNotSolid = ENT.SetNotSolid
EntDetours.SetNoDraw = SetNoDraw
EntDetours.SetModel = SetModel
EntDetours.PhysicsInitSphere = PhysicsInitSphere
EntDetours.SetCollisionBounds = SetCollisionBounds
EntDetours.SetCollisionGroup = SetCollisionGroup
EntDetours.SetNotSolid = SetNotSolid

-- Convenience functions that will set the Mass/Model variables in the ACF table for the entity
function Contraption.SetMass(Entity, Mass)
Entity.ACF.Mass = Mass

if Entity.ACF_OnMassChange then
Entity:ACF_OnMassChange(Entity:GetPhysicsObject():GetMass(), Mass)
end

if Ent.IsACFEntity and Ent.ACF and Number ~= Ent.ACF.LegalMass then
return
SetMass(Entity:GetPhysicsObject(), Mass)
end

if Ent.ACF_OnMassChange then
Ent:ACF_OnMassChange(self:GetMass(), Number)
function Contraption.SetModel(Entity, Model)
Entity.ACF.Model = Model

SetModel(Entity, Model)
end

SetMass(self, Number)
end
end
function OBJ:SetMass(Mass)
local Ent = self:GetEntity()

do -- SetModel
-- Reject any changes to the model on ACF entities
-- Models can only be set to whatever Ent.ACF.Model is
local SetModel = SetModel or ENT.SetModel
-- Required due for AD2 support, if this isn't present then entities will never get set to their required weight on dupe paste
if Ent.IsACFEntity then Contraption.SetMass(self, Ent.ACF.Mass) return end

function ENT:SetModel(String)
if self.IsACFEntity and self.ACF and String ~= self.ACF.Model then
return
if Ent.ACF_OnMassChange then
Ent:ACF_OnMassChange(self:GetMass(), Mass)
end

SetMass(self, Mass)
end

SetModel(self, String)
end
end
function ENT:SetModel(Model)
if self.IsACFEntity then Contraption.SetModel(self, self.ACF.Model) return end

do -- SetNoDraw
local SetNoDraw = SetNoDraw or ENT.SetNoDraw
SetModel(self, Model)
end

function ENT:SetNoDraw(Bool)
if Bool and self.IsACFEntity then
return
-- All of these should prevent the relevant functions from occurring on ACF entities, but only if LegalChecks are enabled
-- Will also call ACF.CheckLegal at the same time as preventing the function usage, because likely something else is amiss
function ENT:PhysicsInitSphere(...)
if self.IsACFEntity and ACF.LegalChecks then ACF.CheckLegal(self) return false end

return PhysicsInitSphere(self, ...)
end

SetNoDraw(self, Bool)
end
end
function ENT:SetCollisionBounds(...)
if self.IsACFEntity and ACF.LegalChecks then ACF.CheckLegal(self) return end

SetCollisionBounds(self, ...)
end

function ENT:SetCollisionGroup(Group)
if self.IsACFEntity and ACF.LegalChecks and (BlockedGroups[Group] == true) then ACF.CheckLegal(self) return end

SetCollisionGroup(self, Group)
end

function ENT:SetNoDraw(...)
if self.IsACFEntity and ACF.LegalChecks then ACF.CheckLegal(self) return end

SetNoDraw(self, ...)
end

function ENT:SetNotSolid(...)
if self.IsACFEntity then ACF.CheckLegal(self) end

SetNotSolid(self, ...)
end

hook.Remove("Initialize","ACF Meta Detour")
end)
end)
end
8 changes: 8 additions & 0 deletions lua/acf/contraption/overrides_cl.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
hook.Add("OnEntityCreated", "ACF Stub Exploitables",function(Entity)
timer.Simple(1,function()
if not IsValid(Entity) then return end
if not Entity.IsACFEntity then return end

Entity.RenderOverride = nil
end)
end)
2 changes: 2 additions & 0 deletions lua/acf/core/globals.lua
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ do -- ACF global vars

-- General Settings
ACF.LegalChecks = true -- Whether or not IsLegal checks should be run on ACF entities
ACF.NameAndShame = false -- Whether or not IsLegal checks should message everyone* about ACF entities getting disabled
ACF.VehicleLegalChecks = true -- Whether or not IsLegal checks should be run on vehicle entities
ACF.Year = 1945
ACF.IllegalDisableTime = 30 -- Time in seconds for an entity to be disabled when it fails ACF.IsLegal
Expand Down Expand Up @@ -166,6 +167,7 @@ elseif CLIENT then
CreateClientConVar("acf_maxroundsdisplay", 16, true, false, "Maximum rounds to display before using bulk display (0 to only display bulk)", 0, 5000)
CreateClientConVar("acf_drawboxes", 1, true, false, "Whether or not to draw hitboxes on ACF entities", 0, 1)
CreateClientConVar("acf_legalhints", 1, true, true, "If enabled, ACF will throw a warning hint whenever an entity gets disabled.", 0, 1)
CreateClientConVar("acf_legalshame", 0, true, true, "If enabled, you will get a message in console from the server if someone else has an ACF entity get disabled, but only when the server has that logging enabled.", 0, 1)
CreateClientConVar("acf_debris", 1, true, false, "Toggles ACF Debris.", 0, 1)
CreateClientConVar("acf_debris_collision", 0, true, false, "Toggles debris collisions with other entities.", 0, 1)
CreateClientConVar("acf_debris_gibmultiplier", 1, true, false, "The amount of gibs spawned when created by ACF debris.", 0, 1)
Expand Down
6 changes: 6 additions & 0 deletions lua/acf/core/utilities/util_cl.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
local ACF = ACF
local ReceiveShame = GetConVar("acf_legalshame")

do -- Custom fonts
surface.CreateFont("ACF_Title", {
Expand Down Expand Up @@ -34,6 +35,11 @@ do -- Networked notifications

notification.AddLegacy(net.ReadString(), Type, 7)
end)

net.Receive("ACF_NameAndShame", function()
if not ReceiveShame:GetBool() then return end
MsgN(net.ReadString())
end)
end

do -- Panel helpers
Expand Down
14 changes: 14 additions & 0 deletions lua/acf/core/utilities/util_sv.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,20 @@ local ACF = ACF

do -- Networked notifications
util.AddNetworkString("ACF_Notify")
util.AddNetworkString("ACF_NameAndShame")

function ACF.Shame(Entity, Message)
if not ACF.NameAndShame then return end
local Owner = Entity:CPPIGetOwner()

if not IsValid(Owner) then return end

MsgN("ACF Legal: " .. Owner:GetName() .. " had " .. tostring(Entity) .. " disabled for " .. Message)

net.Start("ACF_NameAndShame")
net.WriteString("ACF Legal: " .. Owner:GetName() .. " had " .. tostring(Entity) .. " disabled for " .. Message)
net.Broadcast()
end

function ACF.SendNotify(Player, Success, Message)
net.Start("ACF_Notify")
Expand Down
21 changes: 6 additions & 15 deletions lua/acf/core/validation_sv.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,12 @@

-- Local Vars -----------------------------------
local ACF = ACF
local Contraption = ACF.Contraption
local StringFind = string.find
local TimerSimple = timer.Simple
local Baddies = ACF.GlobalFilter
local MinimumArmor = ACF.MinimumArmor
local MaximumArmor = ACF.MaximumArmor
local NoCollision = { -- These prevent ACF bullets from hitting an entity
[COLLISION_GROUP_DEBRIS] = true,
[COLLISION_GROUP_IN_VEHICLE] = true,
[COLLISION_GROUP_VEHICLE_CLIP] = true,
[COLLISION_GROUP_DOOR_BLOCKER] = true
}

--[[ ACF Legality Check
ALL SENTS MUST HAVE:
Expand All @@ -39,12 +34,12 @@ function ACF.IsLegal(Entity)
if Phys:GetVolume() then
Entity.ACF.PhysObj = Phys -- Updated PhysObj
else
ACF.Shame(Entity,"having a custom physics object (spherical).")
return false, "Invalid Physics", "Custom physics objects cannot be applied to ACF entities."
end
end
if not Entity:IsSolid() then return false, "Not Solid", "The entity is invisible to projectiles." end
if NoCollision[Entity:GetCollisionGroup()] then return false, "Invalid Collisions", "The entity is invisible to projectiles." end
if Entity.ClipData and next(Entity.ClipData) then return false, "Visual Clip", "Visual clip cannot be applied to ACF entities." end -- No visclip
if not Entity:IsSolid() then ACF.Shame(Entity,"not being solid.") return false, "Not Solid", "The entity is invisible to projectiles." end
if Entity.ClipData and next(Entity.ClipData) then ACF.Shame(Entity,"having visclips.") return false, "Visual Clip", "Visual clip cannot be applied to ACF entities." end -- No visclip
if Entity.IsACFWeapon and not ACF.GunsCanFire then return false, "Cannot fire", "Firing disabled by the servers ACF settings." end
if Entity.IsRack and not ACF.RacksCanFire then return false, "Cannot fire", "Firing disabled by the servers ACF settings." end

Expand Down Expand Up @@ -151,9 +146,7 @@ function ACF.UpdateThickness(Entity, PhysObj, Area, Ductility)
local Mass = Area * (1 + Ductility) ^ 0.5 * Thickness * 0.00078

if Mass ~= Entity.ACF.Mass then
Entity.ACF.Mass = Mass

PhysObj:SetMass(Mass)
Contraption.SetMass(Entity,Mass)
end

return Thickness
Expand All @@ -169,9 +162,7 @@ function ACF.UpdateThickness(Entity, PhysObj, Area, Ductility)
local Armor = ACF.CalcArmor(Area, Ductility, Mass)

if Mass ~= Entity.ACF.Mass then
Entity.ACF.Mass = Mass

PhysObj:SetMass(Mass)
Contraption.SetMass(Entity,Mass)

duplicator.StoreEntityModifier(Entity, "mass", { Mass = Mass })
end
Expand Down
13 changes: 13 additions & 0 deletions lua/acf/menu/data_callbacks.lua
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,19 @@ local Settings = {

Message("Info", "Legality checks for ACF entities have been " .. (Bool and "enabled." or "disabled."))
end,
NameAndShame = function(Player, _, Value)
local Bool = tobool(Value)

if ACF.NameAndShame == Bool then return end

ACF.NameAndShame = Bool

if CLIENT and not IsValid(Player) then return end

if not ACF.LegalChecks then return end

Message("Info", "Public shaming for illegal actions has been " .. (Bool and "enabled." or "disabled."))
end,
VehicleLegalChecks = function(Player, _, Value)
local Bool = tobool(Value)

Expand Down
13 changes: 13 additions & 0 deletions lua/acf/menu/items_cl/settings.lua
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,11 @@ do -- Clientside settings
Hints:SetConVar("acf_legalhints")
end)

ACF.AddClientSettings(251, "Legal Check Name and Shame", function(Base)
local Hints = Base:AddCheckBox("Enable receiving console messages for entities getting disabled.")
Hints:SetConVar("acf_legalshame")
end)

ACF.AddClientSettings(301, "Debris", function(Base)
local Debris = Base:AddCheckBox("Allow creation of clientside debris.")
Debris:SetConVar("acf_debris")
Expand Down Expand Up @@ -149,6 +154,14 @@ do -- Serverside settings
return Value
end)

local LegalCheckNameAndShame = Base:AddCheckBox("Pubicly shame someone in everyone's console for a failed legal check.")
LegalCheckNameAndShame:SetServerData("NameAndShame", "OnChange")
LegalCheckNameAndShame:DefineSetter(function(Panel, _, _, Value)
Panel:SetValue(Value)

return Value
end)

local GunFire = Base:AddCheckBox("Allow guns to fire.")
GunFire:SetServerData("GunsCanFire", "OnChange")
GunFire:DefineSetter(function(Panel, _, _, Value)
Expand Down
1 change: 1 addition & 0 deletions lua/acf/persisted_vars/vars_sv.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

-- Settings
ACF.PersistServerData("LegalChecks", true)
ACF.PersistServerData("NameAndShame", false)
ACF.PersistServerData("VehicleLegalChecks", true)
ACF.PersistServerData("ServerDataAllowAdmin", false)
ACF.PersistServerData("RestrictInfo", true)
Expand Down
10 changes: 2 additions & 8 deletions lua/entities/acf_ammo/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ include("shared.lua")
-- Local Vars -----------------------------------

local ACF = ACF
local Contraption = ACF.Contraption
local ActiveCrates = ACF.AmmoCrates
local Utilities = ACF.Utilities
local TimerCreate = timer.Create
Expand Down Expand Up @@ -423,7 +424,6 @@ do -- ACF Activation and Damage -----------------
local Sounds = Utilities.Sounds
local Damage = ACF.Damage
local Objects = Damage.Objects
local Contraption = ACF.Contraption

local function CookoffCrate(Entity)
if Entity.Ammo <= 1 or Entity.Damaged < Clock.CurTime then -- Detonate when time is up or crate is out of ammo
Expand Down Expand Up @@ -601,14 +601,8 @@ end ---------------------------------------------
do -- Mass Update -------------------------------
local function UpdateMass(Ent)
local Mass = math.floor(Ent.EmptyMass + (Ent.AmmoMass * (Ent.Ammo / math.max(Ent.Capacity, 1))))
local Phys = Ent:GetPhysicsObject()

if IsValid(Phys) then
Ent.ACF.Mass = Mass
Ent.ACF.LegalMass = Mass

Phys:SetMass(Ent.ACF.LegalMass)
end
Contraption.SetMass(Ent,Mass)
end

-------------------------------------------------------------------------------
Expand Down
Loading

0 comments on commit 6e6cd27

Please sign in to comment.