Message ID | 20231211112843.4147157-2-houtao@huaweicloud.com (mailing list archive) |
---|---|
State | Superseded |
Delegated to: | BPF |
Headers | show |
Series | bpf: Fix warnings in kvmalloc_node() | expand |
On Mon, Dec 11, 2023 at 07:28:40PM +0800, Hou Tao wrote: > From: Hou Tao <houtao1@huawei.com> > > An abnormally big cnt may be passed to link_create.uprobe_multi.cnt, > and it will trigger the following warning in kvmalloc_node(): > > if (unlikely(size > INT_MAX)) { > WARN_ON_ONCE(!(flags & __GFP_NOWARN)); > return NULL; > } > > Fix the warning by using __GFP_NOWARN when invoking kvzalloc() in > bpf_uprobe_multi_link_attach(). > > Fixes: 89ae89f53d20 ("bpf: Add multi uprobe link") > Reported-by: xingwei lee <xrivendell7@gmail.com> > Closes: https://lore.kernel.org/bpf/CABOYnLwwJY=yFAGie59LFsUsBAgHfroVqbzZ5edAXbFE3YiNVA@mail.gmail.com > Signed-off-by: Hou Tao <houtao1@huawei.com> Acked-by: Jiri Olsa <jolsa@kernel.org> thanks, jirka > --- > kernel/trace/bpf_trace.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c > index 774cf476a892..07b9b5896d6c 100644 > --- a/kernel/trace/bpf_trace.c > +++ b/kernel/trace/bpf_trace.c > @@ -3378,7 +3378,7 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr > err = -ENOMEM; > > link = kzalloc(sizeof(*link), GFP_KERNEL); > - uprobes = kvcalloc(cnt, sizeof(*uprobes), GFP_KERNEL); > + uprobes = kvcalloc(cnt, sizeof(*uprobes), GFP_KERNEL | __GFP_NOWARN); > > if (!uprobes || !link) > goto error_free; > -- > 2.29.2 >
On Mon, Dec 11, 2023 at 3:27 AM Hou Tao <houtao@huaweicloud.com> wrote: > > From: Hou Tao <houtao1@huawei.com> > > An abnormally big cnt may be passed to link_create.uprobe_multi.cnt, > and it will trigger the following warning in kvmalloc_node(): > > if (unlikely(size > INT_MAX)) { > WARN_ON_ONCE(!(flags & __GFP_NOWARN)); > return NULL; > } > > Fix the warning by using __GFP_NOWARN when invoking kvzalloc() in > bpf_uprobe_multi_link_attach(). > > Fixes: 89ae89f53d20 ("bpf: Add multi uprobe link") > Reported-by: xingwei lee <xrivendell7@gmail.com> > Closes: https://lore.kernel.org/bpf/CABOYnLwwJY=yFAGie59LFsUsBAgHfroVqbzZ5edAXbFE3YiNVA@mail.gmail.com > Signed-off-by: Hou Tao <houtao1@huawei.com> > --- > kernel/trace/bpf_trace.c | 2 +- > 1 file changed, 1 insertion(+), 1 deletion(-) > > diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c > index 774cf476a892..07b9b5896d6c 100644 > --- a/kernel/trace/bpf_trace.c > +++ b/kernel/trace/bpf_trace.c > @@ -3378,7 +3378,7 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr > err = -ENOMEM; > > link = kzalloc(sizeof(*link), GFP_KERNEL); > - uprobes = kvcalloc(cnt, sizeof(*uprobes), GFP_KERNEL); > + uprobes = kvcalloc(cnt, sizeof(*uprobes), GFP_KERNEL | __GFP_NOWARN); __GFP_NOWARN will hide actual malloc failures. Let's limit cnt instead. Both for k and u multi probes.
Hi, On 12/12/2023 12:50 AM, Alexei Starovoitov wrote: > On Mon, Dec 11, 2023 at 3:27 AM Hou Tao <houtao@huaweicloud.com> wrote: >> From: Hou Tao <houtao1@huawei.com> >> >> An abnormally big cnt may be passed to link_create.uprobe_multi.cnt, >> and it will trigger the following warning in kvmalloc_node(): >> >> if (unlikely(size > INT_MAX)) { >> WARN_ON_ONCE(!(flags & __GFP_NOWARN)); >> return NULL; >> } >> >> Fix the warning by using __GFP_NOWARN when invoking kvzalloc() in >> bpf_uprobe_multi_link_attach(). >> >> Fixes: 89ae89f53d20 ("bpf: Add multi uprobe link") >> Reported-by: xingwei lee <xrivendell7@gmail.com> >> Closes: https://lore.kernel.org/bpf/CABOYnLwwJY=yFAGie59LFsUsBAgHfroVqbzZ5edAXbFE3YiNVA@mail.gmail.com >> Signed-off-by: Hou Tao <houtao1@huawei.com> >> --- >> kernel/trace/bpf_trace.c | 2 +- >> 1 file changed, 1 insertion(+), 1 deletion(-) >> >> diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c >> index 774cf476a892..07b9b5896d6c 100644 >> --- a/kernel/trace/bpf_trace.c >> +++ b/kernel/trace/bpf_trace.c >> @@ -3378,7 +3378,7 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr >> err = -ENOMEM; >> >> link = kzalloc(sizeof(*link), GFP_KERNEL); >> - uprobes = kvcalloc(cnt, sizeof(*uprobes), GFP_KERNEL); >> + uprobes = kvcalloc(cnt, sizeof(*uprobes), GFP_KERNEL | __GFP_NOWARN); > __GFP_NOWARN will hide actual malloc failures. > Let's limit cnt instead. Both for k and u multi probes. Do you mean there will be no warning messages when the malloc request can not be fulfilled, right ? Because kvcalloc() will still return -ENOMEM when __GFP_NOWARN is used, so the userspace knows the malloc failed. And I also found out that __GFP_NOWARN only effect the invocation of vmalloc(), because kvmalloc_node() enable __GFP_NOWARN for kmalloc() by default when the passed size is greater than PAGE_SIZE. I also though about fixing the problem by limitation, but I could not get good reference values for these limitations. For multiple kprobe, maybe the number of kallsyms can be used as an anchor (e.g, the number is 207617 on my local dev machine), how about using __roundup_pow_of_two(207617 * 4) = 1 << 20 for multiple kprobes ? For multiple uprobes, maybe (1<<20) is also suitable.
On Tue, Dec 12, 2023 at 11:44:34AM +0800, Hou Tao wrote: > Hi, > > On 12/12/2023 12:50 AM, Alexei Starovoitov wrote: > > On Mon, Dec 11, 2023 at 3:27 AM Hou Tao <houtao@huaweicloud.com> wrote: > >> From: Hou Tao <houtao1@huawei.com> > >> > >> An abnormally big cnt may be passed to link_create.uprobe_multi.cnt, > >> and it will trigger the following warning in kvmalloc_node(): > >> > >> if (unlikely(size > INT_MAX)) { > >> WARN_ON_ONCE(!(flags & __GFP_NOWARN)); > >> return NULL; > >> } > >> > >> Fix the warning by using __GFP_NOWARN when invoking kvzalloc() in > >> bpf_uprobe_multi_link_attach(). > >> > >> Fixes: 89ae89f53d20 ("bpf: Add multi uprobe link") > >> Reported-by: xingwei lee <xrivendell7@gmail.com> > >> Closes: https://lore.kernel.org/bpf/CABOYnLwwJY=yFAGie59LFsUsBAgHfroVqbzZ5edAXbFE3YiNVA@mail.gmail.com > >> Signed-off-by: Hou Tao <houtao1@huawei.com> > >> --- > >> kernel/trace/bpf_trace.c | 2 +- > >> 1 file changed, 1 insertion(+), 1 deletion(-) > >> > >> diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c > >> index 774cf476a892..07b9b5896d6c 100644 > >> --- a/kernel/trace/bpf_trace.c > >> +++ b/kernel/trace/bpf_trace.c > >> @@ -3378,7 +3378,7 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr > >> err = -ENOMEM; > >> > >> link = kzalloc(sizeof(*link), GFP_KERNEL); > >> - uprobes = kvcalloc(cnt, sizeof(*uprobes), GFP_KERNEL); > >> + uprobes = kvcalloc(cnt, sizeof(*uprobes), GFP_KERNEL | __GFP_NOWARN); > > __GFP_NOWARN will hide actual malloc failures. > > Let's limit cnt instead. Both for k and u multi probes. > > Do you mean there will be no warning messages when the malloc request > can not be fulfilled, right ? Because kvcalloc() will still return > -ENOMEM when __GFP_NOWARN is used, so the userspace knows the malloc > failed. And I also found out that __GFP_NOWARN only effect the > invocation of vmalloc(), because kvmalloc_node() enable __GFP_NOWARN for > kmalloc() by default when the passed size is greater than PAGE_SIZE. > > I also though about fixing the problem by limitation, but I could not > get good reference values for these limitations. For multiple kprobe, > maybe the number of kallsyms can be used as an anchor (e.g, the number > is 207617 on my local dev machine), how about using > __roundup_pow_of_two(207617 * 4) = 1 << 20 for multiple kprobes ? For > multiple uprobes, maybe (1<<20) is also suitable. I think available_filter_functions is more relevant, because kallsyms has everything on fedora kernel: # cat available_filter_functions | wc -l 80177 anyway to be on the safe side with some other configs and possible huge kernel modules the '1 << 20' looks good to me, also for uprobe multi jirka
Hi, On 12/12/2023 5:54 PM, Jiri Olsa wrote: > On Tue, Dec 12, 2023 at 11:44:34AM +0800, Hou Tao wrote: >> Hi, >> >> On 12/12/2023 12:50 AM, Alexei Starovoitov wrote: >>> On Mon, Dec 11, 2023 at 3:27 AM Hou Tao <houtao@huaweicloud.com> wrote: >>>> From: Hou Tao <houtao1@huawei.com> >>>> >>>> An abnormally big cnt may be passed to link_create.uprobe_multi.cnt, >>>> and it will trigger the following warning in kvmalloc_node(): >>>> >>>> if (unlikely(size > INT_MAX)) { >>>> WARN_ON_ONCE(!(flags & __GFP_NOWARN)); >>>> return NULL; >>>> } >>>> >>>> Fix the warning by using __GFP_NOWARN when invoking kvzalloc() in >>>> bpf_uprobe_multi_link_attach(). >>>> >>>> Fixes: 89ae89f53d20 ("bpf: Add multi uprobe link") >>>> Reported-by: xingwei lee <xrivendell7@gmail.com> >>>> Closes: https://lore.kernel.org/bpf/CABOYnLwwJY=yFAGie59LFsUsBAgHfroVqbzZ5edAXbFE3YiNVA@mail.gmail.com >>>> Signed-off-by: Hou Tao <houtao1@huawei.com> >>>> --- >>>> kernel/trace/bpf_trace.c | 2 +- >>>> 1 file changed, 1 insertion(+), 1 deletion(-) >>>> >>>> diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c >>>> index 774cf476a892..07b9b5896d6c 100644 >>>> --- a/kernel/trace/bpf_trace.c >>>> +++ b/kernel/trace/bpf_trace.c >>>> @@ -3378,7 +3378,7 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr >>>> err = -ENOMEM; >>>> >>>> link = kzalloc(sizeof(*link), GFP_KERNEL); >>>> - uprobes = kvcalloc(cnt, sizeof(*uprobes), GFP_KERNEL); >>>> + uprobes = kvcalloc(cnt, sizeof(*uprobes), GFP_KERNEL | __GFP_NOWARN); >>> __GFP_NOWARN will hide actual malloc failures. >>> Let's limit cnt instead. Both for k and u multi probes. >> Do you mean there will be no warning messages when the malloc request >> can not be fulfilled, right ? Because kvcalloc() will still return >> -ENOMEM when __GFP_NOWARN is used, so the userspace knows the malloc >> failed. And I also found out that __GFP_NOWARN only effect the >> invocation of vmalloc(), because kvmalloc_node() enable __GFP_NOWARN for >> kmalloc() by default when the passed size is greater than PAGE_SIZE. >> >> I also though about fixing the problem by limitation, but I could not >> get good reference values for these limitations. For multiple kprobe, >> maybe the number of kallsyms can be used as an anchor (e.g, the number >> is 207617 on my local dev machine), how about using >> __roundup_pow_of_two(207617 * 4) = 1 << 20 for multiple kprobes ? For >> multiple uprobes, maybe (1<<20) is also suitable. > I think available_filter_functions is more relevant, because kallsyms > has everything > > on fedora kernel: > # cat available_filter_functions | wc -l > 80177 Agreed. Only functions in available_filter_functions could use kprobe. > > anyway to be on the safe side with some other configs and possible > huge kernel modules the '1 << 20' looks good to me, also for uprobe > multi Thanks. Will post v2 if Alexei is also fine with such limitations. > > jirka
On Tue, Dec 12, 2023 at 6:06 AM Hou Tao <houtao@huaweicloud.com> wrote: > > > anyway to be on the safe side with some other configs and possible > > huge kernel modules the '1 << 20' looks good to me, also for uprobe > > multi > > Thanks. Will post v2 if Alexei is also fine with such limitations. Yeah. The limit looks fine. > >> can not be fulfilled, right ? Because kvcalloc() will still return > >> -ENOMEM when __GFP_NOWARN is used, so the userspace knows the malloc > >> failed. And I also found out that __GFP_NOWARN only effect the > >> invocation of vmalloc(), because kvmalloc_node() enable __GFP_NOWARN for > >> kmalloc() by default when the passed size is greater than PAGE_SIZE. Right, because kmalloc of more than a page will likely fail. But vmalloc() may fail for all kinds of other reasons. Suppressing them all prevents those messages appearing in the future. The warn is there by default, so that users think about memory allocations they request. So it served its exact purpose. Just returning ENOMEM to user space would have been unnoticed and cnt > INT_MAX would continue to be acceptable which potentially opens up DoS, and other abuse.
diff --git a/kernel/trace/bpf_trace.c b/kernel/trace/bpf_trace.c index 774cf476a892..07b9b5896d6c 100644 --- a/kernel/trace/bpf_trace.c +++ b/kernel/trace/bpf_trace.c @@ -3378,7 +3378,7 @@ int bpf_uprobe_multi_link_attach(const union bpf_attr *attr, struct bpf_prog *pr err = -ENOMEM; link = kzalloc(sizeof(*link), GFP_KERNEL); - uprobes = kvcalloc(cnt, sizeof(*uprobes), GFP_KERNEL); + uprobes = kvcalloc(cnt, sizeof(*uprobes), GFP_KERNEL | __GFP_NOWARN); if (!uprobes || !link) goto error_free;