Refactor seccomp rules with interfaces rather than disjunctive normal form.

This replaces the `seccomp.Rule` type with the `seccomp.SyscallRule`
interface, which is an abstraction that defines how to match a syscall's
arguments and RIP.

This has the following benefits:

- The code can verify that rules are self-contained, as the
  `SyscallRule.Render` contract specifies that the rule must jump to
  either a "matched" or "not matched" label, and may not fall through.
  It uses `ProgramBuilder`'s support for asserting unreachability to
  enforce this.
- Rules that match everything are more explicit (no more implicit
  "no rules means everything matches" behavior, instead you have to
  explicitly specify `seccomp.MatchAll{}`).
- "OR" behavior is explicit (a disjunctive rule is marked as `seccomp.Or`
  rather than the current implicit meaning of a list of rules).
- Allows the creation of more sophisticated matching rules that don't work
  on a per-argument basis. This change does not do any of that yet, it
  simply refactors existing rules without changing the way they work.
- Decouples rule-specific rendering code from the larger program generation
  code (BST, architecture check, etc.).

Unfortunately there is no easy way to split this change into multiple
sub-changes without introducing additional complexity to support both forms
of expressing rules, so sorry if this is a large change. But note that it
is actually net-negative in line count.

Despite the size of this change, please review it carefully, as this is a
security-sensitive change.

PiperOrigin-RevId: 571459670
This commit is contained in:
Etienne Perot
2023-10-06 16:19:26 -07:00
committed by gVisor bot
parent 9cb26fd34f
commit addac5f248
39 changed files with 1399 additions and 1372 deletions
+205 -290
View File
File diff suppressed because it is too large Load Diff
+313 -53
View File
@@ -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),
},
}
+99 -128
View File
@@ -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)
}
}
+65 -67
View File
@@ -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),
}
}
@@ -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{}
}
@@ -26,5 +26,5 @@ import (
)
func arch_syscalls(syscalls seccomp.SyscallRules) {
syscalls[unix.SYS_FSTATAT] = []seccomp.Rule{}
syscalls[unix.SYS_FSTATAT] = seccomp.MatchAll{}
}
+34 -38
View File
@@ -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),
},
}
}
+51 -55
View File
@@ -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),
},
}
}
+12 -14
View File
@@ -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
}
+7 -7
View File
@@ -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),
},
+3 -5
View File
@@ -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),
},
}
}
+8 -11
View File
@@ -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))
+3 -3
View File
@@ -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{},
}
}
@@ -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,
@@ -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
}
+18 -21
View File
@@ -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,
})
+17 -19
View File
@@ -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())
+3 -3
View File
@@ -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),
@@ -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,
+30 -26
View File
@@ -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,

Some files were not shown because too many files have changed in this diff Show More