Re: [PATCH bpf-next v3 6/9] bpf, arm64: Fix memory leak in bpf_jit_free
Pu Lehui <[email protected]>
| Newsgroups | dev.linux.lists.sashiko-reviews,org.kernel.vger.bpf |
|---|---|
| Message-ID | <[email protected]> |
On 2026/7/26 0:01, [email protected] wrote: > Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider: > > Pre-existing issues: > - [Critical] `bpf_jit_free()` ignores the return value of `bpf_jit_binary_pack_finalize()`, leading to a Use-After-Free and Double Free if finalization fails. > - [High] Pre-existing percpu memory leak of `priv_stack_ptr` on BPF JIT compilation failure. > - [High] The identical memory leak of `ctx.offset` fixed by this patch in ARM64 remains unfixed in the LoongArch BPF JIT compiler. > -- > > --- Patch [6]: [PATCH bpf-next v3 6/9] bpf, arm64: Fix memory leak in bpf_jit_free --- > commit c1be108f68505531829d01d1fddc5f23ead947da > Author: Pu Lehui <[email protected]> > > bpf, arm64: Fix memory leak in bpf_jit_free > > When JIT compilation fails for a subprogram, the BPF core cleans up > previously compiled subprograms by calling bpf_jit_free(). This commit adds > a missing kvfree(jit_data->ctx.offset) to bpf_jit_free() in ARM64, > preventing a memory leak of the JIT context offsets array. > >> diff --git a/arch/arm64/net/bpf_jit_comp.c b/arch/arm64/net/bpf_jit_comp.c >> index 4cdc7dfb05ba9..f4e4d4578e38a 100644 >> --- a/arch/arm64/net/bpf_jit_comp.c >> +++ b/arch/arm64/net/bpf_jit_comp.c >> @@ -3237,6 +3237,7 @@ void bpf_jit_free(struct bpf_prog *prog) > > [Severity: High] > This isn't a bug introduced by this patch, but is there a pre-existing > percpu memory leak of priv_stack_ptr when JIT compilation fails? > > Looking at bpf_int_jit_compile() when build_body() fails, out_free_hdr frees > ro_header but does not set it to NULL. In the out_off block: > > arch/arm64/net/bpf_jit_comp.c:bpf_int_jit_compile() { > ... > if (!ro_header && priv_stack_ptr) { > free_percpu(priv_stack_ptr); > prog->aux->priv_stack_ptr = NULL; > } > ... > } patch 7 has been covered this. > > Because ro_header is a dangling pointer, this check evaluates to false, > skipping the free. Later, when the BPF core aborts and calls > bpf_jit_free(prog), prog->jited is 0: > > arch/arm64/net/bpf_jit_comp.c:bpf_jit_free() { > if (prog->jited) { > ... > } > ... > } > > This skips the cleanup block entirely, leaving priv_stack_ptr permanently > leaked. Would it be appropriate to address this as well? > >> */ >> if (jit_data) { >> bpf_jit_binary_pack_finalize(jit_data->ro_header, jit_data->header); > > [Severity: Critical] > This is a pre-existing issue, but could ignoring the return value of > bpf_jit_binary_pack_finalize() here lead to a use-after-free and double free? > > If bpf_arch_text_copy() fails during finalization, > bpf_jit_binary_pack_finalize() frees the ro_header internally and returns an > error: patch 9 has been covered this. > > kernel/bpf/core.c:bpf_jit_binary_pack_finalize() { > ... > if (IS_ERR(ptr)) { > bpf_prog_pack_free(ro_header, ro_header->size); > return PTR_ERR(ptr); > } > ... > } > > Since bpf_jit_free() ignores this error, it proceeds to retrieve the freed > header and unconditionally frees it again: > > arch/arm64/net/bpf_jit_comp.c:bpf_jit_free() { > ... > prog->bpf_func = (void *)prog->bpf_func - cfi_get_offset(); > hdr = bpf_jit_binary_pack_hdr(prog); > bpf_jit_binary_pack_free(hdr, NULL); > } > > Inside bpf_jit_binary_pack_free(), it reads ro_header->size (use-after-free) > and calls bpf_prog_pack_free() on it again (double free). Can this cause > memory corruption? > >> + kvfree(jit_data->ctx.offset); > > [Severity: High] > This isn't a bug introduced by this patch, but does the LoongArch BPF JIT > compiler suffer from this exact same memory leak? bugfix has been applied to loongarch tree. https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git/commit/?h=next-20260726&id=47e20d4b3da97ef3881d1e55e43545c22424f3fc > > Looking at the LoongArch implementation, it uses the same multi-pass logic > for subprograms and preserves ctx.offset in jit_data. However, its > bpf_jit_free() does not free ctx.offset: > > arch/loongarch/net/bpf_jit.c:bpf_jit_free() { > ... > if (jit_data) { > bpf_jit_binary_pack_finalize(jit_data->ro_header, jit_data->header); > kfree(jit_data); > } > ... > } > > Should a similar kvfree() be added to arch/loongarch/net/bpf_jit.c? > >> kfree(jit_data); >> } >> prog->bpf_func = (void *)prog->bpf_func - cfi_get_offset(); >