-
Notifications
You must be signed in to change notification settings - Fork 165
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
fix(driver-modern-bpf): fix execve USER vs MEMORY reads + cleanup + enforce upper bounds in push__bytebuf #633
fix(driver-modern-bpf): fix execve USER vs MEMORY reads + cleanup + enforce upper bounds in push__bytebuf #633
Conversation
…t success retval * bpf_probe_read and bpf_probe_read_user used in push__bytebuf do not return bytes but success retval, refactor to reflect this better. * (char *)bytebuf_pointer -> (void *)bytebuf_pointer) Signed-off-by: Melissa Kilby <[email protected]>
Signed-off-by: Melissa Kilby <[email protected]>
Hey @incertum thank you for this I will take a look ASAP :) |
Just checked @incertum the fix should be simple than this, we need to change all |
Thanks @Andreagit97
The |
Hi @incertum
Distinguishing between kernel and user space pointers is essential for s390x. On s390x, kernel and user space have their own address space and, hence, address can overlap. I opened #497 some time ago for the BPF driver and did a couple of reviews on modern BPF in this regard. |
Collectively verified that this fixes issues in execve params 2, 3 and 16. Co-authored-by: Andrea Terzolo <[email protected]> Co-authored-by: Hendrik Brueckner <[email protected]> Signed-off-by: Melissa Kilby <[email protected]>
57d7ff1
to
a94d950
Compare
@Andreagit97 and @hbrueckner I like simpler fixes that actually make sense 😄 , squashed and adjusted last commit accordingly. Thank you! |
@@ -253,11 +256,20 @@ static __always_inline u16 push__charbuf(u8 *data, u64 *payload_pos, unsigned lo | |||
*/ | |||
static __always_inline u16 push__bytebuf(u8 *data, u64 *payload_pos, unsigned long bytebuf_pointer, u16 len_to_read, enum read_memory mem) | |||
{ | |||
u16 total_len = 0; | |||
if (len_to_read > ARGS_ENV_SIZE_MAX) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
only a nit: Maybe it is worth to have some min
/max
macros here? (If so, maybe a follow-up PR).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hbrueckner could skip reading at all if len_to_read = 0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hbrueckner pushed a simple suggestion, let me know, can adjust it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@hbrueckner could skip reading at all if len_to_read = 0
The code is already doing it, if len_to_read=0
we push 0
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added benefit in the modern_bpf API setup is that we exit faster here. Thought @hbrueckner raised a valid point, always be consistent and do min/max checks if you do max checks.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Uhm let's say here there is the usual trade-off:
- save one
bpf_probe_read
in case thelen_to_read
is0
. (not frequent scenario) - add complexity and pay for the checks when
len_to_read
is!=0
. (frequent scenario).
That's exactly the trade-off we have in the old probe, very complex code to save corner cases like this, to be honest, I would avoid this check at least for now, if we notice a real benefit from this we can always introduce it in a second step 🤔
Hi @incertum
I had also the same patch around :-) |
LGTM label has been added. Git tree hash: 880f8010ecd09f0f6d508b3558eae30de14610f8
|
@@ -89,6 +89,9 @@ enum read_memory | |||
/* Paramater maximum size */ | |||
#define MAX_PARAM_SIZE MAX_EVENT_SIZE - 1 | |||
|
|||
/* ARGS or ENV maximum size */ | |||
#define ARGS_ENV_SIZE_MAX 4096 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
not completely understood why we need this 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SAFE_ACCESS
should already protect us from the worst case
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It has been part of the old probe and it may be less for protection and rather more for you don't wanna ever log super super long unbounded strings in your logs. @leogr @FedeDP do you have more insights re what the motivation was in the old probe? Only safe reads or also some guarantees on limits? Lastly for push__charbuf
limits are enforced so it would also be about consistency.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It has been part of the old probe and it may be less for protection and rather more for you don't wanna ever log super super long unbounded strings in your logs.
That's a good point for this reason we use approaches like the snaplen
to let users understand the max dimension they want to send, you can see an example here
libs/driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/sendto.bpf.c
Lines 89 to 98 in 0c280ca
unsigned long bytes_to_read = maps__get_snaplen(); | |
if(bytes_to_read > ret) | |
{ | |
bytes_to_read = ret; | |
} | |
/* Parameter 2: data (type: PT_BYTEBUF) */ | |
unsigned long sent_data_pointer = extract__syscall_argument(regs, 1); | |
auxmap__store_bytebuf_param(auxmap, sent_data_pointer, bytes_to_read, USER); |
The idea of this snaplen
concept is to limit at an higher level so you can chose when to limit rather then implementing it directly at low level
For what concerns the old probe we use this same concept of snaplen
all the others checks are to please the verifier AFAIK 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Those are the two relevant max bounds from old probe
#define ARGS_ENV_SIZE_MAX 4096
#define MAX_PATH_LENGTH 4096
These values are battle proven, so wouldn't go higher before testing modern_bpf in the field.
Probably have a few options here and we can go step-wise, no need to change all now.
- Could start with uniformly enforcing bounds to existing
MAX_PARAM_SIZE
, if I can say so, the value appears extremely large, I think2^12
is reasonable and enough and as mentioned battle proven. If we go this route can change this quickly and reuse the existing macro. - If we need more granular upper bounds can introduce a new enum, similarly to the
read_memory
. For example, for the cmd args I can see that maybe2^13
could be a good choice for an enforced upper bound. Would however perform all bound checks and selecting the corresponding upper bound here and not in the fillers. In addition, fillers can always also enforce a lower value than the max enforced bound.
These bound checks are not unique to Falco or libs, seeing them everywhere and I would be very hesitant deploying anything to production without them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry typo meant the MAX_PARAM_SIZE
you also use in SAFE_ACCESS
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
uhm I got your point maybe MAX_PARAM_SIZE
is big enough, it's the same value we use in the old probe but it could be dangerous...
/* Event maximum size */
#define MAX_EVENT_SIZE 64 * 1024
/* Paramater maximum size */
#define MAX_PARAM_SIZE MAX_EVENT_SIZE - 1
BTW putting a hard-coded value here doesn't seem the right solution, or better let's say it could be the right solution if we were in production and we have to rush, but this is not the case 🤣 let's take our time to think of something more dynamic or configurable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've added some dedicated checks for execve
here https://github.com/falcosecurity/libs/pull/648/files#diff-23e1e00c90562960e7e4110fcc5c62cd89d2ea8a8df3198d7c04512084c7c378R52-R54 :)
…n_to_read Co-authored-by: Hendrik Brueckner <[email protected]> Signed-off-by: Melissa Kilby <[email protected]>
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hi! I'd split the feature/fix ARGS_ENV_SIZE_MAX
from the real fix, and open a PR just for that, if you agree!
The fix is just the driver/modern_bpf/programs/tail_called/events/syscall_dispatched_events/execve.bpf.c
diff, right?
Hi @incertum , @FedeDP , @Andreagit97 ,
trying to catch up on this and #648, my thoughts tend to have the On 7bf2082](7bf2082), checking Wdyt? |
Sounds good :)
Yeah let's say i have only one concern about this, that's what we discovered in #648... a simple difference in how we do stuff can lead to a perf penalty not negligible, i don't think this is the case because we have just an if, but we have to say that the only gain from this |
* move lower bound check for push__bytebuf to auxmap__store_bytebuf_param * address upper bound checks in follow up PRs Co-authored-by: Hendrik Brueckner <[email protected]> Signed-off-by: Melissa Kilby <[email protected]>
Hoping new commit reflects a balance @hbrueckner @Andreagit97 @FedeDP. Small note in favor of keeping the lower bound check: no cmd args is not necessarily an edge case, especially when considering clone/fork family of syscalls. Basing this statement on some experimental observations. However, can always remove the lower bound check in the future if performance tests surface that alternatives are better. |
Hi @incertum ,
Commit looks fine to me.
Makes sense. Perhaps there is also a way higher in the stack to get some statistics on the such events. /lgtm |
LGTM label has been added. Git tree hash: 43a4554e6357ca72e02cc311318429d8a5b28b12
|
/hold |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for these changes :)
/approve
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/approve
[APPROVALNOTIFIER] This PR is APPROVED This pull-request has been approved by: Andreagit97, FedeDP, hbrueckner, incertum The full list of commands accepted by this bot can be found here. The pull request process is described here
Needs approval from an approver in each of these files:
Approvers can indicate their approval by writing |
/unhold |
What type of PR is this?
/kind bug
/kind cleanup
Any specific area of the project related to this PR?
/area driver-modern-bpf
Does this PR require a change in the driver versions?
What this PR does / why we need it:
Reproduce bug and verify fix:
Currently in
driver-modern-bpf
we do not get some execve data, for example:Current master:
After reverting KERNEL reads to
bpf_probe_read
orbpf_probe_read_str
everything seems to be fixed again (this PR):Edited: Actual issue was some wrong USER vs MEMORY reads attribution in execve filler.
CC folks who touched
modern_bpf
so far: @Andreagit97 @hbrueckner @Molter73 @FedeDP @jasondellaluce @leogrWhich issue(s) this PR fixes:
Fixes #
Special notes for your reviewer:
Does this PR introduce a user-facing change?: