Skip to content

Commit

Permalink
usm: shared-libraries: Ignore O_WRONLY opens (DataDog#32402)
Browse files Browse the repository at this point in the history
Co-authored-by: Guy Arbitman <[email protected]>
  • Loading branch information
vitkyrka and guyarb authored Dec 26, 2024
1 parent 701ea4a commit c09e95e
Show file tree
Hide file tree
Showing 3 changed files with 64 additions and 4 deletions.
5 changes: 3 additions & 2 deletions pkg/ebpf/uprobes/attacher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -985,9 +985,10 @@ func (s *SharedLibrarySuite) TestDetectionWithPIDAndRootNamespace() {
t.Cleanup(ua.Stop)

time.Sleep(10 * time.Millisecond)
// simulate a slow (1 second) : open, write, close of the file
// simulate a slow (1 second) : open, read, close of the file
// in a new pid and mount namespaces
o, err := exec.Command("unshare", "--fork", "--pid", "-R", root, "/ash", "-c", fmt.Sprintf("sleep 1 > %s", libpath)).CombinedOutput()
o, err := exec.Command("unshare", "--fork", "--pid", "-R", root, "/ash", "-c",
fmt.Sprintf("touch foo && mv foo %s && sleep 1 < %s", libpath, libpath)).CombinedOutput()
if err != nil {
t.Log(err, string(o))
}
Expand Down
22 changes: 22 additions & 0 deletions pkg/network/ebpf/c/shared-libraries/probes.h
Original file line number Diff line number Diff line change
Expand Up @@ -102,9 +102,24 @@ static __always_inline void do_sys_open_helper_exit(exit_sys_ctx *args) {
return;
}

// This definition is the same for all architectures.
#ifndef O_WRONLY
#define O_WRONLY 00000001
#endif

static __always_inline int should_ignore_flags(int flags)
{
return flags & O_WRONLY;
}

SEC("tracepoint/syscalls/sys_enter_open")
int tracepoint__syscalls__sys_enter_open(enter_sys_open_ctx *args) {
CHECK_BPF_PROGRAM_BYPASSED()

if (should_ignore_flags(args->flags)) {
return 0;
}

do_sys_open_helper_enter(args->filename);
return 0;
}
Expand All @@ -119,6 +134,11 @@ int tracepoint__syscalls__sys_exit_open(exit_sys_ctx *args) {
SEC("tracepoint/syscalls/sys_enter_openat")
int tracepoint__syscalls__sys_enter_openat(enter_sys_openat_ctx *args) {
CHECK_BPF_PROGRAM_BYPASSED()

if (should_ignore_flags(args->flags)) {
return 0;
}

do_sys_open_helper_enter(args->filename);
return 0;
}
Expand All @@ -133,6 +153,8 @@ int tracepoint__syscalls__sys_exit_openat(exit_sys_ctx *args) {
SEC("tracepoint/syscalls/sys_enter_openat2")
int tracepoint__syscalls__sys_enter_openat2(enter_sys_openat2_ctx *args) {
CHECK_BPF_PROGRAM_BYPASSED()
// Unlike the other variants, openat2(2) has the flags embedded inside the
// how argument; we don't bother trying to accessing it for now.
do_sys_open_helper_enter(args->filename);
return 0;
}
Expand Down
41 changes: 39 additions & 2 deletions pkg/network/usm/sharedlibraries/watcher_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,42 @@ func (s *SharedLibrarySuite) TestSharedLibraryDetection() {
}, time.Second*10, 100*time.Millisecond)
}

// Test that shared library files opened for writing only are ignored.
func (s *SharedLibrarySuite) TestSharedLibraryIgnoreWrite() {
t := s.T()

// Since we want to detect that the write _hasn't_ been detected, verify the
// read too to try to ensure that test isn't broken and failing to detect
// the write due to some bug in the test itself.
readPath, readPathID := createTempTestFile(t, "read-foo-libssl.so")
writePath, writePathID := createTempTestFile(t, "write-foo-libssl.so")

registerRecorder := new(utils.CallbackRecorder)
unregisterRecorder := new(utils.CallbackRecorder)

watcher, err := NewWatcher(utils.NewUSMEmptyConfig(), LibsetCrypto,
Rule{
Re: regexp.MustCompile(`foo-libssl.so`),
RegisterCB: registerRecorder.Callback(),
UnregisterCB: unregisterRecorder.Callback(),
},
)
require.NoError(t, err)
watcher.Start()
t.Cleanup(watcher.Stop)

// Use a sleep 1 as in TestSharedLibraryDetectionWithPIDAndRootNamespace
// below to give the watcher a chance to detect the process.
_, err = exec.Command("sh", "-c",
fmt.Sprintf("sleep 1 < %s > %s", readPath, writePath)).CombinedOutput()
require.NoError(t, err)

require.EventuallyWithT(t, func(c *assert.CollectT) {
assert.Equal(c, 1, registerRecorder.CallsForPathID(readPathID))
assert.Equal(c, 0, registerRecorder.CallsForPathID(writePathID))
}, time.Second*5, 10*time.Millisecond)
}

func (s *SharedLibrarySuite) TestLongPath() {
t := s.T()

Expand Down Expand Up @@ -288,9 +324,10 @@ func (s *SharedLibrarySuite) TestSharedLibraryDetectionWithPIDAndRootNamespace()
t.Cleanup(watcher.Stop)

time.Sleep(10 * time.Millisecond)
// simulate a slow (1 second) : open, write, close of the file
// simulate a slow (1 second) : open, read, close of the file
// in a new pid and mount namespaces
o, err := exec.Command("unshare", "--fork", "--pid", "-R", root, "/ash", "-c", fmt.Sprintf("sleep 1 > %s", libpath)).CombinedOutput()
o, err := exec.Command("unshare", "--fork", "--pid", "-R", root, "/ash", "-c",
fmt.Sprintf("touch foo && mv foo %s && sleep 1 < %s", libpath, libpath)).CombinedOutput()
if err != nil {
t.Log(err, string(o))
}
Expand Down

0 comments on commit c09e95e

Please sign in to comment.