summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorWe-unite <3205135446@qq.com>2024-07-19 13:35:36 +0800
committerWe-unite <3205135446@qq.com>2024-07-19 16:34:07 +0800
commit2e37dcf708be08dff963ee08cb7a9557f32e690d (patch)
treee06ce0d1284a8d4ba67c780ad3f92c4e51d93774
parent58b1af7139bd2c4a2682382261fcc545b86d8685 (diff)
downloadgodo-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-xbuild.sh7
-rw-r--r--godo.go157
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
3set -e
4docker_api_version=$(docker version)
5docker_api_version=$(docker version | grep API | head -n 1 | awk '{print $3}')
6echo "Docker API version is $docker_api_version..."
7export DOCKER_API_VERSION=$docker_api_version \ No newline at end of file
diff --git a/godo.go b/godo.go
index 2ba97d1..1ae336b 100644
--- a/godo.go
+++ b/godo.go
@@ -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
41type process struct { 41type 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
49var pids map[int]*process //古希腊掌管进程的神 50var pids sync.Map // 古希腊掌管进程的神,int->*process
50var containers map[string]int // 古希腊掌管容器的神 51var wg sync.WaitGroup // 掌管协程
51var wg sync.WaitGroup // 掌管协程 52var rawChan chan interface{} // 从接收到整理的管道
52var rawChan chan interface{} // 从接收到整理的管道,这里不是原始数据类型,下文解释 53var cookedChan chan Event // 整理好的信息的管道
53var cookedChan chan Event // 整理好的信息的管道
54
55var syscallTable [500]string //记录一下系统调用 54var syscallTable [500]string //记录一下系统调用
56 55
56var containerdPid int
57
57func main() { 58func 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
503func 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}