bpf, arm64: Allocate program buffer using kvcalloc instead of kcalloc
authorAijun Sun <aijun.sun@unisoc.com>
Thu, 4 Aug 2022 02:54:42 +0000 (10:54 +0800)
committerDaniel Borkmann <daniel@iogearbox.net>
Mon, 8 Aug 2022 14:42:43 +0000 (16:42 +0200)
It is not necessary to allocate contiguous physical memory for BPF
program buffer using kcalloc. When the BPF program is large more than
memory page size, kcalloc allocates multiple memory pages from buddy
system. If the device can not provide sufficient memory, for example
in low-end android devices [0], memory allocation for BPF program is
likely to fail.

Test cases in lib/test_bpf.c all pass on ARM64 QEMU.

[0]
  AndroidTestSuit: page allocation failure: order:4,
  mode:0x40dc0(GFP_KERNEL|__GFP_COMP|__GFP_ZERO), nodemask=(null),cpuset=foreground,mems_allowed=0
  Call trace:
   dump_stack+0xa4/0x114
   warn_alloc+0xf8/0x14c
   __alloc_pages_slowpath+0xac8/0xb14
   __alloc_pages_nodemask+0x194/0x3d0
   kmalloc_order_trace+0x44/0x1e8
   __kmalloc+0x29c/0x66c
   bpf_int_jit_compile+0x17c/0x568
   bpf_prog_select_runtime+0x4c/0x1b0
   bpf_prepare_filter+0x5fc/0x6bc
   bpf_prog_create_from_user+0x118/0x1c0
   seccomp_set_mode_filter+0x1c4/0x7cc
   __do_sys_prctl+0x380/0x1424
   __arm64_sys_prctl+0x20/0x2c
   el0_svc_common+0xc8/0x22c
   el0_svc_handler+0x1c/0x28
   el0_svc+0x8/0x100

Signed-off-by: Aijun Sun <aijun.sun@unisoc.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Link: https://lore.kernel.org/bpf/20220804025442.22524-1-aijun.sun@unisoc.com
arch/arm64/net/bpf_jit_comp.c

index 7ca8779..40aa3e7 100644 (file)
@@ -1496,7 +1496,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
        memset(&ctx, 0, sizeof(ctx));
        ctx.prog = prog;
 
-       ctx.offset = kcalloc(prog->len + 1, sizeof(int), GFP_KERNEL);
+       ctx.offset = kvcalloc(prog->len + 1, sizeof(int), GFP_KERNEL);
        if (ctx.offset == NULL) {
                prog = orig_prog;
                goto out_off;
@@ -1601,7 +1601,7 @@ skip_init_ctx:
                        ctx.offset[i] *= AARCH64_INSN_SIZE;
                bpf_prog_fill_jited_linfo(prog, ctx.offset + 1);
 out_off:
-               kfree(ctx.offset);
+               kvfree(ctx.offset);
                kfree(jit_data);
                prog->aux->jit_data = NULL;
        }