summaryrefslogtreecommitdiffhomepage
path: root/runsc/boot/compat.go
diff options
context:
space:
mode:
Diffstat (limited to 'runsc/boot/compat.go')
-rw-r--r--runsc/boot/compat.go72
1 files changed, 66 insertions, 6 deletions
diff --git a/runsc/boot/compat.go b/runsc/boot/compat.go
index 6766953b3..d18c2f802 100644
--- a/runsc/boot/compat.go
+++ b/runsc/boot/compat.go
@@ -17,6 +17,8 @@ package boot
import (
"fmt"
"os"
+ "sync"
+ "syscall"
"github.com/golang/protobuf/proto"
"gvisor.googlesource.com/gvisor/pkg/abi"
@@ -25,7 +27,7 @@ import (
"gvisor.googlesource.com/gvisor/pkg/sentry/arch"
rpb "gvisor.googlesource.com/gvisor/pkg/sentry/arch/registers_go_proto"
"gvisor.googlesource.com/gvisor/pkg/sentry/strace"
- spb "gvisor.googlesource.com/gvisor/pkg/sentry/syscalls/unimplemented_syscall_go_proto"
+ spb "gvisor.googlesource.com/gvisor/pkg/sentry/unimpl/unimplemented_syscall_go_proto"
)
func initCompatLogs(fd int) error {
@@ -40,15 +42,27 @@ func initCompatLogs(fd int) error {
type compatEmitter struct {
sink *log.BasicLogger
nameMap strace.SyscallMap
+
+ // mu protects the fields below.
+ mu sync.Mutex
+
+ // trackers map syscall number to the respective tracker instance.
+ // Protected by 'mu'.
+ trackers map[uint64]syscallTracker
}
func newCompatEmitter(logFD int) (*compatEmitter, error) {
- // Always logs to default logger.
nameMap, ok := strace.Lookup(abi.Linux, arch.AMD64)
if !ok {
return nil, fmt.Errorf("amd64 Linux syscall table not found")
}
- c := &compatEmitter{sink: log.Log(), nameMap: nameMap}
+
+ c := &compatEmitter{
+ // Always logs to default logger.
+ sink: log.Log(),
+ nameMap: nameMap,
+ trackers: make(map[uint64]syscallTracker),
+ }
if logFD > 0 {
f := os.NewFile(uintptr(logFD), "user log file")
@@ -61,10 +75,33 @@ func newCompatEmitter(logFD int) (*compatEmitter, error) {
// Emit implements eventchannel.Emitter.
func (c *compatEmitter) Emit(msg proto.Message) (hangup bool, err error) {
// Only interested in UnimplementedSyscall, skip the rest.
- if us, ok := msg.(*spb.UnimplementedSyscall); ok {
- regs := us.Registers.GetArch().(*rpb.Registers_Amd64).Amd64
- sysnr := regs.OrigRax
+ us, ok := msg.(*spb.UnimplementedSyscall)
+ if !ok {
+ return false, nil
+ }
+ regs := us.Registers.GetArch().(*rpb.Registers_Amd64).Amd64
+
+ c.mu.Lock()
+ defer c.mu.Unlock()
+
+ sysnr := regs.OrigRax
+ tr := c.trackers[sysnr]
+ if tr == nil {
+ switch sysnr {
+ case syscall.SYS_PRCTL, syscall.SYS_ARCH_PRCTL:
+ tr = newCmdTracker(0)
+
+ case syscall.SYS_IOCTL, syscall.SYS_EPOLL_CTL, syscall.SYS_SHMCTL:
+ tr = newCmdTracker(1)
+
+ default:
+ tr = &onceTracker{}
+ }
+ c.trackers[sysnr] = tr
+ }
+ if tr.shouldReport(regs) {
c.sink.Infof("Unsupported syscall: %s, regs: %+v", c.nameMap.Name(uintptr(sysnr)), regs)
+ tr.onReported(regs)
}
return false, nil
}
@@ -74,3 +111,26 @@ func (c *compatEmitter) Close() error {
c.sink = nil
return nil
}
+
+// syscallTracker interface allows filters to apply differently depending on
+// the syscall and arguments.
+type syscallTracker interface {
+ // shouldReport returns true is the syscall should be reported.
+ shouldReport(regs *rpb.AMD64Registers) bool
+
+ // onReported marks the syscall as reported.
+ onReported(regs *rpb.AMD64Registers)
+}
+
+// onceTracker reports only a single time, used for most syscalls.
+type onceTracker struct {
+ reported bool
+}
+
+func (o *onceTracker) shouldReport(_ *rpb.AMD64Registers) bool {
+ return !o.reported
+}
+
+func (o *onceTracker) onReported(_ *rpb.AMD64Registers) {
+ o.reported = true
+}