diff options
author | We-unite <3205135446@qq.com> | 2024-07-19 13:35:36 +0800 |
---|---|---|
committer | We-unite <3205135446@qq.com> | 2024-07-19 16:34:07 +0800 |
commit | 2e37dcf708be08dff963ee08cb7a9557f32e690d (patch) | |
tree | e06ce0d1284a8d4ba67c780ad3f92c4e51d93774 | |
parent | 58b1af7139bd2c4a2682382261fcc545b86d8685 (diff) | |
download | godo-2e37dcf708be08dff963ee08cb7a9557f32e690d.tar.gz godo-2e37dcf708be08dff963ee08cb7a9557f32e690d.zip |
Fix some bugs, and 3nd coroutine can get pid tree.base
For some reasons, the linux kernel has made some changes in syscalls.
As shown in src code, we pay attention to fork/vfork/clone to create
process, while exit/exit_group to kill it. From my opinion, the fork
and clone syscall should be totally different, otherwise there will
be only one syscall. However, according to the logs, I heard only
clone but no fork, exit_group but no exit. Infact, fork calls clone
and then makes some special set. They're different, fork means parents
and children, while clone means calling and callee, which allows to
share sth between caller and callee. Both fork and clone makes a new
process, pthread makes tasks and is called thread. Pid is factually
task id.
Now the 3 coroutines works well, and I've get a process tree by
map[int]*process. Here hides some questions:
- is it right for 2nd corutine to send to 3rd as long as eoe?
- how to make the delay between exit_group and deletePid clear and
suitable?
Next works:
- Change the pids from map into DataBase, which means that we
should devide front-end and back-end. Besides, when you delete
sth(such as process exit), don't delete from databese, instead
just make a tag and record their exit code. In other words, we
judge if it's alive not by entry existance but exit tag.
- Make containers recorded, for instance, rootFS, root-process,
name, id, etc.. And record them in map, maintain this database table.
-rwxr-xr-x | build.sh | 7 | ||||
-rw-r--r-- | godo.go | 157 |
2 files changed, 113 insertions, 51 deletions
diff --git a/build.sh b/build.sh deleted file mode 100755 index 8bdadb3..0000000 --- a/build.sh +++ /dev/null | |||
@@ -1,7 +0,0 @@ | |||
1 | #!/bin/bash | ||
2 | |||
3 | set -e | ||
4 | docker_api_version=$(docker version) | ||
5 | docker_api_version=$(docker version | grep API | head -n 1 | awk '{print $3}') | ||
6 | echo "Docker API version is $docker_api_version..." | ||
7 | export DOCKER_API_VERSION=$docker_api_version \ No newline at end of file | ||
@@ -34,26 +34,27 @@ type Event struct { | |||
34 | pid, ppid int | 34 | pid, ppid int |
35 | syscall int | 35 | syscall int |
36 | argc int | 36 | argc int |
37 | args []string | 37 | argv []string |
38 | cwd string | 38 | cwd string |
39 | } | 39 | } |
40 | 40 | ||
41 | type process struct { | 41 | type process struct { |
42 | cmdline string | 42 | timestamp time.Time |
43 | argv []string | 43 | pid, ppid int |
44 | cwd string | 44 | argv []string |
45 | rootfs string | 45 | cwd string |
46 | children []int | 46 | rootfs string |
47 | children []int | ||
47 | } | 48 | } |
48 | 49 | ||
49 | var pids map[int]*process //古希腊掌管进程的神 | 50 | var pids sync.Map // 古希腊掌管进程的神,int->*process |
50 | var containers map[string]int // 古希腊掌管容器的神 | 51 | var wg sync.WaitGroup // 掌管协程 |
51 | var wg sync.WaitGroup // 掌管协程 | 52 | var rawChan chan interface{} // 从接收到整理的管道 |
52 | var rawChan chan interface{} // 从接收到整理的管道,这里不是原始数据类型,下文解释 | 53 | var cookedChan chan Event // 整理好的信息的管道 |
53 | var cookedChan chan Event // 整理好的信息的管道 | ||
54 | |||
55 | var syscallTable [500]string //记录一下系统调用 | 54 | var syscallTable [500]string //记录一下系统调用 |
56 | 55 | ||
56 | var containerdPid int | ||
57 | |||
57 | func main() { | 58 | func main() { |
58 | // 检查用户身份,并添加auditd规则,监听所有syscall | 59 | // 检查用户身份,并添加auditd规则,监听所有syscall |
59 | if os.Geteuid() != 0 { | 60 | if os.Geteuid() != 0 { |
@@ -72,26 +73,42 @@ func main() { | |||
72 | auditCmd = exec.Command("auditctl", "-D") // 清空所有规则 | 73 | auditCmd = exec.Command("auditctl", "-D") // 清空所有规则 |
73 | auditCmd.Run() | 74 | auditCmd.Run() |
74 | // 设置监听规则 | 75 | // 设置监听规则 |
75 | for i := 0; i < 5; i++ { | 76 | for i := 0; i < len(syscall); i++ { |
76 | auditCmd = exec.Command("auditctl", "-a", "exit,always", "-F", "arch=b64", "-S", syscall[i]) | 77 | auditCmd = exec.Command("auditctl", "-a", "exit,always", "-F", "arch=b64", "-S", syscall[i]) |
77 | auditCmd.Run() | 78 | auditCmd.Run() |
78 | } | 79 | } |
79 | 80 | ||
80 | // 查找pid | 81 | // 查找pid |
81 | containerdPid, err := getPid() | 82 | containerdPid, err = getPid() |
82 | if err != nil { | 83 | if err != nil { |
83 | fmt.Printf("Error finding containerd: %v\n", err) | 84 | fmt.Printf("Error finding containerd: %v\n", err) |
84 | return | 85 | return |
85 | } | 86 | } |
86 | // 数据结构初始化 | 87 | // 数据结构初始化 |
87 | pids = make(map[int]*process) | 88 | // pids = make(map[int]*process) |
88 | containers = make(map[string]int) | 89 | // containers = make(map[string]int) |
89 | 90 | ||
90 | // 创世之神,1号进程 | 91 | // 创世之神,1号进程 |
91 | pids[1] = &process{rootfs: "/", children: make([]int, 0)} | 92 | // pids[1] = &process{rootfs: "/", children: make([]int, 0)} |
92 | pids[1].children = append(pids[1].children, containerdPid) | 93 | // pids[1].children = append(pids[1].children, containerdPid) |
94 | // 1号进程还是不要在进程树上直接出现了,不然它的小儿子们都会出现 | ||
95 | |||
93 | // /usr/bin/containerd,也就是我们最关注的进程 | 96 | // /usr/bin/containerd,也就是我们最关注的进程 |
94 | pids[containerdPid] = &process{cmdline: "/usr/bin/cmdline", rootfs: "/", children: make([]int, 0)} | 97 | // pids[containerdPid] = &process{rootfs: "/", children: make([]int, 0)} |
98 | pids.Store(containerdPid, &process{ | ||
99 | ppid: 1, | ||
100 | pid: containerdPid, | ||
101 | argv: make([]string, 0), | ||
102 | cwd: "/", | ||
103 | rootfs: "/", | ||
104 | children: make([]int, 0), | ||
105 | }) | ||
106 | p, ok := pids.Load(containerdPid) | ||
107 | if !ok { | ||
108 | fmt.Printf("???\n") | ||
109 | return | ||
110 | } | ||
111 | p.(*process).argv = append(p.(*process).argv, "/usr/bin/containerd") | ||
95 | 112 | ||
96 | // 开始运行,解析命令行参数后监听 | 113 | // 开始运行,解析命令行参数后监听 |
97 | if err := fs.Parse(os.Args[1:]); err != nil { | 114 | if err := fs.Parse(os.Args[1:]); err != nil { |
@@ -148,7 +165,7 @@ func getPid() (int, error) { | |||
148 | return pid, nil | 165 | return pid, nil |
149 | } | 166 | } |
150 | } | 167 | } |
151 | err = fmt.Errorf("Error: no containerd process found.\n") | 168 | err = fmt.Errorf("Error: no containerd process found.") |
152 | return 0, err | 169 | return 0, err |
153 | } | 170 | } |
154 | 171 | ||
@@ -362,7 +379,7 @@ func orgnaze() { | |||
362 | ppid: event.ppid, | 379 | ppid: event.ppid, |
363 | pid: event.pid, | 380 | pid: event.pid, |
364 | argc: 0, | 381 | argc: 0, |
365 | args: make([]string, 0), | 382 | argv: make([]string, 0), |
366 | cwd: "", | 383 | cwd: "", |
367 | } | 384 | } |
368 | } | 385 | } |
@@ -377,10 +394,9 @@ func orgnaze() { | |||
377 | if len(match[i][2]) == 0 { | 394 | if len(match[i][2]) == 0 { |
378 | // 代表着匹配到的是十六进制数 | 395 | // 代表着匹配到的是十六进制数 |
379 | str := hexToAscii(string(match[i][3])) | 396 | str := hexToAscii(string(match[i][3])) |
380 | eventTable[eventId].args = append(eventTable[eventId].args, str) | 397 | eventTable[eventId].argv = append(eventTable[eventId].argv, str) |
381 | fmt.Printf("Origin: \"%s\", Res: \"%s\"\n", match[i][3], str) | ||
382 | } else { | 398 | } else { |
383 | eventTable[eventId].args = append(eventTable[eventId].args, string(match[i][2])) | 399 | eventTable[eventId].argv = append(eventTable[eventId].argv, string(match[i][2])) |
384 | } | 400 | } |
385 | } | 401 | } |
386 | eventTable[eventId].argc = argc | 402 | eventTable[eventId].argc = argc |
@@ -408,30 +424,21 @@ func orgnaze() { | |||
408 | } else { | 424 | } else { |
409 | cmdline = string(match[3]) | 425 | cmdline = string(match[3]) |
410 | } | 426 | } |
411 | pEvent.args = strings.Split(cmdline, " ") | 427 | pEvent.argv = strings.Split(cmdline, " ") |
412 | pEvent.argc = len(eventTable[eventId].args) | 428 | pEvent.argc = len(eventTable[eventId].argv) |
413 | } | ||
414 | // 当读到proctitle的时候,而且是个新进程最好检查一下cwd,如果还为空,找proc | ||
415 | if pEvent.cwd == "" && (pEvent.syscall == 57 || pEvent.syscall == 58 || pEvent.syscall == 59) { | ||
416 | cwdFilePath := fmt.Sprintf("/proc/%d/cwd", pEvent.pid) | ||
417 | pEvent.cwd, err[1] = os.Readlink(cwdFilePath) | ||
418 | if err[1] != nil { | ||
419 | pEvent.cwd = "" | ||
420 | break | ||
421 | } | ||
422 | } | 429 | } |
423 | } | 430 | } |
424 | case auparse.AUDIT_EOE: | 431 | case auparse.AUDIT_EOE: |
425 | if eoeRegex.Match(rawEvent.Data) { | 432 | if eoeRegex.Match(rawEvent.Data) { |
426 | match := eoeRegex.FindSubmatch(rawEvent.Data) | 433 | match := eoeRegex.FindSubmatch(rawEvent.Data) |
427 | eventId, err[0] = strconv.Atoi(string(match[1])) | 434 | eventId, err[0] = strconv.Atoi(string(match[1])) |
428 | // TODO: 事件整理完毕,即刻发出,是否合理呢? | 435 | // ATTENTION: 事件整理完毕,即刻发出,是否合理呢? |
429 | cooked = *eventTable[eventId] // 应当采用深拷贝吗?有待实验 | 436 | cooked = *eventTable[eventId] // 应当采用深拷贝吗?有待实验 |
430 | cookedChan <- cooked | 437 | cookedChan <- cooked |
431 | delete(eventTable, eventId) //发出之后就从信息表扔掉,死人别占地 | 438 | delete(eventTable, eventId) //发出之后就从信息表扔掉,死人别占地 |
432 | } | 439 | } |
433 | default: | 440 | default: |
434 | // TODO: 这里也需要做防护 | 441 | // ATTENTION: 这里也需要做防护 |
435 | } | 442 | } |
436 | } | 443 | } |
437 | } | 444 | } |
@@ -453,14 +460,76 @@ func deal() { | |||
453 | // args []string | 460 | // args []string |
454 | // cwd string | 461 | // cwd string |
455 | // } | 462 | // } |
456 | fmt.Printf("recv: %v syscall=%d, ppid=%d, pid=%d, cwd=\"%s\", argc=%d, ", cooked.timestamp, cooked.syscall, cooked.ppid, cooked.pid, cooked.cwd, cooked.argc) | 463 | // type process struct { |
457 | if len(cooked.args) != cooked.argc { | 464 | // timestamp time.Time |
458 | fmt.Printf("Fuck!\n") | 465 | // pid, ppid int |
459 | continue | 466 | // argv []string |
467 | // cwd string | ||
468 | // rootfs string | ||
469 | // children []int | ||
470 | // } | ||
471 | switch syscallTable[cooked.syscall] { | ||
472 | case "fork", "vfork", "clone": | ||
473 | ppid := cooked.ppid | ||
474 | pid := cooked.pid | ||
475 | parent, ok := pids.Load(ppid) | ||
476 | if !ok { | ||
477 | break | ||
478 | } | ||
479 | parent.(*process).children = append(parent.(*process).children, pid) | ||
480 | pids.Store(pid, &process{ | ||
481 | timestamp: cooked.timestamp, | ||
482 | pid: cooked.pid, | ||
483 | ppid: cooked.ppid, | ||
484 | argv: cooked.argv, | ||
485 | cwd: cooked.cwd, | ||
486 | children: make([]int, 0), | ||
487 | }) | ||
488 | fmt.Printf("%v syscall=%d, ppid=%d, pid=%d, cwd=\"%s\", argc=%d, ", cooked.timestamp, cooked.syscall, cooked.ppid, cooked.pid, cooked.cwd, cooked.argc) | ||
489 | for i := 0; i < cooked.argc; i++ { | ||
490 | fmt.Printf("arg[%d]=\"%s\", ", i, cooked.argv[i]) | ||
491 | } | ||
492 | fmt.Printf("\n") | ||
493 | case "exit", "exit_group": | ||
494 | _, ok := pids.Load(cooked.pid) | ||
495 | if !ok { | ||
496 | break | ||
497 | } | ||
498 | go deletePid(cooked) | ||
499 | } | ||
500 | } | ||
501 | } | ||
502 | |||
503 | func deletePid(cooked Event) { | ||
504 | time.Sleep(1 * time.Second) | ||
505 | Process, ok := pids.Load(cooked.pid) | ||
506 | if !ok { | ||
507 | return | ||
508 | } | ||
509 | pProcess := Process.(*process) | ||
510 | |||
511 | // 先从爹那里注销户籍 | ||
512 | parent, ok := pids.Load(pProcess.ppid) | ||
513 | if ok { | ||
514 | pParent := parent.(*process) | ||
515 | for i, child := range pParent.children { | ||
516 | if child == pProcess.pid { | ||
517 | pParent.children = append(pParent.children[:i], pParent.children[i+1:]...) | ||
518 | break | ||
519 | } | ||
460 | } | 520 | } |
461 | for i := 0; i < cooked.argc; i++ { | 521 | } |
462 | fmt.Printf("arg[%d]=\"%s\", ", i, cooked.args[i]) | 522 | |
523 | // 子进程需要收容 | ||
524 | for i := 0; i < len(pProcess.children); i++ { | ||
525 | child, ok := pids.Load(pProcess.children[i]) | ||
526 | if ok { | ||
527 | child.(*process).ppid = 1 | ||
463 | } | 528 | } |
464 | fmt.Printf("\n") | ||
465 | } | 529 | } |
530 | |||
531 | // 可以去死了 | ||
532 | pids.Delete(cooked.pid) | ||
533 | _, ok = pids.Load(cooked.pid) | ||
534 | fmt.Printf("%v Goodbye, %d! ok = %v\n", time.Now(), cooked.pid, ok) | ||
466 | } | 535 | } |