Messages in this thread Patch in this message | | | From | Martin Lau <> | Subject | Re: [PATCH v2] bpf: btf: Fix a missing-check bug | Date | Wed, 24 Oct 2018 18:22:46 +0000 |
| |
On Wed, Oct 24, 2018 at 05:26:23PM +0000, Martin Lau wrote: > On Wed, Oct 24, 2018 at 08:00:19AM -0500, Wenwen Wang wrote: > > In btf_parse(), the header of the user-space btf data 'btf_data' is firstly > > parsed and verified through btf_parse_hdr(). In btf_parse_hdr(), the header > > is copied from user-space 'btf_data' to kernel-space 'btf->hdr' and then > > verified. If no error happens during the verification process, the whole > > data of 'btf_data', including the header, is then copied to 'data' in > > btf_parse(). It is obvious that the header is copied twice here. More > > importantly, no check is enforced after the second copy to make sure the > > headers obtained in these two copies are same. Given that 'btf_data' > > resides in the user space, a malicious user can race to modify the header > > between these two copies. By doing so, the user can inject inconsistent > > data, which can cause undefined behavior of the kernel and introduce > > potential security risk. btw, I am working on a patch that copies the btf_data before parsing/verifying the header. That should avoid this from happening but that will require a bit more code churns for the bpf branch.
> > > > To avoid the above issue, this patch copies the parsed header from > > 'btf->hdr' to 'data'. The remaining part in 'data' is still copied from the > > user-space 'btf_data'. > LGTM. > > Acked-by: Martin KaFai Lau <kafai@fb.com> > > > > > Signed-off-by: Wenwen Wang <wang6495@umn.edu> > > --- > > kernel/bpf/btf.c | 11 ++++++++++- > > 1 file changed, 10 insertions(+), 1 deletion(-) > > > > diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c > > index 378cef7..b52a834a 100644 > > --- a/kernel/bpf/btf.c > > +++ b/kernel/bpf/btf.c > > @@ -2152,6 +2152,7 @@ static struct btf *btf_parse(void __user *btf_data, u32 btf_data_size, > > struct btf_verifier_env *env = NULL; > > struct bpf_verifier_log *log; > > struct btf *btf = NULL; > > + u32 hdr_len; > > u8 *data; > > int err; > > > > @@ -2200,7 +2201,15 @@ static struct btf *btf_parse(void __user *btf_data, u32 btf_data_size, > > btf->data_size = btf_data_size; > > btf->nohdr_data = btf->data + btf->hdr.hdr_len; > > > > - if (copy_from_user(data, btf_data, btf_data_size)) { > > + /* > > + * The header at btf_data could be modified by a malicious user > > + * after it is parsed. So we copy the parsed header here. The > > + * remaining part is still copied from btf_data. > > + */ > > + hdr_len = min_t(u32, btf->hdr.hdr_len, sizeof(btf->hdr)); > > + memcpy(data, &btf->hdr, hdr_len); > > + if (copy_from_user(data + hdr_len, (u8 __user *)btf_data + hdr_len, > > + btf_data_size - hdr_len)) { > > err = -EFAULT; > > goto errout; > > } > > -- > > 2.7.4 > >
| |