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, Nov 6, 2024 at 2:58 PM Kumar Kartikeya Dwivedi <memxor@xxxxxxxxx> wrote:
>
> 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.

After sleeping on it I think I prefer to keep the code as-is.
Removing unmask() in few error path will make it asymmetrical
and harder to reason about.
Right now it's a straightforward hack mask and unmask.
Optional unmask just begs the question... why?
Maybe something will print regs in error path...
Maybe not now, but tomorrow.

So keep it as-is. No need for follow up.





[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