1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
|
package internal
import "C"
import (
"fmt"
. "ioriotng/internal/generated/types"
bpf "github.com/aquasecurity/libbpfgo"
)
func eventLoop(bpfModule *bpf.Module, rawCh <-chan []byte) {
for ev := range events(rawCh) {
fmt.Println(ev.String())
if ev.prevPair != nil {
// Only recycle the previous event, as the current event is the previous
// event of the next event!
ev.prevPair.recycle()
continue
}
}
fmt.Println("Good bye")
}
func events(rawCh <-chan []byte) <-chan *eventPair {
// Channel of events (enter+exit tracepoint results of a syscall).
evCh := make(chan *eventPair)
// Temp. store of sys_enter tracepoints per Tid.
enterEvs := make(map[uint32]*eventPair)
// Track all open files by file descriptor.
files := make(map[int32]file)
// Program or thread name of the current Tid.
comms := make(map[uint32]string)
// Previous event (to calculate time differences between two events)
prevPairs := make(map[uint32]*eventPair)
enter := func(enterEv event) {
enterEvs[enterEv.GetTid()] = newEventPair(enterEv)
}
exit := func(exitEv event) {
ev, ok := enterEvs[exitEv.GetTid()]
if !ok {
exitEv.Recycle()
return
}
delete(enterEvs, exitEv.GetTid())
ev.exitEv = exitEv
// Expect ID one lower, otherwise, enter and exit tracepoints
// don't match up. E.g.:
// enterEv:SYS_ENTER_OPEN => exitEv:SYS_EXIT_OPEN
if ev.enterEv.GetTraceId()-1 != ev.exitEv.GetTraceId() {
ev.tracepointMismatch = true
}
switch v := ev.enterEv.(type) {
case *OpenEvent:
openEv := ev.enterEv.(*OpenEvent)
fd := int32(ev.exitEv.(*RetEvent).Ret)
file := fdFile{fd, string(openEv.Filename[:])}
if fd >= 0 {
files[fd] = file
}
ev.file = file
comm := string(openEv.Comm[:])
comms[openEv.Tid] = comm
case *NameEvent:
nameEvent := ev.enterEv.(*NameEvent)
ev.file = oldnameNewnameFile{
oldname: string(nameEvent.Oldname[:]),
newname: string(nameEvent.Newname[:]),
}
ev.comm, _ = comms[ev.enterEv.GetTid()]
case *PathEvent:
nameEvent := ev.enterEv.(*PathEvent)
ev.file = pathnameFile{string(nameEvent.Pathname[:])}
ev.comm, _ = comms[ev.enterEv.GetTid()]
case *FdEvent:
fd := ev.enterEv.(*FdEvent).Fd
if file_, ok := files[fd]; ok {
ev.file = file_
if ev.is(SYS_ENTER_CLOSE) {
delete(files, fd)
}
} else {
ev.file = fdFile{fd, "?"}
}
ev.comm, _ = comms[ev.enterEv.GetTid()]
case *NullEvent:
ev.comm, _ = comms[ev.enterEv.GetTid()]
default:
panic(fmt.Sprintf("unknown type: %v", v))
}
ev.prevPair, _ = prevPairs[ev.enterEv.GetTid()]
ev.calculateDurations()
prevPairs[ev.enterEv.GetTid()] = ev
fmt.Println(ev.TimeDebugString())
evCh <- ev
}
// Deserialise raw byte stream from BPF ringbuffer.
go func() {
defer close(evCh)
for raw := range rawCh {
switch EventType(raw[0]) {
case ENTER_OPEN_EVENT:
enter(NewOpenEvent(raw))
case EXIT_OPEN_EVENT:
exit(NewFdEvent(raw))
case ENTER_FD_EVENT:
enter(NewFdEvent(raw))
case EXIT_FD_EVENT:
exit(NewFdEvent(raw))
case EXIT_NULL_EVENT:
exit(NewNullEvent(raw))
case EXIT_RET_EVENT:
exit(NewRetEvent(raw))
case ENTER_NAME_EVENT:
enter(NewNameEvent(raw))
case ENTER_PATH_EVENT:
enter(NewPathEvent(raw))
default:
panic(fmt.Sprintf("unhandled event type %v: %v", EventType(raw[0]), raw))
}
}
}()
return evCh
}
|