diff mbox series

[bpf-next,v2,1/3] bpf: Fix memleak due to fentry attach failure

Message ID 20230515130849.57502-2-laoar.shao@gmail.com (mailing list archive)
State Changes Requested
Delegated to: BPF
Headers show
Series bpf: bpf trampoline improvements | expand

Checks

Context Check Description
bpf/vmtest-bpf-next-VM_Test-33 success Logs for test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-20 success Logs for test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-15 success Logs for test_progs on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-10 success Logs for test_maps on s390x with gcc
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for bpf-next, async
netdev/fixes_present success Fixes tag not required for -next series
netdev/header_inline success No static functions without inline keyword in header files
netdev/build_32bit success Errors and warnings before: 10 this patch: 10
netdev/cc_maintainers fail 1 blamed authors not CCed: paulmck@kernel.org; 2 maintainers not CCed: martin.lau@linux.dev paulmck@kernel.org
netdev/build_clang success Errors and warnings before: 8 this patch: 8
netdev/verify_signedoff success Signed-off-by tag matches author and committer
netdev/deprecated_api success None detected
netdev/check_selftest success No net selftest shell script
netdev/verify_fixes success Fixes tag looks correct
netdev/build_allmodconfig_warn success Errors and warnings before: 10 this patch: 10
netdev/checkpatch success total: 0 errors, 0 warnings, 0 checks, 52 lines checked
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
bpf/vmtest-bpf-next-PR success PR summary
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-7 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-5 success Logs for build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-6 success Logs for build for x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-2 success Logs for build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-3 success Logs for build for aarch64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-4 success Logs for build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-8 success Logs for test_maps on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-11 success Logs for test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-12 success Logs for test_maps on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-21 success Logs for test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-22 success Logs for test_progs_no_alu32 on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-23 success Logs for test_progs_no_alu32_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-25 success Logs for test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-26 success Logs for test_progs_no_alu32_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-27 success Logs for test_progs_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-29 success Logs for test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-30 success Logs for test_progs_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-31 success Logs for test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-32 success Logs for test_verifier on aarch64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-34 success Logs for test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-35 success Logs for test_verifier on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-36 success Logs for veristat
bpf/vmtest-bpf-next-VM_Test-9 success Logs for test_maps on aarch64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-13 success Logs for test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-14 success Logs for test_progs on aarch64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-16 success Logs for test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-17 success Logs for test_progs on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-18 success Logs for test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-19 success Logs for test_progs_no_alu32 on aarch64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-24 success Logs for test_progs_no_alu32_parallel on aarch64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-28 success Logs for test_progs_parallel on aarch64 with llvm-17

Commit Message

Yafang Shao May 15, 2023, 1:08 p.m. UTC
If it fails to attach fentry, the allocated bpf trampoline image will be
left in the system. That can be verified by checking /proc/kallsyms.

This meamleak can be verified by a simple bpf program as follows,

  SEC("fentry/trap_init")
  int fentry_run()
  {
      return 0;
  }

It will fail to attach trap_init because this function is freed after
kernel init, and then we can find the trampoline image is left in the
system by checking /proc/kallsyms.
  $ tail /proc/kallsyms
  ffffffffc0613000 t bpf_trampoline_6442453466_1  [bpf]
  ffffffffc06c3000 t bpf_trampoline_6442453466_1  [bpf]

  $ bpftool btf dump file /sys/kernel/btf/vmlinux | grep "FUNC 'trap_init'"
  [2522] FUNC 'trap_init' type_id=119 linkage=static

  $ echo $((6442453466 & 0x7fffffff))
  2522

Note that there are two left bpf trampoline images, that is because the
libbpf will fallback to raw tracepoint if -EINVAL is returned.

Fixes: e21aa341785c ("bpf: Fix fexit trampoline.")
Signed-off-by: Yafang Shao <laoar.shao@gmail.com>
Cc: Song Liu <song@kernel.org>
Cc: Jiri Olsa <olsajiri@gmail.com>
---
 kernel/bpf/trampoline.c | 21 +++++++++++++++------
 1 file changed, 15 insertions(+), 6 deletions(-)

Comments

Song Liu May 15, 2023, 3:52 p.m. UTC | #1
On Mon, May 15, 2023 at 6:09 AM Yafang Shao <laoar.shao@gmail.com> wrote:
>
> If it fails to attach fentry, the allocated bpf trampoline image will be
> left in the system. That can be verified by checking /proc/kallsyms.
>
> This meamleak can be verified by a simple bpf program as follows,
>
>   SEC("fentry/trap_init")
>   int fentry_run()
>   {
>       return 0;
>   }
>
> It will fail to attach trap_init because this function is freed after
> kernel init, and then we can find the trampoline image is left in the
> system by checking /proc/kallsyms.
>   $ tail /proc/kallsyms
>   ffffffffc0613000 t bpf_trampoline_6442453466_1  [bpf]
>   ffffffffc06c3000 t bpf_trampoline_6442453466_1  [bpf]
>
>   $ bpftool btf dump file /sys/kernel/btf/vmlinux | grep "FUNC 'trap_init'"
>   [2522] FUNC 'trap_init' type_id=119 linkage=static
>
>   $ echo $((6442453466 & 0x7fffffff))
>   2522
>
> Note that there are two left bpf trampoline images, that is because the
> libbpf will fallback to raw tracepoint if -EINVAL is returned.
>
> Fixes: e21aa341785c ("bpf: Fix fexit trampoline.")
> Signed-off-by: Yafang Shao <laoar.shao@gmail.com>
> Cc: Song Liu <song@kernel.org>
> Cc: Jiri Olsa <olsajiri@gmail.com>

Acked-by: Song Liu <song@kernel.org>
Daniel Borkmann May 15, 2023, 8:17 p.m. UTC | #2
On 5/15/23 5:52 PM, Song Liu wrote:
> On Mon, May 15, 2023 at 6:09 AM Yafang Shao <laoar.shao@gmail.com> wrote:
>>
>> If it fails to attach fentry, the allocated bpf trampoline image will be
>> left in the system. That can be verified by checking /proc/kallsyms.
>>
>> This meamleak can be verified by a simple bpf program as follows,
>>
>>    SEC("fentry/trap_init")
>>    int fentry_run()
>>    {
>>        return 0;
>>    }
>>
>> It will fail to attach trap_init because this function is freed after
>> kernel init, and then we can find the trampoline image is left in the
>> system by checking /proc/kallsyms.
>>    $ tail /proc/kallsyms
>>    ffffffffc0613000 t bpf_trampoline_6442453466_1  [bpf]
>>    ffffffffc06c3000 t bpf_trampoline_6442453466_1  [bpf]
>>
>>    $ bpftool btf dump file /sys/kernel/btf/vmlinux | grep "FUNC 'trap_init'"
>>    [2522] FUNC 'trap_init' type_id=119 linkage=static
>>
>>    $ echo $((6442453466 & 0x7fffffff))
>>    2522
>>
>> Note that there are two left bpf trampoline images, that is because the
>> libbpf will fallback to raw tracepoint if -EINVAL is returned.
>>
>> Fixes: e21aa341785c ("bpf: Fix fexit trampoline.")
>> Signed-off-by: Yafang Shao <laoar.shao@gmail.com>
>> Cc: Song Liu <song@kernel.org>
>> Cc: Jiri Olsa <olsajiri@gmail.com>
> 
> Acked-by: Song Liu <song@kernel.org>

Won't this trigger a UAF for the case when progs are already running at
this address aka modify_fentry() fails where you would then also hit the
goto out_free path? This looks not correct to me.

Thanks,
Daniel
Song Liu May 15, 2023, 9:14 p.m. UTC | #3
> On May 15, 2023, at 1:17 PM, Daniel Borkmann <daniel@iogearbox.net> wrote:
> 
> On 5/15/23 5:52 PM, Song Liu wrote:
>> On Mon, May 15, 2023 at 6:09 AM Yafang Shao <laoar.shao@gmail.com> wrote:
>>> 
>>> If it fails to attach fentry, the allocated bpf trampoline image will be
>>> left in the system. That can be verified by checking /proc/kallsyms.
>>> 
>>> This meamleak can be verified by a simple bpf program as follows,
>>> 
>>>   SEC("fentry/trap_init")
>>>   int fentry_run()
>>>   {
>>>       return 0;
>>>   }
>>> 
>>> It will fail to attach trap_init because this function is freed after
>>> kernel init, and then we can find the trampoline image is left in the
>>> system by checking /proc/kallsyms.
>>>   $ tail /proc/kallsyms
>>>   ffffffffc0613000 t bpf_trampoline_6442453466_1  [bpf]
>>>   ffffffffc06c3000 t bpf_trampoline_6442453466_1  [bpf]
>>> 
>>>   $ bpftool btf dump file /sys/kernel/btf/vmlinux | grep "FUNC 'trap_init'"
>>>   [2522] FUNC 'trap_init' type_id=119 linkage=static
>>> 
>>>   $ echo $((6442453466 & 0x7fffffff))
>>>   2522
>>> 
>>> Note that there are two left bpf trampoline images, that is because the
>>> libbpf will fallback to raw tracepoint if -EINVAL is returned.
>>> 
>>> Fixes: e21aa341785c ("bpf: Fix fexit trampoline.")
>>> Signed-off-by: Yafang Shao <laoar.shao@gmail.com>
>>> Cc: Song Liu <song@kernel.org>
>>> Cc: Jiri Olsa <olsajiri@gmail.com>
>> Acked-by: Song Liu <song@kernel.org>
> 
> Won't this trigger a UAF for the case when progs are already running at
> this address aka modify_fentry() fails where you would then also hit the
> goto out_free path? This looks not correct to me.

I am not following. If modify_fentry() fails, we will not use the new 
image anywhere, no? Did I miss something?

Thanks,
Song
Daniel Borkmann May 15, 2023, 9:49 p.m. UTC | #4
On 5/15/23 11:14 PM, Song Liu wrote:
>> On May 15, 2023, at 1:17 PM, Daniel Borkmann <daniel@iogearbox.net> wrote:
>> On 5/15/23 5:52 PM, Song Liu wrote:
>>> On Mon, May 15, 2023 at 6:09 AM Yafang Shao <laoar.shao@gmail.com> wrote:
>>>>
>>>> If it fails to attach fentry, the allocated bpf trampoline image will be
>>>> left in the system. That can be verified by checking /proc/kallsyms.
>>>>
>>>> This meamleak can be verified by a simple bpf program as follows,
>>>>
>>>>    SEC("fentry/trap_init")
>>>>    int fentry_run()
>>>>    {
>>>>        return 0;
>>>>    }
>>>>
>>>> It will fail to attach trap_init because this function is freed after
>>>> kernel init, and then we can find the trampoline image is left in the
>>>> system by checking /proc/kallsyms.
>>>>    $ tail /proc/kallsyms
>>>>    ffffffffc0613000 t bpf_trampoline_6442453466_1  [bpf]
>>>>    ffffffffc06c3000 t bpf_trampoline_6442453466_1  [bpf]
>>>>
>>>>    $ bpftool btf dump file /sys/kernel/btf/vmlinux | grep "FUNC 'trap_init'"
>>>>    [2522] FUNC 'trap_init' type_id=119 linkage=static
>>>>
>>>>    $ echo $((6442453466 & 0x7fffffff))
>>>>    2522
>>>>
>>>> Note that there are two left bpf trampoline images, that is because the
>>>> libbpf will fallback to raw tracepoint if -EINVAL is returned.
>>>>
>>>> Fixes: e21aa341785c ("bpf: Fix fexit trampoline.")
>>>> Signed-off-by: Yafang Shao <laoar.shao@gmail.com>
>>>> Cc: Song Liu <song@kernel.org>
>>>> Cc: Jiri Olsa <olsajiri@gmail.com>
>>> Acked-by: Song Liu <song@kernel.org>
>>
>> Won't this trigger a UAF for the case when progs are already running at
>> this address aka modify_fentry() fails where you would then also hit the
>> goto out_free path? This looks not correct to me.
> 
> I am not following. If modify_fentry() fails, we will not use the new
> image anywhere, no? Did I miss something?

Hm, agree, I think I got confused with the again label earlier. Looks ok
indeed. Applied, thanks!
diff mbox series

Patch

diff --git a/kernel/bpf/trampoline.c b/kernel/bpf/trampoline.c
index ac021bc..2a3849c 100644
--- a/kernel/bpf/trampoline.c
+++ b/kernel/bpf/trampoline.c
@@ -251,11 +251,8 @@  static int register_fentry(struct bpf_trampoline *tr, void *new_addr)
 	return tlinks;
 }
 
-static void __bpf_tramp_image_put_deferred(struct work_struct *work)
+static void bpf_tramp_image_free(struct bpf_tramp_image *im)
 {
-	struct bpf_tramp_image *im;
-
-	im = container_of(work, struct bpf_tramp_image, work);
 	bpf_image_ksym_del(&im->ksym);
 	bpf_jit_free_exec(im->image);
 	bpf_jit_uncharge_modmem(PAGE_SIZE);
@@ -263,6 +260,14 @@  static void __bpf_tramp_image_put_deferred(struct work_struct *work)
 	kfree_rcu(im, rcu);
 }
 
+static void __bpf_tramp_image_put_deferred(struct work_struct *work)
+{
+	struct bpf_tramp_image *im;
+
+	im = container_of(work, struct bpf_tramp_image, work);
+	bpf_tramp_image_free(im);
+}
+
 /* callback, fexit step 3 or fentry step 2 */
 static void __bpf_tramp_image_put_rcu(struct rcu_head *rcu)
 {
@@ -438,7 +443,7 @@  static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut
 					  &tr->func.model, tr->flags, tlinks,
 					  tr->func.addr);
 	if (err < 0)
-		goto out;
+		goto out_free;
 
 	set_memory_rox((long)im->image, 1);
 
@@ -468,7 +473,7 @@  static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut
 	}
 #endif
 	if (err)
-		goto out;
+		goto out_free;
 
 	if (tr->cur_image)
 		bpf_tramp_image_put(tr->cur_image);
@@ -480,6 +485,10 @@  static int bpf_trampoline_update(struct bpf_trampoline *tr, bool lock_direct_mut
 		tr->flags = orig_flags;
 	kfree(tlinks);
 	return err;
+
+out_free:
+	bpf_tramp_image_free(im);
+	goto out;
 }
 
 static enum bpf_tramp_prog_type bpf_attach_type_to_tramp(struct bpf_prog *prog)