Skip to content

Commit 5a7947c

Browse files
authored
[usm] add regular and raw tracepoints /sched_process_exit (#33943)
1 parent 9babb0a commit 5a7947c

File tree

9 files changed

+355
-21
lines changed

9 files changed

+355
-21
lines changed

pkg/network/ebpf/c/protocols/tls/native-tls.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,7 +554,31 @@ int BPF_BYPASSABLE_KPROBE(kprobe__tcp_sendmsg, struct sock *sk) {
554554
log_debug("kprobe/tcp_sendmsg: sk=%p", sk);
555555
// map connection tuple during SSL_do_handshake(ctx)
556556
map_ssl_ctx_to_sock(sk);
557+
return 0;
558+
}
559+
560+
static __always_inline void delete_pid_in_maps() {
561+
u64 pid_tgid = bpf_get_current_pid_tgid();
562+
563+
bpf_map_delete_elem(&ssl_read_args, &pid_tgid);
564+
bpf_map_delete_elem(&ssl_read_ex_args, &pid_tgid);
565+
bpf_map_delete_elem(&ssl_write_args, &pid_tgid);
566+
bpf_map_delete_elem(&ssl_write_ex_args, &pid_tgid);
567+
bpf_map_delete_elem(&ssl_ctx_by_pid_tgid, &pid_tgid);
568+
bpf_map_delete_elem(&bio_new_socket_args, &pid_tgid);
569+
}
570+
571+
SEC("tracepoint/sched/sched_process_exit")
572+
int tracepoint__sched__sched_process_exit(void *ctx) {
573+
CHECK_BPF_PROGRAM_BYPASSED()
574+
delete_pid_in_maps();
575+
return 0;
576+
}
557577

578+
SEC("raw_tracepoint/sched_process_exit")
579+
int raw_tracepoint__sched_process_exit(void *ctx) {
580+
CHECK_BPF_PROGRAM_BYPASSED()
581+
delete_pid_in_maps();
558582
return 0;
559583
}
560584

pkg/network/protocols/http/types.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ import "C"
1717
type ConnTuple = C.conn_tuple_t
1818
type SslSock C.ssl_sock_t
1919
type SslReadArgs C.ssl_read_args_t
20+
type SslReadExArgs C.ssl_read_ex_args_t
21+
type SslWriteArgs C.ssl_write_args_t
22+
type SslWriteExArgs C.ssl_write_ex_args_t
2023

2124
type EbpfEvent C.http_event_t
2225
type EbpfTx C.http_transaction_t

pkg/network/protocols/http/types_linux.go

Lines changed: 14 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/network/protocols/http/types_linux_test.go

Lines changed: 12 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pkg/network/usm/ebpf_ssl.go

Lines changed: 132 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ import (
2222

2323
manager "github.com/DataDog/ebpf-manager"
2424
"github.com/cilium/ebpf"
25+
"github.com/cilium/ebpf/features"
2526
"github.com/davecgh/go-spew/spew"
2627

2728
ddebpf "github.com/DataDog/datadog-agent/pkg/ebpf"
@@ -69,6 +70,9 @@ const (
6970
gnutlsRecordSendRetprobe = "uretprobe__gnutls_record_send"
7071
gnutlsByeProbe = "uprobe__gnutls_bye"
7172
gnutlsDeinitProbe = "uprobe__gnutls_deinit"
73+
74+
rawTracepointSchedProcessExit = "raw_tracepoint__sched_process_exit"
75+
oldTracepointSchedProcessExit = "tracepoint__sched__sched_process_exit"
7276
)
7377

7478
var openSSLProbes = []manager.ProbesSelector{
@@ -424,12 +428,23 @@ var opensslSpec = &protocols.ProtocolSpec{
424428
EBPFFuncName: gnutlsDeinitProbe,
425429
},
426430
},
431+
{
432+
ProbeIdentificationPair: manager.ProbeIdentificationPair{
433+
EBPFFuncName: rawTracepointSchedProcessExit,
434+
},
435+
},
436+
{
437+
ProbeIdentificationPair: manager.ProbeIdentificationPair{
438+
EBPFFuncName: oldTracepointSchedProcessExit,
439+
},
440+
},
427441
},
428442
}
429443

430444
type sslProgram struct {
431-
cfg *config.Config
432-
watcher *sharedlibraries.Watcher
445+
cfg *config.Config
446+
watcher *sharedlibraries.Watcher
447+
ebpfManager *manager.Manager
433448
}
434449

435450
func newSSLProgramProtocolFactory(m *manager.Manager, c *config.Config) (protocols.Protocol, error) {
@@ -441,11 +456,18 @@ func newSSLProgramProtocolFactory(m *manager.Manager, c *config.Config) (protoco
441456
watcher *sharedlibraries.Watcher
442457
err error
443458
)
444-
459+
sslProgram := &sslProgram{
460+
cfg: c,
461+
ebpfManager: m,
462+
}
463+
var cleanerCB func(map[uint32]struct{})
464+
if features.HaveProgramType(ebpf.RawTracepoint) != nil {
465+
cleanerCB = sslProgram.cleanupDeadPids
466+
}
445467
procRoot := kernel.ProcFSRoot()
446468

447469
if c.EnableNativeTLSMonitoring && usmconfig.TLSSupported(c) {
448-
watcher, err = sharedlibraries.NewWatcher(c, sharedlibraries.LibsetCrypto,
470+
watcher, err = sharedlibraries.NewWatcher(c, sharedlibraries.LibsetCrypto, cleanerCB,
449471
sharedlibraries.Rule{
450472
Re: regexp.MustCompile(`libssl.so`),
451473
RegisterCB: addHooks(m, procRoot, openSSLProbes),
@@ -467,10 +489,9 @@ func newSSLProgramProtocolFactory(m *manager.Manager, c *config.Config) (protoco
467489
}
468490
}
469491

470-
return &sslProgram{
471-
cfg: c,
472-
watcher: watcher,
473-
}, nil
492+
sslProgram.watcher = watcher
493+
494+
return sslProgram, nil
474495
}
475496

476497
// Name return the program's name.
@@ -495,6 +516,7 @@ func sharedLibrariesConfigureOptions(options *manager.Options, cfg *config.Confi
495516
// ConfigureOptions changes map attributes to the given options.
496517
func (o *sslProgram) ConfigureOptions(options *manager.Options) {
497518
sharedLibrariesConfigureOptions(options, o.cfg)
519+
o.addProcessExitProbe(options)
498520
}
499521

500522
// PreStart is called before the start of the provided eBPF manager.
@@ -534,6 +556,33 @@ func (o *sslProgram) DumpMaps(w io.Writer, mapName string, currentMap *ebpf.Map)
534556
spew.Fdump(w, key, value)
535557
}
536558

559+
case "ssl_read_ex_args": // maps/ssl_read_ex_args (BPF_MAP_TYPE_HASH), key C.__u64, value C.ssl_read_ex_args_t
560+
io.WriteString(w, "Map: '"+mapName+"', key: 'C.__u64', value: 'C.ssl_read_ex_args_t'\n")
561+
iter := currentMap.Iterate()
562+
var key uint64
563+
var value http.SslReadExArgs
564+
for iter.Next(unsafe.Pointer(&key), unsafe.Pointer(&value)) {
565+
spew.Fdump(w, key, value)
566+
}
567+
568+
case "ssl_write_args": // maps/ssl_write_args (BPF_MAP_TYPE_HASH), key C.__u64, value C.ssl_write_args_t
569+
io.WriteString(w, "Map: '"+mapName+"', key: 'C.__u64', value: 'C.ssl_write_args_t'\n")
570+
iter := currentMap.Iterate()
571+
var key uint64
572+
var value http.SslWriteArgs
573+
for iter.Next(unsafe.Pointer(&key), unsafe.Pointer(&value)) {
574+
spew.Fdump(w, key, value)
575+
}
576+
577+
case "ssl_write_ex_args_t": // maps/ssl_write_ex_args_t (BPF_MAP_TYPE_HASH), key C.__u64, value C.ssl_write_args_t
578+
io.WriteString(w, "Map: '"+mapName+"', key: 'C.__u64', value: 'C.ssl_write_ex_args_t'\n")
579+
iter := currentMap.Iterate()
580+
var key uint64
581+
var value http.SslWriteExArgs
582+
for iter.Next(unsafe.Pointer(&key), unsafe.Pointer(&value)) {
583+
spew.Fdump(w, key, value)
584+
}
585+
537586
case "bio_new_socket_args": // maps/bio_new_socket_args (BPF_MAP_TYPE_HASH), key C.__u64, value C.__u32
538587
io.WriteString(w, "Map: '"+mapName+"', key: 'C.__u64', value: 'C.__u32'\n")
539588
iter := currentMap.Iterate()
@@ -773,3 +822,78 @@ func getUID(lib utils.PathIdentifier) string {
773822
func (*sslProgram) IsBuildModeSupported(buildmode.Type) bool {
774823
return true
775824
}
825+
826+
// addProcessExitProbe adds a raw or regular tracepoint program depending on which is supported.
827+
func (o *sslProgram) addProcessExitProbe(options *manager.Options) {
828+
if features.HaveProgramType(ebpf.RawTracepoint) == nil {
829+
// use a raw tracepoint on a supported kernel to intercept terminated threads and clear the corresponding maps
830+
p := &manager.Probe{
831+
ProbeIdentificationPair: manager.ProbeIdentificationPair{
832+
EBPFFuncName: rawTracepointSchedProcessExit,
833+
UID: probeUID,
834+
},
835+
TracepointName: "sched_process_exit",
836+
}
837+
o.ebpfManager.Probes = append(o.ebpfManager.Probes, p)
838+
options.ActivatedProbes = append(options.ActivatedProbes, &manager.ProbeSelector{ProbeIdentificationPair: p.ProbeIdentificationPair})
839+
// exclude regular tracepoint
840+
options.ExcludedFunctions = append(options.ExcludedFunctions, oldTracepointSchedProcessExit)
841+
} else {
842+
// use a regular tracepoint to intercept terminated threads
843+
p := &manager.Probe{
844+
ProbeIdentificationPair: manager.ProbeIdentificationPair{
845+
EBPFFuncName: oldTracepointSchedProcessExit,
846+
UID: probeUID,
847+
},
848+
}
849+
o.ebpfManager.Probes = append(o.ebpfManager.Probes, p)
850+
options.ActivatedProbes = append(options.ActivatedProbes, &manager.ProbeSelector{ProbeIdentificationPair: p.ProbeIdentificationPair})
851+
// exclude a raw tracepoint
852+
options.ExcludedFunctions = append(options.ExcludedFunctions, rawTracepointSchedProcessExit)
853+
}
854+
}
855+
856+
var sslPidKeyMaps = []string{
857+
"ssl_read_args",
858+
"ssl_read_ex_args",
859+
"ssl_write_args",
860+
"ssl_write_ex_args",
861+
"ssl_ctx_by_pid_tgid",
862+
"bio_new_socket_args",
863+
}
864+
865+
// cleanupDeadPids clears maps of terminated processes, is invoked when raw tracepoints unavailable.
866+
func (o *sslProgram) cleanupDeadPids(alivePIDs map[uint32]struct{}) {
867+
for _, mapName := range sslPidKeyMaps {
868+
err := deleteDeadPidsInMap(o.ebpfManager, mapName, alivePIDs)
869+
if err != nil {
870+
log.Debugf("SSL map %q cleanup error: %v", mapName, err)
871+
}
872+
}
873+
}
874+
875+
// deleteDeadPidsInMap finds a map by name and deletes dead processes.
876+
// enters when raw tracepoint is not supported, kernel < 4.17
877+
func deleteDeadPidsInMap(manager *manager.Manager, mapName string, alivePIDs map[uint32]struct{}) error {
878+
emap, _, err := manager.GetMap(mapName)
879+
if err != nil {
880+
return fmt.Errorf("dead process cleaner failed to get map: %q error: %w", mapName, err)
881+
}
882+
883+
var keysToDelete []uint64
884+
var key uint64
885+
value := make([]byte, emap.ValueSize())
886+
iter := emap.Iterate()
887+
888+
for iter.Next(unsafe.Pointer(&key), unsafe.Pointer(&value)) {
889+
pid := uint32(key >> 32)
890+
if _, exists := alivePIDs[pid]; !exists {
891+
keysToDelete = append(keysToDelete, key)
892+
}
893+
}
894+
for _, k := range keysToDelete {
895+
_ = emap.Delete(unsafe.Pointer(&k))
896+
}
897+
898+
return nil
899+
}

0 commit comments

Comments
 (0)