Skip to content

Commit 4ea9448

Browse files
slntoppolsajiri
authored andcommitted
feat: handle parse collected environment variables in execve events
This patch adds: 1. Adds a new field `envs` to the `ExecveEvent` message in the Tetragon API. 2. Updates the Go API to include the new `envs` field in the `ExecveEvent` struct. 3. Adds `--enable-process-environment-variables` flag to conditionally read env vars with ProcessExec events Partially resolves #2648 Signed-off-by: Mikita Iwanowski <[email protected]>
1 parent eaeece2 commit 4ea9448

File tree

9 files changed

+71
-19
lines changed

9 files changed

+71
-19
lines changed

pkg/api/confapi/confapi.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ type TetragonConf struct {
1010
TgCgrpHierarchy uint32 `align:"tg_cgrp_hierarchy"` // Tetragon Cgroup tracking hierarchy ID
1111
TgCgrpSubsysIdx uint32 `align:"tg_cgrp_subsys_idx"` // Tracking Cgroup css idx at compile time
1212
TgCgrpLevel uint32 `align:"tg_cgrp_level"` // Tetragon cgroup level
13+
EnvVarsEnabled uint64 `align:"env_vars_enabled"` // Whether to read environment variables
1314
TgCgrpId uint64 `align:"tg_cgrpid"` // Tetragon cgroup ID
1415
CgrpFsMagic uint64 `align:"cgrp_fs_magic"` // Cgroupv1 or cgroupv2
1516
}

pkg/api/flags.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,15 @@ const (
1010
// EventProcFS for the other option. A correctly formatted event should
1111
// either set EventExecve or EventProcFS.
1212
EventExecve = 0x01
13-
// Available for use
14-
EventAvail1 = 0x02
13+
// EventEnvsData indicates environment variables are received with data event.
14+
EventDataEnvs = 0x02
1515
// EventProcFS indicates the event is generated from a proc interface.
1616
// This happens at Tetragon init when existing processes are being loaded
1717
// into Tetragon event buffer. All events should have either EventExecve or
1818
// EventProcFS set.
1919
EventProcFS = 0x04
20-
// Available for use
21-
EventAvail2 = 0x08
20+
// EventEnvsError indicates an error happened when storing environment variables.
21+
EventErrorEnvs = 0x08
2222
// EventTruncArgs indicates we truncated the processes arguments because
2323
// the buffer size was too small to fit all exec args. Consider increasing
2424
// buffer size to avoid this.

pkg/api/processapi/processapi.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ type MsgExec struct {
8080
SizePath uint16
8181
SizeArgs uint16
8282
SizeCwd uint16
83-
Pad2 uint16
83+
SizeEnvs uint16
8484
}
8585

8686
type MsgExecveKey struct {
@@ -210,6 +210,7 @@ type MsgProcess struct {
210210
Ktime uint64
211211
Filename string
212212
Args string
213+
Envs string
213214
User MsgUserRecord
214215
}
215216

pkg/grpc/exec/exec.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ func GetProcessExec(event *MsgExecveEventUnix, useCache bool) *tetragon.ProcessE
8181
Ancestors: tetragonAncestors,
8282
}
8383

84+
if option.Config.EnableProcessEnvironmentVariables {
85+
tetragonEvent.EnvironmentVariables = proc.GetEnvironmentVariables()
86+
}
87+
8488
if tetragonProcess.Pid == nil {
8589
eventcache.CacheErrors(eventcache.NilProcessPid, notify.EventType(tetragonEvent)).Inc()
8690
return nil

pkg/option/config.go

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,13 @@ type config struct {
3333

3434
EnablePodAnnotations bool
3535

36-
EnableProcessAncestors bool
37-
EnableProcessKprobeAncestors bool
38-
EnableProcessTracepointAncestors bool
39-
EnableProcessUprobeAncestors bool
40-
EnableProcessLsmAncestors bool
41-
EnableProcessUsdtAncestors bool
36+
EnableProcessAncestors bool
37+
EnableProcessKprobeAncestors bool
38+
EnableProcessTracepointAncestors bool
39+
EnableProcessUprobeAncestors bool
40+
EnableProcessLsmAncestors bool
41+
EnableProcessUsdtAncestors bool
42+
EnableProcessEnvironmentVariables bool
4243

4344
EnableProcessNs bool
4445
EnableProcessCred bool

pkg/option/flags.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,8 @@ const (
5151
KeyServerAddress = "server-address"
5252
KeyGopsAddr = "gops-address"
5353

54+
KeyEnableProcessEnvironmentVariables = "enable-process-environment-variables"
55+
5456
KeyEnableAncestors = "enable-ancestors"
5557
KeyEnableProcessCred = "enable-process-cred"
5658
KeyEnableProcessNs = "enable-process-ns"
@@ -195,6 +197,8 @@ func ReadAndSetFlags() error {
195197
Config.EnableProcessUsdtAncestors = slices.Contains(enableAncestors, "usdt")
196198
}
197199

200+
Config.EnableProcessEnvironmentVariables = viper.GetBool(KeyEnableProcessEnvironmentVariables)
201+
198202
Config.GopsAddr = viper.GetString(KeyGopsAddr)
199203

200204
logLevel := viper.GetString(KeyLogLevel)
@@ -386,6 +390,8 @@ func AddFlags(flags *pflag.FlagSet) {
386390
flags.Bool(KeyEnablePodAnnotations, false, "Add pod annotations field to events.")
387391
flags.StringSlice(KeyEnableAncestors, []string{}, "Comma-separated list of process event types to enable ancestors for. Supported event types are: base, kprobe, tracepoint, uprobe, lsm, usdt. Unknown event types will be ignored. Type 'base' enables ancestors for process_exec and process_exit events and is required by all other supported event types for correct reference counting. An empty string disables ancestors completely")
388392

393+
flags.Bool(KeyEnableProcessEnvironmentVariables, false, "Include environment variables in process_exec events. Disabled by default. Note that this option can significantly increase the size of the events and may impact performance")
394+
389395
// Tracing policy file
390396
flags.String(KeyTracingPolicy, "", "Tracing policy file to load at startup")
391397

pkg/process/process.go

Lines changed: 18 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,10 @@ type ProcessInternal struct {
4848
// will be constructed on the fly when returning these extra fields
4949
// about the binary during the corresponding ProcessExec only.
5050
apiBinaryProp *tetragon.BinaryProperties
51+
// EnvironmentVariables is a string map of unprocessed environment variables
52+
// that were passed to the process. This is not stored into the process,
53+
// but is used to construct the ProcessExec event.
54+
environmentVariables string
5155
// garbage collector metadata
5256
color int // Writes should happen only inside gc select channel
5357
refcnt atomic.Uint32
@@ -239,6 +243,14 @@ func (pi *ProcessInternal) NeededAncestors() bool {
239243
return false
240244
}
241245

246+
func (pi *ProcessInternal) GetEnvironmentVariables() string {
247+
if pi == nil {
248+
return ""
249+
}
250+
251+
return pi.environmentVariables
252+
}
253+
242254
// UpdateEventProcessTID Updates the Process.Tid of the event on the fly.
243255
//
244256
// From BPF side as we track processes by their TGID we do not cache TIDs,
@@ -383,11 +395,12 @@ func initProcessInternalExec(
383395
Refcnt: 0,
384396
User: user,
385397
},
386-
capabilities: apiCaps,
387-
apiCreds: apiCreds,
388-
apiBinaryProp: apiBinaryProp,
389-
namespaces: apiNs,
390-
refcntOps: map[string]int32{"process++": 1},
398+
capabilities: apiCaps,
399+
apiCreds: apiCreds,
400+
apiBinaryProp: apiBinaryProp,
401+
environmentVariables: process.Envs,
402+
namespaces: apiNs,
403+
refcntOps: map[string]int32{"process++": 1},
391404
}
392405
pi.refcnt.Store(1)
393406

pkg/sensors/config/confmap/confmap.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ type TetragonConfValue struct {
3434
TgCgrpHierarchy uint32 `align:"tg_cgrp_hierarchy"` // Tetragon Cgroup tracking hierarchy ID
3535
TgCgrpv1SubsysIdx uint32 `align:"tg_cgrpv1_subsys_idx"` // Tracking Cgroupv1 css idx at compile time
3636
TgCgrpLevel uint32 `align:"tg_cgrp_level"` // Tetragon cgroup level
37+
EnvVarsEnabled uint64 `align:"env_vars_enabled"` // Whether to read environment variables
3738
TgCgrpId uint64 `align:"tg_cgrpid"` // Tetragon cgroup ID
3839
CgrpFsMagic uint64 `align:"cgrp_fs_magic"` // Cgroupv1 or cgroupv2
3940
UsePerfRingBuf uint8 `align:"use_perf_ring_buf"` // Use the perf ring buffer rather than the bpf ring buffer
@@ -125,6 +126,10 @@ func UpdateTgRuntimeConf(mapDir string, nspid int) error {
125126
UsePerfRingBuf: usePerfRingBuffer,
126127
}
127128

129+
if option.Config.EnableProcessEnvironmentVariables {
130+
v.EnvVarsEnabled = 1 // Set to 1 if environment variable reading is enabled
131+
}
132+
128133
if err := UpdateConfMap(mapDir, v); err != nil {
129134
log.Warn("failed to update map", "confmap-update", configMapName, logfields.Error, err)
130135
return err

pkg/sensors/exec/exec_linux.go

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ func execParse(reader *bytes.Reader) (processapi.MsgProcess, error) {
8484
proc := processapi.MsgProcess{
8585
Filename: "<enomem>",
8686
Args: "<enomem>",
87+
Envs: "<enomem>",
8788
Size: processapi.MSG_SIZEOF_EXECVE,
8889
}
8990
exec := processapi.MsgExec{}
@@ -110,9 +111,9 @@ func execParse(reader *bytes.Reader) (processapi.MsgProcess, error) {
110111
return proc, err
111112
}
112113

113-
if size != uint32(exec.SizePath+exec.SizeArgs+exec.SizeCwd) {
114-
err := fmt.Errorf("msg exec size larger than argsbuffer, size %d != %d, SizePath %d, SizeArgs %d, SizeCwd %d",
115-
size, exec.SizePath+exec.SizeArgs+exec.SizeCwd, exec.SizePath, exec.SizeArgs, exec.SizeCwd)
114+
if size != uint32(exec.SizePath+exec.SizeArgs+exec.SizeCwd+exec.SizeEnvs) {
115+
err := fmt.Errorf("msg exec size larger than argsbuffer, size %d != %d, SizePath %d, SizeArgs %d, SizeCwd %d, SizeEnvs %d",
116+
size, exec.SizePath+exec.SizeArgs+exec.SizeCwd, exec.SizePath, exec.SizeArgs, exec.SizeCwd, exec.SizeEnvs)
116117
return proc, err
117118
}
118119

@@ -176,6 +177,26 @@ func execParse(reader *bytes.Reader) (processapi.MsgProcess, error) {
176177
cmdArgs = append(cmdArgs, cwd)
177178
}
178179

180+
if exec.SizeEnvs != 0 {
181+
var data []byte
182+
var err error
183+
184+
if exec.Flags&api.EventDataEnvs != 0 {
185+
data, err = readData(exec.SizeEnvs)
186+
if err != nil {
187+
return proc, err
188+
}
189+
// cut the zero byte
190+
data = data[:len(data)-1]
191+
} else {
192+
data = make([]byte, exec.SizeEnvs)
193+
if err := binary.Read(reader, binary.LittleEndian, &data); err != nil {
194+
return proc, err
195+
}
196+
}
197+
proc.Envs = strutils.UTF8FromBPFBytes(bytes.ReplaceAll(data, []byte{0x00}, []byte{' '}))
198+
}
199+
179200
proc.Size = exec.Size
180201
proc.Args = strutils.UTF8FromBPFBytes(bytes.Join(cmdArgs[0:], []byte{0x00}))
181202
return proc, nil

0 commit comments

Comments
 (0)