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();
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.