mirror of
https://github.com/netbirdio/gvisor.git
synced 2026-05-22 17:12:49 -07:00
Merge pull request #1233 from xiaobo55x:compatLog
PiperOrigin-RevId: 284305935
This commit is contained in:
+1
-1
@@ -7,6 +7,7 @@ go_library(
|
||||
srcs = [
|
||||
"compat.go",
|
||||
"compat_amd64.go",
|
||||
"compat_arm64.go",
|
||||
"config.go",
|
||||
"controller.go",
|
||||
"debug.go",
|
||||
@@ -110,7 +111,6 @@ go_test(
|
||||
"//pkg/control/server",
|
||||
"//pkg/log",
|
||||
"//pkg/p9",
|
||||
"//pkg/sentry/arch:registers_go_proto",
|
||||
"//pkg/sentry/context/contexttest",
|
||||
"//pkg/sentry/fs",
|
||||
"//pkg/sentry/kernel/auth",
|
||||
|
||||
+49
-12
@@ -21,10 +21,8 @@ import (
|
||||
"syscall"
|
||||
|
||||
"github.com/golang/protobuf/proto"
|
||||
"gvisor.dev/gvisor/pkg/abi"
|
||||
"gvisor.dev/gvisor/pkg/eventchannel"
|
||||
"gvisor.dev/gvisor/pkg/log"
|
||||
"gvisor.dev/gvisor/pkg/sentry/arch"
|
||||
rpb "gvisor.dev/gvisor/pkg/sentry/arch/registers_go_proto"
|
||||
ucspb "gvisor.dev/gvisor/pkg/sentry/kernel/uncaught_signal_go_proto"
|
||||
"gvisor.dev/gvisor/pkg/sentry/strace"
|
||||
@@ -53,9 +51,9 @@ type compatEmitter struct {
|
||||
}
|
||||
|
||||
func newCompatEmitter(logFD int) (*compatEmitter, error) {
|
||||
nameMap, ok := strace.Lookup(abi.Linux, arch.AMD64)
|
||||
nameMap, ok := getSyscallNameMap()
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("amd64 Linux syscall table not found")
|
||||
return nil, fmt.Errorf("Linux syscall table not found")
|
||||
}
|
||||
|
||||
c := &compatEmitter{
|
||||
@@ -86,16 +84,16 @@ func (c *compatEmitter) Emit(msg proto.Message) (bool, error) {
|
||||
}
|
||||
|
||||
func (c *compatEmitter) emitUnimplementedSyscall(us *spb.UnimplementedSyscall) {
|
||||
regs := us.Registers.GetArch().(*rpb.Registers_Amd64).Amd64
|
||||
regs := us.Registers
|
||||
|
||||
c.mu.Lock()
|
||||
defer c.mu.Unlock()
|
||||
|
||||
sysnr := regs.OrigRax
|
||||
sysnr := syscallNum(regs)
|
||||
tr := c.trackers[sysnr]
|
||||
if tr == nil {
|
||||
switch sysnr {
|
||||
case syscall.SYS_PRCTL, syscall.SYS_ARCH_PRCTL:
|
||||
case syscall.SYS_PRCTL:
|
||||
// args: cmd, ...
|
||||
tr = newArgsTracker(0)
|
||||
|
||||
@@ -112,10 +110,14 @@ func (c *compatEmitter) emitUnimplementedSyscall(us *spb.UnimplementedSyscall) {
|
||||
tr = newArgsTracker(2)
|
||||
|
||||
default:
|
||||
tr = &onceTracker{}
|
||||
tr = newArchArgsTracker(sysnr)
|
||||
if tr == nil {
|
||||
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)
|
||||
@@ -139,10 +141,10 @@ func (c *compatEmitter) Close() error {
|
||||
// the syscall and arguments.
|
||||
type syscallTracker interface {
|
||||
// shouldReport returns true is the syscall should be reported.
|
||||
shouldReport(regs *rpb.AMD64Registers) bool
|
||||
shouldReport(regs *rpb.Registers) bool
|
||||
|
||||
// onReported marks the syscall as reported.
|
||||
onReported(regs *rpb.AMD64Registers)
|
||||
onReported(regs *rpb.Registers)
|
||||
}
|
||||
|
||||
// onceTracker reports only a single time, used for most syscalls.
|
||||
@@ -150,10 +152,45 @@ type onceTracker struct {
|
||||
reported bool
|
||||
}
|
||||
|
||||
func (o *onceTracker) shouldReport(_ *rpb.AMD64Registers) bool {
|
||||
func (o *onceTracker) shouldReport(_ *rpb.Registers) bool {
|
||||
return !o.reported
|
||||
}
|
||||
|
||||
func (o *onceTracker) onReported(_ *rpb.AMD64Registers) {
|
||||
func (o *onceTracker) onReported(_ *rpb.Registers) {
|
||||
o.reported = true
|
||||
}
|
||||
|
||||
// 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 newArgsTracker(argIdx ...int) *argsTracker {
|
||||
return &argsTracker{argsIdx: argIdx, reported: make(map[string]struct{})}
|
||||
}
|
||||
|
||||
// key returns the command based on the syscall argument index.
|
||||
func (a *argsTracker) key(regs *rpb.Registers) string {
|
||||
var rv string
|
||||
for _, idx := range a.argsIdx {
|
||||
rv += fmt.Sprintf("%d|", argVal(idx, regs))
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
||||
func (a *argsTracker) shouldReport(regs *rpb.Registers) bool {
|
||||
if a.count >= reportLimit {
|
||||
return false
|
||||
}
|
||||
_, ok := a.reported[a.key(regs)]
|
||||
return !ok
|
||||
}
|
||||
|
||||
func (a *argsTracker) onReported(regs *rpb.Registers) {
|
||||
a.count++
|
||||
a.reported[a.key(regs)] = struct{}{}
|
||||
}
|
||||
|
||||
+53
-34
@@ -16,62 +16,81 @@ package boot
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"syscall"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi"
|
||||
"gvisor.dev/gvisor/pkg/sentry/arch"
|
||||
rpb "gvisor.dev/gvisor/pkg/sentry/arch/registers_go_proto"
|
||||
"gvisor.dev/gvisor/pkg/sentry/strace"
|
||||
)
|
||||
|
||||
// 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 newArgsTracker(argIdx ...int) *argsTracker {
|
||||
return &argsTracker{argsIdx: argIdx, reported: make(map[string]struct{})}
|
||||
}
|
||||
|
||||
// cmd returns the command based on the syscall argument index.
|
||||
func (a *argsTracker) key(regs *rpb.AMD64Registers) string {
|
||||
var rv string
|
||||
for _, idx := range a.argsIdx {
|
||||
rv += fmt.Sprintf("%d|", argVal(idx, regs))
|
||||
// newRegs create a empty Registers instance.
|
||||
func newRegs() *rpb.Registers {
|
||||
return &rpb.Registers{
|
||||
Arch: &rpb.Registers_Amd64{
|
||||
Amd64: &rpb.AMD64Registers{},
|
||||
},
|
||||
}
|
||||
return rv
|
||||
}
|
||||
|
||||
func argVal(argIdx int, regs *rpb.AMD64Registers) uint32 {
|
||||
func argVal(argIdx int, regs *rpb.Registers) uint32 {
|
||||
amd64Regs := regs.GetArch().(*rpb.Registers_Amd64).Amd64
|
||||
|
||||
switch argIdx {
|
||||
case 0:
|
||||
return uint32(regs.Rdi)
|
||||
return uint32(amd64Regs.Rdi)
|
||||
case 1:
|
||||
return uint32(regs.Rsi)
|
||||
return uint32(amd64Regs.Rsi)
|
||||
case 2:
|
||||
return uint32(regs.Rdx)
|
||||
return uint32(amd64Regs.Rdx)
|
||||
case 3:
|
||||
return uint32(regs.R10)
|
||||
return uint32(amd64Regs.R10)
|
||||
case 4:
|
||||
return uint32(regs.R8)
|
||||
return uint32(amd64Regs.R8)
|
||||
case 5:
|
||||
return uint32(regs.R9)
|
||||
return uint32(amd64Regs.R9)
|
||||
}
|
||||
panic(fmt.Sprintf("invalid syscall argument index %d", argIdx))
|
||||
}
|
||||
|
||||
func (a *argsTracker) shouldReport(regs *rpb.AMD64Registers) bool {
|
||||
if a.count >= reportLimit {
|
||||
return false
|
||||
func setArgVal(argIdx int, argVal uint64, regs *rpb.Registers) {
|
||||
amd64Regs := regs.GetArch().(*rpb.Registers_Amd64).Amd64
|
||||
|
||||
switch argIdx {
|
||||
case 0:
|
||||
amd64Regs.Rdi = argVal
|
||||
case 1:
|
||||
amd64Regs.Rsi = argVal
|
||||
case 2:
|
||||
amd64Regs.Rdx = argVal
|
||||
case 3:
|
||||
amd64Regs.R10 = argVal
|
||||
case 4:
|
||||
amd64Regs.R8 = argVal
|
||||
case 5:
|
||||
amd64Regs.R9 = argVal
|
||||
default:
|
||||
panic(fmt.Sprintf("invalid syscall argument index %d", argIdx))
|
||||
}
|
||||
_, ok := a.reported[a.key(regs)]
|
||||
return !ok
|
||||
}
|
||||
|
||||
func (a *argsTracker) onReported(regs *rpb.AMD64Registers) {
|
||||
a.count++
|
||||
a.reported[a.key(regs)] = struct{}{}
|
||||
func getSyscallNameMap() (strace.SyscallMap, bool) {
|
||||
return strace.Lookup(abi.Linux, arch.AMD64)
|
||||
}
|
||||
|
||||
func syscallNum(regs *rpb.Registers) uint64 {
|
||||
amd64Regs := regs.GetArch().(*rpb.Registers_Amd64).Amd64
|
||||
return amd64Regs.OrigRax
|
||||
}
|
||||
|
||||
func newArchArgsTracker(sysnr uint64) syscallTracker {
|
||||
switch sysnr {
|
||||
case syscall.SYS_ARCH_PRCTL:
|
||||
// args: cmd, ...
|
||||
return newArgsTracker(0)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,91 @@
|
||||
// Copyright 2019 The gVisor Authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package boot
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"gvisor.dev/gvisor/pkg/abi"
|
||||
"gvisor.dev/gvisor/pkg/sentry/arch"
|
||||
rpb "gvisor.dev/gvisor/pkg/sentry/arch/registers_go_proto"
|
||||
"gvisor.dev/gvisor/pkg/sentry/strace"
|
||||
)
|
||||
|
||||
// reportLimit is the max number of events that should be reported per tracker.
|
||||
const reportLimit = 100
|
||||
|
||||
// newRegs create a empty Registers instance.
|
||||
func newRegs() *rpb.Registers {
|
||||
return &rpb.Registers{
|
||||
Arch: &rpb.Registers_Arm64{
|
||||
Arm64: &rpb.ARM64Registers{},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func argVal(argIdx int, regs *rpb.Registers) uint32 {
|
||||
arm64Regs := regs.GetArch().(*rpb.Registers_Arm64).Arm64
|
||||
|
||||
switch argIdx {
|
||||
case 0:
|
||||
return uint32(arm64Regs.R0)
|
||||
case 1:
|
||||
return uint32(arm64Regs.R1)
|
||||
case 2:
|
||||
return uint32(arm64Regs.R2)
|
||||
case 3:
|
||||
return uint32(arm64Regs.R3)
|
||||
case 4:
|
||||
return uint32(arm64Regs.R4)
|
||||
case 5:
|
||||
return uint32(arm64Regs.R5)
|
||||
}
|
||||
panic(fmt.Sprintf("invalid syscall argument index %d", argIdx))
|
||||
}
|
||||
|
||||
func setArgVal(argIdx int, argVal uint64, regs *rpb.Registers) {
|
||||
arm64Regs := regs.GetArch().(*rpb.Registers_Arm64).Arm64
|
||||
|
||||
switch argIdx {
|
||||
case 0:
|
||||
arm64Regs.R0 = argVal
|
||||
case 1:
|
||||
arm64Regs.R1 = argVal
|
||||
case 2:
|
||||
arm64Regs.R2 = argVal
|
||||
case 3:
|
||||
arm64Regs.R3 = argVal
|
||||
case 4:
|
||||
arm64Regs.R4 = argVal
|
||||
case 5:
|
||||
arm64Regs.R5 = argVal
|
||||
default:
|
||||
panic(fmt.Sprintf("invalid syscall argument index %d", argIdx))
|
||||
}
|
||||
}
|
||||
|
||||
func getSyscallNameMap() (strace.SyscallMap, bool) {
|
||||
return strace.Lookup(abi.Linux, arch.ARM64)
|
||||
}
|
||||
|
||||
func syscallNum(regs *rpb.Registers) uint64 {
|
||||
arm64Regs := regs.GetArch().(*rpb.Registers_Arm64).Arm64
|
||||
return arm64Regs.R8
|
||||
}
|
||||
|
||||
func newArchArgsTracker(sysnr uint64) syscallTracker {
|
||||
// currently, no arch specific syscalls need to be handled here.
|
||||
return nil
|
||||
}
|
||||
+25
-20
@@ -16,8 +16,6 @@ package boot
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
rpb "gvisor.dev/gvisor/pkg/sentry/arch/registers_go_proto"
|
||||
)
|
||||
|
||||
func TestOnceTracker(t *testing.T) {
|
||||
@@ -35,31 +33,34 @@ func TestOnceTracker(t *testing.T) {
|
||||
|
||||
func TestArgsTracker(t *testing.T) {
|
||||
for _, tc := range []struct {
|
||||
name string
|
||||
idx []int
|
||||
rdi1 uint64
|
||||
rdi2 uint64
|
||||
rsi1 uint64
|
||||
rsi2 uint64
|
||||
want bool
|
||||
name string
|
||||
idx []int
|
||||
arg1_1 uint64
|
||||
arg1_2 uint64
|
||||
arg2_1 uint64
|
||||
arg2_2 uint64
|
||||
want bool
|
||||
}{
|
||||
{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},
|
||||
{name: "same arg1", idx: []int{0}, arg1_1: 123, arg1_2: 123, want: false},
|
||||
{name: "same arg2", idx: []int{1}, arg2_1: 123, arg2_2: 123, want: false},
|
||||
{name: "diff arg1", idx: []int{0}, arg1_1: 123, arg1_2: 321, want: true},
|
||||
{name: "diff arg2", idx: []int{1}, arg2_1: 123, arg2_2: 321, want: true},
|
||||
{name: "cmd is uint32", idx: []int{0}, arg2_1: 0xdead00000123, arg2_2: 0xbeef00000123, want: false},
|
||||
{name: "same 2 args", idx: []int{0, 1}, arg2_1: 123, arg1_1: 321, arg2_2: 123, arg1_2: 321, want: false},
|
||||
{name: "diff 2 args", idx: []int{0, 1}, arg2_1: 123, arg1_1: 321, arg2_2: 789, arg1_2: 987, want: true},
|
||||
} {
|
||||
t.Run(tc.name, func(t *testing.T) {
|
||||
c := newArgsTracker(tc.idx...)
|
||||
regs := &rpb.AMD64Registers{Rdi: tc.rdi1, Rsi: tc.rsi1}
|
||||
regs := newRegs()
|
||||
setArgVal(0, tc.arg1_1, regs)
|
||||
setArgVal(1, tc.arg2_1, regs)
|
||||
if !c.shouldReport(regs) {
|
||||
t.Error("first call to shouldReport, got: false, want: true")
|
||||
}
|
||||
c.onReported(regs)
|
||||
|
||||
regs.Rdi, regs.Rsi = tc.rdi2, tc.rsi2
|
||||
setArgVal(0, tc.arg1_2, regs)
|
||||
setArgVal(1, tc.arg2_2, regs)
|
||||
if got := c.shouldReport(regs); tc.want != got {
|
||||
t.Errorf("second call to shouldReport, got: %t, want: %t", got, tc.want)
|
||||
}
|
||||
@@ -70,7 +71,9 @@ func TestArgsTracker(t *testing.T) {
|
||||
func TestArgsTrackerLimit(t *testing.T) {
|
||||
c := newArgsTracker(0, 1)
|
||||
for i := 0; i < reportLimit; i++ {
|
||||
regs := &rpb.AMD64Registers{Rdi: 123, Rsi: uint64(i)}
|
||||
regs := newRegs()
|
||||
setArgVal(0, 123, regs)
|
||||
setArgVal(1, uint64(i), regs)
|
||||
if !c.shouldReport(regs) {
|
||||
t.Error("shouldReport before limit was reached, got: false, want: true")
|
||||
}
|
||||
@@ -78,7 +81,9 @@ func TestArgsTrackerLimit(t *testing.T) {
|
||||
}
|
||||
|
||||
// Should hit the count limit now.
|
||||
regs := &rpb.AMD64Registers{Rdi: 123, Rsi: 123456}
|
||||
regs := newRegs()
|
||||
setArgVal(0, 123, regs)
|
||||
setArgVal(1, 123456, regs)
|
||||
if c.shouldReport(regs) {
|
||||
t.Error("shouldReport after limit was reached, got: true, want: false")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user