Cybersecurity-Projects/PROJECTS/beginner/deserialization-gadget-lab/lib/rube/marshal/limits.rb

119 lines
3.5 KiB
Ruby

# ©AngelaMos | 2026
# limits.rb
module Rube
module Marshal
class Limits
DEFAULT_MAX_BYTES = 1_048_576
DEFAULT_MAX_DEPTH = 64
DEFAULT_MAX_NODES = 10_000
DEFAULT_MAX_REGISTERED_OBJECTS = 4_096
DEFAULT_MAX_SYMBOL_DEFINITIONS = 256
DEFAULT_MAX_COLLECTION_ENTRIES = 1_024
DEFAULT_MAX_SCALAR_BYTES = 262_144
DEFAULT_MAX_TOTAL_SCALAR_BYTES = 524_288
DEFAULT_MAX_OBJECT_LINKS = 2_048
ROLE_BYTES = "stream bytes"
ROLE_NODES = "nodes"
ROLE_REGISTERED = "registered objects"
ROLE_SYMBOLS = "symbol definitions"
ROLE_ENTRIES = "collection entries"
ROLE_SCALAR = "scalar bytes"
ROLE_TOTAL_SCALAR = "total scalar bytes"
ROLE_LINKS = "object links"
attr_reader :max_bytes, :max_depth, :max_nodes, :max_registered_objects,
:max_symbol_definitions, :max_collection_entries,
:max_scalar_bytes, :max_total_scalar_bytes, :max_object_links
def initialize(
max_bytes: DEFAULT_MAX_BYTES,
max_depth: DEFAULT_MAX_DEPTH,
max_nodes: DEFAULT_MAX_NODES,
max_registered_objects: DEFAULT_MAX_REGISTERED_OBJECTS,
max_symbol_definitions: DEFAULT_MAX_SYMBOL_DEFINITIONS,
max_collection_entries: DEFAULT_MAX_COLLECTION_ENTRIES,
max_scalar_bytes: DEFAULT_MAX_SCALAR_BYTES,
max_total_scalar_bytes: DEFAULT_MAX_TOTAL_SCALAR_BYTES,
max_object_links: DEFAULT_MAX_OBJECT_LINKS
)
@max_bytes = max_bytes
@max_depth = max_depth
@max_nodes = max_nodes
@max_registered_objects = max_registered_objects
@max_symbol_definitions = max_symbol_definitions
@max_collection_entries = max_collection_entries
@max_scalar_bytes = max_scalar_bytes
@max_total_scalar_bytes = max_total_scalar_bytes
@max_object_links = max_object_links
end
def permissive
self.class.new(
max_bytes: Float::INFINITY,
max_depth: Constants::DEFAULT_MAX_DEPTH,
max_nodes: Float::INFINITY,
max_registered_objects: Float::INFINITY,
max_symbol_definitions: Float::INFINITY,
max_collection_entries: Float::INFINITY,
max_scalar_bytes: Float::INFINITY,
max_total_scalar_bytes: Float::INFINITY,
max_object_links: Float::INFINITY
)
end
end
class Budget
def initialize(limits)
@limits = limits
@nodes = 0
@registered = 0
@symbols = 0
@links = 0
@scalar_total = 0
end
def node!
@nodes += 1
check(@nodes, limits.max_nodes, Limits::ROLE_NODES)
end
def registered!
@registered += 1
check(@registered, limits.max_registered_objects, Limits::ROLE_REGISTERED)
end
def symbol!
@symbols += 1
check(@symbols, limits.max_symbol_definitions, Limits::ROLE_SYMBOLS)
end
def link!
@links += 1
check(@links, limits.max_object_links, Limits::ROLE_LINKS)
end
def entries!(count)
check(count, limits.max_collection_entries, Limits::ROLE_ENTRIES)
end
def scalar!(size)
check(size, limits.max_scalar_bytes, Limits::ROLE_SCALAR)
@scalar_total += size
check(@scalar_total, limits.max_total_scalar_bytes, Limits::ROLE_TOTAL_SCALAR)
end
private
attr_reader :limits
def check(value, ceiling, role)
return if value <= ceiling
raise LimitExceededError, "#{role} #{value} exceeds #{ceiling}"
end
end
end
end