Re: [PATCH bpf v1 0/5] More fixes for crashes due to bad PTR_TO_BTF_ID reg->off

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

 



On Sat, Feb 19, 2022 at 05:40:35PM +0530, Kumar Kartikeya Dwivedi wrote:
> On Sat, Feb 19, 2022 at 05:07:39PM IST, Kumar Kartikeya Dwivedi wrote:
> > A few more fixes for bad PTR_TO_BTF_ID reg->off being accepted in places, that
> > can lead to the kernel crashing. Noticed while making sure my own series for BTF
> > ID pointer in map won't allow stores for pointers with incorrect offsets.
> >
> > I include one example where d_path can crash even if you NULL check
> > PTR_TO_BTF_ID, and one example of how missing NULL check in helper taking
> > PTR_TO_BTF_ID (like bpf_sock_from_file) is a real problem, see the selftest
> > patch.
> >
> > The &f->f_path becomes NULL + offset in case f is NULL, circumventing NULL
> > checks in existing helpers. The only thing needed to trigger this finding an
> > object that embeds the object of interest, and then somehow obtaining a NULL
> > PTR_TO_BTF_ID to it (not hard, esp. due to exception handler for PROBE_MEM loads
> > writing 0 to destination register).
> >
> > However, for the case of patch 2, it is allowed in my series since the next load
> > of the bad pointer stored using:
> >   struct file *f = ...; // some pointer walking returning NULL pointer
> >   map_val->ptr = &f->f_path; // ptr being struct path *
> > ... would be marked as PTR_UNTRUSTED, so it won't be allowed to be passed into
> > the kernel, and hence can be permitted. In referenced case, the PTR_TO_BTF_ID
> > should not be NULL anyway. kptr_get style helper takes PTR_TO_MAP_VALUE in
> > referenced ptr case only, so the load either yields NULL or RCU protected
> > pointer.
> >
> > Tests for patch 1 depend on fixup_kfunc_btf_id in test_verifier, hence will be
> > sent after merge window opens, some other changes after bpf tree merges into
> > bpf-next, but all pending ones can be seen here [0]. Tests for patch 2 are
> > included, and try to trigger crash without the fix, but it's not 100% reliable.
> > We may need special testing helpers or kfuncs to make it thorough, but wanted to
> > wait before getting feedback.
> >
> > Issue fixed by patch 2 is a bit more broader in scope, and would require proper
> > discussion (before being applied) on the correct way forward, as it is
> > technically backwards incompatible change, but hopefully never breaks real
> > programs, only malicious or already incorrect ones.
> >
> > Also, please suggest the right "Fixes" tag for patch 2.
> >
> > As for patch 3 (selftest), please suggest a better way to get a certain type of
> > PTR_TO_BTF_ID which can be NULL or NULL+offset. Can we add kfuncs for testing
> > that return such pointers and make them available to e.g. TC progs, if the fix
> > in patch 2 is acceptable?
> >
> >   [0]: https://github.com/kkdwivedi/linux/commits/fixes-bpf-next
> >
> 
> Looking at BPF CI [1], it seems it surfaces another problem I was seeing locally
> but couldn't craft a reliable test case for, that it forms a non-NULL but
> invalid pointer using pointer walking, in some cases RCU read lock provides
> protection for those cases, but not all (esp. if kernel doesn't clear the old
> pointer that was in use before, and has it sitting in some location). RDI (arg1)
> seems to be pointing somewhere behind the faulting address, which means the
> &f->f_path is bad.
> 
> But this requires a larger discussion.
> 
> In that case, PAGE_SIZE thing won't help. We may have to introduce a PTR_BPF_REF
> flag (e.g. set for ctx args of tracing progs, set based on BTF tagging in other
> places) which tells the verifier that the pointer for the duration of program
> will be valid, so it can be passed into helpers.
> 
> So for cases like &f->f_path it will work, since file + off will still have
> PTR_BPF_REF set in reg state. In case of pointer walking, where dst_reg state
> is updated on walk, we may have to explicitly tag members where PTR_BPF_REF can
> be inherited if parent object has PTR_BPF_REF (i.e. ref to parent implies ref to
> child cases).
> 
> Something like:
> 
> struct foo {
> 	...
> 	struct bar __bpf_ref *p;
> 	struct baz *q;
> 	...
> }
> 
> ... then if getting:
> 
> 	struct foo *f = ...; // PTR_TO_BTF_ID | PTR_BPF_REF
> 	struct bar *p = f->p; // Inherits PTR_BPF_REF
> 	struct baz *q = f->q; // Does not inherit PTR_BPF_REF
> 
> Thoughts?
> 
>   [1]: https://github.com/kernel-patches/bpf/runs/5258413028?check_suite_focus=true

fd_array wasn't zero initialized at alloc time, so it contains garbage.
fd_array[63] read that garbage.
So patches 2 and 3 don't help.
The 'fixes' list for patch 3 is ridiculous. No need.
Pls drop patch 2 and in instead of
+#define bpf_ptr_is_invalid(p) (unlikely((unsigned long)(p) < PAGE_SIZE))
do static inline function that checks
if ((unsigned long)p < user_addr_max())
and bails out.
bpf-next is fine.
Not sure whether patch 1 is strictly necessary after above change.



[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