The kernel needs to a constant offset from the stack for write. The
corresponding kernel verifier code below:
/* stack accesses must be at a fixed offset, so that we can
* determine what type of data were returned.
* See check_stack_read().
*/
if (!tnum_is_const(reg->var_off)) {
char tn_buf[48];
tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
verbose(env, "variable stack access var_off=%s
off=%d size=%d",
tn_buf, off, size);
return -EACCES;
}
You can initialize the array with ' ' to workaround the issue:
struct data_t data;
uint64_t max = sizeof(data.argv);
const char *argp = NULL;
memset(&data, ' ', sizeof(data));
bpf_probe_read(&argp, sizeof(argp), (void *)&__argv[0]);
uint64_t len = bpf_probe_read_str(&data.argv, max, argp);
len &= 0xffffffff; // to avoid: "math between fp pointer and register errs"
bpf_trace_printk("len: %d\\n", len); // sanity check: len is indeed valid
// data.argv[len] = ' ';
On Sun, Jul 1, 2018 at 6:20 PM, Teng Qin <[email protected]> wrote:
> Firstly, note that bpf_probe_read_str adds an extra \0 to the read string.
> So your max should be sizeof(data.argv) - 1 instead in order for
> data.argv[len] = ' ' to work (from Verifier's perspective, logically you
> don't need that extra delimiter~)
>
> Then, Yonghong had a patch a few month ago addressing very similar issue.
> See the example in patch series
> bpf: improve verifier ARG_CONST_SIZE_OR_ZERO semantics
> Does your Kernel have those patches?
>
> However, even with all those the data.argv[len] = ' ' part still fails with
> something about stack offset not being fixed. I will try debug more to see
> how to fix that. For now, you can use a per-CPU array of size 1 for the data
> instead of allocating it on the stack. The following works for me:
> #include <uapi/linux/ptrace.h>
> #include <linux/sched.h>
> #include <linux/fs.h>
>
> #define ARGSIZE 128
>
> struct data_t {
> char argv[ARGSIZE];
> };
>
> BPF_PERF_OUTPUT(events);
> BPF_PERCPU_ARRAY(mem, struct data_t, 1);
> //
> // Here's what I'm trying to do. Let's say this has:
> // __argv[0] = "ls"
> // __argv[1] = "-l"
> // I'm trying to create a buffer with "ls -l", by doing bpf_probe_read_str()
> for
> // each element into the buffer, while keeping track of the length of
> // the previous read so I can insert a space delimiter at that offset,
> // and begin the next read after the delimiter.
> //
> int on_event(struct pt_regs *ctx,
> const char __user *filename,
> const char __user *const __user *__argv,
> const char __user *const __user *__envp)
> {
> int zero = 0;
> struct data_t* data = mem.lookup(&zero);
> if (!data)
> return 0;
>
> uint64_t max = sizeof(data->argv) - 1;
> const char *argp = NULL;
> bpf_probe_read(&argp, sizeof(argp), (void *)&__argv[0]);
> uint64_t len = bpf_probe_read_str(&(data->argv), max, argp);
> len &= 0xffffffff; // to avoid: "math between fp pointer and register
> errs"
> bpf_trace_printk("len: %d\\n", len); // sanity check: len is indeed
> valid
>
> data->argv[len] = ' ';
>
> events.perf_submit(ctx, data, len);
> out:
> return 0;
> }
>
-=-=-=-=-=-=-=-=-=-=-=-
Links: You receive all messages sent to this group.
View/Reply Online (#1385): https://lists.iovisor.org/g/iovisor-dev/message/1385
Mute This Topic: https://lists.iovisor.org/mt/22908709/21656
Group Owner: [email protected]
Unsubscribe: https://lists.iovisor.org/g/iovisor-dev/unsub
[[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-