summaryrefslogtreecommitdiffhomepage
path: root/runsc
diff options
context:
space:
mode:
Diffstat (limited to 'runsc')
-rw-r--r--runsc/boot/compat.go10
-rw-r--r--runsc/boot/compat_amd64.go55
-rw-r--r--runsc/boot/compat_test.go39
3 files changed, 76 insertions, 28 deletions
diff --git a/runsc/boot/compat.go b/runsc/boot/compat.go
index 4c49e90e3..c2a77ebf5 100644
--- a/runsc/boot/compat.go
+++ b/runsc/boot/compat.go
@@ -89,10 +89,16 @@ func (c *compatEmitter) Emit(msg proto.Message) (hangup bool, err error) {
if tr == nil {
switch sysnr {
case syscall.SYS_PRCTL, syscall.SYS_ARCH_PRCTL:
- tr = newCmdTracker(0)
+ // args: cmd, ...
+ tr = newArgsTracker(0)
case syscall.SYS_IOCTL, syscall.SYS_EPOLL_CTL, syscall.SYS_SHMCTL:
- tr = newCmdTracker(1)
+ // args: fd, cmd, ...
+ tr = newArgsTracker(1)
+
+ case syscall.SYS_GETSOCKOPT, syscall.SYS_SETSOCKOPT:
+ // args: fd, level, name, ...
+ tr = newArgsTracker(1, 2)
default:
tr = &onceTracker{}
diff --git a/runsc/boot/compat_amd64.go b/runsc/boot/compat_amd64.go
index 2bb769a49..0c9472f18 100644
--- a/runsc/boot/compat_amd64.go
+++ b/runsc/boot/compat_amd64.go
@@ -20,35 +20,58 @@ import (
rpb "gvisor.googlesource.com/gvisor/pkg/sentry/arch/registers_go_proto"
)
-// cmdTracker reports only a single time for each different command argument in
-// the syscall. It's used for generic syscalls like ioctl to report once per
-// 'cmd'
-type cmdTracker struct {
- // argIdx is the syscall argument index where the command is located.
- argIdx int
- cmds map[uint32]struct{}
+// reportLimit is the max number of events that should be reported per tracker.
+const reportLimit = 100
+
+// argsTracker reports only once for each different combination of arguments.
+// It's used for generic syscalls like ioctl to report once per 'cmd'.
+type argsTracker struct {
+ // argsIdx is the syscall arguments to use as unique ID.
+ argsIdx []int
+ reported map[string]struct{}
+ count int
}
-func newCmdTracker(argIdx int) *cmdTracker {
- return &cmdTracker{argIdx: argIdx, cmds: make(map[uint32]struct{})}
+func newArgsTracker(argIdx ...int) *argsTracker {
+ return &argsTracker{argsIdx: argIdx, reported: make(map[string]struct{})}
}
// cmd returns the command based on the syscall argument index.
-func (c *cmdTracker) cmd(regs *rpb.AMD64Registers) uint32 {
- switch c.argIdx {
+func (a *argsTracker) key(regs *rpb.AMD64Registers) string {
+ var rv string
+ for _, idx := range a.argsIdx {
+ rv += fmt.Sprintf("%d|", argVal(idx, regs))
+ }
+ return rv
+}
+
+func argVal(argIdx int, regs *rpb.AMD64Registers) uint32 {
+ switch argIdx {
case 0:
return uint32(regs.Rdi)
case 1:
return uint32(regs.Rsi)
+ case 2:
+ return uint32(regs.Rdx)
+ case 3:
+ return uint32(regs.R10)
+ case 4:
+ return uint32(regs.R8)
+ case 5:
+ return uint32(regs.R9)
}
- panic(fmt.Sprintf("unsupported syscall argument index %d", c.argIdx))
+ panic(fmt.Sprintf("invalid syscall argument index %d", argIdx))
}
-func (c *cmdTracker) shouldReport(regs *rpb.AMD64Registers) bool {
- _, ok := c.cmds[c.cmd(regs)]
+func (a *argsTracker) shouldReport(regs *rpb.AMD64Registers) bool {
+ if a.count >= reportLimit {
+ return false
+ }
+ _, ok := a.reported[a.key(regs)]
return !ok
}
-func (c *cmdTracker) onReported(regs *rpb.AMD64Registers) {
- c.cmds[c.cmd(regs)] = struct{}{}
+func (a *argsTracker) onReported(regs *rpb.AMD64Registers) {
+ a.count++
+ a.reported[a.key(regs)] = struct{}{}
}
diff --git a/runsc/boot/compat_test.go b/runsc/boot/compat_test.go
index 30b94798a..f1940dd72 100644
--- a/runsc/boot/compat_test.go
+++ b/runsc/boot/compat_test.go
@@ -33,34 +33,53 @@ func TestOnceTracker(t *testing.T) {
}
}
-func TestCmdTracker(t *testing.T) {
+func TestArgsTracker(t *testing.T) {
for _, tc := range []struct {
name string
- idx int
+ idx []int
rdi1 uint64
rdi2 uint64
rsi1 uint64
rsi2 uint64
want bool
}{
- {name: "same rdi", idx: 0, rdi1: 123, rdi2: 123, want: false},
- {name: "same rsi", idx: 1, rsi1: 123, rsi2: 123, want: false},
- {name: "diff rdi", idx: 0, rdi1: 123, rdi2: 321, want: true},
- {name: "diff rsi", idx: 1, rsi1: 123, rsi2: 321, want: true},
- {name: "cmd is uint32", idx: 0, rsi1: 0xdead00000123, rsi2: 0xbeef00000123, want: false},
+ {name: "same rdi", idx: []int{0}, rdi1: 123, rdi2: 123, want: false},
+ {name: "same rsi", idx: []int{1}, rsi1: 123, rsi2: 123, want: false},
+ {name: "diff rdi", idx: []int{0}, rdi1: 123, rdi2: 321, want: true},
+ {name: "diff rsi", idx: []int{1}, rsi1: 123, rsi2: 321, want: true},
+ {name: "cmd is uint32", idx: []int{0}, rsi1: 0xdead00000123, rsi2: 0xbeef00000123, want: false},
+ {name: "same 2 args", idx: []int{0, 1}, rsi1: 123, rdi1: 321, rsi2: 123, rdi2: 321, want: false},
+ {name: "diff 2 args", idx: []int{0, 1}, rsi1: 123, rdi1: 321, rsi2: 789, rdi2: 987, want: true},
} {
t.Run(tc.name, func(t *testing.T) {
- c := newCmdTracker(tc.idx)
+ c := newArgsTracker(tc.idx...)
regs := &rpb.AMD64Registers{Rdi: tc.rdi1, Rsi: tc.rsi1}
if !c.shouldReport(regs) {
- t.Error("first call to checkAndMark, got: false, want: true")
+ t.Error("first call to shouldReport, got: false, want: true")
}
c.onReported(regs)
regs.Rdi, regs.Rsi = tc.rdi2, tc.rsi2
if got := c.shouldReport(regs); tc.want != got {
- t.Errorf("after first call to checkAndMark, got: %t, want: %t", got, tc.want)
+ t.Errorf("second call to shouldReport, got: %t, want: %t", got, tc.want)
}
})
}
}
+
+func TestArgsTrackerLimit(t *testing.T) {
+ c := newArgsTracker(0, 1)
+ for i := 0; i < reportLimit; i++ {
+ regs := &rpb.AMD64Registers{Rdi: 123, Rsi: uint64(i)}
+ if !c.shouldReport(regs) {
+ t.Error("shouldReport before limit was reached, got: false, want: true")
+ }
+ c.onReported(regs)
+ }
+
+ // Should hit the count limit now.
+ regs := &rpb.AMD64Registers{Rdi: 123, Rsi: 123456}
+ if c.shouldReport(regs) {
+ t.Error("shouldReport after limit was reached, got: true, want: false")
+ }
+}