diff --git a/pkg/seccomp/seccomp.go b/pkg/seccomp/seccomp.go index 3ca8a4c2b..30392bc7c 100644 --- a/pkg/seccomp/seccomp.go +++ b/pkg/seccomp/seccomp.go @@ -52,29 +52,24 @@ const ( // making it possible for the process to continue running after a violation. // However, it will leave a SECCOMP audit event trail behind. In any case, the // syscall is still blocked from executing. -func Install(rules SyscallRules, denyRules SyscallRules) error { - defaultAction, err := defaultAction() - if err != nil { - return err - } - +func Install(rules SyscallRules, denyRules SyscallRules, options ProgramOptions) error { // *** DEBUG TIP *** // If you suspect the process is getting killed due to a seccomp violation, uncomment the line // below to get a panic stack trace when there is a violation. - // defaultAction = linux.BPFAction(linux.SECCOMP_RET_TRAP) + // options.DefaultAction = Return(linux.BPFAction(linux.SECCOMP_RET_TRAP)) - log.Infof("Installing seccomp filters for %d syscalls (action=%v)", rules.Size(), defaultAction) + log.Infof("Installing seccomp filters for %d syscalls (action=%v)", rules.Size(), options.DefaultAction) instrs, _, err := BuildProgram([]RuleSet{ { Rules: denyRules, - Action: defaultAction, + Action: options.DefaultAction, }, { Rules: rules, Action: linux.SECCOMP_RET_ALLOW, }, - }, defaultAction, defaultAction) + }, options) if log.IsLogging(log.Debug) { programStr, errDecode := bpf.DecodeInstructions(instrs) if errDecode != nil { @@ -303,6 +298,28 @@ func (m matchedValue) LoadLow32Bits() { m.program.Stmt(bpf.Ld|bpf.Abs|bpf.W, m.dataOffsetLow) } +// ProgramOptions configure a seccomp program. +type ProgramOptions struct { + // DefaultAction is the action returned when none of the rules match. + DefaultAction linux.BPFAction + + // BadArchAction is the action returned when the architecture of the + // syscall structure input doesn't match the one the program expects. + BadArchAction linux.BPFAction +} + +// DefaultProgramOptions returns the default program options. +func DefaultProgramOptions() ProgramOptions { + action, err := defaultAction() + if err != nil { + panic(fmt.Sprintf("cannot determine default seccomp action: %v", err)) + } + return ProgramOptions{ + DefaultAction: action, + BadArchAction: action, + } +} + // BuildStats contains information about seccomp program generation. type BuildStats struct { // SizeBeforeOptimizations and SizeAfterOptimizations correspond to the @@ -320,7 +337,7 @@ type BuildStats struct { // BuildProgram builds a BPF program from the given map of actions to matching // SyscallRules. The single generated program covers all provided RuleSets. -func BuildProgram(rules []RuleSet, defaultAction, badArchAction linux.BPFAction) ([]bpf.Instruction, BuildStats, error) { +func BuildProgram(rules []RuleSet, options ProgramOptions) ([]bpf.Instruction, BuildStats, error) { start := time.Now() program := &syscallProgram{ program: bpf.NewProgramBuilder(), @@ -339,11 +356,11 @@ func BuildProgram(rules []RuleSet, defaultAction, badArchAction linux.BPFAction) // Default label if none of the rules matched: program.Label(defaultLabel) - program.Ret(defaultAction) + program.Ret(options.DefaultAction) // Label if the architecture didn't match: program.Label(badArchLabel) - program.Ret(badArchAction) + program.Ret(options.BadArchAction) insns, err := program.program.Instructions() if err != nil { diff --git a/pkg/seccomp/seccomp_test.go b/pkg/seccomp/seccomp_test.go index ae18af546..4fc21666a 100644 --- a/pkg/seccomp/seccomp_test.go +++ b/pkg/seccomp/seccomp_test.go @@ -70,12 +70,11 @@ func TestBasic(t *testing.T) { } for _, test := range []struct { - name string - ruleSets []RuleSet - wantPanic bool - defaultAction linux.BPFAction - badArchAction linux.BPFAction - specs []spec + name string + ruleSets []RuleSet + wantPanic bool + options ProgramOptions + specs []spec }{ { name: "Single syscall", @@ -85,8 +84,10 @@ func TestBasic(t *testing.T) { Action: linux.SECCOMP_RET_ALLOW, }, }, - defaultAction: linux.SECCOMP_RET_TRAP, - badArchAction: linux.SECCOMP_RET_KILL_THREAD, + options: ProgramOptions{ + DefaultAction: linux.SECCOMP_RET_TRAP, + BadArchAction: linux.SECCOMP_RET_KILL_THREAD, + }, specs: []spec{ { desc: "syscall allowed", @@ -119,8 +120,10 @@ func TestBasic(t *testing.T) { Action: linux.SECCOMP_RET_TRAP, }, }, - defaultAction: linux.SECCOMP_RET_KILL_THREAD, - badArchAction: linux.SECCOMP_RET_KILL_THREAD, + options: ProgramOptions{ + DefaultAction: linux.SECCOMP_RET_KILL_THREAD, + BadArchAction: linux.SECCOMP_RET_KILL_THREAD, + }, specs: []spec{ { desc: "allowed (1a)", @@ -156,8 +159,10 @@ func TestBasic(t *testing.T) { Action: linux.SECCOMP_RET_ALLOW, }, }, - defaultAction: linux.SECCOMP_RET_TRAP, - badArchAction: linux.SECCOMP_RET_KILL_THREAD, + options: ProgramOptions{ + DefaultAction: linux.SECCOMP_RET_TRAP, + BadArchAction: linux.SECCOMP_RET_KILL_THREAD, + }, specs: []spec{ { desc: "allowed (1)", @@ -211,8 +216,10 @@ func TestBasic(t *testing.T) { Action: linux.SECCOMP_RET_ALLOW, }, }, - defaultAction: linux.SECCOMP_RET_TRAP, - badArchAction: linux.SECCOMP_RET_KILL_THREAD, + options: ProgramOptions{ + DefaultAction: linux.SECCOMP_RET_TRAP, + BadArchAction: linux.SECCOMP_RET_KILL_THREAD, + }, specs: []spec{ { desc: "arch (123)", @@ -231,8 +238,10 @@ func TestBasic(t *testing.T) { Action: linux.SECCOMP_RET_ALLOW, }, }, - defaultAction: linux.SECCOMP_RET_TRAP, - badArchAction: linux.SECCOMP_RET_KILL_THREAD, + options: ProgramOptions{ + DefaultAction: linux.SECCOMP_RET_TRAP, + BadArchAction: linux.SECCOMP_RET_KILL_THREAD, + }, specs: []spec{ { desc: "action trap", @@ -254,8 +263,10 @@ func TestBasic(t *testing.T) { Action: linux.SECCOMP_RET_ALLOW, }, }, - defaultAction: linux.SECCOMP_RET_TRAP, - badArchAction: linux.SECCOMP_RET_KILL_THREAD, + options: ProgramOptions{ + DefaultAction: linux.SECCOMP_RET_TRAP, + BadArchAction: linux.SECCOMP_RET_KILL_THREAD, + }, specs: []spec{ { desc: "allowed", @@ -286,8 +297,10 @@ func TestBasic(t *testing.T) { Action: linux.SECCOMP_RET_ALLOW, }, }, - defaultAction: linux.SECCOMP_RET_TRAP, - badArchAction: linux.SECCOMP_RET_KILL_THREAD, + options: ProgramOptions{ + DefaultAction: linux.SECCOMP_RET_TRAP, + BadArchAction: linux.SECCOMP_RET_KILL_THREAD, + }, specs: []spec{ { desc: "match first rule", @@ -335,8 +348,10 @@ func TestBasic(t *testing.T) { Action: linux.SECCOMP_RET_ALLOW, }, }, - defaultAction: linux.SECCOMP_RET_TRAP, - badArchAction: linux.SECCOMP_RET_KILL_THREAD, + options: ProgramOptions{ + DefaultAction: linux.SECCOMP_RET_TRAP, + BadArchAction: linux.SECCOMP_RET_KILL_THREAD, + }, specs: []spec{ { desc: "hit first rule", @@ -381,8 +396,10 @@ func TestBasic(t *testing.T) { Action: linux.SECCOMP_RET_ALLOW, }, }, - defaultAction: linux.SECCOMP_RET_TRAP, - badArchAction: linux.SECCOMP_RET_KILL_THREAD, + options: ProgramOptions{ + DefaultAction: linux.SECCOMP_RET_TRAP, + BadArchAction: linux.SECCOMP_RET_KILL_THREAD, + }, specs: []spec{ { desc: "argument allowed (all match)", @@ -427,8 +444,10 @@ func TestBasic(t *testing.T) { Action: linux.SECCOMP_RET_ALLOW, }, }, - defaultAction: linux.SECCOMP_RET_TRAP, - badArchAction: linux.SECCOMP_RET_KILL_THREAD, + options: ProgramOptions{ + DefaultAction: linux.SECCOMP_RET_TRAP, + BadArchAction: linux.SECCOMP_RET_KILL_THREAD, + }, specs: []spec{ { desc: "arg allowed", @@ -475,8 +494,10 @@ func TestBasic(t *testing.T) { Action: linux.SECCOMP_RET_ALLOW, }, }, - defaultAction: linux.SECCOMP_RET_TRAP, - badArchAction: linux.SECCOMP_RET_KILL_THREAD, + options: ProgramOptions{ + DefaultAction: linux.SECCOMP_RET_TRAP, + BadArchAction: linux.SECCOMP_RET_KILL_THREAD, + }, specs: []spec{ { desc: "high 32bits greater", @@ -518,8 +539,10 @@ func TestBasic(t *testing.T) { Action: linux.SECCOMP_RET_ALLOW, }, }, - defaultAction: linux.SECCOMP_RET_TRAP, - badArchAction: linux.SECCOMP_RET_KILL_THREAD, + options: ProgramOptions{ + DefaultAction: linux.SECCOMP_RET_TRAP, + BadArchAction: linux.SECCOMP_RET_KILL_THREAD, + }, specs: []spec{ { desc: "arg allowed", @@ -564,8 +587,10 @@ func TestBasic(t *testing.T) { Action: linux.SECCOMP_RET_ALLOW, }, }, - defaultAction: linux.SECCOMP_RET_TRAP, - badArchAction: linux.SECCOMP_RET_KILL_THREAD, + options: ProgramOptions{ + DefaultAction: linux.SECCOMP_RET_TRAP, + BadArchAction: linux.SECCOMP_RET_KILL_THREAD, + }, specs: []spec{ { desc: "high 32bits greater", @@ -607,8 +632,10 @@ func TestBasic(t *testing.T) { Action: linux.SECCOMP_RET_ALLOW, }, }, - defaultAction: linux.SECCOMP_RET_TRAP, - badArchAction: linux.SECCOMP_RET_KILL_THREAD, + options: ProgramOptions{ + DefaultAction: linux.SECCOMP_RET_TRAP, + BadArchAction: linux.SECCOMP_RET_KILL_THREAD, + }, specs: []spec{ { desc: "arg allowed (both greater)", @@ -658,8 +685,10 @@ func TestBasic(t *testing.T) { Action: linux.SECCOMP_RET_ALLOW, }, }, - defaultAction: linux.SECCOMP_RET_TRAP, - badArchAction: linux.SECCOMP_RET_KILL_THREAD, + options: ProgramOptions{ + DefaultAction: linux.SECCOMP_RET_TRAP, + BadArchAction: linux.SECCOMP_RET_KILL_THREAD, + }, specs: []spec{ { desc: "high 32bits greater", @@ -701,8 +730,10 @@ func TestBasic(t *testing.T) { Action: linux.SECCOMP_RET_ALLOW, }, }, - defaultAction: linux.SECCOMP_RET_TRAP, - badArchAction: linux.SECCOMP_RET_KILL_THREAD, + options: ProgramOptions{ + DefaultAction: linux.SECCOMP_RET_TRAP, + BadArchAction: linux.SECCOMP_RET_KILL_THREAD, + }, specs: []spec{ { desc: "arg allowed", @@ -752,8 +783,10 @@ func TestBasic(t *testing.T) { Action: linux.SECCOMP_RET_ALLOW, }, }, - defaultAction: linux.SECCOMP_RET_TRAP, - badArchAction: linux.SECCOMP_RET_KILL_THREAD, + options: ProgramOptions{ + DefaultAction: linux.SECCOMP_RET_TRAP, + BadArchAction: linux.SECCOMP_RET_KILL_THREAD, + }, specs: []spec{ { desc: "high 32bits greater", @@ -796,8 +829,10 @@ func TestBasic(t *testing.T) { Action: linux.SECCOMP_RET_ALLOW, }, }, - defaultAction: linux.SECCOMP_RET_TRAP, - badArchAction: linux.SECCOMP_RET_KILL_THREAD, + options: ProgramOptions{ + DefaultAction: linux.SECCOMP_RET_TRAP, + BadArchAction: linux.SECCOMP_RET_KILL_THREAD, + }, specs: []spec{ { desc: "arg allowed", @@ -846,8 +881,10 @@ func TestBasic(t *testing.T) { Action: linux.SECCOMP_RET_ALLOW, }, }, - defaultAction: linux.SECCOMP_RET_TRAP, - badArchAction: linux.SECCOMP_RET_KILL_THREAD, + options: ProgramOptions{ + DefaultAction: linux.SECCOMP_RET_TRAP, + BadArchAction: linux.SECCOMP_RET_KILL_THREAD, + }, specs: []spec{ { desc: "arg allowed (low order mandatory bit)", @@ -913,8 +950,10 @@ func TestBasic(t *testing.T) { Action: linux.SECCOMP_RET_ALLOW, }, }, - defaultAction: linux.SECCOMP_RET_TRAP, - badArchAction: linux.SECCOMP_RET_KILL_THREAD, + options: ProgramOptions{ + DefaultAction: linux.SECCOMP_RET_TRAP, + BadArchAction: linux.SECCOMP_RET_KILL_THREAD, + }, specs: []spec{ { desc: "zero allowed", @@ -975,8 +1014,10 @@ func TestBasic(t *testing.T) { Action: linux.SECCOMP_RET_ALLOW, }, }, - defaultAction: linux.SECCOMP_RET_TRAP, - badArchAction: linux.SECCOMP_RET_KILL_THREAD, + options: ProgramOptions{ + DefaultAction: linux.SECCOMP_RET_TRAP, + BadArchAction: linux.SECCOMP_RET_KILL_THREAD, + }, specs: []spec{ { desc: "allowed", @@ -1001,7 +1042,7 @@ func TestBasic(t *testing.T) { t.Helper() }() var err error - instrs, _, err = BuildProgram(test.ruleSets, test.defaultAction, test.badArchAction) + instrs, _, err = BuildProgram(test.ruleSets, test.options) if err != nil { t.Fatalf("BuildProgram() got error: %v", err) } @@ -1052,7 +1093,10 @@ func TestRandom(t *testing.T) { Rules: syscallRules, Action: linux.SECCOMP_RET_ALLOW, }, - }, linux.SECCOMP_RET_TRAP, linux.SECCOMP_RET_KILL_THREAD) + }, ProgramOptions{ + DefaultAction: linux.SECCOMP_RET_TRAP, + BadArchAction: linux.SECCOMP_RET_KILL_THREAD, + }) if err != nil { t.Fatalf("buildProgram() got error: %v", err) } diff --git a/pkg/seccomp/victim/seccomp_test_victim.go b/pkg/seccomp/victim/seccomp_test_victim.go index 88d0a40f1..8d6e18e18 100644 --- a/pkg/seccomp/victim/seccomp_test_victim.go +++ b/pkg/seccomp/victim/seccomp_test_victim.go @@ -107,7 +107,7 @@ func main() { }) } - if err := seccomp.Install(syscalls, seccomp.NewSyscallRules()); err != nil { + if err := seccomp.Install(syscalls, seccomp.NewSyscallRules(), seccomp.DefaultProgramOptions()); err != nil { fmt.Printf("Failed to install seccomp: %v\n", err) os.Exit(1) } diff --git a/pkg/sentry/platform/kvm/machine.go b/pkg/sentry/platform/kvm/machine.go index 9c539c896..63d61ec8c 100644 --- a/pkg/sentry/platform/kvm/machine.go +++ b/pkg/sentry/platform/kvm/machine.go @@ -791,7 +791,10 @@ func seccompMmapRules(m *machine) { Action: linux.SECCOMP_RET_TRAP, }, } - instrs, _, err := seccomp.BuildProgram(rules, linux.SECCOMP_RET_ALLOW, linux.SECCOMP_RET_ALLOW) + instrs, _, err := seccomp.BuildProgram(rules, seccomp.ProgramOptions{ + DefaultAction: linux.SECCOMP_RET_ALLOW, + BadArchAction: linux.SECCOMP_RET_ALLOW, + }) if err != nil { panic(fmt.Sprintf("failed to build rules: %v", err)) } diff --git a/pkg/sentry/platform/ptrace/subprocess_linux.go b/pkg/sentry/platform/ptrace/subprocess_linux.go index b74dd44cd..175da98c9 100644 --- a/pkg/sentry/platform/ptrace/subprocess_linux.go +++ b/pkg/sentry/platform/ptrace/subprocess_linux.go @@ -114,7 +114,10 @@ func attachedThread(flags uintptr, defaultAction linux.BPFAction) (*thread, erro }) } rules = appendArchSeccompRules(rules, defaultAction) - instrs, _, err := seccomp.BuildProgram(rules, defaultAction, defaultAction) + instrs, _, err := seccomp.BuildProgram(rules, seccomp.ProgramOptions{ + DefaultAction: defaultAction, + BadArchAction: defaultAction, + }) if err != nil { return nil, err } diff --git a/pkg/sentry/platform/systrap/subprocess_linux.go b/pkg/sentry/platform/systrap/subprocess_linux.go index c2d5b2e3a..b3ac30bba 100644 --- a/pkg/sentry/platform/systrap/subprocess_linux.go +++ b/pkg/sentry/platform/systrap/subprocess_linux.go @@ -130,7 +130,10 @@ func attachedThread(flags uintptr, defaultAction linux.BPFAction) (*thread, erro rules = append(rules, ruleSet) rules = appendArchSeccompRules(rules) } - instrs, _, err := seccomp.BuildProgram(rules, defaultAction, defaultAction) + instrs, _, err := seccomp.BuildProgram(rules, seccomp.ProgramOptions{ + DefaultAction: defaultAction, + BadArchAction: defaultAction, + }) if err != nil { return nil, err } diff --git a/pkg/sentry/platform/systrap/sysmsg_thread.go b/pkg/sentry/platform/systrap/sysmsg_thread.go index cb6f04a3d..fc0b48762 100644 --- a/pkg/sentry/platform/systrap/sysmsg_thread.go +++ b/pkg/sentry/platform/systrap/sysmsg_thread.go @@ -146,7 +146,10 @@ func sysmsgThreadRules(stubStart uintptr) []bpf.Instruction { Action: linux.SECCOMP_RET_ALLOW, }, }...) - instrs, _, err := seccomp.BuildProgram(rules, linux.SECCOMP_RET_TRAP, linux.SECCOMP_RET_TRAP) + instrs, _, err := seccomp.BuildProgram(rules, seccomp.ProgramOptions{ + DefaultAction: linux.SECCOMP_RET_TRAP, + BadArchAction: linux.SECCOMP_RET_TRAP, + }) if err != nil { panic(fmt.Sprintf("failed to build rules for sysmsg threads: %v", err)) } diff --git a/runsc/boot/filter/dumpfilter/dumpfilter.go b/runsc/boot/filter/dumpfilter/dumpfilter.go index 06474d746..5a707aeaf 100644 --- a/runsc/boot/filter/dumpfilter/dumpfilter.go +++ b/runsc/boot/filter/dumpfilter/dumpfilter.go @@ -49,7 +49,10 @@ func main() { Rules: rules, Action: linux.SECCOMP_RET_ALLOW, }, - }, linux.SECCOMP_RET_ERRNO, linux.SECCOMP_RET_ERRNO) + }, seccomp.ProgramOptions{ + DefaultAction: linux.SECCOMP_RET_ERRNO, + BadArchAction: linux.SECCOMP_RET_ERRNO, + }) if err != nil { log.Warningf("%v", err) os.Exit(1) diff --git a/runsc/boot/filter/filter.go b/runsc/boot/filter/filter.go index 6b9a91568..cc31f6a1a 100644 --- a/runsc/boot/filter/filter.go +++ b/runsc/boot/filter/filter.go @@ -79,7 +79,7 @@ func Rules(opt Options) (seccomp.SyscallRules, seccomp.SyscallRules) { // Install seccomp filters based on the given platform. func Install(opt Options) error { rules, denyRules := Rules(opt) - return seccomp.Install(rules, denyRules) + return seccomp.Install(rules, denyRules, seccomp.DefaultProgramOptions()) } // Report writes a warning message to the log. diff --git a/runsc/fsgofer/filter/filter.go b/runsc/fsgofer/filter/filter.go index 9e03f9d91..710aeb760 100644 --- a/runsc/fsgofer/filter/filter.go +++ b/runsc/fsgofer/filter/filter.go @@ -53,7 +53,7 @@ func Install(opt Options) error { // when not enabled. s.Merge(instrumentationFilters()) - return seccomp.Install(s, seccomp.DenyNewExecMappings) + return seccomp.Install(s, seccomp.DenyNewExecMappings, seccomp.DefaultProgramOptions()) } // report writes a warning message to the log. diff --git a/runsc/specutils/seccomp/seccomp.go b/runsc/specutils/seccomp/seccomp.go index 61e61ecac..fc1711d26 100644 --- a/runsc/specutils/seccomp/seccomp.go +++ b/runsc/specutils/seccomp/seccomp.go @@ -51,7 +51,10 @@ func BuildProgram(s *specs.LinuxSeccomp) (bpf.Program, error) { return bpf.Program{}, fmt.Errorf("invalid seccomp rules: %w", err) } - instrs, _, err := seccomp.BuildProgram(ruleset, defaultAction, killThreadAction) + instrs, _, err := seccomp.BuildProgram(ruleset, seccomp.ProgramOptions{ + DefaultAction: defaultAction, + BadArchAction: killThreadAction, + }) if err != nil { return bpf.Program{}, fmt.Errorf("building seccomp program: %w", err) } diff --git a/test/secbench/secbench.go b/test/secbench/secbench.go index c9f13732c..766d3009e 100644 --- a/test/secbench/secbench.go +++ b/test/secbench/secbench.go @@ -49,7 +49,10 @@ func BenchFromSyscallRules(b *testing.B, name string, profile secbenchdef.Profil Rules: rules, Action: linux.SECCOMP_RET_ALLOW, }, - }, linux.SECCOMP_RET_ERRNO, linux.SECCOMP_RET_ERRNO) + }, seccomp.ProgramOptions{ + DefaultAction: linux.SECCOMP_RET_ERRNO, + BadArchAction: linux.SECCOMP_RET_ERRNO, + }) if err != nil { b.Fatalf("BuildProgram() failed: %v", err) }