Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Postfix operator for matchBinaries selector #2689

Merged
merged 4 commits into from
Aug 14, 2024

Conversation

anfedotoff
Copy link
Contributor

@anfedotoff anfedotoff commented Jul 18, 2024

Details can be found in #2679.

  • BPF selector part
  • Tetragon selector part
  • Postfix operator test for matchBinaries selector
  • Update docs
Add the Postfix and NotPostfix operators to the matchBinaries selector.

@anfedotoff anfedotoff requested a review from a team as a code owner July 18, 2024 10:03
@anfedotoff anfedotoff requested a review from olsajiri July 18, 2024 10:03
@anfedotoff anfedotoff marked this pull request as draft July 18, 2024 10:03
Copy link

netlify bot commented Jul 18, 2024

Deploy Preview for tetragon ready!

Name Link
🔨 Latest commit a750259
🔍 Latest deploy log https://app.netlify.com/sites/tetragon/deploys/66ba07b02e4fa7000898a747
😎 Deploy Preview https://deploy-preview-2689--tetragon.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify site configuration.

@anfedotoff anfedotoff changed the title wip: Postfix operator in matchBinaries action wip: Postfix operator for matchBinaries selector Jul 18, 2024
@mtardy mtardy self-requested a review July 18, 2024 11:06
@mtardy mtardy added release-note/minor This PR introduces a minor user-visible change area/bpf This is related to BPF code labels Jul 18, 2024
@anfedotoff anfedotoff force-pushed the matchbinaries-postfix branch 3 times, most recently from 72ffd1a to 3ad08ce Compare July 19, 2024 11:20
@anfedotoff anfedotoff changed the title wip: Postfix operator for matchBinaries selector Postfix operator for matchBinaries selector Jul 19, 2024
@anfedotoff anfedotoff marked this pull request as ready for review July 19, 2024 11:26
mtardy
mtardy previously approved these changes Jul 22, 2024
Copy link
Member

@mtardy mtardy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks that's a great addition! Would love an ack from Kev since we are touching a few bits of its STRING code.

My main nit would be to add a test using the perfring framework to check for a missing event so that we are sure this thing works as intended, and I'm good! :)

bpf/process/types/basic.h Outdated Show resolved Hide resolved
bpf/process/types/basic.h Outdated Show resolved Hide resolved
pkg/sensors/tracing/kprobe_test.go Outdated Show resolved Hide resolved
pkg/sensors/tracing/kprobe_test.go Show resolved Hide resolved

The `values` field has to be a map of `strings`. The default behaviour
is `followForks: true`, so all the child processes are followed.
The current limitation is 4 values.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the limitation here is outdated but it's out of the scope of this PR

@mtardy mtardy linked an issue Jul 22, 2024 that may be closed by this pull request
2 tasks
Copy link
Contributor

@kevsecurity kevsecurity left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we need to store the last 128 chars of the binary path in execve_send (bpf/process/bpf_execve_event.c) in a new part of the struct binary, specifically for postfix matching.
I think we need a copy of copy_reverse() (called file_copy_reverse()) that only copies file paths from buffer expected to be BINARY_PATH_MAX_LENGTH in size, leaving the original with the PATH_MASK position masking.

@mtardy
Copy link
Member

mtardy commented Jul 22, 2024

I think we need to store the last 128 chars of the binary path in execve_send (bpf/process/bpf_execve_event.c) in a new part of the struct binary, specifically for postfix matching.

I think we need a copy of copy_reverse() (called file_copy_reverse()) that only copies file paths from buffer expected to be BINARY_PATH_MAX_LENGTH in size, leaving the original with the PATH_MASK position masking.

Thanks kev I completely overlooked this previous struggle. Indeed, for the binary we don't store the whole path so you have a few cases to take into account:

  • path is short enough you can do what you did
  • path is too long and you need to store at exec time the end of it (at least 128 chars). You can lazily reverse it when needed.

@kevsecurity
Copy link
Contributor

Thanks kev I completely overlooked this previous struggle. Indeed, for the binary we don't store the whole path so you have a few cases to take into account:

  • path is short enough you can do what you did
  • path is too long and you need to store at exec time the end of it (at least 128 chars). You can lazily reverse it when needed.

Personally, I'd always copy the end into the new end slot to save extra logic when matching. I agree that you should lazily reverse it the first time you do a postfix match on it, but this has race conditions. I think the simple solution (not necessarily the cheapest or best) is to have two extra slots, not one extra slot! So struct binary could look like:

struct binary {
	// length of the path stored in path, this should be < BINARY_PATH_MAX_LEN
	// but can contain negative value in case of copy error.
	// While s16 would be sufficient, 32 bits are handy for alignment.
	__s32 path_length;
	__u8 reversed;
	__u8 pad[3];
	// BINARY_PATH_MAX_LEN first bytes of the path
	char path[BINARY_PATH_MAX_LEN];
	char end[BINARY_PATH_MAX_LEN];
	char end_r[BINARY_PATH_MAX_LEN];
}; // All fields aligned so no 'packed' attribute

On execution, copy the end of the path into end. On first postfix lookup, reverse end into end_r and set reversed to true. If another thread is doing the same then end will be unaffected, so end_r will end up with the same values, even if one thread is still reversing end into end_r while another is using end_r. If reversed is true, then just match on end_r and assume it has already been reversed.

@anfedotoff
Copy link
Contributor Author

Thanks kev I completely overlooked this previous struggle. Indeed, for the binary we don't store the whole path so you have a few cases to take into account:

  • path is short enough you can do what you did
  • path is too long and you need to store at exec time the end of it (at least 128 chars). You can lazily reverse it when needed.

Personally, I'd always copy the end into the new end slot to save extra logic when matching. I agree that you should lazily reverse it the first time you do a postfix match on it, but this has race conditions. I think the simple solution (not necessarily the cheapest or best) is to have two extra slots, not one extra slot! So struct binary could look like:

struct binary {
	// length of the path stored in path, this should be < BINARY_PATH_MAX_LEN
	// but can contain negative value in case of copy error.
	// While s16 would be sufficient, 32 bits are handy for alignment.
	__s32 path_length;
	__u8 reversed;
	__u8 pad[3];
	// BINARY_PATH_MAX_LEN first bytes of the path
	char path[BINARY_PATH_MAX_LEN];
	char end[BINARY_PATH_MAX_LEN];
	char end_r[BINARY_PATH_MAX_LEN];
}; // All fields aligned so no 'packed' attribute

On execution, copy the end of the path into end. On first postfix lookup, reverse end into end_r and set reversed to true. If another thread is doing the same then end will be unaffected, so end_r will end up with the same values, even if one thread is still reversing end into end_r while another is using end_r. If reversed is true, then just match on end_r and assume it has already been reversed.

Thanks for such detailed advice! I'll try to implement the logic you described.

@mtardy mtardy dismissed their stale review July 22, 2024 13:42

Remember that they are challenges for long path

@mtardy
Copy link
Member

mtardy commented Jul 22, 2024

I just remember I had a very early draft branch from October but I don't think it'll really help you here, it was similar to the advice given here.

@anfedotoff
Copy link
Contributor Author

@mtardy , @kevsecurity , guys, can I ask you to review again, please?

@mtardy
Copy link
Member

mtardy commented Aug 9, 2024

@mtardy , @kevsecurity , guys, can I ask you to review again, please?

sure, note that you can use that btw even if a message is fine of course.
image

Copy link
Member

@mtardy mtardy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks a lot for those updates :), here are some comments. My main point would be to add a test with a long binary like in 67348f6 so that we make sure this PR works and doesn't break.

bpf/lib/process.h Outdated Show resolved Hide resolved
bpf/process/bpf_execve_event.c Outdated Show resolved Hide resolved
bpf/process/types/basic.h Outdated Show resolved Hide resolved
bpf/process/types/basic.h Outdated Show resolved Hide resolved
bpf/process/types/basic.h Outdated Show resolved Hide resolved
bpf/process/types/basic.h Outdated Show resolved Hide resolved
@kevsecurity
Copy link
Contributor

It's looking good. Address the few things including some tests and we should be good to merge.

@anfedotoff anfedotoff force-pushed the matchbinaries-postfix branch 3 times, most recently from 8e4afae to a750259 Compare August 12, 2024 13:01
bpf/lib/process.h Outdated Show resolved Hide resolved
bpf/lib/process.h Show resolved Hide resolved
bpf/process/bpf_execve_event.c Outdated Show resolved Hide resolved
bpf/process/bpf_execve_event.c Outdated Show resolved Hide resolved
bpf/process/bpf_execve_event.c Outdated Show resolved Hide resolved
bpf/process/types/basic.h Outdated Show resolved Hide resolved
pkg/api/processapi/processapi.go Outdated Show resolved Hide resolved
@anfedotoff anfedotoff force-pushed the matchbinaries-postfix branch 5 times, most recently from 0e5788f to b439d09 Compare August 13, 2024 09:25
Copy link
Contributor

@kevsecurity kevsecurity left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Copy link
Member

@mtardy mtardy left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, it's almost ready, the only small blocker for me is to have a first commit that compiles & runs (the struct should be synchronized between kernel/user), the rest is nits and followups.

bpf/lib/process.h Show resolved Hide resolved
bpf/process/bpf_execve_event.c Show resolved Hide resolved
Comment on lines +389 to +392
__u64 revlen = event->exe.len;

if (event->exe.len > STRING_POSTFIX_MAX_LENGTH - 1)
revlen = STRING_POSTFIX_MAX_LENGTH - 1;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: you could also write revlen into the struct so that you don't need to recompute it again, not sure it's better than this but you could downsize again here and use 16/16 bytes, so that you get path_len and end_len/rev_len?

// if end_r contains reversed path postfix
__u32 reversed;

bpf/process/types/basic.h Show resolved Hide resolved
bpf/process/types/basic.h Outdated Show resolved Hide resolved
pkg/sensors/tracing/kprobe_test.go Show resolved Hide resolved
Adding postfix/notpostfix cases to match_binaries function
allows to support postfix operator in matchBinaries selector.
Modifying 'binary' struct to hold path postfix.

Signed-off-by: Andrei Fedotov <anfedotoff@yandex-team.ru>
Adding Postifx and NotPostfix operators to matchBinaries selector as it
already done for matchArgs selector.

Signed-off-by: Andrei Fedotov <anfedotoff@yandex-team.ru>
Adding tests for Postix and NotPostfix operators in
TestKprobeMatchBinaries and TestKprobeMatchBinariesPerfring.
Adding TestKprobeMatchBinariesLargePath test.

Signed-off-by: Andrei Fedotov <anfedotoff@yandex-team.ru>
Signed-off-by: Andrei Fedotov <anfedotoff@yandex-team.ru>
@anfedotoff
Copy link
Contributor Author

anfedotoff commented Aug 14, 2024

@mtardy , I think now it's ready:)

@mtardy
Copy link
Member

mtardy commented Aug 14, 2024

@mtardy , I think now it's ready:)

Yep thanks again, let's merge this! 🌮 🎉

@mtardy mtardy merged commit ecdb38f into cilium:main Aug 14, 2024
49 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/bpf This is related to BPF code release-note/minor This PR introduces a minor user-visible change
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support Postfix operator in matchBinaries selector
3 participants