mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Improve seccomp ruleset debug logging readability.
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
This commit is contained in:
committed by
gVisor bot
parent
4c76c84ed0
commit
326e1681e7
@@ -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"
|
||||
}
|
||||
|
||||
+14
-9
@@ -19,7 +19,6 @@ package seccomp
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
@@ -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(": ")
|
||||
if len(ssrs.rules) == 0 {
|
||||
sb.WriteString("(no rules)")
|
||||
sb.WriteString("Vsyscall ")
|
||||
} else {
|
||||
sb.WriteString("Syscall ")
|
||||
}
|
||||
sb.WriteString(fmt.Sprintf("%3d: ", ssrs.sysno))
|
||||
switch len(ssrs.rules) {
|
||||
case 0:
|
||||
sb.WriteString("(no rules)")
|
||||
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())
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,6 @@ package seccomp
|
||||
import (
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"golang.org/x/sys/unix"
|
||||
@@ -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
|
||||
@@ -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.
|
||||
@@ -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"
|
||||
@@ -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))
|
||||
@@ -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))
|
||||
@@ -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)
|
||||
@@ -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`.
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
@@ -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`.
|
||||
@@ -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 {
|
||||
sb.WriteString("arg")
|
||||
sb.WriteString(strconv.Itoa(i))
|
||||
varName = fmt.Sprintf("arg[%d]", i)
|
||||
}
|
||||
if strings.Contains(str, "VAL") {
|
||||
sb.WriteString(strings.ReplaceAll(str, "VAL", varName))
|
||||
} else {
|
||||
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()
|
||||
|
||||
Reference in New Issue
Block a user