diff options
author | We-unite <3205135446@qq.com> | 2024-07-23 19:32:09 +0800 |
---|---|---|
committer | We-unite <3205135446@qq.com> | 2024-07-25 17:09:45 +0800 |
commit | fc61a4a525846fa31ee2288df4e82f745bb39c95 (patch) | |
tree | e97c7b942c7e843782efbcc48882e6c0854df473 | |
parent | cf5618ff2e2a183c5bdf6444787dccdcbf26ce76 (diff) | |
download | godo-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!
-rw-r--r-- | src/basefunc.go | 40 | ||||
-rw-r--r-- | src/deal.go | 173 | ||||
-rw-r--r-- | src/global.go | 2 | ||||
-rw-r--r-- | src/godo.go | 18 | ||||
-rw-r--r-- | src/mongo.go | 79 | ||||
-rw-r--r-- | src/organize.go | 79 |
6 files changed, 266 insertions, 125 deletions
diff --git a/src/basefunc.go b/src/basefunc.go index 5fff3e8..2f39507 100644 --- a/src/basefunc.go +++ b/src/basefunc.go | |||
@@ -4,32 +4,46 @@ import ( | |||
4 | "bufio" | 4 | "bufio" |
5 | "fmt" | 5 | "fmt" |
6 | "os" | 6 | "os" |
7 | "os/exec" | ||
7 | "path/filepath" | 8 | "path/filepath" |
8 | "regexp" | ||
9 | "strconv" | 9 | "strconv" |
10 | "strings" | 10 | "strings" |
11 | "time" | 11 | "time" |
12 | ) | 12 | ) |
13 | 13 | ||
14 | func figureOutSyscalls() error { | 14 | func figureOutSyscalls() error { |
15 | NRRegex := regexp.MustCompile(`#define __NR_(.*?) (\d+)$`) | 15 | cmd := exec.Command("ausyscall", "--dump") |
16 | file, err := os.Open("/usr/include/asm/unistd_64.h") | 16 | stdout, err := cmd.StdoutPipe() |
17 | if err != nil { | 17 | if err != nil { |
18 | return err | 18 | return err |
19 | } | 19 | } |
20 | defer file.Close() | ||
21 | 20 | ||
22 | scanner := bufio.NewScanner(file) | 21 | if err := cmd.Start(); err != nil { |
23 | for scanner.Scan() { | 22 | return err |
23 | } | ||
24 | |||
25 | scanner := bufio.NewScanner(stdout) | ||
26 | for i := 0; scanner.Scan(); i++ { | ||
27 | if i == 0 { | ||
28 | continue | ||
29 | } | ||
24 | line := scanner.Text() | 30 | line := scanner.Text() |
25 | if NRRegex.MatchString(line) { | 31 | parts := strings.Split(line, "\t") |
26 | match := NRRegex.FindStringSubmatch(line) | 32 | if len(parts) != 2 { |
27 | num, err := strconv.Atoi(match[2]) | 33 | return fmt.Errorf("invalid ausyscall format") |
28 | if err != nil { | ||
29 | return err | ||
30 | } | ||
31 | syscallTable[num] = match[1] | ||
32 | } | 34 | } |
35 | num, err := strconv.Atoi(parts[0]) | ||
36 | if err != nil { | ||
37 | return err | ||
38 | } | ||
39 | syscallTable[num] = parts[1] | ||
40 | } | ||
41 | |||
42 | if err := scanner.Err(); err != nil { | ||
43 | return err | ||
44 | } | ||
45 | if err := cmd.Wait(); err != nil { | ||
46 | return err | ||
33 | } | 47 | } |
34 | return nil | 48 | return nil |
35 | } | 49 | } |
diff --git a/src/deal.go b/src/deal.go index 118d914..783dab8 100644 --- a/src/deal.go +++ b/src/deal.go | |||
@@ -1,51 +1,48 @@ | |||
1 | package main | 1 | package main |
2 | 2 | ||
3 | import ( | 3 | import ( |
4 | "context" | ||
5 | "fmt" | 4 | "fmt" |
5 | "sync" | ||
6 | "time" | 6 | "time" |
7 | 7 | ||
8 | "go.mongodb.org/mongo-driver/bson" | 8 | "go.mongodb.org/mongo-driver/bson" |
9 | "go.mongodb.org/mongo-driver/mongo" | ||
10 | "go.mongodb.org/mongo-driver/mongo/options" | ||
11 | ) | 9 | ) |
12 | 10 | ||
13 | const ( | 11 | const ( |
14 | dbName string = "test" | 12 | dbName string = "test" |
15 | colName string = "pids" | 13 | pidColName string = "pids" |
16 | ) | 14 | ) |
17 | 15 | ||
16 | var mongoMutex sync.Mutex | ||
17 | var pidCol mongoClient | ||
18 | |||
18 | func deal() { | 19 | func deal() { |
19 | defer wg.Done() | 20 | defer wg.Done() |
20 | var cooked Event | 21 | var cooked Event |
21 | var ok bool | 22 | var ok bool |
22 | 23 | ||
23 | var err error | 24 | var err error |
24 | var mongo *mongo.Client | ||
25 | var res []bson.M | 25 | var res []bson.M |
26 | 26 | ||
27 | mongo, err = connect() | 27 | if err = pidCol.Connect(dbName, pidColName); err != nil { |
28 | if err != nil { | 28 | fmt.Printf("Error connecting the mongodb: %v\n", err) |
29 | fmt.Printf("Err connecting the mongodb: %v\n", err) | ||
30 | } | 29 | } |
31 | pidCol := mongo.Database(dbName).Collection(colName) | 30 | if err = pidCol.Drop(); err != nil { |
32 | 31 | fmt.Printf("Error drop the mongodb: %v\n", err) | |
33 | err = pidCol.Drop(context.Background()) | ||
34 | if err != nil { | ||
35 | fmt.Printf("Err drop: %v\n", err) | ||
36 | } | 32 | } |
37 | 33 | ||
38 | _, err = pidCol.InsertOne(context.Background(), bson.M{ | 34 | err = pidCol.InsertOne(bson.M{ |
39 | "ppid": 1, | 35 | "ppid": 1, |
40 | "pid": containerdPid, | 36 | "pid": containerdPid, |
41 | "cwd": "/", | 37 | "cwd": "/", |
38 | "children": bson.M{}, | ||
42 | }) | 39 | }) |
43 | if err != nil { | 40 | if err != nil { |
44 | fmt.Printf("Err containerd: %v", err) | 41 | fmt.Printf("Err containerd: %v", err) |
45 | return | 42 | return |
46 | } | 43 | } |
47 | |||
48 | fmt.Printf("Containerd: %d\n", containerdPid) | 44 | fmt.Printf("Containerd: %d\n", containerdPid) |
45 | defer pidCol.Disconnect() | ||
49 | 46 | ||
50 | for { | 47 | for { |
51 | cooked, ok = <-cookedChan | 48 | cooked, ok = <-cookedChan |
@@ -54,81 +51,115 @@ func deal() { | |||
54 | } | 51 | } |
55 | 52 | ||
56 | switch syscallTable[cooked.syscall] { | 53 | switch syscallTable[cooked.syscall] { |
57 | case "fork", "vfork", "clone": | 54 | case "clone": |
58 | // 有无父进程在观察中 | 55 | // 有无父进程在观察中 |
59 | res, err = findDocuments(mongo, "test", "pids", bson.M{"pid": cooked.ppid}) | 56 | res, err = pidCol.Finddoc(bson.M{"pid": cooked.ppid}) |
60 | if err != nil || len(res) != 1 { | 57 | if err != nil || len(res) != 1 { |
61 | break | 58 | break |
62 | } | 59 | } |
63 | 60 | ||
64 | // 自身是否已经记录 | 61 | // 自身是否已经记录 |
65 | res, err = findDocuments(mongo, "test", "pids", bson.M{"pid": cooked.pid}) | 62 | res, err = pidCol.Finddoc(bson.M{"pid": cooked.pid}) |
66 | if err != nil { | 63 | if err != nil { |
67 | fmt.Printf("Err finding: %v\n", err) | 64 | fmt.Printf("Err finding: %v\n", err) |
68 | break | 65 | break |
69 | } else if len(res) != 0 { | ||
70 | fmt.Printf("Err inserting pid %v: already in db: %v\n", cooked.pid, res) | ||
71 | break | ||
72 | } | ||
73 | |||
74 | doc := []bson.A{} | ||
75 | for _, str := range cooked.argv { | ||
76 | doc = append(doc, bson.A{str}) | ||
77 | } | 66 | } |
78 | _, err := pidCol.InsertOne(context.Background(), bson.M{ | 67 | mongoMutex.Lock() |
79 | "timestamp": cooked.timestamp, | 68 | if len(res) != 0 { |
80 | "ppid": cooked.ppid, | 69 | // 进程原本就存在,换言之别的消息先到了 |
81 | "pid": cooked.pid, | 70 | // 所有先行抵达的消息必须保留execve/children字段 |
82 | "cwd": cooked.cwd, | 71 | // 此处不再更新 |
83 | "args": doc, | 72 | // 以防把原有信息更没了 |
84 | "children": []bson.M{}, | 73 | pidCol.UpdateOne(bson.M{"pid": cooked.pid}, bson.M{ |
85 | }) | 74 | "start_timestamp": cooked.timestamp, |
86 | if err != nil { | 75 | "ppid": cooked.ppid, |
87 | fmt.Printf("Err insert: %v\n", err) | 76 | "pid": cooked.pid, |
77 | "cwd": cooked.cwd, | ||
78 | // "execve": []bson.M{}, | ||
79 | "args": cooked.argv, | ||
80 | // "children": []bson.M{}, | ||
81 | }) | ||
82 | } else { | ||
83 | // 这进程本是新修的 | ||
84 | pidCol.InsertOne(bson.M{ | ||
85 | "start_timestamp": cooked.timestamp, | ||
86 | "ppid": cooked.ppid, | ||
87 | "pid": cooked.pid, | ||
88 | "cwd": cooked.cwd, | ||
89 | "execve": []bson.M{}, | ||
90 | "args": cooked.argv, | ||
91 | "children": []bson.M{}, | ||
92 | }) | ||
88 | } | 93 | } |
89 | 94 | ||
90 | _, err = pidCol.UpdateOne(context.Background(), bson.M{"pid": cooked.pid}, bson.M{ | 95 | pidCol.UpdateOne(bson.M{"pid": cooked.ppid}, bson.M{ |
91 | "$push": bson.M{ | 96 | "$push": bson.M{ |
92 | "children": cooked.pid, | 97 | "children": cooked.pid, |
93 | }, | 98 | }, |
94 | }) | 99 | }) |
100 | mongoMutex.Unlock() | ||
101 | case "execve": | ||
102 | // 父进程在不在?不在扔 | ||
103 | res, err = pidCol.Finddoc(bson.M{"pid": cooked.ppid}) | ||
104 | if err != nil || len(res) != 1 { | ||
105 | break | ||
106 | } | ||
107 | |||
108 | // 首先检查进程是否存在,如不存在则为之创建 | ||
109 | res, err = pidCol.Finddoc(bson.M{"pid": cooked.pid}) | ||
95 | if err != nil { | 110 | if err != nil { |
96 | fmt.Printf("Err insert: %v\n", err) | 111 | break |
112 | } | ||
113 | mongoMutex.Lock() | ||
114 | if len(res) == 1 { | ||
115 | // 自身已在,直接记录 | ||
116 | pidCol.UpdateOne(bson.M{"pid": cooked.pid}, bson.M{ | ||
117 | "$push": bson.M{ | ||
118 | "execve": bson.M{ | ||
119 | "timestamp": cooked.timestamp, | ||
120 | "args": cooked.argv, | ||
121 | }, | ||
122 | }, | ||
123 | }) | ||
124 | } else { | ||
125 | // 先fork抵达,插入 | ||
126 | pidCol.InsertOne(bson.M{ | ||
127 | "children": []bson.M{}, | ||
128 | "execve": []bson.M{ | ||
129 | { | ||
130 | "timestamp": cooked.timestamp, | ||
131 | "execve": cooked.argv, | ||
132 | }, | ||
133 | }, | ||
134 | }) | ||
97 | } | 135 | } |
136 | mongoMutex.Unlock() | ||
98 | case "exit", "exit_group": | 137 | case "exit", "exit_group": |
99 | // TODO: 记得补全退出逻辑 | 138 | go deletePid(cooked) |
100 | // 上哪找exit code呢? | ||
101 | } | 139 | } |
102 | } | 140 | } |
103 | } | 141 | } |
104 | 142 | ||
105 | func connect() (*mongo.Client, error) { | 143 | func deletePid(cooked Event) { |
106 | client, err := mongo.NewClient(options.Client().ApplyURI("mongodb://localhost:27017")) | 144 | time.Sleep(1 * time.Second) |
107 | 145 | mongoMutex.Lock() | |
108 | if err != nil { | 146 | // 先从老爹那里销户 |
109 | return nil, err | 147 | pidCol.UpdateOne(bson.M{"pid": cooked.ppid}, bson.M{ |
110 | } | 148 | "$pull": bson.M{ |
111 | 149 | "children": cooked.pid, | |
112 | ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) | 150 | }, |
113 | err = client.Connect(ctx) | 151 | }) |
114 | |||
115 | if err != nil { | ||
116 | return nil, err | ||
117 | } | ||
118 | |||
119 | return client, nil | ||
120 | } | ||
121 | |||
122 | func findDocuments(client *mongo.Client, dbName, colName string, filter bson.M) ([]bson.M, error) { | ||
123 | collection := client.Database(dbName).Collection(colName) | ||
124 | |||
125 | cur, err := collection.Find(context.Background(), filter) | ||
126 | if err != nil { | ||
127 | return nil, err | ||
128 | } | ||
129 | 152 | ||
130 | var results []bson.M | 153 | // 孩子们需要收容 |
131 | err = cur.All(context.Background(), &results) | 154 | // 不必到children里一个个找,直接看ppid即可 |
155 | pidCol.UpdateMany(bson.M{"ppid": cooked.pid}, bson.M{"ppid": 1}) | ||
132 | 156 | ||
133 | return results, err | 157 | // 可以去死了 |
158 | pidCol.UpdateOne(bson.M{"pid": cooked.pid}, bson.M{ | ||
159 | "$set": bson.M{ | ||
160 | "exit_timestamp": cooked.timestamp, | ||
161 | "exit_code": cooked.exit_code, | ||
162 | }, | ||
163 | }) | ||
164 | mongoMutex.Unlock() | ||
134 | } | 165 | } |
diff --git a/src/global.go b/src/global.go index 0439df6..c3001ab 100644 --- a/src/global.go +++ b/src/global.go | |||
@@ -9,6 +9,7 @@ type Event struct { | |||
9 | timestamp time.Time | 9 | timestamp time.Time |
10 | pid, ppid int | 10 | pid, ppid int |
11 | syscall int | 11 | syscall int |
12 | exit_code uint64 | ||
12 | argc int | 13 | argc int |
13 | argv []string | 14 | argv []string |
14 | cwd string | 15 | cwd string |
@@ -23,7 +24,6 @@ type process struct { | |||
23 | children []int | 24 | children []int |
24 | } | 25 | } |
25 | 26 | ||
26 | var pids sync.Map // 古希腊掌管进程的神,int->*process | ||
27 | var wg sync.WaitGroup // 掌管协程 | 27 | var wg sync.WaitGroup // 掌管协程 |
28 | var rawChan chan interface{} // 从接收到整理的管道 | 28 | var rawChan chan interface{} // 从接收到整理的管道 |
29 | var cookedChan chan Event // 整理好的信息的管道 | 29 | var cookedChan chan Event // 整理好的信息的管道 |
diff --git a/src/godo.go b/src/godo.go index 72f68c0..cc29a01 100644 --- a/src/godo.go +++ b/src/godo.go | |||
@@ -51,26 +51,8 @@ func main() { | |||
51 | } | 51 | } |
52 | 52 | ||
53 | // 创世之神,1号进程 | 53 | // 创世之神,1号进程 |
54 | // pids[1] = &process{rootfs: "/", children: make([]int, 0)} | ||
55 | // pids[1].children = append(pids[1].children, containerdPid) | ||
56 | // 1号进程还是不要在进程树上直接出现了,不然它的小儿子们都会出现 | 54 | // 1号进程还是不要在进程树上直接出现了,不然它的小儿子们都会出现 |
57 | |||
58 | // /usr/bin/containerd,也就是我们最关注的进程 | 55 | // /usr/bin/containerd,也就是我们最关注的进程 |
59 | // pids[containerdPid] = &process{rootfs: "/", children: make([]int, 0)} | ||
60 | pids.Store(containerdPid, &process{ | ||
61 | ppid: 1, | ||
62 | pid: containerdPid, | ||
63 | argv: make([]string, 0), | ||
64 | cwd: "/", | ||
65 | rootfs: "/", | ||
66 | children: make([]int, 0), | ||
67 | }) | ||
68 | p, ok := pids.Load(containerdPid) | ||
69 | if !ok { | ||
70 | fmt.Printf("???\n") | ||
71 | return | ||
72 | } | ||
73 | p.(*process).argv = append(p.(*process).argv, "/usr/bin/containerd") | ||
74 | 56 | ||
75 | // 开始运行,解析命令行参数后监听 | 57 | // 开始运行,解析命令行参数后监听 |
76 | if err := fs.Parse(os.Args[1:]); err != nil { | 58 | if err := fs.Parse(os.Args[1:]); err != nil { |
diff --git a/src/mongo.go b/src/mongo.go new file mode 100644 index 0000000..d00abd2 --- /dev/null +++ b/src/mongo.go | |||
@@ -0,0 +1,79 @@ | |||
1 | package main | ||
2 | |||
3 | import ( | ||
4 | "context" | ||
5 | "time" | ||
6 | |||
7 | "go.mongodb.org/mongo-driver/bson" | ||
8 | "go.mongodb.org/mongo-driver/mongo" | ||
9 | "go.mongodb.org/mongo-driver/mongo/options" | ||
10 | ) | ||
11 | |||
12 | type mongoClient struct { | ||
13 | dbName, colName string | ||
14 | client *mongo.Client | ||
15 | col *mongo.Collection | ||
16 | } | ||
17 | |||
18 | func (mc *mongoClient) Connect(dbName, colName string) error { | ||
19 | var err error | ||
20 | mc.client, err = mongo.NewClient(options.Client().ApplyURI("mongodb://localhost:27017")) | ||
21 | |||
22 | if err != nil { | ||
23 | return err | ||
24 | } | ||
25 | |||
26 | ctx, _ := context.WithTimeout(context.Background(), 10*time.Second) | ||
27 | err = mc.client.Connect(ctx) | ||
28 | if err != nil { | ||
29 | return err | ||
30 | } | ||
31 | |||
32 | mc.col = mc.client.Database(dbName).Collection(colName) | ||
33 | mc.dbName = dbName | ||
34 | mc.colName = colName | ||
35 | return nil | ||
36 | } | ||
37 | |||
38 | func (mc *mongoClient) InsertOne(document interface{}) error { | ||
39 | _, err := mc.col.InsertOne(context.Background(), document) | ||
40 | return err | ||
41 | } | ||
42 | |||
43 | func (mc *mongoClient) UpdateOne(filter, update interface{}) error { | ||
44 | _, err := mc.col.UpdateOne(context.Background(), filter, update) | ||
45 | return err | ||
46 | } | ||
47 | |||
48 | func (mc *mongoClient) UpdateMany(filter, update interface{}) error { | ||
49 | _, err := mc.col.UpdateMany(context.Background(), filter, update) | ||
50 | return err | ||
51 | } | ||
52 | |||
53 | func (mc *mongoClient) Finddoc(filter bson.M) ([]bson.M, error) { | ||
54 | cur, err := mc.col.Find(context.Background(), filter) | ||
55 | if err != nil { | ||
56 | return nil, err | ||
57 | } | ||
58 | |||
59 | var results []bson.M | ||
60 | err = cur.All(context.Background(), &results) | ||
61 | |||
62 | return results, err | ||
63 | } | ||
64 | |||
65 | func (mc *mongoClient) Drop() error { | ||
66 | return mc.col.Drop(context.Background()) | ||
67 | } | ||
68 | |||
69 | func (mc *mongoClient) Disconnect() error { | ||
70 | err := mc.client.Disconnect(context.Background()) | ||
71 | if err != nil { | ||
72 | return err | ||
73 | } | ||
74 | mc.col = nil | ||
75 | mc.client = nil | ||
76 | mc.dbName = "" | ||
77 | mc.colName = "" | ||
78 | return nil | ||
79 | } | ||
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 @@ | |||
1 | package main | 1 | package main |
2 | 2 | ||
3 | import ( | 3 | import ( |
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: 这里也需要做防护 |