diff --git a/pkg/seccomp/seccomp_rules.go b/pkg/seccomp/seccomp_rules.go index ffdf42884..10c6a824b 100644 --- a/pkg/seccomp/seccomp_rules.go +++ b/pkg/seccomp/seccomp_rules.go @@ -337,11 +337,14 @@ func (MatchAll) Render(program *syscallProgram, labelSet *labelSet) { func (MatchAll) String() string { return "true" } // Or expresses an "OR" (a disjunction) over a set of `SyscallRule`s. -// If an Or is empty, it will not match anything. +// An `Or` may not be empty. type Or []SyscallRule // Render implements `SyscallRule.Render`. func (or Or) Render(program *syscallProgram, labelSet *labelSet) { + if len(or) == 0 { + panic("Or expression cannot be empty") + } // If `len(or) == 1`, this will be optimized away to be the same as // rendering the single rule in the disjunction. for i, rule := range or { @@ -358,7 +361,7 @@ func (or Or) Render(program *syscallProgram, labelSet *labelSet) { func (or Or) String() string { switch len(or) { case 0: - return "false" + return "invalid" case 1: return or[0].String() default: @@ -376,11 +379,14 @@ 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. +// An `And` may not be empty. type And []SyscallRule // Render implements `SyscallRule.Render`. func (and And) Render(program *syscallProgram, labelSet *labelSet) { + if len(and) == 0 { + panic("And expression cannot be empty") + } // 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 { @@ -397,7 +403,7 @@ func (and And) Render(program *syscallProgram, labelSet *labelSet) { func (and And) String() string { switch len(and) { case 0: - return "true" + return "invalid" case 1: return and[0].String() default: diff --git a/pkg/seccomp/seccomp_test.go b/pkg/seccomp/seccomp_test.go index cd6dcee95..41364b473 100644 --- a/pkg/seccomp/seccomp_test.go +++ b/pkg/seccomp/seccomp_test.go @@ -72,6 +72,7 @@ func TestBasic(t *testing.T) { for _, test := range []struct { name string ruleSets []RuleSet + wantPanic bool defaultAction linux.BPFAction badArchAction linux.BPFAction specs []spec @@ -305,6 +306,18 @@ func TestBasic(t *testing.T) { }, }, }, + { + name: "empty Or is invalid", + ruleSets: []RuleSet{ + { + Rules: MakeSyscallRules(map[uintptr]SyscallRule{ + 1: Or{}, + }), + Action: linux.SECCOMP_RET_ALLOW, + }, + }, + wantPanic: true, + }, { name: "And of multiple rules", ruleSets: []RuleSet{ @@ -342,6 +355,18 @@ func TestBasic(t *testing.T) { }, }, }, + { + name: "empty And is invalid", + ruleSets: []RuleSet{ + { + Rules: MakeSyscallRules(map[uintptr]SyscallRule{ + 1: And{}, + }), + Action: linux.SECCOMP_RET_ALLOW, + }, + }, + wantPanic: true, + }, { name: "EqualTo", ruleSets: []RuleSet{ @@ -905,9 +930,28 @@ func TestBasic(t *testing.T) { }, } { t.Run(test.name, func(t *testing.T) { - instrs, _, err := BuildProgram(test.ruleSets, test.defaultAction, test.badArchAction) - if err != nil { - t.Fatalf("BuildProgram() got error: %v", err) + var instrs []bpf.Instruction + var panicErr any + func() { + t.Helper() + defer func() { + panicErr = recover() + t.Helper() + }() + var err error + instrs, _, err = BuildProgram(test.ruleSets, test.defaultAction, test.badArchAction) + if err != nil { + t.Fatalf("BuildProgram() got error: %v", err) + } + }() + if test.wantPanic { + if panicErr == nil { + t.Fatal("BuildProgram did not panick") + } + return + } + if panicErr != nil { + t.Fatalf("BuildProgram unexpectedly panicked: %v", panicErr) } p, err := bpf.Compile(instrs, true /* optimize */) if err != nil {