diff mbox series

[bpf-next,v1,05/10] arch/x86: Implement arch_bpf_stack_walk

Message ID 20230713023232.1411523-6-memxor@gmail.com (mailing list archive)
State Changes Requested
Delegated to: BPF
Headers show
Series Exceptions - 1/2 | expand

Checks

Context Check Description
bpf/vmtest-bpf-next-VM_Test-26 success Logs for test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-12 fail Logs for test_progs on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-16 fail Logs for test_progs_no_alu32 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: 1317 this patch: 1317
netdev/cc_maintainers warning 16 maintainers not CCed: tglx@linutronix.de hpa@zytor.com dsahern@kernel.org mingo@redhat.com kpsingh@kernel.org x86@kernel.org john.fastabend@gmail.com sdf@google.com yhs@fb.com netdev@vger.kernel.org song@kernel.org dave.hansen@linux.intel.com davem@davemloft.net jolsa@kernel.org haoluo@google.com bp@alien8.de
netdev/build_clang fail Errors and warnings before: 159 this patch: 156
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 No Fixes tag
netdev/build_allmodconfig_warn success Errors and warnings before: 1330 this patch: 1330
netdev/checkpatch warning WARNING: line length of 103 exceeds 80 columns WARNING: line length of 90 exceeds 80 columns WARNING: line length of 92 exceeds 80 columns WARNING: line length of 96 exceeds 80 columns WARNING: line length of 97 exceeds 80 columns
netdev/kdoc success Errors and warnings before: 0 this patch: 0
netdev/source_inline success Was 0 now: 0
bpf/vmtest-bpf-next-VM_Test-9 success Logs for test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-19 success Logs for test_progs_no_alu32_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-20 success Logs for test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-22 success Logs for test_progs_parallel on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-23 success Logs for test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-25 success Logs for test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-27 success Logs for test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-29 success Logs for veristat
bpf/vmtest-bpf-next-VM_Test-10 success Logs for test_maps on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-11 fail Logs for test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-13 success Logs for test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-14 success Logs for test_progs on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-15 fail Logs for test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-17 success Logs for test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-18 success Logs for test_progs_no_alu32 on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-21 success Logs for test_progs_no_alu32_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-24 success Logs for test_progs_parallel on x86_64 with llvm-16
bpf/vmtest-bpf-next-VM_Test-28 success Logs for test_verifier on x86_64 with llvm-16
bpf/vmtest-bpf-next-PR fail PR summary
bpf/vmtest-bpf-next-VM_Test-1 success Logs for ${{ matrix.test }} on ${{ matrix.arch }} with ${{ matrix.toolchain_full }}
bpf/vmtest-bpf-next-VM_Test-2 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-3 success Logs for build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-4 fail Logs for build for s390x with gcc
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-7 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-8 success Logs for veristat

Commit Message

Kumar Kartikeya Dwivedi July 13, 2023, 2:32 a.m. UTC
The plumbing for offline unwinding when we throw an exception in
programs would require walking the stack, hence introduce a new
arch_bpf_stack_walk function. This is provided when the JIT supports
exceptions, i.e. bpf_jit_supports_exceptions is true. The arch-specific
code is really minimal, hence it should straightforward to extend this
support to other architectures as well, as it reuses the logic of
arch_stack_walk, but allowing access to unwind_state data.

Once the stack pointer and frame pointer are known for the main subprog
during the unwinding, we know the stack layout and location of any
callee-saved registers which must be restored before we return back to
the kernel.

This handling will be added in the next patch.

Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
---
 arch/x86/net/bpf_jit_comp.c | 21 +++++++++++++++++++++
 include/linux/filter.h      |  2 ++
 kernel/bpf/core.c           |  9 +++++++++
 3 files changed, 32 insertions(+)

Comments

Alexei Starovoitov July 14, 2023, 10:05 p.m. UTC | #1
On Thu, Jul 13, 2023 at 08:02:27AM +0530, Kumar Kartikeya Dwivedi wrote:
> The plumbing for offline unwinding when we throw an exception in
> programs would require walking the stack, hence introduce a new
> arch_bpf_stack_walk function. This is provided when the JIT supports
> exceptions, i.e. bpf_jit_supports_exceptions is true. The arch-specific
> code is really minimal, hence it should straightforward to extend this
> support to other architectures as well, as it reuses the logic of
> arch_stack_walk, but allowing access to unwind_state data.
> 
> Once the stack pointer and frame pointer are known for the main subprog
> during the unwinding, we know the stack layout and location of any
> callee-saved registers which must be restored before we return back to
> the kernel.
> 
> This handling will be added in the next patch.
> 
> Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
> ---
>  arch/x86/net/bpf_jit_comp.c | 21 +++++++++++++++++++++
>  include/linux/filter.h      |  2 ++
>  kernel/bpf/core.c           |  9 +++++++++
>  3 files changed, 32 insertions(+)
> 
> diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
> index 438adb695daa..d326503ce242 100644
> --- a/arch/x86/net/bpf_jit_comp.c
> +++ b/arch/x86/net/bpf_jit_comp.c
> @@ -16,6 +16,7 @@
>  #include <asm/set_memory.h>
>  #include <asm/nospec-branch.h>
>  #include <asm/text-patching.h>
> +#include <asm/unwind.h>
>  
>  static u8 *emit_code(u8 *ptr, u32 bytes, unsigned int len)
>  {
> @@ -2660,3 +2661,23 @@ void bpf_jit_free(struct bpf_prog *prog)
>  
>  	bpf_prog_unlock_free(prog);
>  }
> +
> +bool bpf_jit_supports_exceptions(void)
> +{
> +	return IS_ENABLED(CONFIG_UNWINDER_ORC) || IS_ENABLED(CONFIG_UNWINDER_FRAME_POINTER);
> +}
> +
> +void arch_bpf_stack_walk(bool (*consume_fn)(void *cookie, u64 ip, u64 sp, u64 bp), void *cookie)
> +{
> +#if defined(CONFIG_UNWINDER_ORC) || defined(CONFIG_UNWINDER_FRAME_POINTER)
> +	struct unwind_state state;
> +	unsigned long addr;
> +
> +	for (unwind_start(&state, current, NULL, NULL); !unwind_done(&state);
> +	     unwind_next_frame(&state)) {
> +		addr = unwind_get_return_address(&state);

I think these steps will work even with UNWINDER_GUESS.
What is the reason for #ifdef ?

> +		if (!addr || !consume_fn(cookie, (u64)addr, (u64)state.sp, (u64)state.bp))
> +			break;
> +	}
> +#endif
> +}
> diff --git a/include/linux/filter.h b/include/linux/filter.h
> index f69114083ec7..21ac801330bb 100644
> --- a/include/linux/filter.h
> +++ b/include/linux/filter.h
> @@ -920,6 +920,8 @@ bool bpf_jit_needs_zext(void);
>  bool bpf_jit_supports_subprog_tailcalls(void);
>  bool bpf_jit_supports_kfunc_call(void);
>  bool bpf_jit_supports_far_kfunc_call(void);
> +bool bpf_jit_supports_exceptions(void);
> +void arch_bpf_stack_walk(bool (*consume_fn)(void *cookie, u64 ip, u64 sp, u64 bp), void *cookie);
>  bool bpf_helper_changes_pkt_data(void *func);
>  
>  static inline bool bpf_dump_raw_ok(const struct cred *cred)
> diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> index 5c484b2bc3d6..5e224cf0ec27 100644
> --- a/kernel/bpf/core.c
> +++ b/kernel/bpf/core.c
> @@ -2770,6 +2770,15 @@ int __weak bpf_arch_text_invalidate(void *dst, size_t len)
>  	return -ENOTSUPP;
>  }
>  
> +bool __weak bpf_jit_supports_exceptions(void)
> +{
> +	return false;
> +}
> +
> +void __weak arch_bpf_stack_walk(bool (*consume_fn)(void *cookie, u64 ip, u64 sp, u64 bp), void *cookie)
> +{
> +}
> +
>  #ifdef CONFIG_BPF_SYSCALL
>  static int __init bpf_global_ma_init(void)
>  {
> -- 
> 2.40.1
>
Kumar Kartikeya Dwivedi July 17, 2023, 4:29 p.m. UTC | #2
On Sat, 15 Jul 2023 at 03:35, Alexei Starovoitov
<alexei.starovoitov@gmail.com> wrote:
>
> On Thu, Jul 13, 2023 at 08:02:27AM +0530, Kumar Kartikeya Dwivedi wrote:
> > The plumbing for offline unwinding when we throw an exception in
> > programs would require walking the stack, hence introduce a new
> > arch_bpf_stack_walk function. This is provided when the JIT supports
> > exceptions, i.e. bpf_jit_supports_exceptions is true. The arch-specific
> > code is really minimal, hence it should straightforward to extend this
> > support to other architectures as well, as it reuses the logic of
> > arch_stack_walk, but allowing access to unwind_state data.
> >
> > Once the stack pointer and frame pointer are known for the main subprog
> > during the unwinding, we know the stack layout and location of any
> > callee-saved registers which must be restored before we return back to
> > the kernel.
> >
> > This handling will be added in the next patch.
> >
> > Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
> > ---
> >  arch/x86/net/bpf_jit_comp.c | 21 +++++++++++++++++++++
> >  include/linux/filter.h      |  2 ++
> >  kernel/bpf/core.c           |  9 +++++++++
> >  3 files changed, 32 insertions(+)
> >
> > diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
> > index 438adb695daa..d326503ce242 100644
> > --- a/arch/x86/net/bpf_jit_comp.c
> > +++ b/arch/x86/net/bpf_jit_comp.c
> > @@ -16,6 +16,7 @@
> >  #include <asm/set_memory.h>
> >  #include <asm/nospec-branch.h>
> >  #include <asm/text-patching.h>
> > +#include <asm/unwind.h>
> >
> >  static u8 *emit_code(u8 *ptr, u32 bytes, unsigned int len)
> >  {
> > @@ -2660,3 +2661,23 @@ void bpf_jit_free(struct bpf_prog *prog)
> >
> >       bpf_prog_unlock_free(prog);
> >  }
> > +
> > +bool bpf_jit_supports_exceptions(void)
> > +{
> > +     return IS_ENABLED(CONFIG_UNWINDER_ORC) || IS_ENABLED(CONFIG_UNWINDER_FRAME_POINTER);
> > +}
> > +
> > +void arch_bpf_stack_walk(bool (*consume_fn)(void *cookie, u64 ip, u64 sp, u64 bp), void *cookie)
> > +{
> > +#if defined(CONFIG_UNWINDER_ORC) || defined(CONFIG_UNWINDER_FRAME_POINTER)
> > +     struct unwind_state state;
> > +     unsigned long addr;
> > +
> > +     for (unwind_start(&state, current, NULL, NULL); !unwind_done(&state);
> > +          unwind_next_frame(&state)) {
> > +             addr = unwind_get_return_address(&state);
>
> I think these steps will work even with UNWINDER_GUESS.
> What is the reason for #ifdef ?

I think we require both unwind_state::sp and unwind_state::bp, but
arch/x86/include/asm/unwind.h does not include unwind_state::bp when
both UNWINDER_ORC and UNWINDER_FRAME_POINTER are unset.

Although it might be possible to calculate and save bp offset during
JIT in bpf_prog_aux (by adding roundup(stack_depth) + 8 (push rax if
tail call reachable) + callee_regs_saved) for the subprog
corresponding to a frame. Then we can make it work everywhere.
The JIT will abstract get_prog_bp(sp) using an arch specific helper.

Let me know if I misunderstood something.

>
> > +             if (!addr || !consume_fn(cookie, (u64)addr, (u64)state.sp, (u64)state.bp))
> > +                     break;
> > +     }
> > +#endif
> > +}
> > diff --git a/include/linux/filter.h b/include/linux/filter.h
> > index f69114083ec7..21ac801330bb 100644
> > --- a/include/linux/filter.h
> > +++ b/include/linux/filter.h
> > @@ -920,6 +920,8 @@ bool bpf_jit_needs_zext(void);
> >  bool bpf_jit_supports_subprog_tailcalls(void);
> >  bool bpf_jit_supports_kfunc_call(void);
> >  bool bpf_jit_supports_far_kfunc_call(void);
> > +bool bpf_jit_supports_exceptions(void);
> > +void arch_bpf_stack_walk(bool (*consume_fn)(void *cookie, u64 ip, u64 sp, u64 bp), void *cookie);
> >  bool bpf_helper_changes_pkt_data(void *func);
> >
> >  static inline bool bpf_dump_raw_ok(const struct cred *cred)
> > diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
> > index 5c484b2bc3d6..5e224cf0ec27 100644
> > --- a/kernel/bpf/core.c
> > +++ b/kernel/bpf/core.c
> > @@ -2770,6 +2770,15 @@ int __weak bpf_arch_text_invalidate(void *dst, size_t len)
> >       return -ENOTSUPP;
> >  }
> >
> > +bool __weak bpf_jit_supports_exceptions(void)
> > +{
> > +     return false;
> > +}
> > +
> > +void __weak arch_bpf_stack_walk(bool (*consume_fn)(void *cookie, u64 ip, u64 sp, u64 bp), void *cookie)
> > +{
> > +}
> > +
> >  #ifdef CONFIG_BPF_SYSCALL
> >  static int __init bpf_global_ma_init(void)
> >  {
> > --
> > 2.40.1
> >
Alexei Starovoitov July 17, 2023, 5:29 p.m. UTC | #3
On Mon, Jul 17, 2023 at 9:29 AM Kumar Kartikeya Dwivedi
<memxor@gmail.com> wrote:
>
> On Sat, 15 Jul 2023 at 03:35, Alexei Starovoitov
> <alexei.starovoitov@gmail.com> wrote:
> >
> > On Thu, Jul 13, 2023 at 08:02:27AM +0530, Kumar Kartikeya Dwivedi wrote:
> > > The plumbing for offline unwinding when we throw an exception in
> > > programs would require walking the stack, hence introduce a new
> > > arch_bpf_stack_walk function. This is provided when the JIT supports
> > > exceptions, i.e. bpf_jit_supports_exceptions is true. The arch-specific
> > > code is really minimal, hence it should straightforward to extend this
> > > support to other architectures as well, as it reuses the logic of
> > > arch_stack_walk, but allowing access to unwind_state data.
> > >
> > > Once the stack pointer and frame pointer are known for the main subprog
> > > during the unwinding, we know the stack layout and location of any
> > > callee-saved registers which must be restored before we return back to
> > > the kernel.
> > >
> > > This handling will be added in the next patch.
> > >
> > > Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
> > > ---
> > >  arch/x86/net/bpf_jit_comp.c | 21 +++++++++++++++++++++
> > >  include/linux/filter.h      |  2 ++
> > >  kernel/bpf/core.c           |  9 +++++++++
> > >  3 files changed, 32 insertions(+)
> > >
> > > diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
> > > index 438adb695daa..d326503ce242 100644
> > > --- a/arch/x86/net/bpf_jit_comp.c
> > > +++ b/arch/x86/net/bpf_jit_comp.c
> > > @@ -16,6 +16,7 @@
> > >  #include <asm/set_memory.h>
> > >  #include <asm/nospec-branch.h>
> > >  #include <asm/text-patching.h>
> > > +#include <asm/unwind.h>
> > >
> > >  static u8 *emit_code(u8 *ptr, u32 bytes, unsigned int len)
> > >  {
> > > @@ -2660,3 +2661,23 @@ void bpf_jit_free(struct bpf_prog *prog)
> > >
> > >       bpf_prog_unlock_free(prog);
> > >  }
> > > +
> > > +bool bpf_jit_supports_exceptions(void)
> > > +{
> > > +     return IS_ENABLED(CONFIG_UNWINDER_ORC) || IS_ENABLED(CONFIG_UNWINDER_FRAME_POINTER);
> > > +}
> > > +
> > > +void arch_bpf_stack_walk(bool (*consume_fn)(void *cookie, u64 ip, u64 sp, u64 bp), void *cookie)
> > > +{
> > > +#if defined(CONFIG_UNWINDER_ORC) || defined(CONFIG_UNWINDER_FRAME_POINTER)
> > > +     struct unwind_state state;
> > > +     unsigned long addr;
> > > +
> > > +     for (unwind_start(&state, current, NULL, NULL); !unwind_done(&state);
> > > +          unwind_next_frame(&state)) {
> > > +             addr = unwind_get_return_address(&state);
> >
> > I think these steps will work even with UNWINDER_GUESS.
> > What is the reason for #ifdef ?
>
> I think we require both unwind_state::sp and unwind_state::bp, but
> arch/x86/include/asm/unwind.h does not include unwind_state::bp when
> both UNWINDER_ORC and UNWINDER_FRAME_POINTER are unset.
>
> Although it might be possible to calculate and save bp offset during
> JIT in bpf_prog_aux (by adding roundup(stack_depth) + 8 (push rax if
> tail call reachable) + callee_regs_saved) for the subprog
> corresponding to a frame. Then we can make it work everywhere.
> The JIT will abstract get_prog_bp(sp) using an arch specific helper.
>
> Let me know if I misunderstood something.

JITed progs always have frames. So we're effectively doing
unconditional UNWINDER_FRAME_POINTER.
I think the intended usage of arch_bpf_stack_walk() is to only walk
bpf frames _in this patch set_, if so the extra #ifdefs are misleading.
If in follow-ups we're going to unwind through JITed progs _and_
through kfunc/helpers then this ifdef will be necessary.
I suspect we might want something like this in the future.
So the ifdef is ok to have from the start, but the comment is necessary
to describe what it is for.
Kumar Kartikeya Dwivedi July 17, 2023, 7:07 p.m. UTC | #4
On Mon, 17 Jul 2023 at 22:59, Alexei Starovoitov
<alexei.starovoitov@gmail.com> wrote:
>
> On Mon, Jul 17, 2023 at 9:29 AM Kumar Kartikeya Dwivedi
> <memxor@gmail.com> wrote:
> >
> > On Sat, 15 Jul 2023 at 03:35, Alexei Starovoitov
> > <alexei.starovoitov@gmail.com> wrote:
> > >
> > > On Thu, Jul 13, 2023 at 08:02:27AM +0530, Kumar Kartikeya Dwivedi wrote:
> > > > The plumbing for offline unwinding when we throw an exception in
> > > > programs would require walking the stack, hence introduce a new
> > > > arch_bpf_stack_walk function. This is provided when the JIT supports
> > > > exceptions, i.e. bpf_jit_supports_exceptions is true. The arch-specific
> > > > code is really minimal, hence it should straightforward to extend this
> > > > support to other architectures as well, as it reuses the logic of
> > > > arch_stack_walk, but allowing access to unwind_state data.
> > > >
> > > > Once the stack pointer and frame pointer are known for the main subprog
> > > > during the unwinding, we know the stack layout and location of any
> > > > callee-saved registers which must be restored before we return back to
> > > > the kernel.
> > > >
> > > > This handling will be added in the next patch.
> > > >
> > > > Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com>
> > > > ---
> > > >  arch/x86/net/bpf_jit_comp.c | 21 +++++++++++++++++++++
> > > >  include/linux/filter.h      |  2 ++
> > > >  kernel/bpf/core.c           |  9 +++++++++
> > > >  3 files changed, 32 insertions(+)
> > > >
> > > > diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
> > > > index 438adb695daa..d326503ce242 100644
> > > > --- a/arch/x86/net/bpf_jit_comp.c
> > > > +++ b/arch/x86/net/bpf_jit_comp.c
> > > > @@ -16,6 +16,7 @@
> > > >  #include <asm/set_memory.h>
> > > >  #include <asm/nospec-branch.h>
> > > >  #include <asm/text-patching.h>
> > > > +#include <asm/unwind.h>
> > > >
> > > >  static u8 *emit_code(u8 *ptr, u32 bytes, unsigned int len)
> > > >  {
> > > > @@ -2660,3 +2661,23 @@ void bpf_jit_free(struct bpf_prog *prog)
> > > >
> > > >       bpf_prog_unlock_free(prog);
> > > >  }
> > > > +
> > > > +bool bpf_jit_supports_exceptions(void)
> > > > +{
> > > > +     return IS_ENABLED(CONFIG_UNWINDER_ORC) || IS_ENABLED(CONFIG_UNWINDER_FRAME_POINTER);
> > > > +}
> > > > +
> > > > +void arch_bpf_stack_walk(bool (*consume_fn)(void *cookie, u64 ip, u64 sp, u64 bp), void *cookie)
> > > > +{
> > > > +#if defined(CONFIG_UNWINDER_ORC) || defined(CONFIG_UNWINDER_FRAME_POINTER)
> > > > +     struct unwind_state state;
> > > > +     unsigned long addr;
> > > > +
> > > > +     for (unwind_start(&state, current, NULL, NULL); !unwind_done(&state);
> > > > +          unwind_next_frame(&state)) {
> > > > +             addr = unwind_get_return_address(&state);
> > >
> > > I think these steps will work even with UNWINDER_GUESS.
> > > What is the reason for #ifdef ?
> >
> > I think we require both unwind_state::sp and unwind_state::bp, but
> > arch/x86/include/asm/unwind.h does not include unwind_state::bp when
> > both UNWINDER_ORC and UNWINDER_FRAME_POINTER are unset.
> >
> > Although it might be possible to calculate and save bp offset during
> > JIT in bpf_prog_aux (by adding roundup(stack_depth) + 8 (push rax if
> > tail call reachable) + callee_regs_saved) for the subprog
> > corresponding to a frame. Then we can make it work everywhere.
> > The JIT will abstract get_prog_bp(sp) using an arch specific helper.
> >
> > Let me know if I misunderstood something.
>
> JITed progs always have frames. So we're effectively doing
> unconditional UNWINDER_FRAME_POINTER.
> I think the intended usage of arch_bpf_stack_walk() is to only walk
> bpf frames _in this patch set_, if so the extra #ifdefs are misleading.
> If in follow-ups we're going to unwind through JITed progs _and_
> through kfunc/helpers then this ifdef will be necessary.
> I suspect we might want something like this in the future.

I think we actually do unwind through bpf_throw at the very least, so
we are going through both kernel and BPF frames.

> So the ifdef is ok to have from the start, but the comment is necessary
> to describe what it is for.

I'll add the comment in v2.
diff mbox series

Patch

diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c
index 438adb695daa..d326503ce242 100644
--- a/arch/x86/net/bpf_jit_comp.c
+++ b/arch/x86/net/bpf_jit_comp.c
@@ -16,6 +16,7 @@ 
 #include <asm/set_memory.h>
 #include <asm/nospec-branch.h>
 #include <asm/text-patching.h>
+#include <asm/unwind.h>
 
 static u8 *emit_code(u8 *ptr, u32 bytes, unsigned int len)
 {
@@ -2660,3 +2661,23 @@  void bpf_jit_free(struct bpf_prog *prog)
 
 	bpf_prog_unlock_free(prog);
 }
+
+bool bpf_jit_supports_exceptions(void)
+{
+	return IS_ENABLED(CONFIG_UNWINDER_ORC) || IS_ENABLED(CONFIG_UNWINDER_FRAME_POINTER);
+}
+
+void arch_bpf_stack_walk(bool (*consume_fn)(void *cookie, u64 ip, u64 sp, u64 bp), void *cookie)
+{
+#if defined(CONFIG_UNWINDER_ORC) || defined(CONFIG_UNWINDER_FRAME_POINTER)
+	struct unwind_state state;
+	unsigned long addr;
+
+	for (unwind_start(&state, current, NULL, NULL); !unwind_done(&state);
+	     unwind_next_frame(&state)) {
+		addr = unwind_get_return_address(&state);
+		if (!addr || !consume_fn(cookie, (u64)addr, (u64)state.sp, (u64)state.bp))
+			break;
+	}
+#endif
+}
diff --git a/include/linux/filter.h b/include/linux/filter.h
index f69114083ec7..21ac801330bb 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -920,6 +920,8 @@  bool bpf_jit_needs_zext(void);
 bool bpf_jit_supports_subprog_tailcalls(void);
 bool bpf_jit_supports_kfunc_call(void);
 bool bpf_jit_supports_far_kfunc_call(void);
+bool bpf_jit_supports_exceptions(void);
+void arch_bpf_stack_walk(bool (*consume_fn)(void *cookie, u64 ip, u64 sp, u64 bp), void *cookie);
 bool bpf_helper_changes_pkt_data(void *func);
 
 static inline bool bpf_dump_raw_ok(const struct cred *cred)
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 5c484b2bc3d6..5e224cf0ec27 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -2770,6 +2770,15 @@  int __weak bpf_arch_text_invalidate(void *dst, size_t len)
 	return -ENOTSUPP;
 }
 
+bool __weak bpf_jit_supports_exceptions(void)
+{
+	return false;
+}
+
+void __weak arch_bpf_stack_walk(bool (*consume_fn)(void *cookie, u64 ip, u64 sp, u64 bp), void *cookie)
+{
+}
+
 #ifdef CONFIG_BPF_SYSCALL
 static int __init bpf_global_ma_init(void)
 {