diff options
author | We-unite <3205135446@qq.com> | 2024-07-31 11:46:01 +0800 |
---|---|---|
committer | We-unite <3205135446@qq.com> | 2024-08-01 15:10:36 +0800 |
commit | 3efeef969ebc344c993ce0fc46f557c7d8560525 (patch) | |
tree | f0f917080c64c8def6922c365465f1ee5371c464 | |
parent | d6c6e13796435f9e1e59fec891aa53680748a2d7 (diff) | |
download | godo-3efeef969ebc344c993ce0fc46f557c7d8560525.tar.gz godo-3efeef969ebc344c993ce0fc46f557c7d8560525.zip |
Use netlink connector to recv pid info, fix exec
For some reasons, kernel-connector can catch exec event, but it
doesn't tell me about what the process exec and what're its args.
So we should use audit to collect these infomations, and complete
in the database.
However, there's different delays between connector and audit,
although they both use netlink socket, as a result of which, exec
may comes before fork. we deal with it the same way. But, there's
also exec event lost, may because of the check for ppid in exec
event, but it's necessary, and if is deleted, too much irrelavent
infomation would flood into database, i've tried. So make it there,
just go forward.
Besides, what's newly discovered is that pthread_create also use
clone syscall, but if pid 1 has a thread 2, the exec info will say
that pid 2 execs. So i shouldn't ignore connector msg that childPid
ne childTgid.
This is my first attempt to use git-submodule function in my own pro-
ject, also golang local package. Congratulations!
Now, fight to fix about file operations. Hope that there wouldn't
be too many fucking bugs.
-rw-r--r-- | .gitignore | 3 | ||||
-rw-r--r-- | .gitmodules | 3 | ||||
-rw-r--r-- | src/deal.go | 30 | ||||
-rw-r--r-- | src/global.go | 7 | ||||
-rw-r--r-- | src/go.work | 6 | ||||
-rw-r--r-- | src/go.work.sum | 4 | ||||
-rw-r--r-- | src/godo.go | 82 | ||||
m--------- | src/netlink | 0 | ||||
-rw-r--r-- | src/organize.go | 31 |
9 files changed, 117 insertions, 49 deletions
@@ -1,5 +1,6 @@ | |||
1 | .vscode/* | 1 | .vscode/* |
2 | godo | 2 | */godo |
3 | */hello | ||
3 | 4 | ||
4 | old/* | 5 | old/* |
5 | !old/*.* | 6 | !old/*.* |
diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..6a63c7b --- /dev/null +++ b/.gitmodules | |||
@@ -0,0 +1,3 @@ | |||
1 | [submodule "src/netlink"] | ||
2 | path = src/netlink | ||
3 | url = https://github.com/We-unite/netlink | ||
diff --git a/src/deal.go b/src/deal.go index 717344c..3119fff 100644 --- a/src/deal.go +++ b/src/deal.go | |||
@@ -98,12 +98,15 @@ func deletePid(cooked Event) { | |||
98 | "$set": bson.M{ | 98 | "$set": bson.M{ |
99 | "exit_timestamp": cooked.timestamp, | 99 | "exit_timestamp": cooked.timestamp, |
100 | "exit_code": cooked.exit_code, | 100 | "exit_code": cooked.exit_code, |
101 | "exit_signal": cooked.exit_signal, | ||
101 | }, | 102 | }, |
102 | }) | 103 | }) |
103 | mongoMutex.Unlock() | 104 | mongoMutex.Unlock() |
105 | fmt.Printf("Exit: %v\t%6d\t%6d\n", cooked.timestamp, cooked.pid, cooked.exit_code) | ||
104 | } | 106 | } |
105 | 107 | ||
106 | func dealNewPid(cooked Event) { | 108 | func dealNewPid(cooked Event) { |
109 | fmt.Printf("Fork: %v\t%6d\t%6d\n", cooked.timestamp, cooked.ppid, cooked.pid) | ||
107 | // 有无父进程在观察中 | 110 | // 有无父进程在观察中 |
108 | docRes, err = pidCol.Finddoc(bson.M{"pid": cooked.ppid}) | 111 | docRes, err = pidCol.Finddoc(bson.M{"pid": cooked.ppid}) |
109 | if err != nil || len(docRes) != 1 { | 112 | if err != nil || len(docRes) != 1 { |
@@ -153,6 +156,7 @@ func dealNewPid(cooked Event) { | |||
153 | } | 156 | } |
154 | 157 | ||
155 | func dealExecve(cooked Event) { | 158 | func dealExecve(cooked Event) { |
159 | fmt.Printf("EXEC: %6d\t%6d\n", cooked.ppid, cooked.pid) | ||
156 | // 父进程在不在?不在扔 | 160 | // 父进程在不在?不在扔 |
157 | docRes, err = pidCol.Finddoc(bson.M{"pid": cooked.ppid}) | 161 | docRes, err = pidCol.Finddoc(bson.M{"pid": cooked.ppid}) |
158 | if err != nil || len(docRes) != 1 { | 162 | if err != nil || len(docRes) != 1 { |
@@ -175,19 +179,19 @@ func dealExecve(cooked Event) { | |||
175 | }, | 179 | }, |
176 | }, | 180 | }, |
177 | }) | 181 | }) |
178 | // } else { | 182 | } else { |
179 | // // 先fork抵达,插入 | 183 | // 先fork抵达,插入 |
180 | // pidCol.InsertOne(bson.M{ | 184 | pidCol.InsertOne(bson.M{ |
181 | // "ppid": cooked.ppid, | 185 | "ppid": cooked.ppid, |
182 | // "pid": cooked.pid, | 186 | "pid": cooked.pid, |
183 | // "children": []bson.M{}, | 187 | "children": []bson.M{}, |
184 | // "execve": []bson.M{ | 188 | "execve": []bson.M{ |
185 | // { | 189 | { |
186 | // "timestamp": cooked.timestamp, | 190 | "timestamp": cooked.timestamp, |
187 | // "execArgs": cooked.argv, | 191 | "execArgs": cooked.argv, |
188 | // }, | 192 | }, |
189 | // }, | 193 | }, |
190 | // }) | 194 | }) |
191 | } | 195 | } |
192 | mongoMutex.Unlock() | 196 | mongoMutex.Unlock() |
193 | } | 197 | } |
diff --git a/src/global.go b/src/global.go index f0f909c..a266b1b 100644 --- a/src/global.go +++ b/src/global.go | |||
@@ -33,12 +33,13 @@ type Event struct { | |||
33 | timestamp time.Time | 33 | timestamp time.Time |
34 | pid, ppid int | 34 | pid, ppid int |
35 | syscall int | 35 | syscall int |
36 | exit_code uint64 | 36 | syscallParam [4]uint64 |
37 | pathName string | ||
37 | argc int | 38 | argc int |
38 | argv []string | 39 | argv []string |
39 | cwd string | 40 | cwd string |
40 | syscallParam [4]uint64 | 41 | exit_code uint64 |
41 | pathName string | 42 | exit_signal int |
42 | } | 43 | } |
43 | 44 | ||
44 | func (event Event) String() string { | 45 | func (event Event) String() string { |
diff --git a/src/go.work b/src/go.work new file mode 100644 index 0000000..5b6c957 --- /dev/null +++ b/src/go.work | |||
@@ -0,0 +1,6 @@ | |||
1 | go 1.21.5 | ||
2 | |||
3 | use ( | ||
4 | ./netlink | ||
5 | ./ | ||
6 | ) \ No newline at end of file | ||
diff --git a/src/go.work.sum b/src/go.work.sum new file mode 100644 index 0000000..8201e39 --- /dev/null +++ b/src/go.work.sum | |||
@@ -0,0 +1,4 @@ | |||
1 | golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= | ||
2 | golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= | ||
3 | golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= | ||
4 | golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= | ||
diff --git a/src/godo.go b/src/godo.go index 0edcc9f..c332c86 100644 --- a/src/godo.go +++ b/src/godo.go | |||
@@ -1,11 +1,15 @@ | |||
1 | package main | 1 | package main |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "bufio" | ||
4 | "flag" | 5 | "flag" |
5 | "fmt" | 6 | "fmt" |
6 | "log" | 7 | "log" |
8 | "netlink" | ||
7 | "os" | 9 | "os" |
8 | "os/exec" | 10 | "os/exec" |
11 | "strings" | ||
12 | "syscall" | ||
9 | "time" | 13 | "time" |
10 | 14 | ||
11 | "github.com/elastic/go-libaudit/v2" | 15 | "github.com/elastic/go-libaudit/v2" |
@@ -37,7 +41,8 @@ func main() { | |||
37 | auditCmd = exec.Command("auditctl", "-D") // 清空所有规则 | 41 | auditCmd = exec.Command("auditctl", "-D") // 清空所有规则 |
38 | auditCmd.Run() | 42 | auditCmd.Run() |
39 | 43 | ||
40 | pidSyscall := []string{"fork", "vfork", "clone", "execve", "exit", "exit_group"} | 44 | pidSyscall := []string{"execve"} |
45 | // pidSyscall := []string{"fork", "vfork", "clone", "execve", "exit", "exit_group"} | ||
41 | // 设置监听规则 | 46 | // 设置监听规则 |
42 | for i := 0; i < len(pidSyscall); i++ { | 47 | for i := 0; i < len(pidSyscall); i++ { |
43 | auditCmd = exec.Command("auditctl", "-a", "exit,always", "-F", "arch=b64", "-S", pidSyscall[i]) | 48 | auditCmd = exec.Command("auditctl", "-a", "exit,always", "-F", "arch=b64", "-S", pidSyscall[i]) |
@@ -77,6 +82,10 @@ func coroutine(client *libaudit.AuditClient) { | |||
77 | // 各协程至此开始 | 82 | // 各协程至此开始 |
78 | rawChan = make(chan interface{}) | 83 | rawChan = make(chan interface{}) |
79 | cookedChan = make(chan Event) | 84 | cookedChan = make(chan Event) |
85 | |||
86 | wg.Add(1) | ||
87 | go procWatch() | ||
88 | |||
80 | wg.Add(1) | 89 | wg.Add(1) |
81 | go receive(client) | 90 | go receive(client) |
82 | wg.Add(1) | 91 | wg.Add(1) |
@@ -87,3 +96,74 @@ func coroutine(client *libaudit.AuditClient) { | |||
87 | wg.Wait() | 96 | wg.Wait() |
88 | time.Sleep(2 * time.Second) | 97 | time.Sleep(2 * time.Second) |
89 | } | 98 | } |
99 | |||
100 | func procWatch() error { | ||
101 | ns, err := netlink.NewNetlinkSocket(syscall.NETLINK_CONNECTOR, 12345) | ||
102 | if err != nil { | ||
103 | fmt.Printf("Error creating socket: %v\n", err) | ||
104 | return err | ||
105 | } | ||
106 | defer ns.Close() | ||
107 | for { | ||
108 | res, err := ns.Receive() | ||
109 | if err != nil { | ||
110 | fmt.Printf("Error recv: %v\n", err) | ||
111 | continue | ||
112 | } | ||
113 | for i := 0; i < len(res); i++ { | ||
114 | procEvent := netlink.ParseProcEvent(res[i].Data) | ||
115 | switch procEvent.What { | ||
116 | case netlink.PROC_EVENT_FORK: | ||
117 | data := procEvent.Data.(netlink.ProcEventFork) | ||
118 | cooked := Event{ | ||
119 | tag: NEWPID, | ||
120 | ppid: int(data.ParentTgid), | ||
121 | pid: int(data.ChildPid), | ||
122 | timestamp: time.Now(), | ||
123 | } | ||
124 | checkProc(&cooked) | ||
125 | if data.ChildPid != data.ChildTgid { | ||
126 | cooked.ppid = int(data.ChildTgid) | ||
127 | cooked.pid = int(data.ChildPid) | ||
128 | } | ||
129 | cookedChan <- cooked | ||
130 | case netlink.PROC_EVENT_EXIT: | ||
131 | data := procEvent.Data.(netlink.ProcEventExit) | ||
132 | cooked := Event{ | ||
133 | tag: PIDEXIT, | ||
134 | timestamp: time.Now(), | ||
135 | pid: int(data.ProcessPid), | ||
136 | exit_code: uint64(data.ExitCode), | ||
137 | exit_signal: int(data.ExitSignal), | ||
138 | } | ||
139 | cookedChan <- cooked | ||
140 | default: | ||
141 | } | ||
142 | } | ||
143 | } | ||
144 | } | ||
145 | |||
146 | func checkProc(pCooked *Event) { | ||
147 | fileName := fmt.Sprintf("/proc/%d/cmdline", pCooked.pid) | ||
148 | fd, err := os.Open(fileName) | ||
149 | if err != nil { | ||
150 | fmt.Printf("Err opening file %s: %v\n", fileName, err) | ||
151 | return | ||
152 | } | ||
153 | |||
154 | scanner := bufio.NewScanner(fd) | ||
155 | scanner.Split(bufio.ScanLines) | ||
156 | for scanner.Scan() { | ||
157 | line := scanner.Text() | ||
158 | pCooked.argv = append(pCooked.argv, strings.Split(line, "\x00")...) | ||
159 | } | ||
160 | pCooked.argc = len(pCooked.argv) | ||
161 | fd.Close() | ||
162 | |||
163 | fileName = fmt.Sprintf("/proc/%d/cwd", pCooked.pid) | ||
164 | pCooked.cwd, err = os.Readlink(fileName) | ||
165 | if err != nil { | ||
166 | fmt.Printf("Err readlink %s: %v\n", fileName, err) | ||
167 | pCooked.cwd = "" | ||
168 | } | ||
169 | } | ||
diff --git a/src/netlink b/src/netlink new file mode 160000 | |||
Subproject 10d3ea361f0bcafb9b92054440984d32421aeb7 | |||
diff --git a/src/organize.go b/src/organize.go index d7a1df1..238509f 100644 --- a/src/organize.go +++ b/src/organize.go | |||
@@ -47,7 +47,6 @@ func orgnaze() { | |||
47 | break | 47 | break |
48 | } | 48 | } |
49 | rawEvent = raw.(libaudit.RawAuditMessage) | 49 | rawEvent = raw.(libaudit.RawAuditMessage) |
50 | fmt.Printf("type=%v msg=%s\n", rawEvent.Type, rawEvent.Data) | ||
51 | 50 | ||
52 | switch rawEvent.Type { | 51 | switch rawEvent.Type { |
53 | case auparse.AUDIT_SYSCALL: | 52 | case auparse.AUDIT_SYSCALL: |
@@ -100,24 +99,6 @@ func syscallRaw(rawEvent libaudit.RawAuditMessage) { | |||
100 | } | 99 | } |
101 | 100 | ||
102 | switch syscallTable[event.syscall] { | 101 | switch syscallTable[event.syscall] { |
103 | case "clone": | ||
104 | if exit == 0 || event.pid > exit { | ||
105 | // exit=0是给新进程的返回,没用 | ||
106 | // pid>exit,证明有问题,抛弃 | ||
107 | break | ||
108 | } else { | ||
109 | eventTable.Store(eventId, &Event{ | ||
110 | tag: NEWPID, | ||
111 | timestamp: event.timestamp, | ||
112 | syscall: event.syscall, | ||
113 | exit_code: 0, | ||
114 | ppid: event.pid, | ||
115 | pid: exit, | ||
116 | argc: 0, | ||
117 | argv: make([]string, 0), | ||
118 | cwd: "", | ||
119 | }) | ||
120 | } | ||
121 | case "execve": | 102 | case "execve": |
122 | eventTable.Store(eventId, &Event{ | 103 | eventTable.Store(eventId, &Event{ |
123 | tag: EXECVE, | 104 | tag: EXECVE, |
@@ -130,18 +111,6 @@ func syscallRaw(rawEvent libaudit.RawAuditMessage) { | |||
130 | argv: make([]string, 0), | 111 | argv: make([]string, 0), |
131 | cwd: "", | 112 | cwd: "", |
132 | }) | 113 | }) |
133 | case "exit", "exit_group": | ||
134 | eventTable.Store(eventId, &Event{ | ||
135 | tag: PIDEXIT, | ||
136 | timestamp: event.timestamp, | ||
137 | syscall: event.syscall, | ||
138 | exit_code: a[0], | ||
139 | ppid: event.ppid, | ||
140 | pid: event.pid, | ||
141 | argc: 0, | ||
142 | argv: make([]string, 0), | ||
143 | cwd: "", | ||
144 | }) | ||
145 | case "open": | 114 | case "open": |
146 | // 检查打开的权限 | 115 | // 检查打开的权限 |
147 | if a[1]&(syscall.O_APPEND|syscall.O_WRONLY|syscall.O_RDWR|syscall.O_TRUNC) == 0 { | 116 | if a[1]&(syscall.O_APPEND|syscall.O_WRONLY|syscall.O_RDWR|syscall.O_TRUNC) == 0 { |