Class: SeccompTools::Audit::Policy
- Inherits:
-
Object
- Object
- SeccompTools::Audit::Policy
- Defined in:
- lib/seccomp-tools/audit/policy.rb
Overview
One architecture's view of a filter: given a syscall number, which actions can an attacker reach? Built from that arch's section leaves (already arch-filtered by Explain::Analysis).
A leaf is reachable for syscall nr when every plain sys_number fact on its path is satisfied
by nr - this one predicate covers ==, ranges, and jset bit-tests (so it sees an x32 guard
written either way). Argument and opaque facts are not consulted: arguments are
attacker-controlled and the executor already dropped self-contradictory paths, so a surviving
leaf is reachable under some argument choice. The stance is deliberately conservative - "could an
attacker reach this action?".
Constant Summary collapse
- SYS =
Const::BPF::SeccompData::SYS_NUMBER
Instance Attribute Summary collapse
-
#arch_sym ⇒ Symbol?
readonly
The architecture symbol whose syscall names apply (+nil+ when unknown).
-
#arch_val ⇒ Integer?
readonly
The
AUDIT_ARCHvalue (+nil+ when the filter never branches onarch). -
#leaves ⇒ Array<Symbolic::Executor::Leaf>
readonly
This section's leaves.
-
#title ⇒ Object
readonly
Display title for this section (arch symbol or
0x... (unknown)).
Instance Method Summary collapse
-
#arch_name ⇒ String
A display name for this section's architecture (+"amd64"+, or
"0x... (unknown)"). -
#condition_for(nr, action = 'ALLOW') ⇒ String?
The argument condition under which
nrreachesaction, rendered likeexplain(+"filename == 0x..."+), ornilwhen it is unconditional or the arch is unknown. -
#default_label ⇒ String?
The action of the catch-all (default) path, e.g.
-
#explicitly_denied?(nr) ⇒ Boolean
Was syscall
nrsingled out for denial (a rule pinssys_number == nrto a non-+ALLOW+ action), as opposed to merely being absent from an allowlist? Distinguishes a real "blocked one equivalent but not another" gap from allowlist omissions. -
#initialize(analysis, section) ⇒ Policy
constructor
A new instance of Policy.
-
#number(name) ⇒ Integer?
The number of syscall
nameon this arch, ornilif the arch lacks it. -
#reachable_actions(nr) ⇒ Array<String>
The distinct actions reachable for syscall number
nr. -
#reachable_as_allow?(nr) ⇒ Boolean
Can syscall
nrreachALLOW?. -
#table ⇒ Hash{Symbol=>Integer}?
This arch's
name => numbertable, ornilwhen the section has no known architecture.
Constructor Details
#initialize(analysis, section) ⇒ Policy
Returns a new instance of Policy.
34 35 36 37 38 39 |
# File 'lib/seccomp-tools/audit/policy.rb', line 34 def initialize(analysis, section) @analysis = analysis @arch_val, @arch_sym, @title, @leaves = section @fusion = @arch_sym && Explain::QwordFusion.new(@arch_sym) @renderer = @fusion && Explain::Renderer.new(@fusion) end |
Instance Attribute Details
#arch_sym ⇒ Symbol? (readonly)
Returns The architecture symbol whose syscall names apply (+nil+ when unknown).
26 27 28 |
# File 'lib/seccomp-tools/audit/policy.rb', line 26 def arch_sym @arch_sym end |
#arch_val ⇒ Integer? (readonly)
Returns The AUDIT_ARCH value (+nil+ when the filter never branches on arch).
24 25 26 |
# File 'lib/seccomp-tools/audit/policy.rb', line 24 def arch_val @arch_val end |
#leaves ⇒ Array<Symbolic::Executor::Leaf> (readonly)
Returns This section's leaves.
30 31 32 |
# File 'lib/seccomp-tools/audit/policy.rb', line 30 def leaves @leaves end |
#title ⇒ Object (readonly)
Returns Display title for this section (arch symbol or 0x... (unknown)).
28 29 30 |
# File 'lib/seccomp-tools/audit/policy.rb', line 28 def title @title end |
Instance Method Details
#arch_name ⇒ String
A display name for this section's architecture (+"amd64"+, or "0x... (unknown)").
43 44 45 |
# File 'lib/seccomp-tools/audit/policy.rb', line 43 def arch_name (@arch_sym || @title).to_s end |
#condition_for(nr, action = 'ALLOW') ⇒ String?
The argument condition under which nr reaches action, rendered like explain
(+"filename == 0x..."+), or nil when it is unconditional or the arch is unknown.
100 101 102 103 104 105 106 107 |
# File 'lib/seccomp-tools/audit/policy.rb', line 100 def condition_for(nr, action = 'ALLOW') return nil unless @renderer ls = reachable_leaves(nr).select { |l| Explain::Verdict.label(l.ret) == action } conds = @fusion.merge_or(ls.map { |l| @analysis.facts(l).residual }) .map { |list| @renderer.conjunction(@fusion.fold(list), name_of(nr)) }.uniq conds.include?('') ? nil : conds.join(' or ') end |
#default_label ⇒ String?
The action of the catch-all (default) path, e.g. "ALLOW" / "ERRNO(5)".
67 68 69 |
# File 'lib/seccomp-tools/audit/policy.rb', line 67 def default_label @analysis.default_label(@leaves) end |
#explicitly_denied?(nr) ⇒ Boolean
Was syscall nr singled out for denial (a rule pins sys_number == nr to a non-+ALLOW+
action), as opposed to merely being absent from an allowlist? Distinguishes a real
"blocked one equivalent but not another" gap from allowlist omissions.
90 91 92 93 |
# File 'lib/seccomp-tools/audit/policy.rb', line 90 def explicitly_denied?(nr) !reachable_as_allow?(nr) && @leaves.any? { |l| @analysis.facts(l).sys_eq == nr && Explain::Verdict.label(l.ret) != 'ALLOW' } end |
#number(name) ⇒ Integer?
The number of syscall name on this arch, or nil if the arch lacks it.
61 62 63 |
# File 'lib/seccomp-tools/audit/policy.rb', line 61 def number(name) table && table[name] end |
#reachable_actions(nr) ⇒ Array<String>
The distinct actions reachable for syscall number nr.
74 75 76 |
# File 'lib/seccomp-tools/audit/policy.rb', line 74 def reachable_actions(nr) reachable_leaves(nr).map { |l| Explain::Verdict.label(l.ret) }.uniq end |
#reachable_as_allow?(nr) ⇒ Boolean
Can syscall nr reach ALLOW?
81 82 83 |
# File 'lib/seccomp-tools/audit/policy.rb', line 81 def reachable_as_allow?(nr) reachable_leaves(nr).any? { |l| Explain::Verdict.label(l.ret) == 'ALLOW' } end |
#table ⇒ Hash{Symbol=>Integer}?
This arch's name => number table, or nil when the section has no known architecture.
@arch_sym is always nil or a supported architecture (the CLI rejects an undetectable host
before we get here), so the table lookup never fails.
52 53 54 55 56 |
# File 'lib/seccomp-tools/audit/policy.rb', line 52 def table return @table if defined?(@table) @table = @arch_sym && Const::Syscall.const_get(@arch_sym.upcase) end |