-
Notifications
You must be signed in to change notification settings - Fork 2
/
tracer.go
92 lines (77 loc) · 2.86 KB
/
tracer.go
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
package exectrace
import (
"io"
"os"
"regexp"
"strconv"
"golang.org/x/xerrors"
)
const pidNSPath = "/proc/self/ns/pid"
var nonNumericRegex = regexp.MustCompile(`[^\d]`)
// TracerOpts contains all of the configuration options for the tracer. All are
// optional.
type TracerOpts struct {
// PidNS filters all processes that are in the given PID namespace or in the
// child namespace tree of this given namespace. This is very useful for
// Docker containers, as you can read all processes in a container (or in
// child containers).
//
// You can read the PID namespace ID for a given process by running
// `readlink /proc/x/ns/pid`.
//
// This filter runs in the kernel for high performance.
PidNS uint32
// LogFn is called for each log line that is read from the kernel. All logs
// are considered error logs unless running a debug version of the eBPF
// program.
//
// If unspecified, a default log function is used that logs to stderr.
LogFn func(uid, gid, pid uint32, logLine string)
}
// Tracer allows consumers to read exec events from the kernel via an eBPF
// program. `execve()` syscalls are traced in the kernel, and details about the
// event are sent back to this Go interface.
type Tracer interface {
io.Closer
// Read blocks until an exec event is available, then returns it.
Read() (*Event, error)
// FD returns the FD of the loaded eBPF program. This is useful for
// benchmarking.
FD() int
}
// Event contains data about each exec event with many fields for easy
// filtering and logging.
type Event struct {
Filename string `json:"filename"`
// Argv contains the raw argv supplied to the process, including argv[0]
// (which is equal to `filepath.Base(e.Filename)` in most circumstances).
Argv []string `json:"argv"`
// Truncated is true if we were unable to read all process arguments into
// Argv because there were more than 32 arguments, or if one of the
// arguments was greater than or equal to 1023 bytes in length.
//
// It may indicate that the user or process is trying to hide arguments from
// the tracer.
Truncated bool `json:"truncated"`
// These values are of the new process. Keep in mind that the exec call may
// fail and the PID will be released in such a case.
PID uint32 `json:"pid"`
UID uint32 `json:"uid"`
GID uint32 `json:"gid"`
// Comm is the "name" of the parent process, usually the filename of the
// executable (but not always).
Comm string `json:"comm"`
}
// GetPidNS returns the inum of the PidNS used by the current process.
func GetPidNS() (uint32, error) {
rawPidNS, err := os.Readlink(pidNSPath)
if err != nil {
return 0, xerrors.Errorf("readlink %v: %w", pidNSPath, err)
}
rawPidNS = nonNumericRegex.ReplaceAllString(rawPidNS, "")
pidNS, err := strconv.ParseUint(rawPidNS, 10, 32)
if err != nil {
return 0, xerrors.Errorf("parse PidNS %v to uint32: %w", rawPidNS, err)
}
return uint32(pidNS), nil
}