Skip to content

Commit

Permalink
Improve seccomp ruleset debug logging readability.
Browse files Browse the repository at this point in the history
Before (sample ruleset):

```
Hot non-trivial syscalls:
  - sysno=1: {(arg0 == 0x4) => trace (0)}
  - sysno=39[vsyscall]: {(arg0 == 0x14) => errno (0)}
  - sysno=73: {(arg0 == 0x83) => trace (0)}
  - sysno=257: {(arg0 == 0x1cf) => kill thread, (arg0 == 0x71267) => kill process}
Cold non-trivial syscalls:
  - sysno=27[vsyscall]: {(arg0 == 0x4e) => errno (0)}
  - sysno=96[vsyscall]: {(true) => errno (0)}
  - sysno=202[vsyscall]: {(true) => errno (0)}
  - sysno=263: {((arg0 high=halfEq(0x0) && (arg0 low=halfEq(0x1d8) || arg0 low=halfEq(0x73598)))) => kill process, (arg0 == 0x1c295b98) => trap (0)}
  - sysno=265: {(arg0 == 0x1d7) => kill thread, (arg0 == 0x731af) => kill process}
Trivial syscalls:
  - sysno=0: {(true) => trace (0)}
  - sysno=3: {(true) => kill thread}
  - sysno=80: {(true) => kill thread}
  - sysno=81: {(true) => kill process}
```

After (same ruleset):

```
Hot non-trivial syscalls:
  - Syscall    1: (arg[0] == 0x4) => trace
  - Vsyscall  39: (arg[0] == 0x14) => return errno=0x0
  - Syscall   73: (arg[0] == 0x83) => trace
  - Syscall  257: {(arg[0] == 0x1cf) => kill thread; (arg[0] == 0x71267) => kill process}
Cold non-trivial syscalls:
  - Vsyscall  27: (arg[0] == 0x4e) => return errno=0x0
  - Vsyscall  96: return errno=0x0
  - Vsyscall 202: return errno=0x0
  - Syscall  263: {((arg[0].high == 0 && (arg[0].low == 0x1d8 || arg[0].low == 0x73598))) => kill process; (arg[0] == 0x1c295b98) => trap}
  - Syscall  265: {(arg[0] == 0x1d7) => kill thread; (arg[0] == 0x731af) => kill process}
Trivial syscalls:
  - Syscall    0: trace
  - Syscall    3: kill thread
  - Syscall   80: kill thread
  - Syscall   81: kill process
```

PiperOrigin-RevId: 587130340
  • Loading branch information
EtiennePerot authored and gvisor-bot committed Dec 1, 2023
1 parent 4c76c84 commit 326e168
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 37 deletions.
14 changes: 11 additions & 3 deletions pkg/abi/linux/seccomp.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,19 @@ func (a BPFAction) String() string {
case SECCOMP_RET_KILL_THREAD:
return "kill thread"
case SECCOMP_RET_TRAP:
return fmt.Sprintf("trap (%d)", a.Data())
data := a.Data()
if data == 0 {
return "trap"
}
return fmt.Sprintf("trap (data=%#x)", data)
case SECCOMP_RET_ERRNO:
return fmt.Sprintf("errno (%d)", a.Data())
return fmt.Sprintf("return errno=%#x", a.Data())
case SECCOMP_RET_TRACE:
return fmt.Sprintf("trace (%d)", a.Data())
data := a.Data()
if data == 0 {
return "trace"
}
return fmt.Sprintf("trace (data=%#x)", data)
case SECCOMP_RET_ALLOW:
return "allow"
}
Expand Down
21 changes: 13 additions & 8 deletions pkg/seccomp/seccomp.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ package seccomp
import (
"fmt"
"sort"
"strconv"
"strings"
"time"

Expand Down Expand Up @@ -465,19 +464,22 @@ func (ssrs singleSyscallRuleSet) Render(program *syscallProgram, ls *labelSet, n
// `singleSyscallRuleSet`.
func (ssrs singleSyscallRuleSet) String() string {
var sb strings.Builder
sb.WriteString("sysno=")
sb.WriteString(strconv.Itoa(int(ssrs.sysno)))
if ssrs.vsyscall {
sb.WriteString("[vsyscall]")
sb.WriteString("Vsyscall ")
} else {
sb.WriteString("Syscall ")
}
sb.WriteString(": ")
if len(ssrs.rules) == 0 {
sb.WriteString(fmt.Sprintf("%3d: ", ssrs.sysno))
switch len(ssrs.rules) {
case 0:
sb.WriteString("(no rules)")
} else {
case 1:
sb.WriteString(ssrs.rules[0].String())
default:
sb.WriteRune('{')
for i, r := range ssrs.rules {
if i != 0 {
sb.WriteString(", ")
sb.WriteString("; ")
}
sb.WriteString(r.String())
}
Expand All @@ -495,6 +497,9 @@ type syscallRuleAction struct {

// String returns a human-friendly representation of the `syscallRuleAction`.
func (sra syscallRuleAction) String() string {
if _, isMatchAll := sra.rule.(MatchAll); isMatchAll {
return sra.action.String()
}
return fmt.Sprintf("(%v) => %v", sra.rule.String(), sra.action)
}

Expand Down
95 changes: 69 additions & 26 deletions pkg/seccomp/seccomp_rules.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ package seccomp
import (
"fmt"
"sort"
"strconv"
"strings"

"golang.org/x/sys/unix"
Expand Down Expand Up @@ -52,6 +51,8 @@ func seccompDataOffsetArgHigh(i int) uint32 {
// or RIP value.
type ValueMatcher interface {
// String returns a human-readable representation of the match rule.
// If the returned string contains "VAL", it will be replaced with
// the symbolic name of the value being matched against.
String() string

// Repr returns a string that will be used for asserting equality between
Expand All @@ -73,6 +74,12 @@ type ValueMatcher interface {

// halfValueMatcher verifies a 32-bit value.
type halfValueMatcher interface {
// String returns a human-friendly representation of the check being done
// against the 32-bit value.
// The string "x.(high|low) {{halfValueMatcher.String()}}" should read well,
// e.g. "x.low == 0xffff".
String() string

// Repr returns a string that will be used for asserting equality between
// two `halfValueMatcher` instances. It must therefore be unique to the
// `halfValueMatcher` implementation and to its parameters.
Expand All @@ -93,6 +100,11 @@ type halfValueMatcher interface {
// halfAnyValue implements `halfValueMatcher` and matches any value.
type halfAnyValue struct{}

// String implements `halfValueMatcher.String`.
func (halfAnyValue) String() string {
return "== *"
}

// Repr implements `halfValueMatcher.Repr`.
func (halfAnyValue) Repr() string {
return "halfAnyValue"
Expand All @@ -106,6 +118,14 @@ func (halfAnyValue) HalfRender(program *syscallProgram, labelSet *labelSet) {
// halfEqualTo implements `halfValueMatcher` and matches a specific 32-bit value.
type halfEqualTo uint32

// String implements `halfValueMatcher.String`.
func (heq halfEqualTo) String() string {
if heq == 0 {
return "== 0"
}
return fmt.Sprintf("== %#x", uint32(heq))
}

// Repr implements `halfValueMatcher.Repr`.
func (heq halfEqualTo) Repr() string {
return fmt.Sprintf("halfEq(%#x)", uint32(heq))
Expand All @@ -121,6 +141,11 @@ func (heq halfEqualTo) HalfRender(program *syscallProgram, labelSet *labelSet) {
// bitwise operation.
type halfNotSet uint32

// String implements `halfValueMatcher.String`.
func (hns halfNotSet) String() string {
return fmt.Sprintf("& %#x == 0", uint32(hns))
}

// Repr implements `halfValueMatcher.Repr`.
func (hns halfNotSet) Repr() string {
return fmt.Sprintf("halfNotSet(%#x)", uint32(hns))
Expand All @@ -139,6 +164,14 @@ type halfMaskedEqual struct {
value uint32
}

// String implements `halfValueMatcher.String`.
func (hmeq halfMaskedEqual) String() string {
if hmeq.value == 0 {
return fmt.Sprintf("& %#x == 0", hmeq.mask)
}
return fmt.Sprintf("& %#x == %#x", hmeq.mask, hmeq.value)
}

// Repr implements `halfValueMatcher.Repr`.
func (hmeq halfMaskedEqual) Repr() string {
return fmt.Sprintf("halfMaskedEqual(%#x, %#x)", hmeq.mask, hmeq.value)
Expand Down Expand Up @@ -167,7 +200,21 @@ type splitMatcher struct {

// String implements `ValueMatcher.String`.
func (sm splitMatcher) String() string {
return sm.Repr()
if sm.repr == "" {
_, highIsAnyValue := sm.highMatcher.(halfAnyValue)
_, lowIsAnyValue := sm.lowMatcher.(halfAnyValue)
if highIsAnyValue && lowIsAnyValue {
return "== *"
}
if highIsAnyValue {
return fmt.Sprintf("VAL.low %s", sm.lowMatcher.String())
}
if lowIsAnyValue {
return fmt.Sprintf("VAL.high %s", sm.highMatcher.String())
}
return fmt.Sprintf("(VAL.high %s && VAL.low %s)", sm.highMatcher.String(), sm.lowMatcher.String())
}
return sm.repr
}

// Repr implements `ValueMatcher.Repr`.
Expand Down Expand Up @@ -290,6 +337,9 @@ type EqualTo uintptr

// String implements `ValueMatcher.String`.
func (eq EqualTo) String() string {
if eq == 0 {
return "== 0"
}
return fmt.Sprintf("== %#x", uintptr(eq))
}

Expand Down Expand Up @@ -459,12 +509,12 @@ type NonNegativeFD struct{}

// String implements `ValueMatcher.String`.
func (NonNegativeFD) String() string {
return fmt.Sprintf("NonNegativeFD")
return "is non-negative FD"
}

// Repr implements `ValueMatcher.Repr`.
func (NonNegativeFD) Repr() string {
return NonNegativeFD{}.String()
return "NonNegativeFD"
}

// Render implements `ValueMatcher.Render`.
Expand Down Expand Up @@ -762,39 +812,32 @@ func (pa PerArg) String() string {
writtenArgs := 0
for i, arg := range pa {
if arg == nil {
arg = AnyValue{}
continue
}
if _, isAny := arg.(AnyValue); isAny {
// Check if all future arguments are also "any value"; if so, stop here.
allIsAny := true
for j := i + 1; j < len(pa); j++ {
if pa[j] == nil {
continue
}
if _, isAny := pa[j].(AnyValue); !isAny {
allIsAny = false
break
}
}
if allIsAny {
break
}
continue
}
if i != 0 {
if writtenArgs != 0 {
sb.WriteString(" && ")
}
str := arg.String()
var varName string
if i == RuleIP {
sb.WriteString("rip")
varName = "rip"
} else {
varName = fmt.Sprintf("arg[%d]", i)
}
if strings.Contains(str, "VAL") {
sb.WriteString(strings.ReplaceAll(str, "VAL", varName))
} else {
sb.WriteString("arg")
sb.WriteString(strconv.Itoa(i))
sb.WriteString(varName)
sb.WriteRune(' ')
sb.WriteString(str)
}
sb.WriteRune(' ')
sb.WriteString(arg.String())
writtenArgs++
}
if writtenArgs == 0 {
return "*"
return "true"
}
if writtenArgs == 1 {
return sb.String()
Expand Down

0 comments on commit 326e168

Please sign in to comment.