Skip to content

Commit

Permalink
bcc/docs: Add bpf_probe_read_user to docs and tutorials
Browse files Browse the repository at this point in the history
Signed-off-by: Sumanth Korikkar <[email protected]>
  • Loading branch information
sumanthkorikkar committed Apr 23, 2020
1 parent 023154c commit aa3a4a6
Show file tree
Hide file tree
Showing 2 changed files with 36 additions and 8 deletions.
38 changes: 33 additions & 5 deletions docs/reference_guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@ This guide is incomplete. If something feels missing, check the bcc and kernel s
- [7. bpf_get_current_task()](#7-bpf_get_current_task)
- [8. bpf_log2l()](#8-bpf_log2l)
- [9. bpf_get_prandom_u32()](#9-bpf_get_prandom_u32)
- [10. bpf_probe_read_user()](#10-bpf_probe_read_user)
- [11. bpf_probe_read_user_str()](#11-bpf_probe_read_user_str)
- [Debugging](#debugging)
- [1. bpf_override_return()](#1-bpf_override_return)
- [Output](#output)
Expand Down Expand Up @@ -196,7 +198,7 @@ For example:
```C
int count(struct pt_regs *ctx) {
char buf[64];
bpf_probe_read(&buf, sizeof(buf), (void *)PT_REGS_PARM1(ctx));
bpf_probe_read_user(&buf, sizeof(buf), (void *)PT_REGS_PARM1(ctx));
bpf_trace_printk("%s %d", buf, PT_REGS_PARM2(ctx));
return(0);
}
Expand Down Expand Up @@ -242,7 +244,7 @@ int do_trace(struct pt_regs *ctx) {
uint64_t addr;
char path[128];
bpf_usdt_readarg(6, ctx, &addr);
bpf_probe_read(&path, sizeof(path), (void *)addr);
bpf_probe_read_user(&path, sizeof(path), (void *)addr);
bpf_trace_printk("path:%s\\n", path);
return 0;
};
Expand Down Expand Up @@ -372,7 +374,7 @@ Syntax: ```int bpf_probe_read(void *dst, int size, const void *src)```

Return: 0 on success

This copies a memory location to the BPF stack, so that BPF can later operate on it. For safety, all memory reads must pass through bpf_probe_read(). This happens automatically in some cases, such as dereferencing kernel variables, as bcc will rewrite the BPF program to include the necessary bpf_probe_reads().
This copies size bytes from kernel address space to the BPF stack, so that BPF can later operate on it. For safety, all kernel memory reads must pass through bpf_probe_read(). This happens automatically in some cases, such as dereferencing kernel variables, as bcc will rewrite the BPF program to include the necessary bpf_probe_read().

Examples in situ:
[search /examples](https://github.com/iovisor/bcc/search?q=bpf_probe_read+path%3Aexamples&type=Code),
Expand All @@ -386,7 +388,7 @@ Return:
- \> 0 length of the string including the trailing NULL on success
- \< 0 error

This copies a `NULL` terminated string from memory location to BPF stack, so that BPF can later operate on it. In case the string length is smaller than size, the target is not padded with further `NULL` bytes. In case the string length is larger than size, just `size - 1` bytes are copied and the last byte is set to `NULL`.
This copies a `NULL` terminated string from kernel address space to the BPF stack, so that BPF can later operate on it. In case the string length is smaller than size, the target is not padded with further `NULL` bytes. In case the string length is larger than size, just `size - 1` bytes are copied and the last byte is set to `NULL`.

Examples in situ:
[search /examples](https://github.com/iovisor/bcc/search?q=bpf_probe_read_str+path%3Aexamples&type=Code),
Expand Down Expand Up @@ -490,6 +492,32 @@ Example in situ:
[search /examples](https://github.com/iovisor/bcc/search?q=bpf_get_prandom_u32+path%3Aexamples&type=Code),
[search /tools](https://github.com/iovisor/bcc/search?q=bpf_get_prandom_u32+path%3Atools&type=Code)

### 10. bpf_probe_read_user()

Syntax: ```int bpf_probe_read_user(void *dst, int size, const void *src)```

Return: 0 on success

This attempts to safely read size bytes from user address space to the BPF stack, so that BPF can later operate on it. For safety, all user address space memory reads must pass through bpf_probe_read_user().

Examples in situ:
[search /examples](https://github.com/iovisor/bcc/search?q=bpf_probe_read_user+path%3Aexamples&type=Code),
[search /tools](https://github.com/iovisor/bcc/search?q=bpf_probe_read_user+path%3Atools&type=Code)

### 11. bpf_probe_read_user_str()

Syntax: ```int bpf_probe_read_user_str(void *dst, int size, const void *src)```

Return:
- \> 0 length of the string including the trailing NULL on success
- \< 0 error

This copies a `NULL` terminated string from user address space to the BPF stack, so that BPF can later operate on it. In case the string length is smaller than size, the target is not padded with further `NULL` bytes. In case the string length is larger than size, just `size - 1` bytes are copied and the last byte is set to `NULL`.

Examples in situ:
[search /examples](https://github.com/iovisor/bcc/search?q=bpf_probe_read_user_str+path%3Aexamples&type=Code),
[search /tools](https://github.com/iovisor/bcc/search?q=bpf_probe_read_user_str+path%3Atools&type=Code)

## Debugging

### 1. bpf_override_return()
Expand Down Expand Up @@ -1721,7 +1749,7 @@ See the "Understanding eBPF verifier messages" section in the kernel source unde

## 1. Invalid mem access

This can be due to trying to read memory directly, instead of operating on memory on the BPF stack. All memory reads must be passed via bpf_probe_read() to copy memory into the BPF stack, which can be automatic by the bcc rewriter in some cases of simple dereferencing. bpf_probe_read() does all the required checks.
This can be due to trying to read memory directly, instead of operating on memory on the BPF stack. All kernel memory reads must be passed via bpf_probe_read() to copy kernel memory into the BPF stack, which can be automatic by the bcc rewriter in some cases of simple dereferencing. bpf_probe_read() does all the required checks.

Example:

Expand Down
6 changes: 3 additions & 3 deletions docs/tutorial_bcc_python_developer.md
Original file line number Diff line number Diff line change
Expand Up @@ -556,7 +556,7 @@ int count(struct pt_regs *ctx) {
struct key_t key = {};
u64 zero = 0, *val;
bpf_probe_read(&key.c, sizeof(key.c), (void *)PT_REGS_PARM1(ctx));
bpf_probe_read_user(&key.c, sizeof(key.c), (void *)PT_REGS_PARM1(ctx));
// could also use `counts.increment(key)`
val = counts.lookup_or_try_init(&key, &zero);
if (val) {
Expand Down Expand Up @@ -620,7 +620,7 @@ int do_trace(struct pt_regs *ctx) {
uint64_t addr;
char path[128]={0};
bpf_usdt_readarg(6, ctx, &addr);
bpf_probe_read(&path, sizeof(path), (void *)addr);
bpf_probe_read_user(&path, sizeof(path), (void *)addr);
bpf_trace_printk("path:%s\\n", path);
return 0;
};
Expand All @@ -640,7 +640,7 @@ b = BPF(text=bpf_text, usdt_contexts=[u])
Things to learn:

1. ```bpf_usdt_readarg(6, ctx, &addr)```: Read the address of argument 6 from the USDT probe into ```addr```.
1. ```bpf_probe_read(&path, sizeof(path), (void *)addr)```: Now the string ```addr``` points to into our ```path``` variable.
1. ```bpf_probe_read_user(&path, sizeof(path), (void *)addr)```: Now the string ```addr``` points to into our ```path``` variable.
1. ```u = USDT(pid=int(pid))```: Initialize USDT tracing for the given PID.
1. ```u.enable_probe(probe="http__server__request", fn_name="do_trace")```: Attach our ```do_trace()``` BPF C function to the Node.js ```http__server__request``` USDT probe.
1. ```b = BPF(text=bpf_text, usdt_contexts=[u])```: Need to pass in our USDT object, ```u```, to BPF object creation.
Expand Down

0 comments on commit aa3a4a6

Please sign in to comment.