Re: [PATCH bpf-next v3 1/3] bpf: Mark raw_tp arguments with PTR_MAYBE_NULL

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

 



On Wed, 6 Nov 2024 at 16:32, Andrii Nakryiko <andrii.nakryiko@xxxxxxxxx> wrote:
>
> On Mon, Nov 4, 2024 at 9:20 AM Kumar Kartikeya Dwivedi <memxor@xxxxxxxxx> wrote:
> >
> > Arguments to a raw tracepoint are tagged as trusted, which carries the
> > semantics that the pointer will be non-NULL.  However, in certain cases,
> > a raw tracepoint argument may end up being NULL. More context about this
> > issue is available in [0].
> >
> > Thus, there is a discrepancy between the reality, that raw_tp arguments
> > can actually be NULL, and the verifier's knowledge, that they are never
> > NULL, causing explicit NULL checks to be deleted, and accesses to such
> > pointers potentially crashing the kernel.
> >
> > To fix this, mark raw_tp arguments as PTR_MAYBE_NULL, and then special
> > case the dereference and pointer arithmetic to permit it, and allow
> > passing them into helpers/kfuncs; these exceptions are made for raw_tp
> > programs only. Ensure that we don't do this when ref_obj_id > 0, as in
> > that case this is an acquired object and doesn't need such adjustment.
> >
> > The reason we do mask_raw_tp_trusted_reg logic is because other will
> > recheck in places whether the register is a trusted_reg, and then
> > consider our register as untrusted when detecting the presence of the
> > PTR_MAYBE_NULL flag.
> >
> > To allow safe dereference, we enable PROBE_MEM marking when we see loads
> > into trusted pointers with PTR_MAYBE_NULL.
> >
> > While trusted raw_tp arguments can also be passed into helpers or kfuncs
> > where such broken assumption may cause issues, a future patch set will
> > tackle their case separately, as PTR_TO_BTF_ID (without PTR_TRUSTED) can
> > already be passed into helpers and causes similar problems. Thus, they
> > are left alone for now.
> >
> > It is possible that these checks also permit passing non-raw_tp args
> > that are trusted PTR_TO_BTF_ID with null marking. In such a case,
> > allowing dereference when pointer is NULL expands allowed behavior, so
> > won't regress existing programs, and the case of passing these into
> > helpers is the same as above and will be dealt with later.
> >
> > Also update the failure case in tp_btf_nullable selftest to capture the
> > new behavior, as the verifier will no longer cause an error when
> > directly dereference a raw tracepoint argument marked as __nullable.
> >
> >   [0]: https://lore.kernel.org/bpf/ZrCZS6nisraEqehw@xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
> >
> > Reviewed-by: Jiri Olsa <jolsa@xxxxxxxxxx>
> > Reported-by: Juri Lelli <juri.lelli@xxxxxxxxxx>
> > Tested-by: Juri Lelli <juri.lelli@xxxxxxxxxx>
> > Fixes: 3f00c5239344 ("bpf: Allow trusted pointers to be passed to KF_TRUSTED_ARGS kfuncs")
> > Signed-off-by: Kumar Kartikeya Dwivedi <memxor@xxxxxxxxx>
> > ---
> >  include/linux/bpf.h                           |  6 ++
> >  kernel/bpf/btf.c                              |  5 +-
> >  kernel/bpf/verifier.c                         | 79 +++++++++++++++++--
> >  .../bpf/progs/test_tp_btf_nullable.c          |  6 +-
> >  4 files changed, 87 insertions(+), 9 deletions(-)
> >
>
> [...]
>
> > @@ -12065,12 +12109,15 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
> >                         return -EINVAL;
> >                 }
> >
> > +               mask = mask_raw_tp_reg(env, reg);
> >                 if ((is_kfunc_trusted_args(meta) || is_kfunc_rcu(meta)) &&
> >                     (register_is_null(reg) || type_may_be_null(reg->type)) &&
> >                         !is_kfunc_arg_nullable(meta->btf, &args[i])) {
> >                         verbose(env, "Possibly NULL pointer passed to trusted arg%d\n", i);
> > +                       unmask_raw_tp_reg(reg, mask);
>
> Kumar,
>
> Do we really need this unmask? We are already erroring out, restoring
> reg->type is probably not very important at this point?
>

Hello Andrii,
The reason I undid the masking was to ensure if the register type is
printed for some reason,
it stays consistent and the masking isn't visible, but I guess the
verifier state is printed _before_ an instruction is symbolically
executed so it's not helping with anything.

I can send a follow up to remove the additional unmasking steps.

> [...]





[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