-
Notifications
You must be signed in to change notification settings - Fork 752
fix(driver/bpf): bpf_parse_readv_writev_bufs avoid overflow while reading readv/writev iovec struct #1733
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
Conversation
reading readv/writev iovec struct
Raeding the buffer data from the iovec struct requires to go take a
specific area in our buffer to perform the read into the cpu data->buf
map.
New kernels implement the `__check_mem_access` which takes care
of checking if the accessed memory is valid or not in the current
context.
In our case since our scratch buffer is split in a half with two null
terminators, we only need to read the area until the null terminator
happens or the verifier will alert.
Here's the verifier check [0] for this case:
```
bool size_ok = size > 0 || (size == 0 && zero_size_allowed);
struct bpf_reg_state *reg;
if (off >= 0 && size_ok && (u64)off + size <= mem_size)
return 0;
```
[0]: https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/tree/kernel/bpf/verifier.c?id=541c3bad8dc51b253ba8686d0cd7628e6b9b5f4c#n2552
Co-Authored-By: Leonardo Di Donato <leodidonato@gmail.com>
Signed-off-by: Lorenzo Fontana <lo@linux.com>
|
I was having some trouble understanding exactly what effect this change might have, so I wrote a scratch program. I'm mapping the difference in read offset between the old code and the new code: My concern is that when And of course, it's not just 1. Any value of Maybe I just don't understand the intent of this fix, but I'm worried it will cause the probe to start emitting incorrect data! |
|
The key to understanding the change here is that In any case, even if the source buffer was bigger, our architecture does not support reading more than SCRATCH_SIZE_HALF and, even if it could sinsp and scap have hard limits on what is brought into userspace and ultimately at the presentation layer. |
|
Moreover, a bug in the offsets here would only affect |
| #ifdef BPF_FORBIDS_ZERO_ACCESS | ||
| if (to_read) | ||
| if (bpf_probe_read(&data->buf[off & SCRATCH_SIZE_HALF], | ||
| if (bpf_probe_read(&data->buf[off & SCRATCH_SIZE_HALF - 1], |
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.
Parentheses? Is this expression (off & SCRATCH_SIZE_HALF) - 1 or off & (SCRATCH_SIZE_HALF - 1)?
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.
- has precedence over & and I confirm that the generated bpf bytecode is correct.
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.
Based on what you wrote above, is it possible that the intent of the code is (off & SCRATCH_SIZE_HALF) - 1?
|
Hold until we test this on older verifiers (ie., older kernels). |
|
This can be closed, I will post updates on this fix later, debugged the kernel a bit more and understood why this is happening. Stay tuned. |
Reading the buffer data from the iovec struct requires to go take a specific area in our buffer to perform the read into the cpu data->buf
map.
New kernels implement the
__check_mem_accesswhich takes careof checking if the accessed memory is valid or not in the current
context.
In our case since our scratch buffer is split in a half with two null
terminators, we only need to read the area until the null terminator
happens or the verifier will alert.
Here's the verifier check 0 for this case:
Refs #1658
Co-Authored-By: Leonardo Di Donato leodidonato@gmail.com
Signed-off-by: Lorenzo Fontana lo@linux.com