diff --git a/pkg/seccomp/seccomp_rules.go b/pkg/seccomp/seccomp_rules.go index 27fd208dc..ffdf42884 100644 --- a/pkg/seccomp/seccomp_rules.go +++ b/pkg/seccomp/seccomp_rules.go @@ -375,6 +375,45 @@ func (or Or) String() string { } } +// And expresses an "AND" (a conjunction) over a set of `SyscallRule`s. +// If an And is empty, it will match anything. +type And []SyscallRule + +// Render implements `SyscallRule.Render`. +func (and And) Render(program *syscallProgram, labelSet *labelSet) { + // If `len(and) == 1`, this will be optimized away to be the same as + // rendering the single rule in the conjunction. + for i, rule := range and { + frag := program.Record() + nextRuleLabel := labelSet.NewLabel() + rule.Render(program, labelSet.Push(fmt.Sprintf("and[%d]", i), nextRuleLabel, labelSet.Mismatched())) + frag.MustHaveJumpedTo(nextRuleLabel, labelSet.Mismatched()) + program.Label(nextRuleLabel) + } + program.JumpTo(labelSet.Matched()) +} + +// String implements `SyscallRule.String`. +func (and And) String() string { + switch len(and) { + case 0: + return "true" + case 1: + return and[0].String() + default: + var sb strings.Builder + sb.WriteRune('(') + for i, rule := range and { + if i != 0 { + sb.WriteString(" && ") + } + sb.WriteString(rule.String()) + } + sb.WriteRune(')') + return sb.String() + } +} + // merge merges `rule1` and `rule2`, simplifying `MatchAll` and `Or` rules. func merge(rule1, rule2 SyscallRule) SyscallRule { _, rule1IsMatchAll := rule1.(MatchAll) diff --git a/pkg/seccomp/seccomp_test.go b/pkg/seccomp/seccomp_test.go index 11fdc13a2..cd6dcee95 100644 --- a/pkg/seccomp/seccomp_test.go +++ b/pkg/seccomp/seccomp_test.go @@ -305,6 +305,43 @@ func TestBasic(t *testing.T) { }, }, }, + { + name: "And of multiple rules", + ruleSets: []RuleSet{ + { + Rules: MakeSyscallRules(map[uintptr]SyscallRule{ + 1: And{ + PerArg{ + NotEqual(0xf), + }, + PerArg{ + NotEqual(0xe), + }, + }, + }), + Action: linux.SECCOMP_RET_ALLOW, + }, + }, + defaultAction: linux.SECCOMP_RET_TRAP, + badArchAction: linux.SECCOMP_RET_KILL_THREAD, + specs: []spec{ + { + desc: "hit first rule", + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0xf}}, + want: linux.SECCOMP_RET_TRAP, + }, + { + desc: "hit 2nd rule", + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0xe}}, + want: linux.SECCOMP_RET_TRAP, + }, + { + desc: "hit neither rule", + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0xd}}, + want: linux.SECCOMP_RET_ALLOW, + }, + }, + }, { name: "EqualTo", ruleSets: []RuleSet{