diff --git a/pkg/seccomp/seccomp.go b/pkg/seccomp/seccomp.go index 24f07dfc0..5dfa9cf3d 100644 --- a/pkg/seccomp/seccomp.go +++ b/pkg/seccomp/seccomp.go @@ -18,7 +18,6 @@ package seccomp import ( "fmt" - "reflect" "sort" "gvisor.dev/gvisor/pkg/abi/linux" @@ -31,7 +30,7 @@ const ( skipOneInst = 1 // defaultLabel is the label for the default action. - defaultLabel = "default_action" + defaultLabel = label("default_action") ) // NonNegativeFDCheck ensures an FD argument is a non-negative int. @@ -128,31 +127,175 @@ var SyscallName = func(sysno uintptr) string { return fmt.Sprintf("syscall_%d", sysno) } +// syscallProgram builds a BPF program for applying syscall rules. +// It is a stateful struct that is updated as the program is built. +type syscallProgram struct { + // program is the underlying BPF program being built. + program *bpf.ProgramBuilder +} + +// Stmt adds a statement to the program. +func (s *syscallProgram) Stmt(code uint16, k uint32) { + s.program.AddStmt(code, k) +} + +// label is a custom label type which is returned by `labelSet`. +type label string + +// JumpTo adds a jump instruction to the program, jumping to the given label. +func (s *syscallProgram) JumpTo(label label) { + s.program.AddDirectJumpLabel(string(label)) +} + +// If checks a condition and jumps to a label if the condition is true. +// If the condition is false, the program continues executing (no jumping). +func (s *syscallProgram) If(code uint16, k uint32, jt label) { + s.program.AddJump(code, k, 0, skipOneInst) + s.JumpTo(jt) +} + +// IfNot checks a condition and jumps to a label if the condition is false. +// If the condition is true, the program continues executing (no jumping). +func (s *syscallProgram) IfNot(code uint16, k uint32, jf label) { + s.program.AddJump(code, k, skipOneInst, 0) + s.JumpTo(jf) +} + +// Ret adds a return instruction to the program. +func (s *syscallProgram) Ret(action linux.BPFAction) { + s.Stmt(bpf.Ret|bpf.K, uint32(action)) +} + +// Label adds a label to the program. +// It panics if this label has already been added to the program. +func (s *syscallProgram) Label(label label) { + if err := s.program.AddLabel(string(label)); err != nil { + panic(fmt.Sprintf("cannot add label %q to program: %v", label, err)) + } +} + +// Record starts recording the instructions added to the program from now on. +// It returns a syscallFragment which can be used to perform assertions on the +// possible set of outcomes of the set of instruction that has been added +// since `Record` was called. +func (s *syscallProgram) Record() syscallProgramFragment { + return syscallProgramFragment{s.program.Record()} +} + +// syscallProgramFragment represents a fragment of the syscall program. +type syscallProgramFragment struct { + getFragment func() bpf.ProgramFragment +} + +// MustHaveJumpedTo asserts that the fragment must jump to one of the +// given labels. +// The fragment may not jump to any other label, nor return, nor fall through. +func (f syscallProgramFragment) MustHaveJumpedTo(labels ...label) { + fragment := f.getFragment() + outcomes := fragment.Outcomes() + if outcomes.MayFallThrough { + panic(fmt.Sprintf("fragment %v may fall through", fragment)) + } + if outcomes.MayReturn { + panic(fmt.Sprintf("fragment %v may return", fragment)) + } + if outcomes.MayJumpToKnownOffsetBeyondFragment { + panic(fmt.Sprintf("fragment %v may jump to an offset beyond the fragment", fragment)) + } + for jumpLabel := range outcomes.MayJumpToUnresolvedLabels { + found := false + for _, wantLabel := range labels { + if jumpLabel == string(wantLabel) { + found = true + break + } + } + if !found { + panic(fmt.Sprintf("fragment %v may jump to a label %q which is not one of %v", fragment, jumpLabel, labels)) + } + } +} + +// labelSet keeps track of labels that individual rules may jump to if they +// either match or mismatch. +// It can generate unique label names, and can be used recursively within +// rules. +type labelSet struct { + // prefix is a label prefix used when generating label names. + prefix string + + // labelCounter is used to generate unique label names. + labelCounter int + + // ruleMatched is the label that a rule should jump to if it matches. + ruleMatched label + + // ruleMismatched is the label that a rule should jump to if it doesn't + // match. + ruleMismatched label +} + +// NewLabel returns a new unique label. +func (l *labelSet) NewLabel() label { + newLabel := label(fmt.Sprintf("%s#%d", l.prefix, l.labelCounter)) + l.labelCounter++ + return newLabel +} + +// Matched returns the label to jump to if the rule matches. +func (l *labelSet) Matched() label { + return l.ruleMatched +} + +// Mismatched returns the label to jump to if the rule does not match. +func (l *labelSet) Mismatched() label { + return l.ruleMismatched +} + +// Push creates a new labelSet meant to be used in a recursive context of the +// rule currently being rendered. +// Labels generated by this new labelSet will have `labelSuffix` appended to +// this labelSet's current prefix, and will have its matched/mismatched labels +// point to the given labels. +func (l *labelSet) Push(labelSuffix string, newRuleMatch, newRuleMismatch label) *labelSet { + newPrefix := labelSuffix + if l.prefix != "" { + newPrefix = fmt.Sprintf("%s_%s", l.prefix, labelSuffix) + } + return &labelSet{ + prefix: newPrefix, + ruleMatched: newRuleMatch, + ruleMismatched: newRuleMismatch, + } +} + // 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, error) { - program := bpf.NewProgramBuilder() + program := &syscallProgram{ + program: bpf.NewProgramBuilder(), + } // Be paranoid and check that syscall is done in the expected architecture. // // A = seccomp_data.arch - // if (A != AUDIT_ARCH) goto defaultAction. - program.AddStmt(bpf.Ld|bpf.Abs|bpf.W, seccompDataOffsetArch) - // defaultLabel is at the bottom of the program. The size of program - // may exceeds 255 lines, which is the limit of a condition jump. - program.AddJump(bpf.Jmp|bpf.Jeq|bpf.K, LINUX_AUDIT_ARCH, skipOneInst, 0) - program.AddStmt(bpf.Ret|bpf.K, uint32(badArchAction)) + // if (A != AUDIT_ARCH) goto badArchLabel. + badArchLabel := label("badarch") + program.Stmt(bpf.Ld|bpf.Abs|bpf.W, seccompDataOffsetArch) + program.IfNot(bpf.Jmp|bpf.Jeq|bpf.K, LINUX_AUDIT_ARCH, badArchLabel) if err := buildIndex(rules, program); err != nil { return nil, err } - // Exhausted: return defaultAction. - if err := program.AddLabel(defaultLabel); err != nil { - return nil, err - } - program.AddStmt(bpf.Ret|bpf.K, uint32(defaultAction)) + // Default label if none of the rules matched: + program.Label(defaultLabel) + program.Ret(defaultAction) - insns, err := program.Instructions() + // Label if the architecture didn't match: + program.Label(badArchLabel) + program.Ret(badArchAction) + + insns, err := program.program.Instructions() if err != nil { return insns, err } @@ -164,7 +307,7 @@ func BuildProgram(rules []RuleSet, defaultAction, badArchAction linux.BPFAction) } // buildIndex builds a BST to quickly search through all syscalls. -func buildIndex(rules []RuleSet, program *bpf.ProgramBuilder) error { +func buildIndex(rules []RuleSet, program *syscallProgram) error { // Do nothing if rules is empty. if len(rules) == 0 { return nil @@ -199,7 +342,7 @@ func buildIndex(rules []RuleSet, program *bpf.ProgramBuilder) error { // Load syscall number into A and run through BST. // // A = seccomp_data.nr - program.AddStmt(bpf.Ld|bpf.Abs|bpf.W, seccompDataOffsetNR) + program.Stmt(bpf.Ld|bpf.Abs|bpf.W, seccompDataOffsetNR) return root.traverse(buildBSTProgram, rules, program) } @@ -217,209 +360,6 @@ func createBST(syscalls []uintptr) *node { return &parent } -func vsyscallViolationLabel(ruleSetIdx int, sysno uintptr) string { - return fmt.Sprintf("vsyscallViolation_%v_%v", ruleSetIdx, sysno) -} - -func ruleViolationLabel(ruleSetIdx int, sysno uintptr, idx int) string { - return fmt.Sprintf("ruleViolation_%v_%v_%v", ruleSetIdx, sysno, idx) -} - -func ruleLabel(ruleSetIdx int, sysno uintptr, idx int, name string) string { - return fmt.Sprintf("rule_%v_%v_%v_%v", ruleSetIdx, sysno, idx, name) -} - -func checkArgsLabel(sysno uintptr) string { - return fmt.Sprintf("checkArgs_%v", sysno) -} - -// addSyscallArgsCheck adds argument checks for a single system call. It does -// not insert a jump to the default action at the end and it is the -// responsibility of the caller to insert an appropriate jump after calling -// this function. -func addSyscallArgsCheck(p *bpf.ProgramBuilder, rules []Rule, action linux.BPFAction, ruleSetIdx int, sysno uintptr) error { - for ruleidx, rule := range rules { - labelled := false - for i, arg := range rule { - if arg != nil { - // Break out early if using AnyValue since no further - // instructions are required. - if _, ok := arg.(AnyValue); ok { - continue - } - - // Determine the data offset for low and high bits of input. - dataOffsetLow := seccompDataOffsetArgLow(i) - dataOffsetHigh := seccompDataOffsetArgHigh(i) - if i == RuleIP { - dataOffsetLow = seccompDataOffsetIPLow - dataOffsetHigh = seccompDataOffsetIPHigh - } - - // Add the conditional operation. Input values to the BPF - // program are 64bit values. However, comparisons in BPF can - // only be done on 32bit values. This means that we need to do - // multiple BPF comparisons in order to do one logical 64bit - // comparison. - switch a := arg.(type) { - case EqualTo: - // EqualTo checks that both the higher and lower 32bits are equal. - high, low := uint32(a>>32), uint32(a) - - // Assert that the lower 32bits are equal. - // arg_low == low ? continue : violation - p.AddStmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetLow) - p.AddJumpFalseLabel(bpf.Jmp|bpf.Jeq|bpf.K, low, 0, ruleViolationLabel(ruleSetIdx, sysno, ruleidx)) - - // Assert that the lower 32bits are also equal. - // arg_high == high ? continue/success : violation - p.AddStmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetHigh) - p.AddJumpFalseLabel(bpf.Jmp|bpf.Jeq|bpf.K, high, 0, ruleViolationLabel(ruleSetIdx, sysno, ruleidx)) - labelled = true - case NotEqual: - // NotEqual checks that either the higher or lower 32bits - // are *not* equal. - high, low := uint32(a>>32), uint32(a) - labelGood := fmt.Sprintf("ne%v", i) - - // Check if the higher 32bits are (not) equal. - // arg_low == low ? continue : success - p.AddStmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetLow) - p.AddJumpFalseLabel(bpf.Jmp|bpf.Jeq|bpf.K, low, 0, ruleLabel(ruleSetIdx, sysno, ruleidx, labelGood)) - - // Assert that the lower 32bits are not equal (assuming - // higher bits are equal). - // arg_high == high ? violation : continue/success - p.AddStmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetHigh) - p.AddJumpTrueLabel(bpf.Jmp|bpf.Jeq|bpf.K, high, ruleViolationLabel(ruleSetIdx, sysno, ruleidx), 0) - p.AddLabel(ruleLabel(ruleSetIdx, sysno, ruleidx, labelGood)) - labelled = true - case GreaterThan: - // GreaterThan checks that the higher 32bits is greater - // *or* that the higher 32bits are equal and the lower - // 32bits are greater. - high, low := uint32(a>>32), uint32(a) - labelGood := fmt.Sprintf("gt%v", i) - - // Assert the higher 32bits are greater than or equal. - // arg_high >= high ? continue : violation (arg_high < high) - p.AddStmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetHigh) - p.AddJumpFalseLabel(bpf.Jmp|bpf.Jge|bpf.K, high, 0, ruleViolationLabel(ruleSetIdx, sysno, ruleidx)) - - // Assert that the lower 32bits are greater. - // arg_high == high ? continue : success (arg_high > high) - p.AddJumpFalseLabel(bpf.Jmp|bpf.Jeq|bpf.K, high, 0, ruleLabel(ruleSetIdx, sysno, ruleidx, labelGood)) - // arg_low > low ? continue/success : violation (arg_high == high and arg_low <= low) - p.AddStmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetLow) - p.AddJumpFalseLabel(bpf.Jmp|bpf.Jgt|bpf.K, low, 0, ruleViolationLabel(ruleSetIdx, sysno, ruleidx)) - p.AddLabel(ruleLabel(ruleSetIdx, sysno, ruleidx, labelGood)) - labelled = true - case GreaterThanOrEqual: - // GreaterThanOrEqual checks that the higher 32bits is - // greater *or* that the higher 32bits are equal and the - // lower 32bits are greater than or equal. - high, low := uint32(a>>32), uint32(a) - labelGood := fmt.Sprintf("ge%v", i) - - // Assert the higher 32bits are greater than or equal. - // arg_high >= high ? continue : violation (arg_high < high) - p.AddStmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetHigh) - p.AddJumpFalseLabel(bpf.Jmp|bpf.Jge|bpf.K, high, 0, ruleViolationLabel(ruleSetIdx, sysno, ruleidx)) - // arg_high == high ? continue : success (arg_high > high) - p.AddJumpFalseLabel(bpf.Jmp|bpf.Jeq|bpf.K, high, 0, ruleLabel(ruleSetIdx, sysno, ruleidx, labelGood)) - - // Assert that the lower 32bits are greater (assuming the - // higher bits are equal). - // arg_low >= low ? continue/success : violation (arg_high == high and arg_low < low) - p.AddStmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetLow) - p.AddJumpFalseLabel(bpf.Jmp|bpf.Jge|bpf.K, low, 0, ruleViolationLabel(ruleSetIdx, sysno, ruleidx)) - p.AddLabel(ruleLabel(ruleSetIdx, sysno, ruleidx, labelGood)) - labelled = true - case LessThan: - // LessThan checks that the higher 32bits is less *or* that - // the higher 32bits are equal and the lower 32bits are - // less. - high, low := uint32(a>>32), uint32(a) - labelGood := fmt.Sprintf("lt%v", i) - - // Assert the higher 32bits are less than or equal. - // arg_high > high ? violation : continue - p.AddStmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetHigh) - p.AddJumpTrueLabel(bpf.Jmp|bpf.Jgt|bpf.K, high, ruleViolationLabel(ruleSetIdx, sysno, ruleidx), 0) - // arg_high == high ? continue : success (arg_high < high) - p.AddJumpFalseLabel(bpf.Jmp|bpf.Jeq|bpf.K, high, 0, ruleLabel(ruleSetIdx, sysno, ruleidx, labelGood)) - - // Assert that the lower 32bits are less (assuming the - // higher bits are equal). - // arg_low >= low ? violation : continue - p.AddStmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetLow) - p.AddJumpTrueLabel(bpf.Jmp|bpf.Jge|bpf.K, low, ruleViolationLabel(ruleSetIdx, sysno, ruleidx), 0) - p.AddLabel(ruleLabel(ruleSetIdx, sysno, ruleidx, labelGood)) - labelled = true - case LessThanOrEqual: - // LessThan checks that the higher 32bits is less *or* that - // the higher 32bits are equal and the lower 32bits are - // less than or equal. - high, low := uint32(a>>32), uint32(a) - labelGood := fmt.Sprintf("le%v", i) - - // Assert the higher 32bits are less than or equal. - // assert arg_high > high ? violation : continue - p.AddStmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetHigh) - p.AddJumpTrueLabel(bpf.Jmp|bpf.Jgt|bpf.K, high, ruleViolationLabel(ruleSetIdx, sysno, ruleidx), 0) - // arg_high == high ? continue : success - p.AddJumpFalseLabel(bpf.Jmp|bpf.Jeq|bpf.K, high, 0, ruleLabel(ruleSetIdx, sysno, ruleidx, labelGood)) - - // Assert the lower bits are less than or equal (assuming - // the higher bits are equal). - // arg_low > low ? violation : success - p.AddStmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetLow) - p.AddJumpTrueLabel(bpf.Jmp|bpf.Jgt|bpf.K, low, ruleViolationLabel(ruleSetIdx, sysno, ruleidx), 0) - p.AddLabel(ruleLabel(ruleSetIdx, sysno, ruleidx, labelGood)) - labelled = true - case maskedEqual: - // MaskedEqual checks that the bitwise AND of the value and - // mask are equal for both the higher and lower 32bits. - high, low := uint32(a.value>>32), uint32(a.value) - maskHigh, maskLow := uint32(a.mask>>32), uint32(a.mask) - - // Assert that the lower 32bits are equal when masked. - // A <- arg_low. - p.AddStmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetLow) - // A <- arg_low & maskLow - p.AddStmt(bpf.Alu|bpf.And|bpf.K, maskLow) - // Assert that arg_low & maskLow == low. - p.AddJumpFalseLabel(bpf.Jmp|bpf.Jeq|bpf.K, low, 0, ruleViolationLabel(ruleSetIdx, sysno, ruleidx)) - - // Assert that the higher 32bits are equal when masked. - // A <- arg_high - p.AddStmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetHigh) - // A <- arg_high & maskHigh - p.AddStmt(bpf.Alu|bpf.And|bpf.K, maskHigh) - // Assert that arg_high & maskHigh == high. - p.AddJumpFalseLabel(bpf.Jmp|bpf.Jeq|bpf.K, high, 0, ruleViolationLabel(ruleSetIdx, sysno, ruleidx)) - labelled = true - default: - return fmt.Errorf("unknown syscall rule type: %v", reflect.TypeOf(a)) - } - } - } - - // Matched, emit the given action. - p.AddStmt(bpf.Ret|bpf.K, uint32(action)) - - // Label the end of the rule if necessary. This is added for - // the jumps above when the argument check fails. - if labelled { - if err := p.AddLabel(ruleViolationLabel(ruleSetIdx, sysno, ruleidx)); err != nil { - return err - } - } - } - - return nil -} - // buildBSTProgram converts a binary tree started in 'root' into BPF code. The outline of the code // is as follows: // @@ -440,83 +380,58 @@ func addSyscallArgsCheck(p *bpf.ProgramBuilder, rules []Rule, action linux.BPFAc // index_50: // SYS_LISTEN(50), leaf // // (A == 50) ? goto argument check : goto defaultLabel -func buildBSTProgram(n *node, rules []RuleSet, program *bpf.ProgramBuilder) error { +func buildBSTProgram(n *node, rules []RuleSet, program *syscallProgram) error { // Root node is never referenced by label, skip it. if !n.root { - if err := program.AddLabel(n.label()); err != nil { - return err - } + program.Label(n.label()) } + nodeLabelSet := &labelSet{prefix: string(n.label())} + sysno := n.value - program.AddJumpTrueLabel(bpf.Jmp|bpf.Jeq|bpf.K, uint32(sysno), checkArgsLabel(sysno), 0) + frag := program.Record() + checkArgsLabel := label(fmt.Sprintf("checkArgs_%d", sysno)) + program.If(bpf.Jmp|bpf.Jeq|bpf.K, uint32(sysno), checkArgsLabel) if n.left == nil && n.right == nil { // Leaf nodes don't require extra check. - program.AddDirectJumpLabel(defaultLabel) + program.JumpTo(defaultLabel) } else { - // Non-leaf node. Check which turn to take otherwise. Using direct jumps - // in case that the offset may exceed the limit of a conditional jump (255) - program.AddJump(bpf.Jmp|bpf.Jgt|bpf.K, uint32(sysno), 0, skipOneInst) - program.AddDirectJumpLabel(n.right.label()) - program.AddDirectJumpLabel(n.left.label()) + // Non-leaf node. Check which turn to take. + program.If(bpf.Jmp|bpf.Jgt|bpf.K, uint32(sysno), n.right.label()) + program.JumpTo(n.left.label()) } + frag.MustHaveJumpedTo(n.left.label(), n.right.label(), checkArgsLabel) + program.Label(checkArgsLabel) - if err := program.AddLabel(checkArgsLabel(sysno)); err != nil { - return err - } - - emitted := false for ruleSetIdx, rs := range rules { - if _, ok := rs.Rules[sysno]; ok { - // If there are no rules, then this will always match. - // Remember we've done this so that we can emit a - // sensible error. We can't catch all overlaps, but we - // can catch this one at least. - if emitted { - return fmt.Errorf("unreachable action for %v: 0x%x (rule set %d)", SyscallName(sysno), rs.Action, ruleSetIdx) - } - - // Emit a vsyscall check if this rule requires a - // Vsyscall match. This rule ensures that the top bit - // is set in the instruction pointer, which is where - // the vsyscall page will be mapped. - if rs.Vsyscall { - program.AddStmt(bpf.Ld|bpf.Abs|bpf.W, seccompDataOffsetIPHigh) - program.AddJumpFalseLabel(bpf.Jmp|bpf.Jset|bpf.K, 0x80000000, 0, vsyscallViolationLabel(ruleSetIdx, sysno)) - } - - // Emit matchers. - if len(rs.Rules[sysno]) == 0 { - // This is a blanket action. - program.AddStmt(bpf.Ret|bpf.K, uint32(rs.Action)) - emitted = true - } else { - // Add an argument check for these particular - // arguments. This will continue execution and - // check the next rule set. We need to ensure - // that at the very end, we insert a direct - // jump label for the unmatched case. - if err := addSyscallArgsCheck(program, rs.Rules[sysno], rs.Action, ruleSetIdx, sysno); err != nil { - return err - } - } - - // If there was a Vsyscall check for this rule, then we - // need to add an appropriate label for the jump above. - if rs.Vsyscall { - if err := program.AddLabel(vsyscallViolationLabel(ruleSetIdx, sysno)); err != nil { - return err - } - } + rule, ok := rs.Rules[sysno] + if !ok { + continue } - } + ruleSetLabelSet := nodeLabelSet.Push(fmt.Sprintf("rs[%d]", ruleSetIdx), nodeLabelSet.NewLabel(), nodeLabelSet.NewLabel()) + frag := program.Record() - // Not matched? We only need to insert a jump to the default label if - // not default action has been emitted for this call. - if !emitted { - program.AddDirectJumpLabel(defaultLabel) - } + // Emit a vsyscall check if this rule requires a + // Vsyscall match. This rule ensures that the top bit + // is set in the instruction pointer, which is where + // the vsyscall page will be mapped. + if rs.Vsyscall { + program.Stmt(bpf.Ld|bpf.Abs|bpf.W, seccompDataOffsetIPHigh) + program.IfNot(bpf.Jmp|bpf.Jset|bpf.K, 0x80000000, ruleSetLabelSet.Mismatched()) + } + // Add an argument check for these particular + // arguments. This will continue execution and + // check the next rule set. We need to ensure + // that at the very end, we insert a direct + // jump label for the unmatched case. + rule.Render(program, ruleSetLabelSet) + frag.MustHaveJumpedTo(ruleSetLabelSet.Matched(), ruleSetLabelSet.Mismatched()) + program.Label(ruleSetLabelSet.Matched()) + program.Ret(rs.Action) + program.Label(ruleSetLabelSet.Mismatched()) + } + program.JumpTo(defaultLabel) return nil } @@ -531,24 +446,24 @@ type node struct { // label returns the label corresponding to this node. // // If n is nil, then the defaultLabel is returned. -func (n *node) label() string { +func (n *node) label() label { if n == nil { return defaultLabel } - return fmt.Sprintf("index_%v", n.value) + return label(fmt.Sprintf("node_%d", n.value)) } -type traverseFunc func(*node, []RuleSet, *bpf.ProgramBuilder) error +type traverseFunc func(*node, []RuleSet, *syscallProgram) error -func (n *node) traverse(fn traverseFunc, rules []RuleSet, p *bpf.ProgramBuilder) error { +func (n *node) traverse(fn traverseFunc, rules []RuleSet, program *syscallProgram) error { if n == nil { return nil } - if err := fn(n, rules, p); err != nil { + if err := fn(n, rules, program); err != nil { return err } - if err := n.left.traverse(fn, rules, p); err != nil { + if err := n.left.traverse(fn, rules, program); err != nil { return err } - return n.right.traverse(fn, rules, p) + return n.right.traverse(fn, rules, program) } diff --git a/pkg/seccomp/seccomp_rules.go b/pkg/seccomp/seccomp_rules.go index 99c494e0c..24bf8bf1f 100644 --- a/pkg/seccomp/seccomp_rules.go +++ b/pkg/seccomp/seccomp_rules.go @@ -16,8 +16,12 @@ package seccomp import ( "fmt" + "reflect" + "sort" + "strings" "golang.org/x/sys/unix" + "gvisor.dev/gvisor/pkg/bpf" ) // The offsets are based on the following struct in include/linux/seccomp.h. @@ -47,49 +51,49 @@ func seccompDataOffsetArgHigh(i int) uint32 { // AnyValue is marker to indicate any value will be accepted. type AnyValue struct{} -func (a AnyValue) String() (s string) { +func (AnyValue) String() string { return "*" } // EqualTo specifies a value that needs to be strictly matched. type EqualTo uintptr -func (a EqualTo) String() (s string) { +func (a EqualTo) String() string { return fmt.Sprintf("== %#x", uintptr(a)) } // NotEqual specifies a value that is strictly not equal. type NotEqual uintptr -func (a NotEqual) String() (s string) { +func (a NotEqual) String() string { return fmt.Sprintf("!= %#x", uintptr(a)) } // GreaterThan specifies a value that needs to be strictly smaller. type GreaterThan uintptr -func (a GreaterThan) String() (s string) { +func (a GreaterThan) String() string { return fmt.Sprintf("> %#x", uintptr(a)) } // GreaterThanOrEqual specifies a value that needs to be smaller or equal. type GreaterThanOrEqual uintptr -func (a GreaterThanOrEqual) String() (s string) { +func (a GreaterThanOrEqual) String() string { return fmt.Sprintf(">= %#x", uintptr(a)) } // LessThan specifies a value that needs to be strictly greater. type LessThan uintptr -func (a LessThan) String() (s string) { +func (a LessThan) String() string { return fmt.Sprintf("< %#x", uintptr(a)) } // LessThanOrEqual specifies a value that needs to be greater or equal. type LessThanOrEqual uintptr -func (a LessThanOrEqual) String() (s string) { +func (a LessThanOrEqual) String() string { return fmt.Sprintf("<= %#x", uintptr(a)) } @@ -98,7 +102,7 @@ type maskedEqual struct { value uintptr } -func (a maskedEqual) String() (s string) { +func (a maskedEqual) String() string { return fmt.Sprintf("& %#x == %#x", a.mask, a.value) } @@ -112,25 +116,277 @@ func MaskedEqual(mask, value uintptr) any { } } -// Rule stores the allowed syscall arguments. +// SyscallRule expresses a set of rules to verify the arguments of a specific +// syscall. +type SyscallRule interface { + // Render renders the syscall rule in the given `program`. + // The emitted instructions **must** end up jumping to either + // `labelSet.Matched()` or `labelSet.Mismatched()`; they may + // not "fall through" to whatever instructions will be added + // next into the program. + Render(program *syscallProgram, labelSet *labelSet) + + // String returns a human-readable string representing what the rule does. + String() string +} + +// MatchAll implements `SyscallRule` and matches everything. +type MatchAll struct{} + +// Render implements `SyscallRule.Render`. +func (MatchAll) Render(program *syscallProgram, labelSet *labelSet) { + program.JumpTo(labelSet.Matched()) +} + +// String implements `SyscallRule.String`. +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. +type Or []SyscallRule + +// Render implements `SyscallRule.Render`. +func (or Or) Render(program *syscallProgram, labelSet *labelSet) { + // 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 { + frag := program.Record() + nextRuleLabel := labelSet.NewLabel() + rule.Render(program, labelSet.Push(fmt.Sprintf("or[%d]", i), labelSet.Matched(), nextRuleLabel)) + frag.MustHaveJumpedTo(labelSet.Matched(), nextRuleLabel) + program.Label(nextRuleLabel) + } + program.JumpTo(labelSet.Mismatched()) +} + +// String implements `SyscallRule.String`. +func (or Or) String() string { + switch len(or) { + case 0: + return "false" + case 1: + return or[0].String() + default: + var sb strings.Builder + sb.WriteRune('(') + for i, rule := range or { + 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) + _, rule2IsMatchAll := rule2.(MatchAll) + if rule1IsMatchAll || rule2IsMatchAll { + return MatchAll{} + } + rule1Or, rule1IsOr := rule1.(Or) + rule2Or, rule2IsOr := rule2.(Or) + if rule1IsOr && rule2IsOr { + return append(rule1Or, rule2Or...) + } + if rule1IsOr { + return append(rule1Or, rule2) + } + if rule2IsOr { + return append(rule2Or, rule1) + } + return Or{rule1, rule2} +} + +// PerArg implements SyscallRule and verifies the syscall arguments and RIP. // // For example: // -// rule := Rule { +// rule := PerArg{ // EqualTo(linux.ARCH_GET_FS | linux.ARCH_SET_FS), // arg0 // } -type Rule [7]any // 6 arguments + RIP +type PerArg [7]any // 6 arguments + RIP // RuleIP indicates what rules in the Rule array have to be applied to // instruction pointer. const RuleIP = 6 -func (r Rule) String() (s string) { - if len(r) == 0 { +// Render implements `SyscallRule.Render`. +func (pa PerArg) Render(program *syscallProgram, labelSet *labelSet) { + for i, arg := range pa { + if arg == nil { + continue + } + + frag := program.Record() + nextArgLabel := labelSet.NewLabel() + labelSuffix := fmt.Sprintf("arg[%d]", i) + // Determine the data offset for low and high bits of input. + dataOffsetLow := seccompDataOffsetArgLow(i) + dataOffsetHigh := seccompDataOffsetArgHigh(i) + if i == RuleIP { + dataOffsetLow = seccompDataOffsetIPLow + dataOffsetHigh = seccompDataOffsetIPHigh + labelSuffix = "rip" + } + ls := labelSet.Push(labelSuffix, nextArgLabel, labelSet.Mismatched()) + + // Add the conditional operation. Input values to the BPF + // program are 64bit values. However, comparisons in BPF can + // only be done on 32bit values. This means that we need to + // operate on each 32bit half in order to do one logical 64bit + // comparison. + switch a := arg.(type) { + case AnyValue: + program.JumpTo(ls.Matched()) + case EqualTo: + // EqualTo checks that both the higher and lower 32bits are equal. + high, low := uint32(a>>32), uint32(a) + + // Assert that the lower 32bits are equal. + // arg_low == low ? continue : violation + program.Stmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetLow) + program.IfNot(bpf.Jmp|bpf.Jeq|bpf.K, low, ls.Mismatched()) + + // Assert that the higher 32bits are also equal. + // arg_high == high ? continue/success : violation + program.Stmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetHigh) + program.IfNot(bpf.Jmp|bpf.Jeq|bpf.K, high, ls.Mismatched()) + program.JumpTo(ls.Matched()) + case NotEqual: + // NotEqual checks that either the higher or lower 32bits + // are *not* equal. + high, low := uint32(a>>32), uint32(a) + + // Check if the higher 32bits are (not) equal. + // arg_low != low ? success : continue + program.Stmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetLow) + program.IfNot(bpf.Jmp|bpf.Jeq|bpf.K, low, ls.Matched()) + + // Assert that the lower 32bits are not equal (assuming + // higher bits are equal). + // arg_high != high ? success : violation + program.Stmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetHigh) + program.IfNot(bpf.Jmp|bpf.Jeq|bpf.K, high, ls.Matched()) + program.JumpTo(ls.Mismatched()) + case GreaterThan: + // GreaterThan checks that the higher 32bits is greater + // *or* that the higher 32bits are equal and the lower + // 32bits are greater. + high, low := uint32(a>>32), uint32(a) + + // Assert the higher 32bits are greater than or equal. + // arg_high >= high ? continue : violation (arg_high < high) + program.Stmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetHigh) + program.IfNot(bpf.Jmp|bpf.Jge|bpf.K, high, ls.Mismatched()) + + // Assert that the lower 32bits are greater. + // arg_high == high ? continue : success (arg_high > high) + program.IfNot(bpf.Jmp|bpf.Jeq|bpf.K, high, ls.Matched()) + // arg_low > low ? continue/success : violation (arg_high == high and arg_low <= low) + program.Stmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetLow) + program.IfNot(bpf.Jmp|bpf.Jgt|bpf.K, low, ls.Mismatched()) + program.JumpTo(ls.Matched()) + case GreaterThanOrEqual: + // GreaterThanOrEqual checks that the higher 32bits is + // greater *or* that the higher 32bits are equal and the + // lower 32bits are greater than or equal. + high, low := uint32(a>>32), uint32(a) + + // Assert the higher 32bits are greater than or equal. + // arg_high >= high ? continue : violation (arg_high < high) + program.Stmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetHigh) + program.IfNot(bpf.Jmp|bpf.Jge|bpf.K, high, ls.Mismatched()) + // arg_high == high ? continue : success (arg_high > high) + program.IfNot(bpf.Jmp|bpf.Jeq|bpf.K, high, ls.Matched()) + + // Assert that the lower 32bits are greater (assuming the + // higher bits are equal). + // arg_low >= low ? continue/success : violation (arg_high == high and arg_low < low) + program.Stmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetLow) + program.IfNot(bpf.Jmp|bpf.Jge|bpf.K, low, ls.Mismatched()) + program.JumpTo(ls.Matched()) + case LessThan: + // LessThan checks that the higher 32bits is less *or* that + // the higher 32bits are equal and the lower 32bits are + // less. + high, low := uint32(a>>32), uint32(a) + + // Assert the higher 32bits are less than or equal. + // arg_high > high ? violation : continue + program.Stmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetHigh) + program.If(bpf.Jmp|bpf.Jgt|bpf.K, high, ls.Mismatched()) + // arg_high == high ? continue : success (arg_high < high) + program.IfNot(bpf.Jmp|bpf.Jeq|bpf.K, high, ls.Matched()) + + // Assert that the lower 32bits are less (assuming the + // higher bits are equal). + // arg_low >= low ? violation : continue + program.Stmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetLow) + program.If(bpf.Jmp|bpf.Jge|bpf.K, low, ls.Mismatched()) + program.JumpTo(ls.Matched()) + case LessThanOrEqual: + // LessThan checks that the higher 32bits is less *or* that + // the higher 32bits are equal and the lower 32bits are + // less than or equal. + high, low := uint32(a>>32), uint32(a) + + // Assert the higher 32bits are less than or equal. + // assert arg_high > high ? violation : continue + program.Stmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetHigh) + program.If(bpf.Jmp|bpf.Jgt|bpf.K, high, ls.Mismatched()) + // arg_high == high ? continue : success + program.IfNot(bpf.Jmp|bpf.Jeq|bpf.K, high, ls.Matched()) + + // Assert the lower bits are less than or equal (assuming + // the higher bits are equal). + // arg_low > low ? violation : success + program.Stmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetLow) + program.If(bpf.Jmp|bpf.Jgt|bpf.K, low, ls.Mismatched()) + program.JumpTo(ls.Matched()) + case maskedEqual: + // MaskedEqual checks that the bitwise AND of the value and + // mask are equal for both the higher and lower 32bits. + high, low := uint32(a.value>>32), uint32(a.value) + maskHigh, maskLow := uint32(a.mask>>32), uint32(a.mask) + + // Assert that the lower 32bits are equal when masked. + // A <- arg_low. + program.Stmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetLow) + // A <- arg_low & maskLow + program.Stmt(bpf.Alu|bpf.And|bpf.K, maskLow) + // Assert that arg_low & maskLow == low. + program.IfNot(bpf.Jmp|bpf.Jeq|bpf.K, low, ls.Mismatched()) + + // Assert that the higher 32bits are equal when masked. + // A <- arg_high + program.Stmt(bpf.Ld|bpf.Abs|bpf.W, dataOffsetHigh) + // A <- arg_high & maskHigh + program.Stmt(bpf.Alu|bpf.And|bpf.K, maskHigh) + // Assert that arg_high & maskHigh == high. + program.IfNot(bpf.Jmp|bpf.Jeq|bpf.K, high, ls.Mismatched()) + program.JumpTo(ls.Matched()) + default: + panic(fmt.Sprintf("unknown syscall rule type: %v", reflect.TypeOf(a))) + } + frag.MustHaveJumpedTo(ls.Matched(), ls.Mismatched()) + program.Label(nextArgLabel) + } + + // Matched all argument-wise rules, jump to the final rule matched label. + program.JumpTo(labelSet.Matched()) +} + +// String implements `SyscallRule.String`. +func (pa PerArg) String() (s string) { + if len(pa) == 0 { return } s += "( " - for _, arg := range r { + for _, arg := range pa { if arg != nil { s += fmt.Sprintf("%v ", arg) } @@ -139,60 +395,68 @@ func (r Rule) String() (s string) { return } -// SyscallRules stores a map of OR'ed argument rules indexed by the syscall number. -// If the 'Rules' is empty, we treat it as any argument is allowed. +// SyscallRules maps syscall numbers to their corresponding rules. // // For example: // // rules := SyscallRules{ -// syscall.SYS_FUTEX: []Rule{ -// { +// syscall.SYS_FUTEX: Or{ +// PerArg{ // AnyValue{}, // EqualTo(linux.FUTEX_WAIT | linux.FUTEX_PRIVATE_FLAG), -// }, // OR -// { +// }, +// PerArg{ // AnyValue{}, // EqualTo(linux.FUTEX_WAKE | linux.FUTEX_PRIVATE_FLAG), // }, // }, -// syscall.SYS_GETPID: []Rule{}, +// syscall.SYS_GETPID: MatchAll{}, // // } -type SyscallRules map[uintptr][]Rule +type SyscallRules map[uintptr]SyscallRule // NewSyscallRules returns a new SyscallRules. func NewSyscallRules() SyscallRules { - return make(map[uintptr][]Rule) + return make(map[uintptr]SyscallRule) +} + +// String returns a string representation of the syscall rules, one syscall +// per line. +func (sr SyscallRules) String() string { + if len(sr) == 0 { + return "(no rules)" + } + sysnums := make([]uintptr, 0, len(sr)) + for sysno := range sr { + sysnums = append(sysnums, sysno) + } + sort.Slice(sysnums, func(i, j int) bool { + return sysnums[i] < sysnums[j] + }) + var sb strings.Builder + for _, sysno := range sysnums { + sb.WriteString(fmt.Sprintf("syscall %d: %v\n", sysno, sr[sysno])) + } + return strings.TrimSpace(sb.String()) } // AddRule adds the given rule. It will create a new entry for a new syscall, otherwise // it will append to the existing rules. -func (sr SyscallRules) AddRule(sysno uintptr, r Rule) { +func (sr SyscallRules) AddRule(sysno uintptr, r SyscallRule) { if cur, ok := sr[sysno]; ok { - // An empty rules means allow all. Honor it when more rules are added. - if len(cur) == 0 { - sr[sysno] = append(sr[sysno], Rule{}) - } - sr[sysno] = append(sr[sysno], r) + sr[sysno] = merge(cur, r) } else { - sr[sysno] = []Rule{r} + sr[sysno] = r } } // Merge merges the given SyscallRules. -func (sr SyscallRules) Merge(rules SyscallRules) { - for sysno, rs := range rules { +func (sr SyscallRules) Merge(other SyscallRules) { + for sysno, r := range other { if cur, ok := sr[sysno]; ok { - // An empty rules means allow all. Honor it when more rules are added. - if len(cur) == 0 { - sr[sysno] = append(sr[sysno], Rule{}) - } - if len(rs) == 0 { - rs = []Rule{{}} - } - sr[sysno] = append(sr[sysno], rs...) + sr[sysno] = merge(cur, r) } else { - sr[sysno] = rs + sr[sysno] = r } } } @@ -200,18 +464,14 @@ func (sr SyscallRules) Merge(rules SyscallRules) { // DenyNewExecMappings is a set of rules that denies creating new executable // mappings and converting existing ones. var DenyNewExecMappings = SyscallRules{ - unix.SYS_MMAP: []Rule{ - { - AnyValue{}, - AnyValue{}, - MaskedEqual(unix.PROT_EXEC, unix.PROT_EXEC), - }, + unix.SYS_MMAP: PerArg{ + AnyValue{}, + AnyValue{}, + MaskedEqual(unix.PROT_EXEC, unix.PROT_EXEC), }, - unix.SYS_MPROTECT: []Rule{ - { - AnyValue{}, - AnyValue{}, - MaskedEqual(unix.PROT_EXEC, unix.PROT_EXEC), - }, + unix.SYS_MPROTECT: PerArg{ + AnyValue{}, + AnyValue{}, + MaskedEqual(unix.PROT_EXEC, unix.PROT_EXEC), }, } diff --git a/pkg/seccomp/seccomp_test.go b/pkg/seccomp/seccomp_test.go index 169077cc6..bd7f21445 100644 --- a/pkg/seccomp/seccomp_test.go +++ b/pkg/seccomp/seccomp_test.go @@ -24,6 +24,7 @@ import ( "math/rand" "os" "os/exec" + "reflect" "strings" "testing" "time" @@ -88,7 +89,7 @@ func TestBasic(t *testing.T) { name: "Single syscall", ruleSets: []RuleSet{ { - Rules: SyscallRules{1: {}}, + Rules: SyscallRules{1: MatchAll{}}, Action: linux.SECCOMP_RET_ALLOW, }, }, @@ -112,18 +113,16 @@ func TestBasic(t *testing.T) { ruleSets: []RuleSet{ { Rules: SyscallRules{ - 1: []Rule{ - { - EqualTo(0x1), - }, + 1: PerArg{ + EqualTo(0x1), }, }, Action: linux.SECCOMP_RET_ALLOW, }, { Rules: SyscallRules{ - 1: {}, - 2: {}, + 1: MatchAll{}, + 2: MatchAll{}, }, Action: linux.SECCOMP_RET_TRAP, }, @@ -158,9 +157,9 @@ func TestBasic(t *testing.T) { ruleSets: []RuleSet{ { Rules: SyscallRules{ - 1: {}, - 3: {}, - 5: {}, + 1: MatchAll{}, + 3: MatchAll{}, + 5: MatchAll{}, }, Action: linux.SECCOMP_RET_ALLOW, }, @@ -215,7 +214,7 @@ func TestBasic(t *testing.T) { ruleSets: []RuleSet{ { Rules: SyscallRules{ - 1: {}, + 1: MatchAll{}, }, Action: linux.SECCOMP_RET_ALLOW, }, @@ -235,7 +234,7 @@ func TestBasic(t *testing.T) { ruleSets: []RuleSet{ { Rules: SyscallRules{ - 1: {}, + 1: MatchAll{}, }, Action: linux.SECCOMP_RET_ALLOW, }, @@ -255,11 +254,9 @@ func TestBasic(t *testing.T) { ruleSets: []RuleSet{ { Rules: SyscallRules{ - 1: []Rule{ - { - AnyValue{}, - EqualTo(0xf), - }, + 1: PerArg{ + AnyValue{}, + EqualTo(0xf), }, }, Action: linux.SECCOMP_RET_ALLOW, @@ -285,11 +282,11 @@ func TestBasic(t *testing.T) { ruleSets: []RuleSet{ { Rules: SyscallRules{ - 1: []Rule{ - { + 1: Or{ + PerArg{ EqualTo(0xf), }, - { + PerArg{ EqualTo(0xe), }, }, @@ -310,6 +307,11 @@ func TestBasic(t *testing.T) { data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0xe}}, want: linux.SECCOMP_RET_ALLOW, }, + { + desc: "match neither rule", + data: linux.SeccompData{Nr: 1, Arch: LINUX_AUDIT_ARCH, Args: [6]uint64{0xd}}, + want: linux.SECCOMP_RET_TRAP, + }, }, }, { @@ -317,12 +319,10 @@ func TestBasic(t *testing.T) { ruleSets: []RuleSet{ { Rules: SyscallRules{ - 1: []Rule{ - { - EqualTo(0), - EqualTo(math.MaxUint64 - 1), - EqualTo(math.MaxUint32), - }, + 1: PerArg{ + EqualTo(0), + EqualTo(math.MaxUint64 - 1), + EqualTo(math.MaxUint32), }, }, Action: linux.SECCOMP_RET_ALLOW, @@ -365,12 +365,10 @@ func TestBasic(t *testing.T) { ruleSets: []RuleSet{ { Rules: SyscallRules{ - 1: []Rule{ - { - NotEqual(0x7aabbccdd), - NotEqual(math.MaxUint64 - 1), - NotEqual(math.MaxUint32), - }, + 1: PerArg{ + NotEqual(0x7aabbccdd), + NotEqual(math.MaxUint64 - 1), + NotEqual(math.MaxUint32), }, }, Action: linux.SECCOMP_RET_ALLOW, @@ -413,14 +411,12 @@ func TestBasic(t *testing.T) { ruleSets: []RuleSet{ { Rules: SyscallRules{ - 1: []Rule{ - { - // 4294967298 - // Both upper 32 bits and lower 32 bits are non-zero. - // 00000000000000000000000000000010 - // 00000000000000000000000000000010 - GreaterThan(0x00000002_00000002), - }, + 1: PerArg{ + // 4294967298 + // Both upper 32 bits and lower 32 bits are non-zero. + // 00000000000000000000000000000010 + // 00000000000000000000000000000010 + GreaterThan(0x00000002_00000002), }, }, Action: linux.SECCOMP_RET_ALLOW, @@ -461,11 +457,9 @@ func TestBasic(t *testing.T) { ruleSets: []RuleSet{ { Rules: SyscallRules{ - 1: []Rule{ - { - GreaterThan(0xf), - GreaterThan(0xabcd000d), - }, + 1: PerArg{ + GreaterThan(0xf), + GreaterThan(0xabcd000d), }, }, Action: linux.SECCOMP_RET_ALLOW, @@ -506,14 +500,12 @@ func TestBasic(t *testing.T) { ruleSets: []RuleSet{ { Rules: SyscallRules{ - 1: []Rule{ - { - // 4294967298 - // Both upper 32 bits and lower 32 bits are non-zero. - // 00000000000000000000000000000010 - // 00000000000000000000000000000010 - GreaterThanOrEqual(0x00000002_00000002), - }, + 1: PerArg{ + // 4294967298 + // Both upper 32 bits and lower 32 bits are non-zero. + // 00000000000000000000000000000010 + // 00000000000000000000000000000010 + GreaterThanOrEqual(0x00000002_00000002), }, }, Action: linux.SECCOMP_RET_ALLOW, @@ -554,11 +546,9 @@ func TestBasic(t *testing.T) { ruleSets: []RuleSet{ { Rules: SyscallRules{ - 1: []Rule{ - { - GreaterThanOrEqual(0xf), - GreaterThanOrEqual(0xabcd000d), - }, + 1: PerArg{ + GreaterThanOrEqual(0xf), + GreaterThanOrEqual(0xabcd000d), }, }, Action: linux.SECCOMP_RET_ALLOW, @@ -604,14 +594,12 @@ func TestBasic(t *testing.T) { ruleSets: []RuleSet{ { Rules: SyscallRules{ - 1: []Rule{ - { - // 4294967298 - // Both upper 32 bits and lower 32 bits are non-zero. - // 00000000000000000000000000000010 - // 00000000000000000000000000000010 - LessThan(0x00000002_00000002), - }, + 1: PerArg{ + // 4294967298 + // Both upper 32 bits and lower 32 bits are non-zero. + // 00000000000000000000000000000010 + // 00000000000000000000000000000010 + LessThan(0x00000002_00000002), }, }, Action: linux.SECCOMP_RET_ALLOW, @@ -652,11 +640,9 @@ func TestBasic(t *testing.T) { ruleSets: []RuleSet{ { Rules: SyscallRules{ - 1: []Rule{ - { - LessThan(0x1), - LessThan(0xabcd000d), - }, + 1: PerArg{ + LessThan(0x1), + LessThan(0xabcd000d), }, }, Action: linux.SECCOMP_RET_ALLOW, @@ -702,14 +688,12 @@ func TestBasic(t *testing.T) { ruleSets: []RuleSet{ { Rules: SyscallRules{ - 1: []Rule{ - { - // 4294967298 - // Both upper 32 bits and lower 32 bits are non-zero. - // 00000000000000000000000000000010 - // 00000000000000000000000000000010 - LessThanOrEqual(0x00000002_00000002), - }, + 1: PerArg{ + // 4294967298 + // Both upper 32 bits and lower 32 bits are non-zero. + // 00000000000000000000000000000010 + // 00000000000000000000000000000010 + LessThanOrEqual(0x00000002_00000002), }, }, Action: linux.SECCOMP_RET_ALLOW, @@ -751,11 +735,9 @@ func TestBasic(t *testing.T) { ruleSets: []RuleSet{ { Rules: SyscallRules{ - 1: []Rule{ - { - LessThanOrEqual(0x1), - LessThanOrEqual(0xabcd000d), - }, + 1: PerArg{ + LessThanOrEqual(0x1), + LessThanOrEqual(0xabcd000d), }, }, Action: linux.SECCOMP_RET_ALLOW, @@ -801,13 +783,11 @@ func TestBasic(t *testing.T) { ruleSets: []RuleSet{ { Rules: SyscallRules{ - 1: []Rule{ - { - // x & 00000001 00000011 (0x103) == 00000000 00000001 (0x1) - // Input x must have lowest order bit set and - // must *not* have 8th or second lowest order bit set. - MaskedEqual(0x103, 0x1), - }, + 1: PerArg{ + // x & 00000001 00000011 (0x103) == 00000000 00000001 (0x1) + // Input x must have lowest order bit set and + // must *not* have 8th or second lowest order bit set. + MaskedEqual(0x103, 0x1), }, }, Action: linux.SECCOMP_RET_ALLOW, @@ -873,10 +853,8 @@ func TestBasic(t *testing.T) { ruleSets: []RuleSet{ { Rules: SyscallRules{ - 1: []Rule{ - { - RuleIP: EqualTo(0x7aabbccdd), - }, + 1: PerArg{ + RuleIP: EqualTo(0x7aabbccdd), }, }, Action: linux.SECCOMP_RET_ALLOW, @@ -926,11 +904,11 @@ func TestBasic(t *testing.T) { func TestRandom(t *testing.T) { rand.Seed(time.Now().UnixNano()) size := rand.Intn(50) + 1 - syscallRules := make(map[uintptr][]Rule) + syscallRules := make(map[uintptr]SyscallRule) for len(syscallRules) < size { n := uintptr(rand.Intn(200)) if _, ok := syscallRules[n]; !ok { - syscallRules[n] = []Rule{} + syscallRules[n] = MatchAll{} } } @@ -1019,50 +997,43 @@ func TestRealDeal(t *testing.T) { func TestMerge(t *testing.T) { for _, tst := range []struct { name string - main []Rule - merge []Rule - want []Rule + main SyscallRule + merge SyscallRule + want SyscallRule }{ { - name: "empty both", - main: nil, - merge: nil, - want: []Rule{{}, {}}, + name: "AllowAll both", + main: MatchAll{}, + merge: MatchAll{}, + want: MatchAll{}, }, { - name: "empty main", - main: nil, - merge: []Rule{{}}, - want: []Rule{{}, {}}, + name: "AllowAll and Or", + main: MatchAll{}, + merge: Or{}, + want: MatchAll{}, }, { - name: "empty merge", - main: []Rule{{}}, - merge: nil, - want: []Rule{{}, {}}, + name: "Or and AllowAll", + main: Or{}, + merge: MatchAll{}, + want: MatchAll{}, + }, + { + name: "2 Ors", + main: Or{PerArg{EqualTo(0)}}, + merge: Or{PerArg{EqualTo(1)}}, + want: Or{PerArg{EqualTo(0)}, PerArg{EqualTo(1)}}, }, } { t.Run(tst.name, func(t *testing.T) { mainRules := SyscallRules{1: tst.main} mergeRules := SyscallRules{1: tst.merge} mainRules.Merge(mergeRules) - if got, want := len(mainRules[1]), len(tst.want); got != want { - t.Errorf("wrong length, got: %d, want: %d", got, want) - } - for i, r := range mainRules[1] { - if r != tst.want[i] { - t.Errorf("result, got: %v, want: %v", r, tst.want[i]) - } + wantRules := SyscallRules{1: tst.want} + if !reflect.DeepEqual(mainRules, wantRules) { + t.Errorf("got rules:\n%v\nwant rules:\n%v\n", mainRules, wantRules) } }) } } - -// TestAddRule ensures that empty rules are not erased when rules are added. -func TestAddRule(t *testing.T) { - rules := SyscallRules{1: {}} - rules.AddRule(1, Rule{}) - if got, want := len(rules[1]), 2; got != want { - t.Errorf("len(rules[1]), got: %d, want: %d", got, want) - } -} diff --git a/pkg/seccomp/victim/seccomp_test_victim.go b/pkg/seccomp/victim/seccomp_test_victim.go index 8bed7ac7d..8b55d3a4f 100644 --- a/pkg/seccomp/victim/seccomp_test_victim.go +++ b/pkg/seccomp/victim/seccomp_test_victim.go @@ -30,69 +30,69 @@ func main() { flag.Parse() syscalls := seccomp.SyscallRules{ - unix.SYS_ACCEPT: {}, - unix.SYS_BIND: {}, - unix.SYS_BRK: {}, - unix.SYS_CLOCK_GETTIME: {}, - unix.SYS_CLONE: {}, - unix.SYS_CLOSE: {}, - unix.SYS_DUP: {}, - unix.SYS_DUP3: {}, - unix.SYS_EPOLL_CREATE1: {}, - unix.SYS_EPOLL_CTL: {}, - unix.SYS_EPOLL_PWAIT: {}, - unix.SYS_EXIT: {}, - unix.SYS_EXIT_GROUP: {}, - unix.SYS_FALLOCATE: {}, - unix.SYS_FCHMOD: {}, - unix.SYS_FCNTL: {}, - unix.SYS_FSTAT: {}, - unix.SYS_FSYNC: {}, - unix.SYS_FTRUNCATE: {}, - unix.SYS_FUTEX: {}, - unix.SYS_GETDENTS64: {}, - unix.SYS_GETPEERNAME: {}, - unix.SYS_GETPID: {}, - unix.SYS_GETSOCKNAME: {}, - unix.SYS_GETSOCKOPT: {}, - unix.SYS_GETTID: {}, - unix.SYS_GETTIMEOFDAY: {}, - unix.SYS_LISTEN: {}, - unix.SYS_LSEEK: {}, - unix.SYS_MADVISE: {}, - unix.SYS_MINCORE: {}, - unix.SYS_MMAP: {}, - unix.SYS_MPROTECT: {}, - unix.SYS_MUNLOCK: {}, - unix.SYS_MUNMAP: {}, - unix.SYS_NANOSLEEP: {}, - unix.SYS_OPENAT: {}, - unix.SYS_PPOLL: {}, - unix.SYS_PREAD64: {}, - unix.SYS_PSELECT6: {}, - unix.SYS_PWRITE64: {}, - unix.SYS_READ: {}, - unix.SYS_READLINKAT: {}, - unix.SYS_READV: {}, - unix.SYS_RECVMSG: {}, - unix.SYS_RENAMEAT: {}, - unix.SYS_RESTART_SYSCALL: {}, - unix.SYS_RT_SIGACTION: {}, - unix.SYS_RT_SIGPROCMASK: {}, - unix.SYS_RT_SIGRETURN: {}, - unix.SYS_SCHED_YIELD: {}, - unix.SYS_SENDMSG: {}, - unix.SYS_SETITIMER: {}, - unix.SYS_SET_ROBUST_LIST: {}, - unix.SYS_SETSOCKOPT: {}, - unix.SYS_SHUTDOWN: {}, - unix.SYS_SIGALTSTACK: {}, - unix.SYS_SOCKET: {}, - unix.SYS_SYNC_FILE_RANGE: {}, - unix.SYS_TGKILL: {}, - unix.SYS_UTIMENSAT: {}, - unix.SYS_WRITE: {}, - unix.SYS_WRITEV: {}, + unix.SYS_ACCEPT: seccomp.MatchAll{}, + unix.SYS_BIND: seccomp.MatchAll{}, + unix.SYS_BRK: seccomp.MatchAll{}, + unix.SYS_CLOCK_GETTIME: seccomp.MatchAll{}, + unix.SYS_CLONE: seccomp.MatchAll{}, + unix.SYS_CLOSE: seccomp.MatchAll{}, + unix.SYS_DUP: seccomp.MatchAll{}, + unix.SYS_DUP3: seccomp.MatchAll{}, + unix.SYS_EPOLL_CREATE1: seccomp.MatchAll{}, + unix.SYS_EPOLL_CTL: seccomp.MatchAll{}, + unix.SYS_EPOLL_PWAIT: seccomp.MatchAll{}, + unix.SYS_EXIT: seccomp.MatchAll{}, + unix.SYS_EXIT_GROUP: seccomp.MatchAll{}, + unix.SYS_FALLOCATE: seccomp.MatchAll{}, + unix.SYS_FCHMOD: seccomp.MatchAll{}, + unix.SYS_FCNTL: seccomp.MatchAll{}, + unix.SYS_FSTAT: seccomp.MatchAll{}, + unix.SYS_FSYNC: seccomp.MatchAll{}, + unix.SYS_FTRUNCATE: seccomp.MatchAll{}, + unix.SYS_FUTEX: seccomp.MatchAll{}, + unix.SYS_GETDENTS64: seccomp.MatchAll{}, + unix.SYS_GETPEERNAME: seccomp.MatchAll{}, + unix.SYS_GETPID: seccomp.MatchAll{}, + unix.SYS_GETSOCKNAME: seccomp.MatchAll{}, + unix.SYS_GETSOCKOPT: seccomp.MatchAll{}, + unix.SYS_GETTID: seccomp.MatchAll{}, + unix.SYS_GETTIMEOFDAY: seccomp.MatchAll{}, + unix.SYS_LISTEN: seccomp.MatchAll{}, + unix.SYS_LSEEK: seccomp.MatchAll{}, + unix.SYS_MADVISE: seccomp.MatchAll{}, + unix.SYS_MINCORE: seccomp.MatchAll{}, + unix.SYS_MMAP: seccomp.MatchAll{}, + unix.SYS_MPROTECT: seccomp.MatchAll{}, + unix.SYS_MUNLOCK: seccomp.MatchAll{}, + unix.SYS_MUNMAP: seccomp.MatchAll{}, + unix.SYS_NANOSLEEP: seccomp.MatchAll{}, + unix.SYS_OPENAT: seccomp.MatchAll{}, + unix.SYS_PPOLL: seccomp.MatchAll{}, + unix.SYS_PREAD64: seccomp.MatchAll{}, + unix.SYS_PSELECT6: seccomp.MatchAll{}, + unix.SYS_PWRITE64: seccomp.MatchAll{}, + unix.SYS_READ: seccomp.MatchAll{}, + unix.SYS_READLINKAT: seccomp.MatchAll{}, + unix.SYS_READV: seccomp.MatchAll{}, + unix.SYS_RECVMSG: seccomp.MatchAll{}, + unix.SYS_RENAMEAT: seccomp.MatchAll{}, + unix.SYS_RESTART_SYSCALL: seccomp.MatchAll{}, + unix.SYS_RT_SIGACTION: seccomp.MatchAll{}, + unix.SYS_RT_SIGPROCMASK: seccomp.MatchAll{}, + unix.SYS_RT_SIGRETURN: seccomp.MatchAll{}, + unix.SYS_SCHED_YIELD: seccomp.MatchAll{}, + unix.SYS_SENDMSG: seccomp.MatchAll{}, + unix.SYS_SETITIMER: seccomp.MatchAll{}, + unix.SYS_SET_ROBUST_LIST: seccomp.MatchAll{}, + unix.SYS_SETSOCKOPT: seccomp.MatchAll{}, + unix.SYS_SHUTDOWN: seccomp.MatchAll{}, + unix.SYS_SIGALTSTACK: seccomp.MatchAll{}, + unix.SYS_SOCKET: seccomp.MatchAll{}, + unix.SYS_SYNC_FILE_RANGE: seccomp.MatchAll{}, + unix.SYS_TGKILL: seccomp.MatchAll{}, + unix.SYS_UTIMENSAT: seccomp.MatchAll{}, + unix.SYS_WRITE: seccomp.MatchAll{}, + unix.SYS_WRITEV: seccomp.MatchAll{}, } arch_syscalls(syscalls) @@ -102,10 +102,8 @@ func main() { die := *dieFlag if !die { - syscalls[syscall] = []seccomp.Rule{ - { - seccomp.EqualTo(0), - }, + syscalls[syscall] = seccomp.PerArg{ + seccomp.EqualTo(0), } } diff --git a/pkg/seccomp/victim/seccomp_test_victim_amd64.go b/pkg/seccomp/victim/seccomp_test_victim_amd64.go index 5c1ecc301..264ee2e75 100644 --- a/pkg/seccomp/victim/seccomp_test_victim_amd64.go +++ b/pkg/seccomp/victim/seccomp_test_victim_amd64.go @@ -26,8 +26,8 @@ import ( ) func arch_syscalls(syscalls seccomp.SyscallRules) { - syscalls[unix.SYS_ARCH_PRCTL] = []seccomp.Rule{} - syscalls[unix.SYS_EPOLL_WAIT] = []seccomp.Rule{} - syscalls[unix.SYS_NEWFSTATAT] = []seccomp.Rule{} - syscalls[unix.SYS_OPEN] = []seccomp.Rule{} + syscalls[unix.SYS_ARCH_PRCTL] = seccomp.MatchAll{} + syscalls[unix.SYS_EPOLL_WAIT] = seccomp.MatchAll{} + syscalls[unix.SYS_NEWFSTATAT] = seccomp.MatchAll{} + syscalls[unix.SYS_OPEN] = seccomp.MatchAll{} } diff --git a/pkg/seccomp/victim/seccomp_test_victim_arm64.go b/pkg/seccomp/victim/seccomp_test_victim_arm64.go index 9647e2758..73ea69ea5 100644 --- a/pkg/seccomp/victim/seccomp_test_victim_arm64.go +++ b/pkg/seccomp/victim/seccomp_test_victim_arm64.go @@ -26,5 +26,5 @@ import ( ) func arch_syscalls(syscalls seccomp.SyscallRules) { - syscalls[unix.SYS_FSTATAT] = []seccomp.Rule{} + syscalls[unix.SYS_FSTATAT] = seccomp.MatchAll{} } diff --git a/pkg/sentry/devices/accel/seccomp_filters.go b/pkg/sentry/devices/accel/seccomp_filters.go index 488778fd7..ee3809eef 100644 --- a/pkg/sentry/devices/accel/seccomp_filters.go +++ b/pkg/sentry/devices/accel/seccomp_filters.go @@ -25,92 +25,88 @@ import ( func Filters() seccomp.SyscallRules { nonNegativeFD := seccomp.NonNegativeFDCheck() return seccomp.SyscallRules{ - unix.SYS_OPENAT: []seccomp.Rule{ - { - // All paths that we openat() are absolute, so we pass a dirfd - // of -1 (which is invalid for relative paths, but ignored for - // absolute paths) to hedge against bugs involving AT_FDCWD or - // real dirfds. - seccomp.EqualTo(^uintptr(0)), - seccomp.AnyValue{}, - seccomp.MaskedEqual(unix.O_CREAT|unix.O_NOFOLLOW, unix.O_NOFOLLOW), - seccomp.AnyValue{}, - }, + unix.SYS_OPENAT: seccomp.PerArg{ + // All paths that we openat() are absolute, so we pass a dirfd + // of -1 (which is invalid for relative paths, but ignored for + // absolute paths) to hedge against bugs involving AT_FDCWD or + // real dirfds. + seccomp.EqualTo(^uintptr(0)), + seccomp.AnyValue{}, + seccomp.MaskedEqual(unix.O_CREAT|unix.O_NOFOLLOW, unix.O_NOFOLLOW), + seccomp.AnyValue{}, }, - unix.SYS_GETDENTS64: {}, - unix.SYS_IOCTL: []seccomp.Rule{ - { + unix.SYS_GETDENTS64: seccomp.MatchAll{}, + unix.SYS_IOCTL: seccomp.Or{ + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(gasket.GASKET_IOCTL_RESET), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(gasket.GASKET_IOCTL_SET_EVENTFD), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(gasket.GASKET_IOCTL_CLEAR_EVENTFD), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(gasket.GASKET_IOCTL_NUMBER_PAGE_TABLES), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(gasket.GASKET_IOCTL_PAGE_TABLE_SIZE), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(gasket.GASKET_IOCTL_SIMPLE_PAGE_TABLE_SIZE), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(gasket.GASKET_IOCTL_PARTITION_PAGE_TABLE), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(gasket.GASKET_IOCTL_MAP_BUFFER), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(gasket.GASKET_IOCTL_UNMAP_BUFFER), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(gasket.GASKET_IOCTL_CLEAR_INTERRUPT_COUNTS), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(gasket.GASKET_IOCTL_REGISTER_INTERRUPT), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(gasket.GASKET_IOCTL_UNREGISTER_INTERRUPT), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(gasket.GASKET_IOCTL_MAP_DMA_BUF), }, }, - unix.SYS_EVENTFD2: []seccomp.Rule{ - { + unix.SYS_EVENTFD2: seccomp.Or{ + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(linux.EFD_NONBLOCK), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(linux.EFD_NONBLOCK | linux.EFD_SEMAPHORE), }, }, - unix.SYS_MREMAP: []seccomp.Rule{ - { - seccomp.AnyValue{}, - seccomp.EqualTo(0), /* old_size */ - seccomp.AnyValue{}, - seccomp.EqualTo(linux.MREMAP_MAYMOVE | linux.MREMAP_FIXED), - seccomp.AnyValue{}, - seccomp.EqualTo(0), - }, + unix.SYS_MREMAP: seccomp.PerArg{ + seccomp.AnyValue{}, + seccomp.EqualTo(0), /* old_size */ + seccomp.AnyValue{}, + seccomp.EqualTo(linux.MREMAP_MAYMOVE | linux.MREMAP_FIXED), + seccomp.AnyValue{}, + seccomp.EqualTo(0), }, } } diff --git a/pkg/sentry/devices/nvproxy/seccomp_filters.go b/pkg/sentry/devices/nvproxy/seccomp_filters.go index fcf1fc1c8..a4ff6f0db 100644 --- a/pkg/sentry/devices/nvproxy/seccomp_filters.go +++ b/pkg/sentry/devices/nvproxy/seccomp_filters.go @@ -26,165 +26,161 @@ func Filters() seccomp.SyscallRules { nonNegativeFD := seccomp.NonNegativeFDCheck() notIocSizeMask := ^(((uintptr(1) << linux.IOC_SIZEBITS) - 1) << linux.IOC_SIZESHIFT) // for ioctls taking arbitrary size return seccomp.SyscallRules{ - unix.SYS_OPENAT: []seccomp.Rule{ - { - // All paths that we openat() are absolute, so we pass a dirfd - // of -1 (which is invalid for relative paths, but ignored for - // absolute paths) to hedge against bugs involving AT_FDCWD or - // real dirfds. - seccomp.EqualTo(^uintptr(0)), - seccomp.AnyValue{}, - seccomp.MaskedEqual(unix.O_NOFOLLOW|unix.O_CREAT, unix.O_NOFOLLOW), - seccomp.AnyValue{}, - }, + unix.SYS_OPENAT: seccomp.PerArg{ + // All paths that we openat() are absolute, so we pass a dirfd + // of -1 (which is invalid for relative paths, but ignored for + // absolute paths) to hedge against bugs involving AT_FDCWD or + // real dirfds. + seccomp.EqualTo(^uintptr(0)), + seccomp.AnyValue{}, + seccomp.MaskedEqual(unix.O_NOFOLLOW|unix.O_CREAT, unix.O_NOFOLLOW), + seccomp.AnyValue{}, }, - unix.SYS_IOCTL: []seccomp.Rule{ - { + unix.SYS_IOCTL: seccomp.Or{ + seccomp.PerArg{ nonNegativeFD, seccomp.MaskedEqual(notIocSizeMask, frontendIoctlCmd(nvgpu.NV_ESC_CARD_INFO, 0)), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(frontendIoctlCmd(nvgpu.NV_ESC_CHECK_VERSION_STR, nvgpu.SizeofRMAPIVersion)), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(frontendIoctlCmd(nvgpu.NV_ESC_REGISTER_FD, nvgpu.SizeofIoctlRegisterFD)), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(frontendIoctlCmd(nvgpu.NV_ESC_ALLOC_OS_EVENT, nvgpu.SizeofIoctlAllocOSEvent)), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(frontendIoctlCmd(nvgpu.NV_ESC_FREE_OS_EVENT, nvgpu.SizeofIoctlFreeOSEvent)), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(frontendIoctlCmd(nvgpu.NV_ESC_SYS_PARAMS, nvgpu.SizeofIoctlSysParams)), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(frontendIoctlCmd(nvgpu.NV_ESC_RM_ALLOC_MEMORY, nvgpu.SizeofIoctlNVOS02ParametersWithFD)), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(frontendIoctlCmd(nvgpu.NV_ESC_RM_FREE, nvgpu.SizeofNVOS00Parameters)), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(frontendIoctlCmd(nvgpu.NV_ESC_RM_CONTROL, nvgpu.SizeofNVOS54Parameters)), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(frontendIoctlCmd(nvgpu.NV_ESC_RM_ALLOC, nvgpu.SizeofNVOS21Parameters)), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(frontendIoctlCmd(nvgpu.NV_ESC_RM_ALLOC, nvgpu.SizeofNVOS64Parameters)), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(frontendIoctlCmd(nvgpu.NV_ESC_RM_DUP_OBJECT, nvgpu.SizeofNVOS55Parameters)), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(frontendIoctlCmd(nvgpu.NV_ESC_RM_SHARE, nvgpu.SizeofNVOS57Parameters)), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(frontendIoctlCmd(nvgpu.NV_ESC_RM_VID_HEAP_CONTROL, nvgpu.SizeofNVOS32Parameters)), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(frontendIoctlCmd(nvgpu.NV_ESC_RM_MAP_MEMORY, nvgpu.SizeofIoctlNVOS33ParametersWithFD)), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(frontendIoctlCmd(nvgpu.NV_ESC_RM_UNMAP_MEMORY, nvgpu.SizeofNVOS34Parameters)), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(frontendIoctlCmd(nvgpu.NV_ESC_RM_UPDATE_DEVICE_MAPPING_INFO, nvgpu.SizeofNVOS56Parameters)), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(nvgpu.UVM_INITIALIZE), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(nvgpu.UVM_DEINITIALIZE), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(nvgpu.UVM_CREATE_RANGE_GROUP), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(nvgpu.UVM_DESTROY_RANGE_GROUP), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(nvgpu.UVM_REGISTER_GPU_VASPACE), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(nvgpu.UVM_UNREGISTER_GPU_VASPACE), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(nvgpu.UVM_REGISTER_CHANNEL), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(nvgpu.UVM_UNREGISTER_CHANNEL), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(nvgpu.UVM_MAP_EXTERNAL_ALLOCATION), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(nvgpu.UVM_FREE), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(nvgpu.UVM_REGISTER_GPU), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(nvgpu.UVM_UNREGISTER_GPU), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(nvgpu.UVM_PAGEABLE_MEM_ACCESS), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(nvgpu.UVM_MAP_DYNAMIC_PARALLELISM_REGION), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(nvgpu.UVM_ALLOC_SEMAPHORE_POOL), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(nvgpu.UVM_VALIDATE_VA_RANGE), }, - { + seccomp.PerArg{ nonNegativeFD, seccomp.EqualTo(nvgpu.UVM_CREATE_EXTERNAL_RANGE), }, }, - unix.SYS_MREMAP: []seccomp.Rule{ - { - seccomp.AnyValue{}, - seccomp.EqualTo(0), /* old_size */ - seccomp.AnyValue{}, - seccomp.EqualTo(linux.MREMAP_MAYMOVE | linux.MREMAP_FIXED), - seccomp.AnyValue{}, - seccomp.EqualTo(0), - }, + unix.SYS_MREMAP: seccomp.PerArg{ + seccomp.AnyValue{}, + seccomp.EqualTo(0), /* old_size */ + seccomp.AnyValue{}, + seccomp.EqualTo(linux.MREMAP_MAYMOVE | linux.MREMAP_FIXED), + seccomp.AnyValue{}, + seccomp.EqualTo(0), }, } } diff --git a/pkg/sentry/platform/kvm/filters.go b/pkg/sentry/platform/kvm/filters.go index 7fe56cf73..c00a12895 100644 --- a/pkg/sentry/platform/kvm/filters.go +++ b/pkg/sentry/platform/kvm/filters.go @@ -25,34 +25,32 @@ import ( func (k *KVM) SyscallFilters() seccomp.SyscallRules { r := k.archSyscallFilters() r.Merge(seccomp.SyscallRules{ - unix.SYS_IOCTL: []seccomp.Rule{ - { + unix.SYS_IOCTL: seccomp.Or{ + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(KVM_RUN), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(KVM_SET_USER_MEMORY_REGION), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(KVM_GET_REGS), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(KVM_SET_REGS), }, }, - unix.SYS_MEMBARRIER: []seccomp.Rule{ - { - seccomp.EqualTo(linux.MEMBARRIER_CMD_PRIVATE_EXPEDITED), - seccomp.EqualTo(0), - }, + unix.SYS_MEMBARRIER: seccomp.PerArg{ + seccomp.EqualTo(linux.MEMBARRIER_CMD_PRIVATE_EXPEDITED), + seccomp.EqualTo(0), }, - unix.SYS_MMAP: {}, - unix.SYS_RT_SIGSUSPEND: {}, - unix.SYS_RT_SIGTIMEDWAIT: {}, - _SYS_KVM_RETURN_TO_HOST: {}, + unix.SYS_MMAP: seccomp.MatchAll{}, + unix.SYS_RT_SIGSUSPEND: seccomp.MatchAll{}, + unix.SYS_RT_SIGTIMEDWAIT: seccomp.MatchAll{}, + _SYS_KVM_RETURN_TO_HOST: seccomp.MatchAll{}, }) return r } diff --git a/pkg/sentry/platform/kvm/filters_amd64.go b/pkg/sentry/platform/kvm/filters_amd64.go index 506ba981c..7e83ab360 100644 --- a/pkg/sentry/platform/kvm/filters_amd64.go +++ b/pkg/sentry/platform/kvm/filters_amd64.go @@ -25,24 +25,24 @@ import ( // KVM platform. func (k *KVM) archSyscallFilters() seccomp.SyscallRules { return seccomp.SyscallRules{ - unix.SYS_ARCH_PRCTL: { - { + unix.SYS_ARCH_PRCTL: seccomp.Or{ + seccomp.PerArg{ seccomp.EqualTo(linux.ARCH_GET_FS), }, - { + seccomp.PerArg{ seccomp.EqualTo(linux.ARCH_GET_GS), }, }, - unix.SYS_IOCTL: []seccomp.Rule{ - { + unix.SYS_IOCTL: seccomp.Or{ + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(KVM_INTERRUPT), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(KVM_NMI), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(KVM_GET_REGS), }, diff --git a/pkg/sentry/platform/kvm/filters_arm64.go b/pkg/sentry/platform/kvm/filters_arm64.go index 77c651fb2..99ffcc4cc 100644 --- a/pkg/sentry/platform/kvm/filters_arm64.go +++ b/pkg/sentry/platform/kvm/filters_arm64.go @@ -27,11 +27,9 @@ import ( // KVM platform. func (*KVM) archSyscallFilters() seccomp.SyscallRules { return seccomp.SyscallRules{ - unix.SYS_IOCTL: { - { - seccomp.AnyValue{}, - seccomp.EqualTo(KVM_SET_VCPU_EVENTS), - }, + unix.SYS_IOCTL: seccomp.PerArg{ + seccomp.AnyValue{}, + seccomp.EqualTo(KVM_SET_VCPU_EVENTS), }, } } diff --git a/pkg/sentry/platform/kvm/machine.go b/pkg/sentry/platform/kvm/machine.go index 9c103b11e..2708f7ddc 100644 --- a/pkg/sentry/platform/kvm/machine.go +++ b/pkg/sentry/platform/kvm/machine.go @@ -776,24 +776,21 @@ func seccompMmapRules(m *machine) { if err := sighandling.ReplaceSignalHandler(unix.SIGSYS, addrOfSigsysHandler(), &savedSigsysHandler); err != nil { panic(fmt.Sprintf("Unable to set handler for signal %d: %v", bluepillSignal, err)) } - rules := []seccomp.RuleSet{} - rules = append(rules, []seccomp.RuleSet{ + rules := []seccomp.RuleSet{ // Trap mmap system calls and handle them in sigsysGoHandler { Rules: seccomp.SyscallRules{ - unix.SYS_MMAP: { - { - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.MaskedEqual(unix.PROT_EXEC, 0), - /* MAP_DENYWRITE is ignored and used only for filtering. */ - seccomp.MaskedEqual(unix.MAP_DENYWRITE, 0), - }, + unix.SYS_MMAP: seccomp.PerArg{ + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.MaskedEqual(unix.PROT_EXEC, 0), + /* MAP_DENYWRITE is ignored and used only for filtering. */ + seccomp.MaskedEqual(unix.MAP_DENYWRITE, 0), }, }, Action: linux.SECCOMP_RET_TRAP, }, - }...) + } instrs, err := seccomp.BuildProgram(rules, linux.SECCOMP_RET_ALLOW, linux.SECCOMP_RET_ALLOW) if err != nil { panic(fmt.Sprintf("failed to build rules: %v", err)) diff --git a/pkg/sentry/platform/ptrace/filters.go b/pkg/sentry/platform/ptrace/filters.go index ba4503b0d..5a34bf161 100644 --- a/pkg/sentry/platform/ptrace/filters.go +++ b/pkg/sentry/platform/ptrace/filters.go @@ -22,8 +22,8 @@ import ( // SyscallFilters returns syscalls made exclusively by the ptrace platform. func (*PTrace) SyscallFilters() seccomp.SyscallRules { return seccomp.SyscallRules{ - unix.SYS_PTRACE: {}, - unix.SYS_TGKILL: {}, - unix.SYS_WAIT4: {}, + unix.SYS_PTRACE: seccomp.MatchAll{}, + unix.SYS_TGKILL: seccomp.MatchAll{}, + unix.SYS_WAIT4: seccomp.MatchAll{}, } } diff --git a/pkg/sentry/platform/ptrace/subprocess_amd64.go b/pkg/sentry/platform/ptrace/subprocess_amd64.go index d1ae9c1b2..c957487b7 100644 --- a/pkg/sentry/platform/ptrace/subprocess_amd64.go +++ b/pkg/sentry/platform/ptrace/subprocess_amd64.go @@ -184,9 +184,9 @@ func appendArchSeccompRules(rules []seccomp.RuleSet, defaultAction linux.BPFActi // Rules for trapping vsyscall access. seccomp.RuleSet{ Rules: seccomp.SyscallRules{ - unix.SYS_GETTIMEOFDAY: {}, - unix.SYS_TIME: {}, - unix.SYS_GETCPU: {}, // SYS_GETCPU was not defined in package syscall on amd64. + unix.SYS_GETTIMEOFDAY: seccomp.MatchAll{}, + unix.SYS_TIME: seccomp.MatchAll{}, + unix.SYS_GETCPU: seccomp.MatchAll{}, // SYS_GETCPU was not defined in package syscall on amd64. }, Action: linux.SECCOMP_RET_TRAP, Vsyscall: true, @@ -195,8 +195,9 @@ func appendArchSeccompRules(rules []seccomp.RuleSet, defaultAction linux.BPFActi rules = append(rules, seccomp.RuleSet{ Rules: seccomp.SyscallRules{ - unix.SYS_ARCH_PRCTL: []seccomp.Rule{ - {seccomp.EqualTo(linux.ARCH_SET_CPUID), seccomp.EqualTo(0)}, + unix.SYS_ARCH_PRCTL: seccomp.PerArg{ + seccomp.EqualTo(linux.ARCH_SET_CPUID), + seccomp.EqualTo(0), }, }, Action: linux.SECCOMP_RET_ALLOW, diff --git a/pkg/sentry/platform/ptrace/subprocess_arm64.go b/pkg/sentry/platform/ptrace/subprocess_arm64.go index b61a79aca..e4f540229 100644 --- a/pkg/sentry/platform/ptrace/subprocess_arm64.go +++ b/pkg/sentry/platform/ptrace/subprocess_arm64.go @@ -113,7 +113,7 @@ func dumpRegs(regs *arch.Registers) string { } // adjustInitregsRip adjust the current register RIP value to -// be just before the system call instruction excution +// be just before the system call instruction execution func (t *thread) adjustInitRegsRip() { t.initRegs.Pc -= initRegsRipAdjustment } diff --git a/pkg/sentry/platform/ptrace/subprocess_linux.go b/pkg/sentry/platform/ptrace/subprocess_linux.go index a73a3d143..a6ce81a56 100644 --- a/pkg/sentry/platform/ptrace/subprocess_linux.go +++ b/pkg/sentry/platform/ptrace/subprocess_linux.go @@ -80,38 +80,35 @@ func attachedThread(flags uintptr, defaultAction linux.BPFAction) (*thread, erro if defaultAction != linux.SECCOMP_RET_ALLOW { rules = append(rules, seccomp.RuleSet{ Rules: seccomp.SyscallRules{ - unix.SYS_CLONE: []seccomp.Rule{ + unix.SYS_CLONE: seccomp.Or{ // Allow creation of new subprocesses (used by the master). - {seccomp.EqualTo(unix.CLONE_FILES | unix.SIGKILL)}, + seccomp.PerArg{seccomp.EqualTo(unix.CLONE_FILES | unix.SIGKILL)}, // Allow creation of new threads within a single address space (used by addresss spaces). - {seccomp.EqualTo( - unix.CLONE_FILES | - unix.CLONE_FS | - unix.CLONE_SIGHAND | - unix.CLONE_THREAD | - unix.CLONE_PTRACE | - unix.CLONE_VM)}, + seccomp.PerArg{ + seccomp.EqualTo( + unix.CLONE_FILES | + unix.CLONE_FS | + unix.CLONE_SIGHAND | + unix.CLONE_THREAD | + unix.CLONE_PTRACE | + unix.CLONE_VM)}, }, // For the initial process creation. - unix.SYS_WAIT4: {}, - unix.SYS_EXIT: {}, + unix.SYS_WAIT4: seccomp.MatchAll{}, + unix.SYS_EXIT: seccomp.MatchAll{}, // For the stub prctl dance (all). - unix.SYS_PRCTL: []seccomp.Rule{ - {seccomp.EqualTo(unix.PR_SET_PDEATHSIG), seccomp.EqualTo(unix.SIGKILL)}, - }, - unix.SYS_GETPPID: {}, + unix.SYS_PRCTL: seccomp.PerArg{seccomp.EqualTo(unix.PR_SET_PDEATHSIG), seccomp.EqualTo(unix.SIGKILL)}, + unix.SYS_GETPPID: seccomp.MatchAll{}, // For the stub to stop itself (all). - unix.SYS_GETPID: {}, - unix.SYS_KILL: []seccomp.Rule{ - {seccomp.AnyValue{}, seccomp.EqualTo(unix.SIGSTOP)}, - }, + unix.SYS_GETPID: seccomp.MatchAll{}, + unix.SYS_KILL: seccomp.PerArg{seccomp.AnyValue{}, seccomp.EqualTo(unix.SIGSTOP)}, // Injected to support the address space operations. - unix.SYS_MMAP: {}, - unix.SYS_MUNMAP: {}, + unix.SYS_MMAP: seccomp.MatchAll{}, + unix.SYS_MUNMAP: seccomp.MatchAll{}, }, Action: linux.SECCOMP_RET_ALLOW, }) diff --git a/pkg/sentry/platform/systrap/filters.go b/pkg/sentry/platform/systrap/filters.go index fb33d7181..00c37b679 100644 --- a/pkg/sentry/platform/systrap/filters.go +++ b/pkg/sentry/platform/systrap/filters.go @@ -23,61 +23,59 @@ import ( // SyscallFilters returns syscalls made exclusively by the systrap platform. func (p *Systrap) SyscallFilters() seccomp.SyscallRules { r := seccomp.SyscallRules{ - unix.SYS_PTRACE: { - { + unix.SYS_PTRACE: seccomp.Or{ + seccomp.PerArg{ seccomp.EqualTo(unix.PTRACE_ATTACH), }, - { + seccomp.PerArg{ seccomp.EqualTo(unix.PTRACE_CONT), seccomp.AnyValue{}, seccomp.EqualTo(0), seccomp.EqualTo(0), }, - { + seccomp.PerArg{ seccomp.EqualTo(unix.PTRACE_GETEVENTMSG), }, - { + seccomp.PerArg{ seccomp.EqualTo(unix.PTRACE_GETREGSET), seccomp.AnyValue{}, seccomp.EqualTo(linux.NT_PRSTATUS), }, - { + seccomp.PerArg{ seccomp.EqualTo(unix.PTRACE_GETSIGINFO), }, - { + seccomp.PerArg{ seccomp.EqualTo(unix.PTRACE_SETOPTIONS), seccomp.AnyValue{}, seccomp.EqualTo(0), seccomp.EqualTo(unix.PTRACE_O_TRACESYSGOOD | unix.PTRACE_O_TRACEEXIT | unix.PTRACE_O_EXITKILL), }, - { + seccomp.PerArg{ seccomp.EqualTo(unix.PTRACE_SETREGSET), seccomp.AnyValue{}, seccomp.EqualTo(linux.NT_PRSTATUS), }, - { + seccomp.PerArg{ seccomp.EqualTo(linux.PTRACE_SETSIGMASK), seccomp.AnyValue{}, seccomp.EqualTo(8), }, - { + seccomp.PerArg{ seccomp.EqualTo(unix.PTRACE_SYSEMU), seccomp.AnyValue{}, seccomp.EqualTo(0), seccomp.EqualTo(0), }, - { + seccomp.PerArg{ seccomp.EqualTo(unix.PTRACE_DETACH), }, }, - unix.SYS_TGKILL: {}, - unix.SYS_WAIT4: {}, - unix.SYS_SETPRIORITY: { - { - seccomp.EqualTo(unix.PRIO_PROCESS), - seccomp.AnyValue{}, - seccomp.EqualTo(sysmsgThreadPriority), - }, + unix.SYS_TGKILL: seccomp.MatchAll{}, + unix.SYS_WAIT4: seccomp.MatchAll{}, + unix.SYS_SETPRIORITY: seccomp.PerArg{ + seccomp.EqualTo(unix.PRIO_PROCESS), + seccomp.AnyValue{}, + seccomp.EqualTo(sysmsgThreadPriority), }, } r.Merge(p.archSyscallFilters()) diff --git a/pkg/sentry/platform/systrap/filters_arm64.go b/pkg/sentry/platform/systrap/filters_arm64.go index b14698d82..53f7d036b 100644 --- a/pkg/sentry/platform/systrap/filters_arm64.go +++ b/pkg/sentry/platform/systrap/filters_arm64.go @@ -26,13 +26,13 @@ import ( // SyscallFilters returns syscalls made exclusively by the systrap platform. func (*Systrap) archSyscallFilters() seccomp.SyscallRules { return seccomp.SyscallRules{ - unix.SYS_PTRACE: { - { + unix.SYS_PTRACE: seccomp.Or{ + seccomp.PerArg{ seccomp.EqualTo(unix.PTRACE_GETREGSET), seccomp.AnyValue{}, seccomp.EqualTo(linux.NT_ARM_TLS), }, - { + seccomp.PerArg{ seccomp.EqualTo(unix.PTRACE_SETREGSET), seccomp.AnyValue{}, seccomp.EqualTo(linux.NT_ARM_TLS), diff --git a/pkg/sentry/platform/systrap/subprocess_amd64.go b/pkg/sentry/platform/systrap/subprocess_amd64.go index eecc3667e..5cc9262aa 100644 --- a/pkg/sentry/platform/systrap/subprocess_amd64.go +++ b/pkg/sentry/platform/systrap/subprocess_amd64.go @@ -185,19 +185,19 @@ func appendArchSeccompRules(rules []seccomp.RuleSet) []seccomp.RuleSet { // Rules for trapping vsyscall access. { Rules: seccomp.SyscallRules{ - unix.SYS_GETTIMEOFDAY: {}, - unix.SYS_TIME: {}, - unix.SYS_GETCPU: {}, // SYS_GETCPU was not defined in package syscall on amd64. + unix.SYS_GETTIMEOFDAY: seccomp.MatchAll{}, + unix.SYS_TIME: seccomp.MatchAll{}, + unix.SYS_GETCPU: seccomp.MatchAll{}, // SYS_GETCPU was not defined in package syscall on amd64. }, Action: linux.SECCOMP_RET_TRAP, Vsyscall: true, }, { Rules: seccomp.SyscallRules{ - unix.SYS_ARCH_PRCTL: []seccomp.Rule{ - {seccomp.EqualTo(linux.ARCH_SET_CPUID), seccomp.EqualTo(0)}, - {seccomp.EqualTo(linux.ARCH_SET_FS)}, - {seccomp.EqualTo(linux.ARCH_GET_FS)}, + unix.SYS_ARCH_PRCTL: seccomp.Or{ + seccomp.PerArg{seccomp.EqualTo(linux.ARCH_SET_CPUID), seccomp.EqualTo(0)}, + seccomp.PerArg{seccomp.EqualTo(linux.ARCH_SET_FS)}, + seccomp.PerArg{seccomp.EqualTo(linux.ARCH_GET_FS)}, }, }, Action: linux.SECCOMP_RET_ALLOW, diff --git a/pkg/sentry/platform/systrap/subprocess_linux.go b/pkg/sentry/platform/systrap/subprocess_linux.go index bb112ec40..6da1e3d01 100644 --- a/pkg/sentry/platform/systrap/subprocess_linux.go +++ b/pkg/sentry/platform/systrap/subprocess_linux.go @@ -55,17 +55,17 @@ func attachedThread(flags uintptr, defaultAction linux.BPFAction) (*thread, erro if defaultAction != linux.SECCOMP_RET_ALLOW { ruleSet := seccomp.RuleSet{ Rules: seccomp.SyscallRules{ - unix.SYS_CLONE: []seccomp.Rule{ + unix.SYS_CLONE: seccomp.Or{ // Allow creation of new subprocesses (used by the master). - {seccomp.EqualTo(unix.CLONE_FILES | unix.SIGKILL)}, + seccomp.PerArg{seccomp.EqualTo(unix.CLONE_FILES | unix.SIGKILL)}, // Allow creation of new sysmsg thread. - {seccomp.EqualTo( + seccomp.PerArg{seccomp.EqualTo( unix.CLONE_FILES | unix.CLONE_FS | unix.CLONE_VM | unix.CLONE_PTRACE)}, // Allow creation of new threads within a single address space (used by addresss spaces). - {seccomp.EqualTo( + seccomp.PerArg{seccomp.EqualTo( unix.CLONE_FILES | unix.CLONE_FS | unix.CLONE_SIGHAND | @@ -75,50 +75,54 @@ func attachedThread(flags uintptr, defaultAction linux.BPFAction) (*thread, erro }, // For the initial process creation. - unix.SYS_WAIT4: {}, - unix.SYS_EXIT: {}, + unix.SYS_WAIT4: seccomp.MatchAll{}, + unix.SYS_EXIT: seccomp.MatchAll{}, // For the stub prctl dance (all). - unix.SYS_PRCTL: []seccomp.Rule{ - {seccomp.EqualTo(unix.PR_SET_PDEATHSIG), seccomp.EqualTo(unix.SIGKILL)}, - {seccomp.EqualTo(linux.PR_SET_NO_NEW_PRIVS), seccomp.EqualTo(1)}, + unix.SYS_PRCTL: seccomp.Or{ + seccomp.PerArg{seccomp.EqualTo(unix.PR_SET_PDEATHSIG), seccomp.EqualTo(unix.SIGKILL)}, + seccomp.PerArg{seccomp.EqualTo(linux.PR_SET_NO_NEW_PRIVS), seccomp.EqualTo(1)}, }, - unix.SYS_GETPPID: {}, + unix.SYS_GETPPID: seccomp.MatchAll{}, // For the stub to stop itself (all). - unix.SYS_GETPID: {}, - unix.SYS_KILL: []seccomp.Rule{ - {seccomp.AnyValue{}, seccomp.EqualTo(unix.SIGSTOP)}, + unix.SYS_GETPID: seccomp.MatchAll{}, + unix.SYS_KILL: seccomp.PerArg{ + seccomp.AnyValue{}, + seccomp.EqualTo(unix.SIGSTOP), }, // Injected to support the address space operations. - unix.SYS_MMAP: {}, - unix.SYS_MUNMAP: {}, + unix.SYS_MMAP: seccomp.MatchAll{}, + unix.SYS_MUNMAP: seccomp.MatchAll{}, // For sysmsg threads. Look at sysmsg/sighandler.c for more details. - unix.SYS_RT_SIGRETURN: {}, - unix.SYS_SCHED_YIELD: {}, - unix.SYS_FUTEX: { - seccomp.Rule{ + unix.SYS_RT_SIGRETURN: seccomp.MatchAll{}, + unix.SYS_SCHED_YIELD: seccomp.MatchAll{}, + unix.SYS_FUTEX: seccomp.Or{ + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(linux.FUTEX_WAIT), seccomp.AnyValue{}, seccomp.AnyValue{}, }, - seccomp.Rule{ + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(linux.FUTEX_WAKE), seccomp.AnyValue{}, seccomp.AnyValue{}, }, }, - unix.SYS_SIGALTSTACK: {}, - unix.SYS_TKILL: { - {seccomp.AnyValue{}, seccomp.EqualTo(unix.SIGSTOP)}, + unix.SYS_SIGALTSTACK: seccomp.MatchAll{}, + unix.SYS_TKILL: seccomp.PerArg{ + seccomp.AnyValue{}, + seccomp.EqualTo(unix.SIGSTOP), }, - unix.SYS_GETTID: {}, - seccomp.SYS_SECCOMP: { - {seccomp.EqualTo(linux.SECCOMP_SET_MODE_FILTER), seccomp.EqualTo(0), seccomp.AnyValue{}}, + unix.SYS_GETTID: seccomp.MatchAll{}, + seccomp.SYS_SECCOMP: seccomp.PerArg{ + seccomp.EqualTo(linux.SECCOMP_SET_MODE_FILTER), + seccomp.EqualTo(0), + seccomp.AnyValue{}, }, }, Action: linux.SECCOMP_RET_ALLOW, diff --git a/pkg/sentry/platform/systrap/sysmsg_thread.go b/pkg/sentry/platform/systrap/sysmsg_thread.go index 3642d5aca..f6b809293 100644 --- a/pkg/sentry/platform/systrap/sysmsg_thread.go +++ b/pkg/sentry/platform/systrap/sysmsg_thread.go @@ -104,8 +104,8 @@ func sysmsgThreadRules(stubStart uintptr) []bpf.Instruction { // Allow instructions from the sysmsg code stub, which is limited by one page. { Rules: seccomp.SyscallRules{ - unix.SYS_FUTEX: { - { + unix.SYS_FUTEX: seccomp.Or{ + seccomp.PerArg{ seccomp.GreaterThan(stubStart), seccomp.EqualTo(linux.FUTEX_WAKE), seccomp.EqualTo(1), @@ -114,7 +114,7 @@ func sysmsgThreadRules(stubStart uintptr) []bpf.Instruction { seccomp.EqualTo(0), seccomp.GreaterThan(stubStart), // rip }, - { + seccomp.PerArg{ seccomp.GreaterThan(stubStart), seccomp.EqualTo(linux.FUTEX_WAIT), seccomp.AnyValue{}, @@ -124,27 +124,23 @@ func sysmsgThreadRules(stubStart uintptr) []bpf.Instruction { seccomp.GreaterThan(stubStart), // rip }, }, - unix.SYS_RT_SIGRETURN: { - { - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.GreaterThan(stubStart), // rip - }, + unix.SYS_RT_SIGRETURN: seccomp.PerArg{ + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.GreaterThan(stubStart), // rip }, - unix.SYS_SCHED_YIELD: { - { - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.GreaterThan(stubStart), // rip - }, + unix.SYS_SCHED_YIELD: seccomp.PerArg{ + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.GreaterThan(stubStart), // rip }, }, Action: linux.SECCOMP_RET_ALLOW, diff --git a/pkg/sentry/platform/systrap/sysmsg_thread_amd64.go b/pkg/sentry/platform/systrap/sysmsg_thread_amd64.go index 3af671e6a..dc83a51dc 100644 --- a/pkg/sentry/platform/systrap/sysmsg_thread_amd64.go +++ b/pkg/sentry/platform/systrap/sysmsg_thread_amd64.go @@ -25,17 +25,17 @@ func appendSysThreadArchSeccompRules(rules []seccomp.RuleSet) []seccomp.RuleSet { // Rules for trapping vsyscall access. Rules: seccomp.SyscallRules{ - unix.SYS_GETTIMEOFDAY: {}, - unix.SYS_TIME: {}, - unix.SYS_GETCPU: {}, // SYS_GETCPU was not defined in package syscall on amd64. + unix.SYS_GETTIMEOFDAY: seccomp.MatchAll{}, + unix.SYS_TIME: seccomp.MatchAll{}, + unix.SYS_GETCPU: seccomp.MatchAll{}, // SYS_GETCPU was not defined in package syscall on amd64. }, Action: linux.SECCOMP_RET_TRAP, Vsyscall: true, }, { Rules: seccomp.SyscallRules{ - unix.SYS_ARCH_PRCTL: { - { + unix.SYS_ARCH_PRCTL: seccomp.Or{ + seccomp.PerArg{ seccomp.EqualTo(linux.ARCH_SET_FS), seccomp.AnyValue{}, seccomp.AnyValue{}, @@ -44,7 +44,7 @@ func appendSysThreadArchSeccompRules(rules []seccomp.RuleSet) []seccomp.RuleSet seccomp.AnyValue{}, seccomp.GreaterThan(stubStart), // rip }, - { + seccomp.PerArg{ seccomp.EqualTo(linux.ARCH_GET_FS), seccomp.AnyValue{}, seccomp.AnyValue{}, diff --git a/runsc/boot/filter/config.go b/runsc/boot/filter/config.go index b63098f81..0a0866d0b 100644 --- a/runsc/boot/filter/config.go +++ b/runsc/boot/filter/config.go @@ -25,75 +25,69 @@ import ( // allowedSyscalls is the set of syscalls executed by the Sentry to the host OS. var allowedSyscalls = seccomp.SyscallRules{ - unix.SYS_CLOCK_GETTIME: {}, - unix.SYS_CLOSE: {}, - unix.SYS_DUP: {}, - unix.SYS_DUP3: []seccomp.Rule{ - { - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.EqualTo(unix.O_CLOEXEC), - }, + unix.SYS_CLOCK_GETTIME: seccomp.MatchAll{}, + unix.SYS_CLOSE: seccomp.MatchAll{}, + unix.SYS_DUP: seccomp.MatchAll{}, + unix.SYS_DUP3: seccomp.PerArg{ + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.EqualTo(unix.O_CLOEXEC), }, - unix.SYS_EPOLL_CREATE1: {}, - unix.SYS_EPOLL_CTL: {}, - unix.SYS_EPOLL_PWAIT: []seccomp.Rule{ - { - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.EqualTo(0), - }, + unix.SYS_EPOLL_CREATE1: seccomp.MatchAll{}, + unix.SYS_EPOLL_CTL: seccomp.MatchAll{}, + unix.SYS_EPOLL_PWAIT: seccomp.PerArg{ + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.EqualTo(0), }, - unix.SYS_EVENTFD2: []seccomp.Rule{ - { - seccomp.EqualTo(0), - seccomp.EqualTo(0), - }, + unix.SYS_EVENTFD2: seccomp.PerArg{ + seccomp.EqualTo(0), + seccomp.EqualTo(0), }, - unix.SYS_EXIT: {}, - unix.SYS_EXIT_GROUP: {}, - unix.SYS_FALLOCATE: {}, - unix.SYS_FCHMOD: {}, - unix.SYS_FCNTL: []seccomp.Rule{ - { + unix.SYS_EXIT: seccomp.MatchAll{}, + unix.SYS_EXIT_GROUP: seccomp.MatchAll{}, + unix.SYS_FALLOCATE: seccomp.MatchAll{}, + unix.SYS_FCHMOD: seccomp.MatchAll{}, + unix.SYS_FCNTL: seccomp.Or{ + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(unix.F_GETFL), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(unix.F_SETFL), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(unix.F_GETFD), }, }, - unix.SYS_FSTAT: {}, - unix.SYS_FSYNC: {}, - unix.SYS_FTRUNCATE: {}, - unix.SYS_FUTEX: []seccomp.Rule{ - { + unix.SYS_FSTAT: seccomp.MatchAll{}, + unix.SYS_FSYNC: seccomp.MatchAll{}, + unix.SYS_FTRUNCATE: seccomp.MatchAll{}, + unix.SYS_FUTEX: seccomp.Or{ + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(linux.FUTEX_WAIT | linux.FUTEX_PRIVATE_FLAG), seccomp.AnyValue{}, seccomp.AnyValue{}, }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(linux.FUTEX_WAKE | linux.FUTEX_PRIVATE_FLAG), seccomp.AnyValue{}, }, // Non-private variants are included for flipcall support. They are otherwise - // unncessary, as the sentry will use only private futexes internally. - { + // unnecessary, as the sentry will use only private futexes internally. + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(linux.FUTEX_WAIT), seccomp.AnyValue{}, seccomp.AnyValue{}, }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(linux.FUTEX_WAKE), seccomp.AnyValue{}, @@ -101,269 +95,241 @@ var allowedSyscalls = seccomp.SyscallRules{ }, // getcpu is used by some versions of the Go runtime and by the hostcpu // package on arm64. - unix.SYS_GETCPU: []seccomp.Rule{ - { - seccomp.AnyValue{}, - seccomp.EqualTo(0), - seccomp.EqualTo(0), - }, + unix.SYS_GETCPU: seccomp.PerArg{ + seccomp.AnyValue{}, + seccomp.EqualTo(0), + seccomp.EqualTo(0), }, - unix.SYS_GETPID: {}, - unix.SYS_GETRANDOM: {}, - unix.SYS_GETSOCKOPT: []seccomp.Rule{ - { + unix.SYS_GETPID: seccomp.MatchAll{}, + unix.SYS_GETRANDOM: seccomp.MatchAll{}, + unix.SYS_GETSOCKOPT: seccomp.Or{ + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(unix.SOL_SOCKET), seccomp.EqualTo(unix.SO_DOMAIN), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(unix.SOL_SOCKET), seccomp.EqualTo(unix.SO_TYPE), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(unix.SOL_SOCKET), seccomp.EqualTo(unix.SO_ERROR), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(unix.SOL_SOCKET), seccomp.EqualTo(unix.SO_SNDBUF), }, }, - unix.SYS_GETTID: {}, - unix.SYS_GETTIMEOFDAY: {}, - unix.SYS_IOCTL: []seccomp.Rule{ + unix.SYS_GETTID: seccomp.MatchAll{}, + unix.SYS_GETTIMEOFDAY: seccomp.MatchAll{}, + unix.SYS_IOCTL: seccomp.Or{ // These commands are needed for host FD. - { + seccomp.PerArg{ seccomp.AnyValue{}, /* fd */ seccomp.EqualTo(linux.FIONREAD), seccomp.AnyValue{}, /* int* */ }, // These commands are needed for terminal support, but we only allow // setting/getting termios and winsize. - { + seccomp.PerArg{ seccomp.AnyValue{}, /* fd */ seccomp.EqualTo(linux.TCGETS), seccomp.AnyValue{}, /* termios struct */ }, - { + seccomp.PerArg{ seccomp.AnyValue{}, /* fd */ seccomp.EqualTo(linux.TCSETS), seccomp.AnyValue{}, /* termios struct */ }, - { + seccomp.PerArg{ seccomp.AnyValue{}, /* fd */ seccomp.EqualTo(linux.TCSETSF), seccomp.AnyValue{}, /* termios struct */ }, - { + seccomp.PerArg{ seccomp.AnyValue{}, /* fd */ seccomp.EqualTo(linux.TCSETSW), seccomp.AnyValue{}, /* termios struct */ }, - { + seccomp.PerArg{ seccomp.AnyValue{}, /* fd */ seccomp.EqualTo(linux.TIOCSWINSZ), seccomp.AnyValue{}, /* winsize struct */ }, - { + seccomp.PerArg{ seccomp.AnyValue{}, /* fd */ seccomp.EqualTo(linux.TIOCGWINSZ), seccomp.AnyValue{}, /* winsize struct */ }, - { + seccomp.PerArg{ seccomp.AnyValue{}, /* fd */ seccomp.EqualTo(linux.SIOCGIFTXQLEN), seccomp.AnyValue{}, /* ifreq struct */ }, }, - unix.SYS_LSEEK: {}, - unix.SYS_MADVISE: {}, - unix.SYS_MEMBARRIER: []seccomp.Rule{ - { - seccomp.EqualTo(linux.MEMBARRIER_CMD_GLOBAL), - seccomp.EqualTo(0), - }, + unix.SYS_LSEEK: seccomp.MatchAll{}, + unix.SYS_MADVISE: seccomp.MatchAll{}, + unix.SYS_MEMBARRIER: seccomp.PerArg{ + seccomp.EqualTo(linux.MEMBARRIER_CMD_GLOBAL), + seccomp.EqualTo(0), }, - unix.SYS_MINCORE: {}, - unix.SYS_MLOCK: {}, - unix.SYS_MMAP: []seccomp.Rule{ - { + unix.SYS_MINCORE: seccomp.MatchAll{}, + unix.SYS_MLOCK: seccomp.MatchAll{}, + unix.SYS_MMAP: seccomp.Or{ + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.AnyValue{}, seccomp.AnyValue{}, seccomp.EqualTo(unix.MAP_SHARED), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.AnyValue{}, seccomp.AnyValue{}, seccomp.EqualTo(unix.MAP_SHARED | unix.MAP_FIXED), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.AnyValue{}, seccomp.AnyValue{}, seccomp.EqualTo(unix.MAP_PRIVATE), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.AnyValue{}, seccomp.AnyValue{}, seccomp.EqualTo(unix.MAP_PRIVATE | unix.MAP_ANONYMOUS), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.AnyValue{}, seccomp.AnyValue{}, seccomp.EqualTo(unix.MAP_PRIVATE | unix.MAP_ANONYMOUS | unix.MAP_STACK), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.AnyValue{}, seccomp.AnyValue{}, seccomp.EqualTo(unix.MAP_PRIVATE | unix.MAP_ANONYMOUS | unix.MAP_NORESERVE), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.AnyValue{}, seccomp.EqualTo(unix.PROT_WRITE | unix.PROT_READ), seccomp.EqualTo(unix.MAP_PRIVATE | unix.MAP_ANONYMOUS | unix.MAP_FIXED), }, }, - unix.SYS_MPROTECT: {}, - unix.SYS_MUNLOCK: {}, - unix.SYS_MUNMAP: {}, - unix.SYS_NANOSLEEP: {}, - unix.SYS_PPOLL: {}, - unix.SYS_PREAD64: {}, - unix.SYS_PREADV: {}, - unix.SYS_PREADV2: {}, - unix.SYS_PWRITE64: {}, - unix.SYS_PWRITEV: {}, - unix.SYS_PWRITEV2: {}, - unix.SYS_READ: {}, - unix.SYS_RECVMSG: []seccomp.Rule{ - { + unix.SYS_MPROTECT: seccomp.MatchAll{}, + unix.SYS_MUNLOCK: seccomp.MatchAll{}, + unix.SYS_MUNMAP: seccomp.MatchAll{}, + unix.SYS_NANOSLEEP: seccomp.MatchAll{}, + unix.SYS_PPOLL: seccomp.MatchAll{}, + unix.SYS_PREAD64: seccomp.MatchAll{}, + unix.SYS_PREADV: seccomp.MatchAll{}, + unix.SYS_PREADV2: seccomp.MatchAll{}, + unix.SYS_PWRITE64: seccomp.MatchAll{}, + unix.SYS_PWRITEV: seccomp.MatchAll{}, + unix.SYS_PWRITEV2: seccomp.MatchAll{}, + unix.SYS_READ: seccomp.MatchAll{}, + unix.SYS_RECVMSG: seccomp.Or{ + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.AnyValue{}, seccomp.EqualTo(unix.MSG_DONTWAIT | unix.MSG_TRUNC), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.AnyValue{}, seccomp.EqualTo(unix.MSG_DONTWAIT | unix.MSG_TRUNC | unix.MSG_PEEK), }, }, - unix.SYS_RECVMMSG: []seccomp.Rule{ - { - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.EqualTo(fdbased.MaxMsgsPerRecv), - seccomp.EqualTo(unix.MSG_DONTWAIT), - seccomp.EqualTo(0), - }, + unix.SYS_RECVMMSG: seccomp.PerArg{ + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.EqualTo(fdbased.MaxMsgsPerRecv), + seccomp.EqualTo(unix.MSG_DONTWAIT), + seccomp.EqualTo(0), }, - unix.SYS_SENDMMSG: []seccomp.Rule{ - { - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.EqualTo(unix.MSG_DONTWAIT), - }, + unix.SYS_SENDMMSG: seccomp.PerArg{ + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.EqualTo(unix.MSG_DONTWAIT), }, - unix.SYS_RESTART_SYSCALL: {}, - unix.SYS_RT_SIGACTION: {}, - unix.SYS_RT_SIGPROCMASK: {}, - unix.SYS_RT_SIGRETURN: {}, - unix.SYS_SCHED_YIELD: {}, - unix.SYS_SENDMSG: []seccomp.Rule{ - { - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.EqualTo(unix.MSG_DONTWAIT | unix.MSG_NOSIGNAL), - }, + unix.SYS_RESTART_SYSCALL: seccomp.MatchAll{}, + unix.SYS_RT_SIGACTION: seccomp.MatchAll{}, + unix.SYS_RT_SIGPROCMASK: seccomp.MatchAll{}, + unix.SYS_RT_SIGRETURN: seccomp.MatchAll{}, + unix.SYS_SCHED_YIELD: seccomp.MatchAll{}, + unix.SYS_SENDMSG: seccomp.PerArg{ + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.EqualTo(unix.MSG_DONTWAIT | unix.MSG_NOSIGNAL), }, - unix.SYS_SETITIMER: {}, - unix.SYS_SHUTDOWN: []seccomp.Rule{ + unix.SYS_SETITIMER: seccomp.MatchAll{}, + unix.SYS_SHUTDOWN: seccomp.Or{ // Used by fs/host to shutdown host sockets. - {seccomp.AnyValue{}, seccomp.EqualTo(unix.SHUT_RD)}, - {seccomp.AnyValue{}, seccomp.EqualTo(unix.SHUT_WR)}, + seccomp.PerArg{seccomp.AnyValue{}, seccomp.EqualTo(unix.SHUT_RD)}, + seccomp.PerArg{seccomp.AnyValue{}, seccomp.EqualTo(unix.SHUT_WR)}, // Used by unet to shutdown connections. - {seccomp.AnyValue{}, seccomp.EqualTo(unix.SHUT_RDWR)}, + seccomp.PerArg{seccomp.AnyValue{}, seccomp.EqualTo(unix.SHUT_RDWR)}, }, - unix.SYS_SIGALTSTACK: {}, - unix.SYS_STATX: {}, - unix.SYS_SYNC_FILE_RANGE: {}, - unix.SYS_TEE: []seccomp.Rule{ - { - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.EqualTo(1), /* len */ - seccomp.EqualTo(unix.SPLICE_F_NONBLOCK), /* flags */ - }, + unix.SYS_SIGALTSTACK: seccomp.MatchAll{}, + unix.SYS_STATX: seccomp.MatchAll{}, + unix.SYS_SYNC_FILE_RANGE: seccomp.MatchAll{}, + unix.SYS_TEE: seccomp.PerArg{ + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.EqualTo(1), /* len */ + seccomp.EqualTo(unix.SPLICE_F_NONBLOCK), /* flags */ }, - unix.SYS_TIMER_CREATE: []seccomp.Rule{ - { - seccomp.EqualTo(unix.CLOCK_THREAD_CPUTIME_ID), /* which */ - seccomp.AnyValue{}, /* sevp */ - seccomp.AnyValue{}, /* timerid */ - }, + unix.SYS_TIMER_CREATE: seccomp.PerArg{ + seccomp.EqualTo(unix.CLOCK_THREAD_CPUTIME_ID), /* which */ + seccomp.AnyValue{}, /* sevp */ + seccomp.AnyValue{}, /* timerid */ }, - unix.SYS_TIMER_DELETE: []seccomp.Rule{}, - unix.SYS_TIMER_SETTIME: []seccomp.Rule{ - { - seccomp.AnyValue{}, /* timerid */ - seccomp.EqualTo(0), /* flags */ - seccomp.AnyValue{}, /* new_value */ - seccomp.EqualTo(0), /* old_value */ - }, + unix.SYS_TIMER_DELETE: seccomp.MatchAll{}, + unix.SYS_TIMER_SETTIME: seccomp.PerArg{ + seccomp.AnyValue{}, /* timerid */ + seccomp.EqualTo(0), /* flags */ + seccomp.AnyValue{}, /* new_value */ + seccomp.EqualTo(0), /* old_value */ }, - unix.SYS_TGKILL: []seccomp.Rule{ - { - seccomp.EqualTo(uint64(os.Getpid())), - }, + unix.SYS_TGKILL: seccomp.PerArg{ + seccomp.EqualTo(uint64(os.Getpid())), }, - unix.SYS_UTIMENSAT: []seccomp.Rule{ - { - seccomp.AnyValue{}, - seccomp.EqualTo(0), /* null pathname */ - seccomp.AnyValue{}, - seccomp.EqualTo(0), /* flags */ - }, + unix.SYS_UTIMENSAT: seccomp.PerArg{ + seccomp.AnyValue{}, + seccomp.EqualTo(0), /* null pathname */ + seccomp.AnyValue{}, + seccomp.EqualTo(0), /* flags */ }, - unix.SYS_WRITE: {}, + unix.SYS_WRITE: seccomp.MatchAll{}, // For rawfile.NonBlockingWriteIovec. - unix.SYS_WRITEV: []seccomp.Rule{ - { - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.GreaterThan(0), - }, + unix.SYS_WRITEV: seccomp.PerArg{ + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.GreaterThan(0), }, } func controlServerFilters(fd int) seccomp.SyscallRules { return seccomp.SyscallRules{ - unix.SYS_ACCEPT4: []seccomp.Rule{ - { - seccomp.EqualTo(fd), - }, + unix.SYS_ACCEPT4: seccomp.PerArg{ + seccomp.EqualTo(fd), }, - unix.SYS_LISTEN: []seccomp.Rule{ - { - seccomp.EqualTo(fd), - seccomp.EqualTo(16 /* unet.backlog */), - }, + unix.SYS_LISTEN: seccomp.PerArg{ + seccomp.EqualTo(fd), + seccomp.EqualTo(16 /* unet.backlog */), }, - unix.SYS_GETSOCKOPT: []seccomp.Rule{ - { - seccomp.AnyValue{}, - seccomp.EqualTo(unix.SOL_SOCKET), - seccomp.EqualTo(unix.SO_PEERCRED), - }, + unix.SYS_GETSOCKOPT: seccomp.PerArg{ + seccomp.AnyValue{}, + seccomp.EqualTo(unix.SOL_SOCKET), + seccomp.EqualTo(unix.SO_PEERCRED), }, } } @@ -376,112 +342,84 @@ func hostFilesystemFilters() seccomp.SyscallRules { // don't know what set of arguments will trigger a future vulnerability. validFDCheck := seccomp.NonNegativeFDCheck() return seccomp.SyscallRules{ - unix.SYS_FCHOWNAT: []seccomp.Rule{ - { - validFDCheck, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.EqualTo(unix.AT_EMPTY_PATH | unix.AT_SYMLINK_NOFOLLOW), - }, + unix.SYS_FCHOWNAT: seccomp.PerArg{ + validFDCheck, + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.EqualTo(unix.AT_EMPTY_PATH | unix.AT_SYMLINK_NOFOLLOW), }, - unix.SYS_FCHMODAT: []seccomp.Rule{ - { - validFDCheck, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - }, + unix.SYS_FCHMODAT: seccomp.PerArg{ + validFDCheck, + seccomp.AnyValue{}, + seccomp.AnyValue{}, }, - unix.SYS_UNLINKAT: []seccomp.Rule{ - { - validFDCheck, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - }, + unix.SYS_UNLINKAT: seccomp.PerArg{ + validFDCheck, + seccomp.AnyValue{}, + seccomp.AnyValue{}, }, - unix.SYS_GETDENTS64: []seccomp.Rule{ - { - validFDCheck, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - }, + unix.SYS_GETDENTS64: seccomp.PerArg{ + validFDCheck, + seccomp.AnyValue{}, + seccomp.AnyValue{}, }, - unix.SYS_OPENAT: []seccomp.Rule{ - { - validFDCheck, - seccomp.AnyValue{}, - seccomp.MaskedEqual(unix.O_NOFOLLOW, unix.O_NOFOLLOW), - seccomp.AnyValue{}, - }, + unix.SYS_OPENAT: seccomp.PerArg{ + validFDCheck, + seccomp.AnyValue{}, + seccomp.MaskedEqual(unix.O_NOFOLLOW, unix.O_NOFOLLOW), + seccomp.AnyValue{}, }, - unix.SYS_LINKAT: []seccomp.Rule{ - { - validFDCheck, - seccomp.AnyValue{}, - validFDCheck, - seccomp.AnyValue{}, - seccomp.EqualTo(0), - }, + unix.SYS_LINKAT: seccomp.PerArg{ + validFDCheck, + seccomp.AnyValue{}, + validFDCheck, + seccomp.AnyValue{}, + seccomp.EqualTo(0), }, - unix.SYS_MKDIRAT: []seccomp.Rule{ - { - validFDCheck, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - }, + unix.SYS_MKDIRAT: seccomp.PerArg{ + validFDCheck, + seccomp.AnyValue{}, + seccomp.AnyValue{}, }, - unix.SYS_MKNODAT: []seccomp.Rule{ - { - validFDCheck, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - }, + unix.SYS_MKNODAT: seccomp.PerArg{ + validFDCheck, + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.AnyValue{}, }, - unix.SYS_SYMLINKAT: []seccomp.Rule{ - { - seccomp.AnyValue{}, - validFDCheck, - seccomp.AnyValue{}, - }, + unix.SYS_SYMLINKAT: seccomp.PerArg{ + seccomp.AnyValue{}, + validFDCheck, + seccomp.AnyValue{}, }, - unix.SYS_FSTATFS: []seccomp.Rule{ - { - validFDCheck, - seccomp.AnyValue{}, - }, + unix.SYS_FSTATFS: seccomp.PerArg{ + validFDCheck, + seccomp.AnyValue{}, }, - unix.SYS_READLINKAT: []seccomp.Rule{ - { - validFDCheck, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - }, + unix.SYS_READLINKAT: seccomp.PerArg{ + validFDCheck, + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.AnyValue{}, }, - unix.SYS_UTIMENSAT: []seccomp.Rule{ - { - validFDCheck, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - }, + unix.SYS_UTIMENSAT: seccomp.PerArg{ + validFDCheck, + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.AnyValue{}, }, - unix.SYS_RENAMEAT: []seccomp.Rule{ - { - validFDCheck, - seccomp.AnyValue{}, - validFDCheck, - seccomp.AnyValue{}, - }, + unix.SYS_RENAMEAT: seccomp.PerArg{ + validFDCheck, + seccomp.AnyValue{}, + validFDCheck, + seccomp.AnyValue{}, }, - archFstatAtSysNo(): []seccomp.Rule{ - { - validFDCheck, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - }, + archFstatAtSysNo(): seccomp.PerArg{ + validFDCheck, + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.AnyValue{}, }, } } diff --git a/runsc/boot/filter/config_amd64.go b/runsc/boot/filter/config_amd64.go index 16cb690ab..2f2020c17 100644 --- a/runsc/boot/filter/config_amd64.go +++ b/runsc/boot/filter/config_amd64.go @@ -23,23 +23,21 @@ import ( ) func init() { - allowedSyscalls[unix.SYS_CLONE] = []seccomp.Rule{ + allowedSyscalls[unix.SYS_CLONE] = seccomp.PerArg{ // parent_tidptr and child_tidptr are always 0 because neither // CLONE_PARENT_SETTID nor CLONE_CHILD_SETTID are used. - { - seccomp.EqualTo( - unix.CLONE_VM | - unix.CLONE_FS | - unix.CLONE_FILES | - unix.CLONE_SETTLS | - unix.CLONE_SIGHAND | - unix.CLONE_SYSVSEM | - unix.CLONE_THREAD), - seccomp.AnyValue{}, // newsp - seccomp.EqualTo(0), // parent_tidptr - seccomp.EqualTo(0), // child_tidptr - seccomp.AnyValue{}, // tls - }, + seccomp.EqualTo( + unix.CLONE_VM | + unix.CLONE_FS | + unix.CLONE_FILES | + unix.CLONE_SETTLS | + unix.CLONE_SIGHAND | + unix.CLONE_SYSVSEM | + unix.CLONE_THREAD), + seccomp.AnyValue{}, // newsp + seccomp.EqualTo(0), // parent_tidptr + seccomp.EqualTo(0), // child_tidptr + seccomp.AnyValue{}, // tls } } diff --git a/runsc/boot/filter/config_arm64.go b/runsc/boot/filter/config_arm64.go index 4f9a50dda..73a9fdb14 100644 --- a/runsc/boot/filter/config_arm64.go +++ b/runsc/boot/filter/config_arm64.go @@ -23,23 +23,21 @@ import ( ) func init() { - allowedSyscalls[unix.SYS_CLONE] = []seccomp.Rule{ - { - seccomp.EqualTo( - unix.CLONE_VM | - unix.CLONE_FS | - unix.CLONE_FILES | - unix.CLONE_SIGHAND | - unix.CLONE_SYSVSEM | - unix.CLONE_THREAD), - seccomp.AnyValue{}, // newsp - // These arguments are left uninitialized by the Go - // runtime, so they may be anything (and are unused by - // the host). - seccomp.AnyValue{}, // parent_tidptr - seccomp.AnyValue{}, // tls - seccomp.AnyValue{}, // child_tidptr - }, + allowedSyscalls[unix.SYS_CLONE] = seccomp.PerArg{ + seccomp.EqualTo( + unix.CLONE_VM | + unix.CLONE_FS | + unix.CLONE_FILES | + unix.CLONE_SIGHAND | + unix.CLONE_SYSVSEM | + unix.CLONE_THREAD), + seccomp.AnyValue{}, // newsp + // These arguments are left uninitialized by the Go + // runtime, so they may be anything (and are unused by + // the host). + seccomp.AnyValue{}, // parent_tidptr + seccomp.AnyValue{}, // tls + seccomp.AnyValue{}, // child_tidptr } } diff --git a/runsc/boot/filter/config_profile.go b/runsc/boot/filter/config_profile.go index 9b4b6c4bc..a16dd53fb 100644 --- a/runsc/boot/filter/config_profile.go +++ b/runsc/boot/filter/config_profile.go @@ -25,12 +25,10 @@ import ( // profileFilters returns extra syscalls made by runtime/pprof package. func profileFilters() seccomp.SyscallRules { return seccomp.SyscallRules{ - unix.SYS_OPENAT: []seccomp.Rule{ - { - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.EqualTo(unix.O_RDONLY | unix.O_LARGEFILE | unix.O_CLOEXEC), - }, + unix.SYS_OPENAT: seccomp.PerArg{ + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.EqualTo(unix.O_RDONLY | unix.O_LARGEFILE | unix.O_CLOEXEC), }, } } diff --git a/runsc/boot/filter/extra_filters_asan.go b/runsc/boot/filter/extra_filters_asan.go index 416b39a0f..279359814 100644 --- a/runsc/boot/filter/extra_filters_asan.go +++ b/runsc/boot/filter/extra_filters_asan.go @@ -26,9 +26,9 @@ import ( func instrumentationFilters() seccomp.SyscallRules { Report("ASAN is enabled: syscall filters less restrictive!") return seccomp.SyscallRules{ - unix.SYS_CLONE: {}, - unix.SYS_MMAP: {}, - unix.SYS_SCHED_GETAFFINITY: {}, - unix.SYS_SET_ROBUST_LIST: {}, + unix.SYS_CLONE: seccomp.MatchAll{}, + unix.SYS_MMAP: seccomp.MatchAll{}, + unix.SYS_SCHED_GETAFFINITY: seccomp.MatchAll{}, + unix.SYS_SET_ROBUST_LIST: seccomp.MatchAll{}, } } diff --git a/runsc/boot/filter/extra_filters_hostinet.go b/runsc/boot/filter/extra_filters_hostinet.go index 0c48da16d..977e388e7 100644 --- a/runsc/boot/filter/extra_filters_hostinet.go +++ b/runsc/boot/filter/extra_filters_hostinet.go @@ -24,97 +24,95 @@ import ( // hostInetFilters contains syscalls that are needed by sentry/socket/hostinet. func hostInetFilters(allowRawSockets bool) seccomp.SyscallRules { rules := seccomp.SyscallRules{ - unix.SYS_ACCEPT4: []seccomp.Rule{ - { - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.EqualTo(unix.SOCK_NONBLOCK | unix.SOCK_CLOEXEC), - }, + unix.SYS_ACCEPT4: seccomp.PerArg{ + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.EqualTo(unix.SOCK_NONBLOCK | unix.SOCK_CLOEXEC), }, - unix.SYS_BIND: {}, - unix.SYS_CONNECT: {}, - unix.SYS_GETPEERNAME: {}, - unix.SYS_GETSOCKNAME: {}, - unix.SYS_IOCTL: []seccomp.Rule{ - { + unix.SYS_BIND: seccomp.MatchAll{}, + unix.SYS_CONNECT: seccomp.MatchAll{}, + unix.SYS_GETPEERNAME: seccomp.MatchAll{}, + unix.SYS_GETSOCKNAME: seccomp.MatchAll{}, + unix.SYS_IOCTL: seccomp.Or{ + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(unix.SIOCGIFCONF), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(unix.SIOCETHTOOL), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(unix.SIOCGIFFLAGS), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(unix.SIOCGIFHWADDR), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(unix.SIOCGIFINDEX), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(unix.SIOCGIFMTU), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(unix.SIOCGIFNAME), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(unix.SIOCGIFNETMASK), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(unix.TIOCOUTQ), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(unix.TIOCINQ), }, }, - unix.SYS_LISTEN: {}, - unix.SYS_READV: {}, - unix.SYS_RECVFROM: {}, - unix.SYS_RECVMSG: {}, - unix.SYS_SENDMSG: {}, - unix.SYS_SENDTO: {}, - unix.SYS_SHUTDOWN: []seccomp.Rule{ - { + unix.SYS_LISTEN: seccomp.MatchAll{}, + unix.SYS_READV: seccomp.MatchAll{}, + unix.SYS_RECVFROM: seccomp.MatchAll{}, + unix.SYS_RECVMSG: seccomp.MatchAll{}, + unix.SYS_SENDMSG: seccomp.MatchAll{}, + unix.SYS_SENDTO: seccomp.MatchAll{}, + unix.SYS_SHUTDOWN: seccomp.Or{ + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(unix.SHUT_RD), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(unix.SHUT_WR), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(unix.SHUT_RDWR), }, }, - unix.SYS_WRITEV: {}, + unix.SYS_WRITEV: seccomp.MatchAll{}, } // Need NETLINK_ROUTE and stream sockets to query host interfaces and // routes. - socketRules := []seccomp.Rule{ - seccomp.Rule{ + socketRules := seccomp.Or{ + seccomp.PerArg{ seccomp.EqualTo(unix.AF_NETLINK), seccomp.EqualTo(unix.SOCK_RAW | unix.SOCK_CLOEXEC), seccomp.EqualTo(unix.NETLINK_ROUTE), }, - seccomp.Rule{ + seccomp.PerArg{ seccomp.EqualTo(unix.AF_INET), seccomp.EqualTo(unix.SOCK_STREAM), seccomp.EqualTo(0), }, - seccomp.Rule{ + seccomp.PerArg{ seccomp.EqualTo(unix.AF_INET6), seccomp.EqualTo(unix.SOCK_STREAM), seccomp.EqualTo(0), @@ -128,7 +126,7 @@ func hostInetFilters(allowRawSockets bool) seccomp.SyscallRules { stypes = append(stypes, hostinet.AllowedRawSocketTypes...) } for _, sock := range stypes { - rule := seccomp.Rule{ + rule := seccomp.PerArg{ seccomp.EqualTo(sock.Family), // We always set SOCK_NONBLOCK and SOCK_CLOEXEC. seccomp.EqualTo(sock.Type | linux.SOCK_NONBLOCK | linux.SOCK_CLOEXEC), @@ -145,12 +143,9 @@ func hostInetFilters(allowRawSockets bool) seccomp.SyscallRules { // Generate rules for socket options based on hostinet's supported // socket options. - getSockOptRules := []seccomp.Rule{} - setSockOptRules := []seccomp.Rule{} - for _, opt := range hostinet.SockOpts { if opt.AllowGet { - getSockOptRules = append(getSockOptRules, seccomp.Rule{ + rules.AddRule(unix.SYS_GETSOCKOPT, seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(opt.Level), seccomp.EqualTo(opt.Name), @@ -158,7 +153,7 @@ func hostInetFilters(allowRawSockets bool) seccomp.SyscallRules { } if opt.AllowSet { if opt.Size > 0 { - setSockOptRules = append(setSockOptRules, seccomp.Rule{ + rules.AddRule(unix.SYS_SETSOCKOPT, seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(opt.Level), seccomp.EqualTo(opt.Name), @@ -166,7 +161,7 @@ func hostInetFilters(allowRawSockets bool) seccomp.SyscallRules { seccomp.EqualTo(opt.Size), }) } else { - setSockOptRules = append(setSockOptRules, seccomp.Rule{ + rules.AddRule(unix.SYS_SETSOCKOPT, seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(opt.Level), seccomp.EqualTo(opt.Name), @@ -174,8 +169,6 @@ func hostInetFilters(allowRawSockets bool) seccomp.SyscallRules { } } } - rules[unix.SYS_GETSOCKOPT] = getSockOptRules - rules[unix.SYS_SETSOCKOPT] = setSockOptRules return rules } diff --git a/runsc/boot/filter/extra_filters_msan.go b/runsc/boot/filter/extra_filters_msan.go index 8873f9cf9..942f347c5 100644 --- a/runsc/boot/filter/extra_filters_msan.go +++ b/runsc/boot/filter/extra_filters_msan.go @@ -26,9 +26,9 @@ import ( func instrumentationFilters() seccomp.SyscallRules { Report("MSAN is enabled: syscall filters less restrictive!") return seccomp.SyscallRules{ - unix.SYS_CLONE: {}, - unix.SYS_MMAP: {}, - unix.SYS_SCHED_GETAFFINITY: {}, - unix.SYS_SET_ROBUST_LIST: {}, + unix.SYS_CLONE: seccomp.MatchAll{}, + unix.SYS_MMAP: seccomp.MatchAll{}, + unix.SYS_SCHED_GETAFFINITY: seccomp.MatchAll{}, + unix.SYS_SET_ROBUST_LIST: seccomp.MatchAll{}, } } diff --git a/runsc/boot/filter/extra_filters_race.go b/runsc/boot/filter/extra_filters_race.go index 9db5d0c96..04955dcce 100644 --- a/runsc/boot/filter/extra_filters_race.go +++ b/runsc/boot/filter/extra_filters_race.go @@ -26,17 +26,17 @@ import ( func instrumentationFilters() seccomp.SyscallRules { Report("TSAN is enabled: syscall filters less restrictive!") return archInstrumentationFilters(seccomp.SyscallRules{ - unix.SYS_BRK: {}, - unix.SYS_CLOCK_NANOSLEEP: {}, - unix.SYS_CLONE: {}, - unix.SYS_CLONE3: {}, - unix.SYS_FUTEX: {}, - unix.SYS_MMAP: {}, - unix.SYS_MUNLOCK: {}, - unix.SYS_NANOSLEEP: {}, - unix.SYS_OPENAT: {}, - unix.SYS_RSEQ: {}, - unix.SYS_SET_ROBUST_LIST: {}, - unix.SYS_SCHED_GETAFFINITY: {}, + unix.SYS_BRK: seccomp.MatchAll{}, + unix.SYS_CLOCK_NANOSLEEP: seccomp.MatchAll{}, + unix.SYS_CLONE: seccomp.MatchAll{}, + unix.SYS_CLONE3: seccomp.MatchAll{}, + unix.SYS_FUTEX: seccomp.MatchAll{}, + unix.SYS_MMAP: seccomp.MatchAll{}, + unix.SYS_MUNLOCK: seccomp.MatchAll{}, + unix.SYS_NANOSLEEP: seccomp.MatchAll{}, + unix.SYS_OPENAT: seccomp.MatchAll{}, + unix.SYS_RSEQ: seccomp.MatchAll{}, + unix.SYS_SET_ROBUST_LIST: seccomp.MatchAll{}, + unix.SYS_SCHED_GETAFFINITY: seccomp.MatchAll{}, }) } diff --git a/runsc/boot/filter/extra_filters_race_amd64.go b/runsc/boot/filter/extra_filters_race_amd64.go index e7e8eb602..c5932d44a 100644 --- a/runsc/boot/filter/extra_filters_race_amd64.go +++ b/runsc/boot/filter/extra_filters_race_amd64.go @@ -23,8 +23,8 @@ import ( ) func archInstrumentationFilters(f seccomp.SyscallRules) seccomp.SyscallRules { - f[unix.SYS_OPEN] = []seccomp.Rule{} + f[unix.SYS_OPEN] = seccomp.MatchAll{} // Used within glibc's malloc. - f[unix.SYS_TIME] = []seccomp.Rule{} + f[unix.SYS_TIME] = seccomp.MatchAll{} return f } diff --git a/runsc/fsgofer/filter/config.go b/runsc/fsgofer/filter/config.go index 379cfdcc3..6940165a7 100644 --- a/runsc/fsgofer/filter/config.go +++ b/runsc/fsgofer/filter/config.go @@ -24,69 +24,63 @@ import ( // allowedSyscalls is the set of syscalls executed by the gofer. var allowedSyscalls = seccomp.SyscallRules{ - unix.SYS_ACCEPT: {}, - unix.SYS_CLOCK_GETTIME: {}, - unix.SYS_CLOSE: {}, - unix.SYS_DUP: {}, - unix.SYS_EPOLL_CTL: {}, - unix.SYS_EPOLL_PWAIT: []seccomp.Rule{ - { - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.EqualTo(0), - }, + unix.SYS_ACCEPT: seccomp.MatchAll{}, + unix.SYS_CLOCK_GETTIME: seccomp.MatchAll{}, + unix.SYS_CLOSE: seccomp.MatchAll{}, + unix.SYS_DUP: seccomp.MatchAll{}, + unix.SYS_EPOLL_CTL: seccomp.MatchAll{}, + unix.SYS_EPOLL_PWAIT: seccomp.PerArg{ + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.EqualTo(0), }, - unix.SYS_EVENTFD2: []seccomp.Rule{ - { - seccomp.EqualTo(0), - seccomp.EqualTo(0), - }, + unix.SYS_EVENTFD2: seccomp.PerArg{ + seccomp.EqualTo(0), + seccomp.EqualTo(0), }, - unix.SYS_EXIT: {}, - unix.SYS_EXIT_GROUP: {}, - unix.SYS_FALLOCATE: []seccomp.Rule{ - { - seccomp.AnyValue{}, - seccomp.EqualTo(0), - }, + unix.SYS_EXIT: seccomp.MatchAll{}, + unix.SYS_EXIT_GROUP: seccomp.MatchAll{}, + unix.SYS_FALLOCATE: seccomp.PerArg{ + seccomp.AnyValue{}, + seccomp.EqualTo(0), }, - unix.SYS_FCHMOD: {}, - unix.SYS_FCHMODAT: {}, - unix.SYS_FCHOWNAT: {}, - unix.SYS_FCNTL: []seccomp.Rule{ - { + unix.SYS_FCHMOD: seccomp.MatchAll{}, + unix.SYS_FCHMODAT: seccomp.MatchAll{}, + unix.SYS_FCHOWNAT: seccomp.MatchAll{}, + unix.SYS_FCNTL: seccomp.Or{ + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(unix.F_GETFL), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(unix.F_SETFL), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(unix.F_GETFD), }, // Used by flipcall.PacketWindowAllocator.Init(). - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(unix.F_ADD_SEALS), }, }, - unix.SYS_FSTAT: {}, - unix.SYS_FSTATFS: {}, - unix.SYS_FSYNC: {}, - unix.SYS_FTRUNCATE: {}, - unix.SYS_FUTEX: { - seccomp.Rule{ + unix.SYS_FSTAT: seccomp.MatchAll{}, + unix.SYS_FSTATFS: seccomp.MatchAll{}, + unix.SYS_FSYNC: seccomp.MatchAll{}, + unix.SYS_FTRUNCATE: seccomp.MatchAll{}, + unix.SYS_FUTEX: seccomp.Or{ + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(linux.FUTEX_WAIT | linux.FUTEX_PRIVATE_FLAG), seccomp.AnyValue{}, seccomp.AnyValue{}, seccomp.EqualTo(0), }, - seccomp.Rule{ + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(linux.FUTEX_WAKE | linux.FUTEX_PRIVATE_FLAG), seccomp.AnyValue{}, @@ -94,13 +88,13 @@ var allowedSyscalls = seccomp.SyscallRules{ seccomp.EqualTo(0), }, // Non-private futex used for flipcall. - seccomp.Rule{ + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(linux.FUTEX_WAIT), seccomp.AnyValue{}, seccomp.AnyValue{}, }, - seccomp.Rule{ + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.EqualTo(linux.FUTEX_WAKE), seccomp.AnyValue{}, @@ -109,122 +103,117 @@ var allowedSyscalls = seccomp.SyscallRules{ }, // getcpu is used by some versions of the Go runtime and by the hostcpu // package on arm64. - unix.SYS_GETCPU: []seccomp.Rule{ - { - seccomp.AnyValue{}, - seccomp.EqualTo(0), - seccomp.EqualTo(0), - }, + unix.SYS_GETCPU: seccomp.PerArg{ + seccomp.AnyValue{}, + seccomp.EqualTo(0), + seccomp.EqualTo(0), }, - unix.SYS_GETDENTS64: {}, - unix.SYS_GETPID: {}, - unix.SYS_GETRANDOM: {}, - unix.SYS_GETTID: {}, - unix.SYS_GETTIMEOFDAY: {}, - unix.SYS_LINKAT: {}, - unix.SYS_LSEEK: {}, - unix.SYS_MADVISE: {}, - unix.SYS_MEMFD_CREATE: {}, /// Used by flipcall.PacketWindowAllocator.Init(). - unix.SYS_MKDIRAT: {}, - unix.SYS_MKNODAT: {}, - unix.SYS_MMAP: []seccomp.Rule{ - { + unix.SYS_GETDENTS64: seccomp.MatchAll{}, + unix.SYS_GETPID: seccomp.MatchAll{}, + unix.SYS_GETRANDOM: seccomp.MatchAll{}, + unix.SYS_GETTID: seccomp.MatchAll{}, + unix.SYS_GETTIMEOFDAY: seccomp.MatchAll{}, + unix.SYS_LINKAT: seccomp.MatchAll{}, + unix.SYS_LSEEK: seccomp.MatchAll{}, + unix.SYS_MADVISE: seccomp.MatchAll{}, + unix.SYS_MEMFD_CREATE: seccomp.MatchAll{}, // Used by flipcall.PacketWindowAllocator.Init(). + unix.SYS_MKDIRAT: seccomp.MatchAll{}, + unix.SYS_MKNODAT: seccomp.MatchAll{}, + unix.SYS_MMAP: seccomp.Or{ + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.AnyValue{}, seccomp.AnyValue{}, seccomp.EqualTo(unix.MAP_SHARED), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.AnyValue{}, seccomp.AnyValue{}, seccomp.EqualTo(unix.MAP_PRIVATE | unix.MAP_ANONYMOUS), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.AnyValue{}, seccomp.AnyValue{}, seccomp.EqualTo(unix.MAP_PRIVATE | unix.MAP_ANONYMOUS | unix.MAP_FIXED), }, }, - unix.SYS_MPROTECT: {}, - unix.SYS_MUNMAP: {}, - unix.SYS_NANOSLEEP: {}, - unix.SYS_OPENAT: {}, - unix.SYS_PPOLL: {}, - unix.SYS_PREAD64: {}, - unix.SYS_PWRITE64: {}, - unix.SYS_READ: {}, - unix.SYS_READLINKAT: {}, - unix.SYS_RECVMSG: []seccomp.Rule{ - { + unix.SYS_MPROTECT: seccomp.MatchAll{}, + unix.SYS_MUNMAP: seccomp.MatchAll{}, + unix.SYS_NANOSLEEP: seccomp.MatchAll{}, + unix.SYS_OPENAT: seccomp.MatchAll{}, + unix.SYS_PPOLL: seccomp.MatchAll{}, + unix.SYS_PREAD64: seccomp.MatchAll{}, + unix.SYS_PWRITE64: seccomp.MatchAll{}, + unix.SYS_READ: seccomp.MatchAll{}, + unix.SYS_READLINKAT: seccomp.MatchAll{}, + unix.SYS_RECVMSG: seccomp.Or{ + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.AnyValue{}, seccomp.EqualTo(unix.MSG_DONTWAIT | unix.MSG_TRUNC), }, - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.AnyValue{}, seccomp.EqualTo(unix.MSG_DONTWAIT | unix.MSG_TRUNC | unix.MSG_PEEK), }, }, - unix.SYS_RENAMEAT: {}, - unix.SYS_RESTART_SYSCALL: {}, + unix.SYS_RENAMEAT: seccomp.MatchAll{}, + unix.SYS_RESTART_SYSCALL: seccomp.MatchAll{}, // May be used by the runtime during panic(). - unix.SYS_RT_SIGACTION: {}, - unix.SYS_RT_SIGPROCMASK: {}, - unix.SYS_RT_SIGRETURN: {}, - unix.SYS_SCHED_YIELD: {}, - unix.SYS_SENDMSG: []seccomp.Rule{ + unix.SYS_RT_SIGACTION: seccomp.MatchAll{}, + unix.SYS_RT_SIGPROCMASK: seccomp.MatchAll{}, + unix.SYS_RT_SIGRETURN: seccomp.MatchAll{}, + unix.SYS_SCHED_YIELD: seccomp.MatchAll{}, + unix.SYS_SENDMSG: seccomp.Or{ // Used by fdchannel.Endpoint.SendFD(). - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.AnyValue{}, seccomp.EqualTo(0), }, // Used by unet.SocketWriter.WriteVec(). - { + seccomp.PerArg{ seccomp.AnyValue{}, seccomp.AnyValue{}, seccomp.EqualTo(unix.MSG_DONTWAIT | unix.MSG_NOSIGNAL), }, }, - unix.SYS_SHUTDOWN: []seccomp.Rule{ - {seccomp.AnyValue{}, seccomp.EqualTo(unix.SHUT_RDWR)}, + unix.SYS_SHUTDOWN: seccomp.PerArg{ + seccomp.AnyValue{}, + seccomp.EqualTo(unix.SHUT_RDWR), }, - unix.SYS_SIGALTSTACK: {}, + unix.SYS_SIGALTSTACK: seccomp.MatchAll{}, // Used by fdchannel.NewConnectedSockets(). - unix.SYS_SOCKETPAIR: { - { - seccomp.EqualTo(unix.AF_UNIX), - seccomp.EqualTo(unix.SOCK_SEQPACKET | unix.SOCK_CLOEXEC), - seccomp.EqualTo(0), - }, + unix.SYS_SOCKETPAIR: seccomp.PerArg{ + seccomp.EqualTo(unix.AF_UNIX), + seccomp.EqualTo(unix.SOCK_SEQPACKET | unix.SOCK_CLOEXEC), + seccomp.EqualTo(0), }, - unix.SYS_SYMLINKAT: {}, - unix.SYS_TGKILL: []seccomp.Rule{ - { - seccomp.EqualTo(uint64(os.Getpid())), - }, + unix.SYS_SYMLINKAT: seccomp.MatchAll{}, + unix.SYS_TGKILL: seccomp.PerArg{ + seccomp.EqualTo(uint64(os.Getpid())), }, - unix.SYS_UNLINKAT: {}, - unix.SYS_UTIMENSAT: {}, - unix.SYS_WRITE: {}, + unix.SYS_UNLINKAT: seccomp.MatchAll{}, + unix.SYS_UTIMENSAT: seccomp.MatchAll{}, + unix.SYS_WRITE: seccomp.MatchAll{}, } var udsCommonSyscalls = seccomp.SyscallRules{ - unix.SYS_SOCKET: []seccomp.Rule{ - { + unix.SYS_SOCKET: seccomp.Or{ + seccomp.PerArg{ seccomp.EqualTo(unix.AF_UNIX), seccomp.EqualTo(unix.SOCK_STREAM), seccomp.EqualTo(0), }, - { + seccomp.PerArg{ seccomp.EqualTo(unix.AF_UNIX), seccomp.EqualTo(unix.SOCK_DGRAM), seccomp.EqualTo(0), }, - { + seccomp.PerArg{ seccomp.EqualTo(unix.AF_UNIX), seccomp.EqualTo(unix.SOCK_SEQPACKET), seccomp.EqualTo(0), @@ -233,16 +222,16 @@ var udsCommonSyscalls = seccomp.SyscallRules{ } var udsOpenSyscalls = seccomp.SyscallRules{ - unix.SYS_CONNECT: {}, + unix.SYS_CONNECT: seccomp.MatchAll{}, } var udsCreateSyscalls = seccomp.SyscallRules{ - unix.SYS_ACCEPT4: {}, - unix.SYS_BIND: {}, - unix.SYS_LISTEN: {}, + unix.SYS_ACCEPT4: seccomp.MatchAll{}, + unix.SYS_BIND: seccomp.MatchAll{}, + unix.SYS_LISTEN: seccomp.MatchAll{}, } var xattrSyscalls = seccomp.SyscallRules{ - unix.SYS_FGETXATTR: {}, - unix.SYS_FSETXATTR: {}, + unix.SYS_FGETXATTR: seccomp.MatchAll{}, + unix.SYS_FSETXATTR: seccomp.MatchAll{}, } diff --git a/runsc/fsgofer/filter/config_amd64.go b/runsc/fsgofer/filter/config_amd64.go index 37daf58d8..6ee286b03 100644 --- a/runsc/fsgofer/filter/config_amd64.go +++ b/runsc/fsgofer/filter/config_amd64.go @@ -23,24 +23,22 @@ import ( ) func init() { - allowedSyscalls[unix.SYS_CLONE] = []seccomp.Rule{ + allowedSyscalls[unix.SYS_CLONE] = seccomp.PerArg{ // parent_tidptr and child_tidptr are always 0 because neither // CLONE_PARENT_SETTID nor CLONE_CHILD_SETTID are used. - { - seccomp.EqualTo( - unix.CLONE_VM | - unix.CLONE_FS | - unix.CLONE_FILES | - unix.CLONE_SETTLS | - unix.CLONE_SIGHAND | - unix.CLONE_SYSVSEM | - unix.CLONE_THREAD), - seccomp.AnyValue{}, // newsp - seccomp.EqualTo(0), // parent_tidptr - seccomp.EqualTo(0), // child_tidptr - seccomp.AnyValue{}, // tls - }, + seccomp.EqualTo( + unix.CLONE_VM | + unix.CLONE_FS | + unix.CLONE_FILES | + unix.CLONE_SETTLS | + unix.CLONE_SIGHAND | + unix.CLONE_SYSVSEM | + unix.CLONE_THREAD), + seccomp.AnyValue{}, // newsp + seccomp.EqualTo(0), // parent_tidptr + seccomp.EqualTo(0), // child_tidptr + seccomp.AnyValue{}, // tls } - allowedSyscalls[unix.SYS_NEWFSTATAT] = []seccomp.Rule{} + allowedSyscalls[unix.SYS_NEWFSTATAT] = seccomp.MatchAll{} } diff --git a/runsc/fsgofer/filter/config_arm64.go b/runsc/fsgofer/filter/config_arm64.go index 3a7b668cf..3e68801ab 100644 --- a/runsc/fsgofer/filter/config_arm64.go +++ b/runsc/fsgofer/filter/config_arm64.go @@ -23,26 +23,24 @@ import ( ) func init() { - allowedSyscalls[unix.SYS_CLONE] = []seccomp.Rule{ + allowedSyscalls[unix.SYS_CLONE] = seccomp.PerArg{ // parent_tidptr and child_tidptr are always 0 because neither // CLONE_PARENT_SETTID nor CLONE_CHILD_SETTID are used. - { - seccomp.EqualTo( - unix.CLONE_VM | - unix.CLONE_FS | - unix.CLONE_FILES | - unix.CLONE_SIGHAND | - unix.CLONE_SYSVSEM | - unix.CLONE_THREAD), - seccomp.AnyValue{}, // newsp - // These arguments are left uninitialized by the Go - // runtime, so they may be anything (and are unused by - // the host). - seccomp.AnyValue{}, // parent_tidptr - seccomp.AnyValue{}, // tls - seccomp.AnyValue{}, // child_tidptr - }, + seccomp.EqualTo( + unix.CLONE_VM | + unix.CLONE_FS | + unix.CLONE_FILES | + unix.CLONE_SIGHAND | + unix.CLONE_SYSVSEM | + unix.CLONE_THREAD), + seccomp.AnyValue{}, // newsp + // These arguments are left uninitialized by the Go + // runtime, so they may be anything (and are unused by + // the host). + seccomp.AnyValue{}, // parent_tidptr + seccomp.AnyValue{}, // tls + seccomp.AnyValue{}, // child_tidptr } - allowedSyscalls[unix.SYS_FSTATAT] = []seccomp.Rule{} + allowedSyscalls[unix.SYS_FSTATAT] = seccomp.MatchAll{} } diff --git a/runsc/fsgofer/filter/config_profile.go b/runsc/fsgofer/filter/config_profile.go index 49a416e89..a729adcb2 100644 --- a/runsc/fsgofer/filter/config_profile.go +++ b/runsc/fsgofer/filter/config_profile.go @@ -20,28 +20,22 @@ import ( ) var profileFilters = seccomp.SyscallRules{ - unix.SYS_OPENAT: []seccomp.Rule{ - { - seccomp.AnyValue{}, - seccomp.AnyValue{}, - seccomp.EqualTo(unix.O_RDONLY | unix.O_LARGEFILE | unix.O_CLOEXEC), - }, + unix.SYS_OPENAT: seccomp.PerArg{ + seccomp.AnyValue{}, + seccomp.AnyValue{}, + seccomp.EqualTo(unix.O_RDONLY | unix.O_LARGEFILE | unix.O_CLOEXEC), }, - unix.SYS_SETITIMER: {}, - unix.SYS_TIMER_CREATE: []seccomp.Rule{ - { - seccomp.EqualTo(unix.CLOCK_THREAD_CPUTIME_ID), /* which */ - seccomp.AnyValue{}, /* sevp */ - seccomp.AnyValue{}, /* timerid */ - }, + unix.SYS_SETITIMER: seccomp.MatchAll{}, + unix.SYS_TIMER_CREATE: seccomp.PerArg{ + seccomp.EqualTo(unix.CLOCK_THREAD_CPUTIME_ID), /* which */ + seccomp.AnyValue{}, /* sevp */ + seccomp.AnyValue{}, /* timerid */ }, - unix.SYS_TIMER_DELETE: []seccomp.Rule{}, - unix.SYS_TIMER_SETTIME: []seccomp.Rule{ - { - seccomp.AnyValue{}, /* timerid */ - seccomp.EqualTo(0), /* flags */ - seccomp.AnyValue{}, /* new_value */ - seccomp.EqualTo(0), /* old_value */ - }, + unix.SYS_TIMER_DELETE: seccomp.MatchAll{}, + unix.SYS_TIMER_SETTIME: seccomp.PerArg{ + seccomp.AnyValue{}, /* timerid */ + seccomp.EqualTo(0), /* flags */ + seccomp.AnyValue{}, /* new_value */ + seccomp.EqualTo(0), /* old_value */ }, } diff --git a/runsc/fsgofer/filter/extra_filters_msan.go b/runsc/fsgofer/filter/extra_filters_msan.go index e5915652f..00ffd9f4b 100644 --- a/runsc/fsgofer/filter/extra_filters_msan.go +++ b/runsc/fsgofer/filter/extra_filters_msan.go @@ -27,7 +27,7 @@ import ( func instrumentationFilters() seccomp.SyscallRules { log.Warningf("*** SECCOMP WARNING: MSAN is enabled: syscall filters less restrictive!") return seccomp.SyscallRules{ - unix.SYS_SCHED_GETAFFINITY: {}, - unix.SYS_SET_ROBUST_LIST: {}, + unix.SYS_SCHED_GETAFFINITY: seccomp.MatchAll{}, + unix.SYS_SET_ROBUST_LIST: seccomp.MatchAll{}, } } diff --git a/runsc/fsgofer/filter/extra_filters_race.go b/runsc/fsgofer/filter/extra_filters_race.go index 45e7be028..f68136dde 100644 --- a/runsc/fsgofer/filter/extra_filters_race.go +++ b/runsc/fsgofer/filter/extra_filters_race.go @@ -27,18 +27,18 @@ import ( func instrumentationFilters() seccomp.SyscallRules { log.Warningf("*** SECCOMP WARNING: TSAN is enabled: syscall filters less restrictive!") return archInstrumentationFilters(seccomp.SyscallRules{ - unix.SYS_BRK: {}, - unix.SYS_CLOCK_NANOSLEEP: {}, - unix.SYS_CLONE: {}, - unix.SYS_CLONE3: {}, - unix.SYS_FUTEX: {}, - unix.SYS_MADVISE: {}, - unix.SYS_MMAP: {}, - unix.SYS_MUNLOCK: {}, - unix.SYS_NANOSLEEP: {}, - unix.SYS_OPENAT: {}, - unix.SYS_RSEQ: {}, - unix.SYS_SET_ROBUST_LIST: {}, - unix.SYS_SCHED_GETAFFINITY: {}, + unix.SYS_BRK: seccomp.MatchAll{}, + unix.SYS_CLOCK_NANOSLEEP: seccomp.MatchAll{}, + unix.SYS_CLONE: seccomp.MatchAll{}, + unix.SYS_CLONE3: seccomp.MatchAll{}, + unix.SYS_FUTEX: seccomp.MatchAll{}, + unix.SYS_MADVISE: seccomp.MatchAll{}, + unix.SYS_MMAP: seccomp.MatchAll{}, + unix.SYS_MUNLOCK: seccomp.MatchAll{}, + unix.SYS_NANOSLEEP: seccomp.MatchAll{}, + unix.SYS_OPENAT: seccomp.MatchAll{}, + unix.SYS_RSEQ: seccomp.MatchAll{}, + unix.SYS_SET_ROBUST_LIST: seccomp.MatchAll{}, + unix.SYS_SCHED_GETAFFINITY: seccomp.MatchAll{}, }) } diff --git a/runsc/fsgofer/filter/extra_filters_race_amd64.go b/runsc/fsgofer/filter/extra_filters_race_amd64.go index e7e8eb602..c5932d44a 100644 --- a/runsc/fsgofer/filter/extra_filters_race_amd64.go +++ b/runsc/fsgofer/filter/extra_filters_race_amd64.go @@ -23,8 +23,8 @@ import ( ) func archInstrumentationFilters(f seccomp.SyscallRules) seccomp.SyscallRules { - f[unix.SYS_OPEN] = []seccomp.Rule{} + f[unix.SYS_OPEN] = seccomp.MatchAll{} // Used within glibc's malloc. - f[unix.SYS_TIME] = []seccomp.Rule{} + f[unix.SYS_TIME] = seccomp.MatchAll{} return f } diff --git a/runsc/specutils/seccomp/seccomp.go b/runsc/specutils/seccomp/seccomp.go index 0ef7a4d54..a8e74ed93 100644 --- a/runsc/specutils/seccomp/seccomp.go +++ b/runsc/specutils/seccomp/seccomp.go @@ -121,7 +121,7 @@ func convertRules(s *specs.LinuxSeccomp) ([]seccomp.RuleSet, error) { } // Args - rules, err := convertArgs(syscall.Args) + rule, err := convertArgs(syscall.Args) if err != nil { return nil, err } @@ -136,9 +136,7 @@ func convertRules(s *specs.LinuxSeccomp) ([]seccomp.RuleSet, error) { continue } - for _, rule := range rules { - sysRules.AddRule(uintptr(syscallNo), rule) - } + sysRules.AddRule(uintptr(syscallNo), rule) } ruleset = append(ruleset, seccomp.RuleSet{ @@ -151,7 +149,7 @@ func convertRules(s *specs.LinuxSeccomp) ([]seccomp.RuleSet, error) { } // convertArgs converts an OCI seccomp argument rule to a list of seccomp.Rule. -func convertArgs(args []specs.LinuxSeccompArg) ([]seccomp.Rule, error) { +func convertArgs(args []specs.LinuxSeccompArg) (seccomp.SyscallRule, error) { argCounts := make([]uint, 6) for _, arg := range args { @@ -177,12 +175,12 @@ func convertArgs(args []specs.LinuxSeccompArg) ([]seccomp.Rule, error) { } if hasMultipleArgs { - rules := []seccomp.Rule{} + rules := seccomp.Or{} // Old runc behavior - do this for compatibility. // Add rules as ORs by adding separate Rules. for _, arg := range args { - rule := seccomp.Rule{nil, nil, nil, nil, nil, nil} + rule := seccomp.PerArg{nil, nil, nil, nil, nil, nil} if err := convertRule(arg, &rule); err != nil { return nil, err @@ -195,33 +193,33 @@ func convertArgs(args []specs.LinuxSeccompArg) ([]seccomp.Rule, error) { } // Add rules as ANDs by adding to the same Rule. - rule := seccomp.Rule{nil, nil, nil, nil, nil, nil} + rule := seccomp.PerArg{nil, nil, nil, nil, nil, nil} for _, arg := range args { if err := convertRule(arg, &rule); err != nil { return nil, err } } - return []seccomp.Rule{rule}, nil + return rule, nil } -// convertRule converts and adds the arg to a rule. -func convertRule(arg specs.LinuxSeccompArg, rule *seccomp.Rule) error { +// convertRule converts and adds the arg to a PerArg rule. +func convertRule(arg specs.LinuxSeccompArg, perArg *seccomp.PerArg) error { switch arg.Op { case specs.OpEqualTo: - rule[arg.Index] = seccomp.EqualTo(arg.Value) + perArg[arg.Index] = seccomp.EqualTo(arg.Value) case specs.OpNotEqual: - rule[arg.Index] = seccomp.NotEqual(arg.Value) + perArg[arg.Index] = seccomp.NotEqual(arg.Value) case specs.OpGreaterThan: - rule[arg.Index] = seccomp.GreaterThan(arg.Value) + perArg[arg.Index] = seccomp.GreaterThan(arg.Value) case specs.OpGreaterEqual: - rule[arg.Index] = seccomp.GreaterThanOrEqual(arg.Value) + perArg[arg.Index] = seccomp.GreaterThanOrEqual(arg.Value) case specs.OpLessThan: - rule[arg.Index] = seccomp.LessThan(arg.Value) + perArg[arg.Index] = seccomp.LessThan(arg.Value) case specs.OpLessEqual: - rule[arg.Index] = seccomp.LessThanOrEqual(arg.Value) + perArg[arg.Index] = seccomp.LessThanOrEqual(arg.Value) case specs.OpMaskedEqual: - rule[arg.Index] = seccomp.MaskedEqual(uintptr(arg.Value), uintptr(arg.ValueTwo)) + perArg[arg.Index] = seccomp.MaskedEqual(uintptr(arg.Value), uintptr(arg.ValueTwo)) default: return fmt.Errorf("unsupported operand: %q", arg.Op) }