Re: [RFC PATCH bpf-next v1 1/2] bpf: Explore PTR_TO_STACK as R0 for bpf_dynptr_slice_rdwr

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

 



On Wed, 19 Feb 2025 at 13:51, Kumar Kartikeya Dwivedi <memxor@xxxxxxxxx> wrote:
>
> For the bpf_dynptr_slice_rdwr kfunc, the verifier may return a pointer
> to the underlying packet (if the requested slice is linear), or copy out
> the data to the buffer passed into the kfunc. The verifier performs
> symbolic execution assuming the returned value is a PTR_TO_MEM of a
> certain size (passed into the kfunc), and ensures reads and writes are
> within bounds.
>
> A complication arises when the passed in buffer is a stack pointer. The
> returned pointer may be used to perform writes (unlike bpf_dynptr_slice),
> but the verifier will be unaware of which stack slots such writes may
> end up overwriting. As such, a program may end up overwriting stack data
> (such as spilled pointers) through such return values by accident, which
> may cause undefined behavior.
>
> Fix this by exploring an additional path whenever the passed in argument
> is a PTR_TO_STACK, and explore a path where the returned buffer is the
> same as this stack pointer. This allows us to ensure that the program
> doesn't introduce unsafe behavior when this condition is triggered at
> runtime.
>
> The push_stack() call is performed after kfunc processing is over,
> simply fixing up the return type to PTR_TO_STACK with proper frameno,
> off, and var_off.
>
> Fixes: 66e3a13e7c2c ("bpf: Add bpf_dynptr_slice and bpf_dynptr_slice_rdwr")
> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@xxxxxxxxx>
> ---
>  [...]
>         }
>
> +       /* Push a state for exploration where the returned buffer is pointing to
> +        * the stack buffer passed into bpf_dynptr_slice_rdwr, otherwise we
> +        * cannot see writes to the stack solely through marking it as
> +        * PTR_TO_MEM. We don't do the same for bpf_dynptr_slice, because the
> +        * returned pointer is MEM_RDONLY, hence cannot be used to write to the
> +        * stack.
> +        */
> +       if (!insn->off && meta.arg_stack.found &&
> +           insn->imm == special_kfunc_list[KF_bpf_dynptr_slice_rdwr]) {
> +               struct bpf_verifier_state *branch;
> +               struct bpf_reg_state *regs, *r0;
> +
> +               branch = push_stack(env, env->insn_idx + 1, env->insn_idx, false);
> +               if (!branch) {
> +                       verbose(env, "failed to push state to explore stack buffer in r0\n");
> +                       return -ENOMEM;
> +               }
> +
> +               regs = branch->frame[branch->curframe]->regs;
> +               r0 = &regs[BPF_REG_0];
> +
> +               r0->type = PTR_TO_STACK;

I forgot to fold in a hunk.
This needs to be marked PTR_MAYBE_NULL (preserve the set reg->id).

> [...]
>




[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