aboutsummaryrefslogtreecommitdiffstats
path: root/src/organize.go
diff options
context:
space:
mode:
authorWe-unite <3205135446@qq.com>2024-07-23 19:32:09 +0800
committerWe-unite <3205135446@qq.com>2024-07-25 17:09:45 +0800
commitfc61a4a525846fa31ee2288df4e82f745bb39c95 (patch)
treee97c7b942c7e843782efbcc48882e6c0854df473 /src/organize.go
parentcf5618ff2e2a183c5bdf6444787dccdcbf26ce76 (diff)
downloadgodo-fc61a4a525846fa31ee2288df4e82f745bb39c95.tar.gz
godo-fc61a4a525846fa31ee2288df4e82f745bb39c95.zip
Try ot fix the out-of-order bug, add EXECVE to itthings_left
The Most important work during this time is to find out solution to the out-of-order bug. Discribe it here in detail: info from audit may be out of order, which means fork may comes after execve, even after exit. What an absurd penomenon to see a process not yet created to work or exit! To deal with this problem, I've tried several ways: - in the 2nd coroutine, when EOE msg comes, if it's a fork/clone event, send it immediately, otherwise wait for some time(such as 100 ms). But after all it delays longer, and has other problems. - the 2nd coroutine doesn't send directly, but record all the finished event id in a slice, and another thread checks once every one second, if there are sth in slice, send corresponding events in the order of event id. But: event that happens first doesn't always has lower id or time, for example, 1 forks 2, then 2 execve, the audit in kernel it self may gets execve before fork(maybe fork makes other settings), which means execve has earlier timestamp and lower event id. The out- of-order problem is not completely resolved. If we then add delays to non-clone event, a more serious problem happens: we must use mutex to lock the slice recording finished event id to prevent crush between send thread and wait thread, but the wait thread can't get the mutex again, because there are to much clone event and frequent send! - So I use no delay but mongodb, when an execve comes, if pid is not recorded, just insert it and wait for the fork. It does works, but some other works is still left to do: - what should i do if 2 forks 3 comes before 1 forks 2? Now I suggest it doesn't happen, but what if? - when execve comes before fork, i recorded it, but if this process has a parent i don't care, delete, or stays there? Also, as mentioned above, I've add EXECVE field in process into db, records all the execve(time, and args) from the same process. Besides, exit_timestamp and exit_code can be caught now, but too many process has no exit info. This is also to be fixed. Now, let's listen to the file changed by process. Don't forget the to-do works listed above!
Diffstat (limited to 'src/organize.go')
-rw-r--r--src/organize.go79
1 files changed, 57 insertions, 22 deletions
diff --git a/src/organize.go b/src/organize.go
index bb6736a..d963288 100644
--- a/src/organize.go
+++ b/src/organize.go
@@ -1,9 +1,11 @@
1package main 1package main
2 2
3import ( 3import (
4 "fmt"
4 "regexp" 5 "regexp"
5 "strconv" 6 "strconv"
6 "strings" 7 "strings"
8 "sync"
7 9
8 "github.com/elastic/go-libaudit/v2" 10 "github.com/elastic/go-libaudit/v2"
9 "github.com/elastic/go-libaudit/v2/auparse" 11 "github.com/elastic/go-libaudit/v2/auparse"
@@ -19,16 +21,20 @@ func orgnaze() {
19 // 事件信息 21 // 事件信息
20 var eventId, argc int 22 var eventId, argc int
21 var err [6]error 23 var err [6]error
22 var event, cooked Event 24 var event Event
25 var pEvent *Event
26 var tmp any
23 // 为每个事务id存储其信息,事务id在操作系统运行期间是唯一的 27 // 为每个事务id存储其信息,事务id在操作系统运行期间是唯一的
24 eventTable := make(map[int]*Event) 28 var eventTable sync.Map
29
25 // 要用的正则匹配列表 30 // 要用的正则匹配列表
26 syscallRegex := regexp.MustCompile(`audit\((\d+\.\d+):(\d+)\).*?syscall=(\d+).*?(exit=([-+]?\d+).*?)?ppid=(\d+) pid=(\d+).*?$`) 31 syscallRegex := regexp.MustCompile(`audit\((\d+\.\d+):(\d+)\).*?syscall=(\d+).*?(exit=([-+]?\d+))? a0=([0-9a-fA-F]+).*?ppid=(\d+) pid=(\d+).*?$`)
27 execveRegex := regexp.MustCompile(`audit\(\d+\.\d+:(\d+)\): argc=(\d+)`) 32 execveRegex := regexp.MustCompile(`audit\(\d+\.\d+:(\d+)\): argc=(\d+)`)
28 argsRegex := regexp.MustCompile(`a\d+=("(.*?)"|([0-9a-fA-F]+))`) 33 argsRegex := regexp.MustCompile(`a\d+=("(.*?)"|([0-9a-fA-F]+))`)
29 cwdRegex := regexp.MustCompile(`audit\(\d+\.\d+:(\d+)\): cwd="(.*?)"`) 34 cwdRegex := regexp.MustCompile(`audit\(\d+\.\d+:(\d+)\): cwd="(.*?)"`)
30 proctitleRegex := regexp.MustCompile(`audit\(\d+\.\d+:(\d+)\): proctitle=("(.*?)"|([0-9a-fA-F]+))$`) 35 proctitleRegex := regexp.MustCompile(`audit\(\d+\.\d+:(\d+)\): proctitle=("(.*?)"|([0-9a-fA-F]+))$`)
31 eoeRegex := regexp.MustCompile(`audit\(\d+\.\d+:(\d+)\)`) 36 eoeRegex := regexp.MustCompile(`audit\(\d+\.\d+:(\d+)\)`)
37
32 for { 38 for {
33 raw, ok = <-rawChan 39 raw, ok = <-rawChan
34 if !ok { 40 if !ok {
@@ -44,39 +50,53 @@ func orgnaze() {
44 eventId, err[1] = strconv.Atoi(string(match[2])) 50 eventId, err[1] = strconv.Atoi(string(match[2]))
45 event.syscall, err[2] = strconv.Atoi(string(match[3])) 51 event.syscall, err[2] = strconv.Atoi(string(match[3]))
46 var exit int 52 var exit int
47 // exit, err[3] = strconv.Atoi(string(match[4])) 53 var a0 uint64
48 if string(match[5]) == "" { 54 if string(match[5]) == "" {
49 // exit没捕获到 55 // exit没捕获到
50 exit = 0 56 exit = 0
51 } else { 57 } else {
52 exit, err[3] = strconv.Atoi(string(match[5])) 58 exit, err[3] = strconv.Atoi(string(match[5]))
53 } 59 }
54 event.ppid, err[4] = strconv.Atoi(string(match[5])) 60 if string(match[6]) == "" {
55 event.pid, err[5] = strconv.Atoi(string(match[6])) 61 a0 = 0
62 } else {
63 // 系统调用的第一个参数
64 // exit和exit_group都是syscall_define1,只有一个参数
65 // fork没参数,clone几个参数不重要
66 // execve三个参数咱也不关心
67 // 所以看第一个就够了
68 a0, err[4] = strconv.ParseUint(string(match[6]), 16, 64)
69 }
70 event.ppid, err[4] = strconv.Atoi(string(match[7]))
71 event.pid, err[5] = strconv.Atoi(string(match[8]))
56 if syscallTable[event.syscall] == "clone" { 72 if syscallTable[event.syscall] == "clone" {
57 if exit == 0 { 73 if exit == 0 || event.pid > exit {
74 // exit=0是给新进程的返回,没用
75 // pid>exit,证明有问题,抛弃
58 break 76 break
59 } else { 77 } else {
60 eventTable[eventId] = &Event{ 78 eventTable.Store(eventId, &Event{
61 timestamp: event.timestamp, 79 timestamp: event.timestamp,
62 syscall: event.syscall, 80 syscall: event.syscall,
81 exit_code: 0,
63 ppid: event.pid, 82 ppid: event.pid,
64 pid: exit, 83 pid: exit,
65 argc: 0, 84 argc: 0,
66 argv: make([]string, 0), 85 argv: make([]string, 0),
67 cwd: "", 86 cwd: "",
68 } 87 })
69 } 88 }
70 } else { 89 } else {
71 eventTable[eventId] = &Event{ 90 eventTable.Store(eventId, &Event{
72 timestamp: event.timestamp, 91 timestamp: event.timestamp,
73 syscall: event.syscall, 92 syscall: event.syscall,
93 exit_code: a0,
74 ppid: event.ppid, 94 ppid: event.ppid,
75 pid: event.pid, 95 pid: event.pid,
76 argc: 0, 96 argc: 0,
77 argv: make([]string, 0), 97 argv: make([]string, 0),
78 cwd: "", 98 cwd: "",
79 } 99 })
80 } 100 }
81 } 101 }
82 case auparse.AUDIT_EXECVE: 102 case auparse.AUDIT_EXECVE:
@@ -84,34 +104,45 @@ func orgnaze() {
84 match := execveRegex.FindSubmatch(rawEvent.Data) 104 match := execveRegex.FindSubmatch(rawEvent.Data)
85 eventId, err[0] = strconv.Atoi(string(match[1])) 105 eventId, err[0] = strconv.Atoi(string(match[1]))
86 argc, err[1] = strconv.Atoi(string(match[2])) 106 argc, err[1] = strconv.Atoi(string(match[2]))
107 tmp, ok = eventTable.Load(eventId)
108 if !ok {
109 break
110 }
111 pEvent = tmp.(*Event)
87 if err[0] == nil && err[1] == nil && argsRegex.Match(rawEvent.Data) { 112 if err[0] == nil && err[1] == nil && argsRegex.Match(rawEvent.Data) {
88 match := argsRegex.FindAllSubmatch(rawEvent.Data, -1) 113 match := argsRegex.FindAllSubmatch(rawEvent.Data, -1)
89 for i := 0; i < argc; i++ { 114 for i := 0; i < argc; i++ {
90 if len(match[i][2]) == 0 { 115 if len(match[i][2]) == 0 {
91 // 代表着匹配到的是十六进制数 116 // 代表着匹配到的是十六进制数
92 str := hexToAscii(string(match[i][3])) 117 str := hexToAscii(string(match[i][3]))
93 eventTable[eventId].argv = append(eventTable[eventId].argv, str) 118 pEvent.argv = append(pEvent.argv, str)
94 } else { 119 } else {
95 eventTable[eventId].argv = append(eventTable[eventId].argv, string(match[i][2])) 120 pEvent.argv = append(pEvent.argv, string(match[i][2]))
96 } 121 }
97 } 122 }
98 eventTable[eventId].argc = argc 123 pEvent.argc = argc
99 } 124 }
100 } 125 }
101 // case auparse.AUDIT_PATH:
102 case auparse.AUDIT_CWD: 126 case auparse.AUDIT_CWD:
103 if cwdRegex.Match(rawEvent.Data) { 127 if cwdRegex.Match(rawEvent.Data) {
104 match := cwdRegex.FindSubmatch(rawEvent.Data) 128 match := cwdRegex.FindSubmatch(rawEvent.Data)
105 eventId, err[0] = strconv.Atoi(string(match[1])) 129 eventId, err[0] = strconv.Atoi(string(match[1]))
106 eventTable[eventId].cwd = string(match[2]) 130 tmp, ok = eventTable.Load(eventId)
131 if !ok {
132 break
133 }
134 tmp.(*Event).cwd = string(match[2])
107 } 135 }
108 case auparse.AUDIT_PROCTITLE: 136 case auparse.AUDIT_PROCTITLE:
109 if proctitleRegex.Match(rawEvent.Data) { 137 if proctitleRegex.Match(rawEvent.Data) {
110 var cmdline string 138 var cmdline string
111 var pEvent *Event
112 match := proctitleRegex.FindSubmatch(rawEvent.Data) 139 match := proctitleRegex.FindSubmatch(rawEvent.Data)
113 eventId, err[0] = strconv.Atoi(string(match[1])) 140 eventId, err[0] = strconv.Atoi(string(match[1]))
114 pEvent = eventTable[eventId] 141 tmp, ok = eventTable.Load(eventId)
142 if !ok {
143 break
144 }
145 pEvent = tmp.(*Event)
115 if pEvent.argc == 0 { 146 if pEvent.argc == 0 {
116 // 只有等于0,才证明没经过EXECVE提取参数,才允许使用PROCTITLE提取参数 147 // 只有等于0,才证明没经过EXECVE提取参数,才允许使用PROCTITLE提取参数
117 if match[3] == nil { 148 if match[3] == nil {
@@ -121,17 +152,21 @@ func orgnaze() {
121 cmdline = string(match[3]) 152 cmdline = string(match[3])
122 } 153 }
123 pEvent.argv = strings.Split(cmdline, " ") 154 pEvent.argv = strings.Split(cmdline, " ")
124 pEvent.argc = len(eventTable[eventId].argv) 155 pEvent.argc = len(pEvent.argv)
125 } 156 }
126 } 157 }
127 case auparse.AUDIT_EOE: 158 case auparse.AUDIT_EOE:
128 if eoeRegex.Match(rawEvent.Data) { 159 if eoeRegex.Match(rawEvent.Data) {
129 match := eoeRegex.FindSubmatch(rawEvent.Data) 160 match := eoeRegex.FindSubmatch(rawEvent.Data)
130 eventId, err[0] = strconv.Atoi(string(match[1])) 161 eventId, err[0] = strconv.Atoi(string(match[1]))
131 // ATTENTION: 事件整理完毕,即刻发出,是否合理呢? 162 tmp, ok = eventTable.Load(eventId)
132 cooked = *eventTable[eventId] // 应当采用深拷贝吗?有待实验 163 if !ok {
164 break
165 }
166 cooked := *(tmp.(*Event))
133 cookedChan <- cooked 167 cookedChan <- cooked
134 delete(eventTable, eventId) //发出之后就从信息表扔掉,死人别占地 168 eventTable.Delete(eventId) // 死人别占地
169 fmt.Printf("%d: %3d %6d %6d\n", eventId, cooked.syscall, cooked.ppid, cooked.pid)
135 } 170 }
136 default: 171 default:
137 // ATTENTION: 这里也需要做防护 172 // ATTENTION: 这里也需要做防护