From 94838d05e0884128b25603042b8fe5e568ed30ca Mon Sep 17 00:00:00 2001 From: sfx Date: Tue, 23 Jan 2024 07:09:26 -0800 Subject: [PATCH] =?UTF-8?q?=E4=B8=BAsyscall=E6=8F=90=E4=BE=9B=E5=88=9D?= =?UTF-8?q?=E6=AD=A5=E9=85=8D=E7=BD=AE=E6=96=87=E4=BB=B6=E6=94=AF=E6=8C=81?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cli/cmd/root.go | 8 +-- tests/config_syscall_test.json | 13 ++-- user/argtype/argtype_base.go | 2 + user/argtype/argtype_flags.go | 37 +++++++++++ user/argtype/iargtype.go | 32 ++++++++++ user/config/config_file.go | 19 +++++- user/config/config_module.go | 103 +++++++++++++++++++++++++++---- user/config/config_point_arg.go | 31 ++++++++++ user/event/event_raw_syscalls.go | 3 +- 9 files changed, 224 insertions(+), 24 deletions(-) diff --git a/cli/cmd/root.go b/cli/cmd/root.go index d7fd4f7..321b21e 100644 --- a/cli/cmd/root.go +++ b/cli/cmd/root.go @@ -285,15 +285,15 @@ func persistentPreRunEFunc(command *cobra.Command, args []string) error { } } - // 2. hook syscall - mconfig.SysCallConf.Parse_SysWhitelist(gconfig) - mconfig.SysCallConf.Parse_SysBlacklist(gconfig.NoSysCall) - // 3. hook config if len(gconfig.ConfigFiles) > 0 { mconfig.LoadConfig(gconfig) } + // 2. hook syscall + mconfig.SysCallConf.Parse_SysWhitelist(gconfig) + mconfig.SysCallConf.Parse_SysBlacklist(gconfig.NoSysCall) + // 4. watch breakpoint var brk_base uint64 = 0x0 if gconfig.BrkLib != "" { diff --git a/tests/config_syscall_test.json b/tests/config_syscall_test.json index 2d57067..876f01c 100644 --- a/tests/config_syscall_test.json +++ b/tests/config_syscall_test.json @@ -6,8 +6,9 @@ "name": "ioctl", "params": [ {"name": "fd", "type": "int"}, - {"name": "cmd", "type": "int"}, - {"name": "arg", "type": "ptr", "filter": ["eq:0x801"]} + {"name": "cmd", "type": "ptr", "filter": ["eq:0xc0306201"]}, + {"name": "arg", "type": "ptr"}, + {"name": "ret", "type": "ptr"} ] }, { @@ -17,9 +18,10 @@ {"name": "sockfd", "type": "int"}, {"name": "buf", "type": "buf", "more":"enter", "size": "x2"}, {"name": "len", "type": "size_t"}, - {"name": "flags", "type": "int", "format": "socket_flags"}, + {"name": "flags", "type": "int", "format": "msg_flags"}, {"name": "addr", "type": "sockaddr"}, - {"name": "addrlen", "type": "socklen_t"} + {"name": "addrlen", "type": "socklen_t"}, + {"name": "ret", "type": "int"} ] }, { @@ -29,7 +31,8 @@ {"name": "sockfd", "type": "int"}, {"name": "buf", "type": "buf", "size": "x2", "more": "exit"}, {"name": "len", "type": "size_t"}, - {"name": "flags", "type": "int", "format": "socket_flags"} + {"name": "flags", "type": "int", "format": "msg_flags"}, + {"name": "ret", "type": "int"} ] } ] diff --git a/user/argtype/argtype_base.go b/user/argtype/argtype_base.go index 8777921..023daa8 100644 --- a/user/argtype/argtype_base.go +++ b/user/argtype/argtype_base.go @@ -739,6 +739,8 @@ func init() { Register(&ARG_STRUCT{}, "struct", TYPE_STRUCT, STRUCT, 0) Register(&ARG_ARRAY{}, "array", TYPE_ARRAY, ARRAY, 0) + PreRegister() + RegisterAliasType(SOCKLEN_T, UINT32) RegisterAliasType(SIZE_T, UINT64) RegisterAliasType(SSIZE_T, INT64) diff --git a/user/argtype/argtype_flags.go b/user/argtype/argtype_flags.go index b3c136e..6a7cb71 100644 --- a/user/argtype/argtype_flags.go +++ b/user/argtype/argtype_flags.go @@ -142,6 +142,30 @@ var SocketFlags []*FlagOp = []*FlagOp{ {"SOCK_NONBLOCK", int32(00004000)}, } +var MsgFlags []*FlagOp = []*FlagOp{ + {"MSG_OOB", int32(1)}, + {"MSG_PEEK", int32(2)}, + {"MSG_DONTROUTE", int32(4)}, + {"MSG_TRYHARD", int32(4)}, + {"MSG_CTRUNC", int32(8)}, + {"MSG_PROBE", int32(0x10)}, + {"MSG_TRUNC", int32(0x20)}, + {"MSG_DONTWAIT", int32(0x40)}, + {"MSG_EOR", int32(0x80)}, + {"MSG_WAITALL", int32(0x100)}, + {"MSG_FIN", int32(0x200)}, + {"MSG_SYN", int32(0x400)}, + {"MSG_CONFIRM", int32(0x800)}, + {"MSG_RST", int32(0x1000)}, + {"MSG_ERRQUEUE", int32(0x2000)}, + {"MSG_NOSIGNAL", int32(0x4000)}, + {"MSG_MORE", int32(0x8000)}, + {"MSG_WAITFORONE", int32(0x10000)}, + {"MSG_BATCH", int32(0x40000)}, + {"MSG_FASTOPEN", int32(0x20000000)}, + {"MSG_CMSG_CLOEXEC", int32(0x40000000)}, +} + var FcntlFlags []*FlagOp = []*FlagOp{ // {"AT_FDCWD", int32(-100)}, {"AT_SYMLINK_NOFOLLOW", int32(0x100)}, @@ -170,6 +194,7 @@ var FcntlFlagsConfig = &FlagsConfig{"stat", FORMAT_HEX, FcntlFlags} var StatxFlagsConfig = &FlagsConfig{"statx", FORMAT_HEX, StatxFlags} var UnlinkFlagsConfig = &FlagsConfig{"unlink", FORMAT_HEX, UnlinkFlags} var MreapFlagsConfig = &FlagsConfig{"mreap", FORMAT_HEX, MreapFlags} +var MsgFlagsConfig = &FlagsConfig{"msg", FORMAT_HEX, MsgFlags} var SocketFlagsConfig = &FlagsConfig{"socket", FORMAT_HEX, SocketFlags} var PermissionFlagsConfig = &FlagsConfig{"permission", FORMAT_OCT, PermissionFlags} @@ -185,6 +210,18 @@ func RegisterFlagsConfig(type_index, parent_index uint32, flags_config *FlagsCon return new_p } +func NewNumFlags(parent_index uint32, flags_config *FlagsConfig) IArgType { + p := GetArgType(parent_index) + new_name := fmt.Sprintf("%s_flags_%s", p.GetName(), flags_config.Name) + new_p := RegisterNew(new_name, p.GetTypeIndex()) + new_i, ok := (new_p).(IArgTypeNum) + if !ok { + panic("...") + } + new_i.SetFlagsConfig(flags_config) + return new_p +} + func NewNumFormat(p IArgType, format_type uint32) IArgType { new_name := fmt.Sprintf("%s_fmt_%d", p.GetName(), format_type) new_p := RegisterNew(new_name, p.GetTypeIndex()) diff --git a/user/argtype/iargtype.go b/user/argtype/iargtype.go index 6e753a3..716d734 100644 --- a/user/argtype/iargtype.go +++ b/user/argtype/iargtype.go @@ -279,6 +279,38 @@ func LazyRegister(type_index uint32) IArgType { } } +func PreRegister() { + // 先注册好各种内置类型 + r_PRE_ARRAY(GetArgType(INT), INT_ARRAY_1, 1) + r_PRE_ARRAY(GetArgType(INT), INT_ARRAY_2, 2) + r_PRE_ARRAY(GetArgType(UINT), UINT_ARRAY_1, 1) + R_POINTER(GetArgType(INT), true) + R_POINTER(GetArgType(UINT), true) + r_STD_STRING() + r_STRING_ARRAY() + r_STACK_T() + PRE_R_STRUCT("timespec", TIMESPEC, &Arg_Timespec{}) + r_SIGSET() + r_SIGINFO() + PRE_R_STRUCT("sigaction", SIGACTION, &Arg_Sigaction{}) + r_EPOLLEVENT() + r_POLLFD() + r_DIRENT() + r_ITTMERSPEC() + r_RUSAGE() + r_UTSNAME() + r_TIMEVAL() + r_TIMEZONE() + r_SYSINFO() + r_STAT() + r_STATFS() + r_IOVEC() + r_IOVEC_X2() + r_MSGHDR() + r_SOCKADDR() + r_BUFFER_X2() +} + func Register(p IArgType, name string, base, index, size uint32) { // 注册有预设的基础类型 if p == nil { diff --git a/user/config/config_file.go b/user/config/config_file.go index d30f9d7..9866c1c 100644 --- a/user/config/config_file.go +++ b/user/config/config_file.go @@ -42,7 +42,7 @@ func (this *FileConfig) GetType() string { return this.Type } -func (this *ParamConfig) GetPointArg(arg_index uint32) *PointArg { +func (this *ParamConfig) GetPointArg(arg_index, point_type uint32) *PointArg { // 参数名省略时 以 a{index} 这样的形式作为名字 arg_name := fmt.Sprintf("a%d", arg_index) if this.Name != "" { @@ -55,7 +55,15 @@ func (this *ParamConfig) GetPointArg(arg_index uint32) *PointArg { reg_index = GetRegIndex(this.Reg) } // 基础配置 - point_arg := NewUprobePointArg(arg_name, POINTER, reg_index) + var point_arg *PointArg + switch point_type { + case EBPF_SYS_ENTER, EBPF_SYS_EXIT, EBPF_SYS_ALL: + point_arg = NewSyscallPointArg(arg_name, POINTER, reg_index, point_type) + case EBPF_UPROBE_ENTER: + point_arg = NewUprobePointArg(arg_name, POINTER, reg_index) + default: + panic("...") + } // 先处理一些比较特殊的情况 to_ptr := false @@ -121,6 +129,13 @@ func (this *ParamConfig) GetPointArg(arg_index uint32) *PointArg { point_arg.SetHexFormat() case "hexdump": point_arg.SetHexFormat() + case "fcntl_flags", "statx_flags", "unlink_flags", "socket_flags", "perm_flags", "msg_flags": + point_arg.SetFlagsFormat(this.Format) + case "": + // 没设置就默认方式处理 + break + default: + panic(fmt.Sprintf("unsupported format type:%s", this.Format)) } // 设置过滤规则 先解析规则 然后取到规则索引 diff --git a/user/config/config_module.go b/user/config/config_module.go index eab6ee4..d4f0d49 100644 --- a/user/config/config_module.go +++ b/user/config/config_module.go @@ -291,7 +291,7 @@ func (this *StackUprobeConfig) GetSyscall() string { } func (this *StackUprobeConfig) Parse_FileConfig(config *UprobeFileConfig) (err error) { - for index, point := range config.Points { + for index, point_config := range config.Points { hook_point := &UprobeArgs{} hook_point.BindSyscall = false hook_point.ExitRead = false @@ -299,19 +299,19 @@ func (this *StackUprobeConfig) Parse_FileConfig(config *UprobeFileConfig) (err e hook_point.LibPath = this.LibPath hook_point.RealFilePath = this.RealFilePath hook_point.NonElfOffset = this.NonElfOffset - hook_point.Name = point.Name - if point.Signal != "" { - hook_point.KillSignal = util.ParseSignal(point.Signal) + hook_point.Name = point_config.Name + if point_config.Signal != "" { + hook_point.KillSignal = util.ParseSignal(point_config.Signal) } // strstr / strstr+0x4 / 0xA94E8 - items := strings.Split(point.Name, "+") + items := strings.Split(point_config.Name, "+") if len(items) == 1 { sym_or_off := items[0] if strings.HasPrefix(sym_or_off, "0x") { offset, err := strconv.ParseUint(sym_or_off, 0, 64) if err != nil { - return errors.New(fmt.Sprintf("parse for %s failed, err:%v", point.Name, err)) + return errors.New(fmt.Sprintf("parse for %s failed, err:%v", point_config.Name, err)) } hook_point.Offset = offset hook_point.Symbol = "" @@ -323,15 +323,15 @@ func (this *StackUprobeConfig) Parse_FileConfig(config *UprobeFileConfig) (err e sym_or_off := items[1] offset, err := strconv.ParseUint(sym_or_off, 0, 64) if err != nil { - return errors.New(fmt.Sprintf("parse for %s failed, err:%v", point.Name, err)) + return errors.New(fmt.Sprintf("parse for %s failed, err:%v", point_config.Name, err)) } hook_point.Offset = offset } else { - return errors.New(fmt.Sprintf("parse for %s failed, err:%v", point.Name, err)) + return errors.New(fmt.Sprintf("parse for %s failed, err:%v", point_config.Name, err)) } - for arg_index, param := range point.Params { - point_arg := param.GetPointArg(uint32(arg_index)) + for arg_index, param := range point_config.Params { + point_arg := param.GetPointArg(uint32(arg_index), EBPF_UPROBE_ENTER) hook_point.PointArgs = append(hook_point.PointArgs, point_arg) } this.Points = append(this.Points, hook_point) @@ -444,8 +444,59 @@ func (this *SyscallConfig) SetArgFilterRule(arg_filter *[]ArgFilter) { this.arg_filter = arg_filter } +func (this *SyscallConfig) GetSyscallPointByNR(nr uint32) *SyscallPoint { + // 后面加个 map 吧 总感觉这样会比较慢 + for _, point_arg := range this.PointArgs { + if point_arg.Nr == nr { + return point_arg + } + } + panic(fmt.Sprintf("unknown nr:%d", nr)) +} + +func (this *SyscallConfig) Parse_FileConfig(config *SyscallFileConfig) (err error) { + for _, point_config := range config.Points { + var a_point_args []*PointArg + var b_point_args []*PointArg + for arg_index, param := range point_config.Params { + if param.Name == "ret" { + // 需要告知用户 syscall 中参数名 ret 仅用于返回值 + point_arg := param.GetPointArg(uint32(arg_index), EBPF_SYS_EXIT) + b_point_args = append(b_point_args, point_arg) + break + } + + var point_type uint32 + switch param.More { + case "", "enter": + point_type = EBPF_SYS_ENTER + case "exit": + point_type = EBPF_SYS_EXIT + case "all": + point_type = EBPF_SYS_ALL + default: + panic(fmt.Sprintf("unknown point_type:%s", param.More)) + } + point_arg := param.GetPointArg(uint32(arg_index), point_type) + + a_p := point_arg.Clone() + a_p.SetGroupType(EBPF_SYS_ENTER) + a_point_args = append(a_point_args, a_p) + + b_p := point_arg.Clone() + b_p.SetGroupType(EBPF_SYS_EXIT) + b_point_args = append(b_point_args, b_p) + + } + point := &SyscallPoint{point_config.Nr, point_config.Name, a_point_args, b_point_args} + this.PointArgs = append(this.PointArgs, point) + } + + return nil +} + func (this *SyscallConfig) Parse_SysWhitelist(gconfig *GlobalConfig) { - if gconfig.SysCall == "" { + if gconfig.SysCall == "" && len(gconfig.ConfigFiles) == 0 { this.Enable = false return } @@ -504,7 +555,9 @@ func (this *SyscallConfig) Parse_SysWhitelist(gconfig *GlobalConfig) { case "%stat": syscall_items = append(syscall_items, []string{"statfs", "fstatfs", "newfstatat", "fstat", "statx"}...) default: - syscall_items = append(syscall_items, v) + if v != "" { + syscall_items = append(syscall_items, v) + } } } // 去重 @@ -516,6 +569,28 @@ func (this *SyscallConfig) Parse_SysWhitelist(gconfig *GlobalConfig) { } } } + if len(this.PointArgs) > 0 { + // 这个分支是配置文件走 + if len(unique_items) == 0 { + // 命令行中不指定任何 syscall 那么会认为配置文件中的所有syscall都生效 + // 这种是用户自定义syscall参数读取方式 + for _, point_arg := range this.PointArgs { + this.SysWhitelist = append(this.SysWhitelist, point_arg.Nr) + } + } else { + // 指定了 syscall 则只从预置配置中选取存在的syscall + // 这种是使用预置配置 + for _, syscall_name := range unique_items { + for _, point_arg := range this.PointArgs { + if point_arg.Name == syscall_name { + this.SysWhitelist = append(this.SysWhitelist, point_arg.Nr) + } + } + } + } + return + } + for _, v := range unique_items { var index_items [][]uint32 syscall_name := v @@ -730,6 +805,10 @@ func (this *ModuleConfig) LoadConfig(gconfig *GlobalConfig) { if err != nil { panic(err) } + err = this.SysCallConf.Parse_FileConfig(config) + if err != nil { + panic(err) + } default: panic(fmt.Sprintf("unsupported config type %s", base_config.Type)) } diff --git a/user/config/config_point_arg.go b/user/config/config_point_arg.go index 5ec6fcf..0e7e2c5 100644 --- a/user/config/config_point_arg.go +++ b/user/config/config_point_arg.go @@ -28,6 +28,27 @@ func (this *PointArg) SetTypeIndex(type_index uint32) { this.TypeIndex = type_index } +func (this *PointArg) SetFlagsFormat(format string) { + var p argtype.IArgType + switch format { + case "fcntl_flags": + p = argtype.NewNumFlags(this.TypeIndex, argtype.FcntlFlagsConfig) + case "statx_flags": + p = argtype.NewNumFlags(this.TypeIndex, argtype.StatxFlagsConfig) + case "unlink_flags": + p = argtype.NewNumFlags(this.TypeIndex, argtype.UnlinkFlagsConfig) + case "msg_flags": + p = argtype.NewNumFlags(this.TypeIndex, argtype.MsgFlagsConfig) + case "socket_flags": + p = argtype.NewNumFlags(this.TypeIndex, argtype.SocketFlagsConfig) + case "perm_flags": + p = argtype.NewNumFlags(this.TypeIndex, argtype.PermissionFlagsConfig) + default: + panic("...") + } + this.TypeIndex = p.GetTypeIndex() +} + func (this *PointArg) SetTypeByName(name string) { this.TypeIndex = argtype.GetArgTypeByName(name).GetTypeIndex() } @@ -121,6 +142,7 @@ func (this *PointArg) Clone() *PointArg { p.RegIndex = this.RegIndex p.TypeIndex = this.TypeIndex p.PointType = this.PointType + p.FilterIndexList = this.FilterIndexList return &p } @@ -133,6 +155,15 @@ func NewPointArg(arg_name string, type_index, point_type uint32) *PointArg { return &point_arg } +func NewSyscallPointArg(arg_name string, type_index, reg_index, point_type uint32) *PointArg { + point_arg := PointArg{} + point_arg.Name = arg_name + point_arg.RegIndex = reg_index + point_arg.TypeIndex = type_index + point_arg.PointType = point_type + return &point_arg +} + func A(arg_name string, type_index uint32) *PointArg { return NewPointArg(arg_name, type_index, EBPF_SYS_ENTER) } diff --git a/user/event/event_raw_syscalls.go b/user/event/event_raw_syscalls.go index 1ceb860..d40b2a5 100644 --- a/user/event/event_raw_syscalls.go +++ b/user/event/event_raw_syscalls.go @@ -39,7 +39,8 @@ func (this *SyscallEvent) ParseEvent() (IEventStruct, error) { func (this *SyscallEvent) ParseContext() (err error) { this.ReadArg(&this.NR) - this.nr_point = config.GetSyscallPointByNR(this.NR) + this.nr_point = this.mconf.SysCallConf.GetSyscallPointByNR(this.NR) + // this.nr_point = config.GetSyscallPointByNR(this.NR) this.PointName = this.nr_point.Name // this.logger.Printf("ParseContext EventId:%d RawSample:\n%s", this.EventId, util.HexDump(this.rec.RawSample, util.COLORRED))