Re: [QUESTION] Check PTR_UNTRUSTED usage in sleepable eBPF iterators

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Sat, 13 Jul 2024 at 18:45, andrea terzolo <andreaterzolo3@xxxxxxxxx> wrote:
>
> Hi folks! I would like to check with you if the verifier failure I'm
> facing is expected. The verifier rejects the following eBPF program in
> recent kernel versions (e.g. 6.8.0-1010-aws). The same program
> correctly works on older kernel versions (e.g. 6.5.0-41-generic) so
> it's unclear to me why now the verifier should reject it.
>
> ```
> #define EXE_PATH_MAX_LEN 512
> char exe_path[EXE_PATH_MAX_LEN];
>
> SEC("iter.s/task")
> int dump_task(struct bpf_iter__task *ctx) {
>   struct task_struct *task = ctx->task;
>
>   if (task == NULL) {
>     return 0;
>   }
>
>   struct file *exe_file = task->mm->exe_file;
>   if (exe_file != NULL) {
>     bpf_d_path(&(exe_file->f_path), exe_path, EXE_PATH_MAX_LEN);
>     bpf_printk("exe path: %s", exe_path);
>   }
>   return 0;
> }
> ```
>
> Verifier log
>
> ```
> -- BEGIN PROG LOAD LOG --
> 0: R1=ctx() R10=fp0
> ; struct task_struct *task = ctx->task;
> 0: (79) r1 = *(u64 *)(r1 +8)          ;
> R1_w=trusted_ptr_or_null_task_struct(id=1)
> ; if (task == NULL) {
> 1: (15) if r1 == 0x0 goto pc+15       ; R1_w=trusted_ptr_task_struct()
> ; struct file *exe_file = task->mm->exe_file;
> 2: (79) r1 = *(u64 *)(r1 +2264)       ; R1_w=untrusted_ptr_mm_struct()
> ; struct file *exe_file = task->mm->exe_file;
> 3: (79) r1 = *(u64 *)(r1 +1176)       ; R1_w=untrusted_ptr_file()
> ; if (exe_file != NULL) {
> 4: (15) if r1 == 0x0 goto pc+12       ; R1_w=untrusted_ptr_file()
> 5: (b7) r2 = 152                      ; R2_w=152
> 6: (0f) r1 += r2                      ;
> R1_w=untrusted_ptr_file(off=152) R2_w=152
> ; bpf_d_path(&(exe_file->f_path), exe_path, EXE_PATH_MAX_LEN);
> 7: (18) r2 = 0xffffa839013ee000       ;
> R2_w=map_value(map=bpf_iter.bss,ks=4,vs=528)
> 9: (b7) r3 = 512                      ; R3_w=512
> 10: (85) call bpf_d_path#147
> R1 type=untrusted_ptr_ expected=ptr_, trusted_ptr_, rcu_ptr_
> processed 10 insns (limit 1000000) max_states_per_insn 0 total_states
> 0 peak_states 0 mark_read 0
> -- END PROG LOAD LOG --
> ```
>
> From what I understand, as soon as we dereference the `struct
> task_struct *task` pointer inside an RCU CS we obtain an untrusted
> pointer (e.g. after `task->mm` we already have an untrusted pointer).
>
Sorry, here I meant "outside an RCU CS" instead of "inside".
>
> This causes the `bpf_d_path` helper to fail because it receives an
> `untrusted_ptr_file`. In this case, I marked the eBPF program as
> sleepable on purpose, to trigger the failure. If I use a not-sleepable
> bpf iterator the `bpf_d_path` helper correctly receives a
> `PTR_TO_BTF_ID` and everything works fine.
>
Ok, I checked the code, and the reason seems that all non-sleepable
eBPF programs are always contained in an RCU CS. So the `in_rcu_cs`
method always returns `true`.
To emulate the same behavior in a sleepable program we need to
explicitly add an RCU CS.

```
#define EXE_PATH_MAX_LEN 512
char exe_path[EXE_PATH_MAX_LEN];

extern void bpf_rcu_read_lock(void) __ksym;
extern void bpf_rcu_read_unlock(void) __ksym;

SEC("iter.s/task")
int dump_task(struct bpf_iter__task *ctx) {
  struct task_struct *task = ctx->task;

  if (task == NULL) {
    return 0;
  }
  bpf_rcu_read_lock();
  struct file *exe_file = task->mm->exe_file;
  if (exe_file != NULL) {
    bpf_d_path(&(exe_file->f_path), exe_path, EXE_PATH_MAX_LEN);
    bpf_printk("exe path: %s", exe_path);
  }
  bpf_rcu_read_unlock();

  return 0;
}
```
>
> I'm wondering if this is the expected behavior and if so, how can I
> continue to use the `bpf_d_path` helper inside this sleepable ebpf
> program? Is there a way to obtain again a `PTR_TO_BTF_ID` for
> `&(exe_file->f_path)` to satisfy the `bpf_d_path` signature?

So what has changed is that now in sleepable progs we explicitly need
to create RCU CS when we dereference trusted pointers if we want to
preserve `PTR_TO_BTF_ID` pointers




[Index of Archives]     [Linux Samsung SoC]     [Linux Rockchip SoC]     [Linux Actions SoC]     [Linux for Synopsys ARC Processors]     [Linux NFS]     [Linux NILFS]     [Linux USB Devel]     [Video for Linux]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]


  Powered by Linux