diff mbox series

[bpf-next,v6,8/9] selftests/bpf: Add tracing prog private stack tests

Message ID 20241020191431.2108197-1-yonghong.song@linux.dev (mailing list archive)
State Superseded
Delegated to: BPF
Headers show
Series bpf: Support private stack for bpf progs | expand

Checks

Context Check Description
bpf/vmtest-bpf-next-PR success PR summary
netdev/series_format success Posting correctly formatted
netdev/tree_selection success Clearly marked for bpf-next, async
netdev/ynl success Generated files up to date; no warnings/errors; no diff in generated;
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: 6 this patch: 6
netdev/build_tools success Errors and warnings before: 0 (+1) this patch: 0 (+1)
netdev/cc_maintainers warning 11 maintainers not CCed: song@kernel.org shuah@kernel.org haoluo@google.com mykolal@fb.com john.fastabend@gmail.com sdf@fomichev.me martin.lau@linux.dev kpsingh@kernel.org linux-kselftest@vger.kernel.org eddyz87@gmail.com jolsa@kernel.org
netdev/build_clang success Errors and warnings before: 7 this patch: 7
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: 9 this patch: 9
netdev/checkpatch fail CHECK: Lines should not end with a '(' ERROR: code indent should use tabs where possible WARNING: added, moved or deleted file(s), does MAINTAINERS need updating? WARNING: please, no spaces at the start of a line
netdev/build_clang_rust success No Rust files in patch. Skipping build
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-1 success Logs for ShellCheck
bpf/vmtest-bpf-next-VM_Test-5 success Logs for aarch64-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-2 success Logs for Unittests
bpf/vmtest-bpf-next-VM_Test-0 success Logs for Lint
bpf/vmtest-bpf-next-VM_Test-3 success Logs for Validate matrix.py
bpf/vmtest-bpf-next-VM_Test-10 success Logs for aarch64-gcc / veristat
bpf/vmtest-bpf-next-VM_Test-12 success Logs for s390x-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-4 success Logs for aarch64-gcc / build / build for aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-9 success Logs for aarch64-gcc / test (test_verifier, false, 360) / test_verifier on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-6 success Logs for aarch64-gcc / test (test_maps, false, 360) / test_maps on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-7 success Logs for aarch64-gcc / test (test_progs, false, 360) / test_progs on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-8 success Logs for aarch64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on aarch64 with gcc
bpf/vmtest-bpf-next-VM_Test-11 success Logs for s390x-gcc / build / build for s390x with gcc
bpf/vmtest-bpf-next-VM_Test-16 success Logs for s390x-gcc / veristat
bpf/vmtest-bpf-next-VM_Test-17 success Logs for set-matrix
bpf/vmtest-bpf-next-VM_Test-18 success Logs for x86_64-gcc / build / build for x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-19 success Logs for x86_64-gcc / build-release
bpf/vmtest-bpf-next-VM_Test-27 success Logs for x86_64-llvm-17 / build / build for x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-33 success Logs for x86_64-llvm-17 / veristat
bpf/vmtest-bpf-next-VM_Test-15 success Logs for s390x-gcc / test (test_verifier, false, 360) / test_verifier on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-28 success Logs for x86_64-llvm-17 / build-release / build for x86_64 with llvm-17-O2
bpf/vmtest-bpf-next-VM_Test-34 success Logs for x86_64-llvm-18 / build / build for x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-35 success Logs for x86_64-llvm-18 / build-release / build for x86_64 with llvm-18-O2
bpf/vmtest-bpf-next-VM_Test-41 success Logs for x86_64-llvm-18 / veristat
bpf/vmtest-bpf-next-VM_Test-14 success Logs for s390x-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-13 success Logs for s390x-gcc / test (test_progs, false, 360) / test_progs on s390x with gcc
bpf/vmtest-bpf-next-VM_Test-20 success Logs for x86_64-gcc / test (test_maps, false, 360) / test_maps on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-21 success Logs for x86_64-gcc / test (test_progs, false, 360) / test_progs on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-22 success Logs for x86_64-gcc / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-23 success Logs for x86_64-gcc / test (test_progs_no_alu32_parallel, true, 30) / test_progs_no_alu32_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-24 success Logs for x86_64-gcc / test (test_progs_parallel, true, 30) / test_progs_parallel on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-25 success Logs for x86_64-gcc / test (test_verifier, false, 360) / test_verifier on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-26 success Logs for x86_64-gcc / veristat / veristat on x86_64 with gcc
bpf/vmtest-bpf-next-VM_Test-29 success Logs for x86_64-llvm-17 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-30 success Logs for x86_64-llvm-17 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-31 success Logs for x86_64-llvm-17 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-32 success Logs for x86_64-llvm-17 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-17
bpf/vmtest-bpf-next-VM_Test-36 success Logs for x86_64-llvm-18 / test (test_maps, false, 360) / test_maps on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-40 success Logs for x86_64-llvm-18 / test (test_verifier, false, 360) / test_verifier on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-37 success Logs for x86_64-llvm-18 / test (test_progs, false, 360) / test_progs on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-38 success Logs for x86_64-llvm-18 / test (test_progs_cpuv4, false, 360) / test_progs_cpuv4 on x86_64 with llvm-18
bpf/vmtest-bpf-next-VM_Test-39 success Logs for x86_64-llvm-18 / test (test_progs_no_alu32, false, 360) / test_progs_no_alu32 on x86_64 with llvm-18

Commit Message

Yonghong Song Oct. 20, 2024, 7:14 p.m. UTC
Some private stack tests are added including:
  - prog with stack size greater than BPF_PSTACK_MIN_SUBTREE_SIZE.
  - prog with stack size less than BPF_PSTACK_MIN_SUBTREE_SIZE.
  - prog with one subprog having MAX_BPF_STACK stack size and another
    subprog having non-zero stack size.
  - prog with callback function.
  - prog with exception in main prog or subprog.

Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
---
 .../selftests/bpf/prog_tests/verifier.c       |   2 +
 .../bpf/progs/verifier_private_stack.c        | 216 ++++++++++++++++++
 2 files changed, 218 insertions(+)
 create mode 100644 tools/testing/selftests/bpf/progs/verifier_private_stack.c

Comments

Jiri Olsa Oct. 20, 2024, 9:59 p.m. UTC | #1
On Sun, Oct 20, 2024 at 12:14:31PM -0700, Yonghong Song wrote:

SNIP

> +__naked __noinline __used
> +static unsigned long loop_callback(void)
> +{
> +	asm volatile (
> +	"call %[bpf_get_prandom_u32];"
> +	"r1 = 42;"
> +	"*(u64 *)(r10 - 512) = r1;"
> +	"call cumulative_stack_depth_subprog;"
> +	"r0 = 0;"
> +	"exit;"
> +	:
> +	: __imm(bpf_get_prandom_u32)
> +	: __clobber_common);
> +}
> +
> +SEC("raw_tp")
> +__description("Private stack, callback")
> +__success
> +__arch_x86_64
> +/* for func loop_callback */
> +__jited("func #1")
> +__jited("	endbr64")

this should fail if CONFIG_X86_KERNEL_IBT is not enabled, right?

hm, but I can see that also in other tests, so I guess it's fine,
should we add it to config.x86_64 ?

jirka
Yonghong Song Oct. 21, 2024, 4:32 a.m. UTC | #2
On 10/20/24 2:59 PM, Jiri Olsa wrote:
> On Sun, Oct 20, 2024 at 12:14:31PM -0700, Yonghong Song wrote:
>
> SNIP
>
>> +__naked __noinline __used
>> +static unsigned long loop_callback(void)
>> +{
>> +	asm volatile (
>> +	"call %[bpf_get_prandom_u32];"
>> +	"r1 = 42;"
>> +	"*(u64 *)(r10 - 512) = r1;"
>> +	"call cumulative_stack_depth_subprog;"
>> +	"r0 = 0;"
>> +	"exit;"
>> +	:
>> +	: __imm(bpf_get_prandom_u32)
>> +	: __clobber_common);
>> +}
>> +
>> +SEC("raw_tp")
>> +__description("Private stack, callback")
>> +__success
>> +__arch_x86_64
>> +/* for func loop_callback */
>> +__jited("func #1")
>> +__jited("	endbr64")
> this should fail if CONFIG_X86_KERNEL_IBT is not enabled, right?
>
> hm, but I can see that also in other tests, so I guess it's fine,
> should we add it to config.x86_64 ?

The CI has CONFIG_X86_KERNEL_IBT as well.

I checked x86 kconfig, I see

config CC_HAS_IBT
         # GCC >= 9 and binutils >= 2.29
         # Retpoline check to work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93654
         # Clang/LLVM >= 14
         # https://github.com/llvm/llvm-project/commit/e0b89df2e0f0130881bf6c39bf31d7f6aac00e0f
         # https://github.com/llvm/llvm-project/commit/dfcf69770bc522b9e411c66454934a37c1f35332
         def_bool ((CC_IS_GCC && $(cc-option, -fcf-protection=branch -mindirect-branch-register)) || \
                   (CC_IS_CLANG && CLANG_VERSION >= 140000)) && \
                   $(as-instr,endbr64)

config X86_KERNEL_IBT
         prompt "Indirect Branch Tracking"
         def_bool y
         depends on X86_64 && CC_HAS_IBT && HAVE_OBJTOOL
         # https://github.com/llvm/llvm-project/commit/9d7001eba9c4cb311e03cd8cdc231f9e579f2d0f
         depends on !LD_IS_LLD || LLD_VERSION >= 140000
         select OBJTOOL
         select X86_CET
         help
           Build the kernel with support for Indirect Branch Tracking, a
           hardware support course-grain forward-edge Control Flow Integrity
           protection. It enforces that all indirect calls must land on
           an ENDBR instruction, as such, the compiler will instrument the
           code with them to make this happen.
         
           In addition to building the kernel with IBT, seal all functions that
           are not indirect call targets, avoiding them ever becoming one.
           
           This requires LTO like objtool runs and will slow down the build. It
           does significantly reduce the number of ENDBR instructions in the
           kernel image.

So CONFIG_X86_KERNEL_IBT will be enabled if clang >= version_14 or newer gcc.
In my system, the gcc version is 13.1. So there is no need to explicitly add
CONFIG_X86_KERNEL_IBT to the selftests/bpf/config.x86_64 file.



>
> jirka
Jiri Olsa Oct. 21, 2024, 10:40 a.m. UTC | #3
On Sun, Oct 20, 2024 at 09:32:38PM -0700, Yonghong Song wrote:
> 
> On 10/20/24 2:59 PM, Jiri Olsa wrote:
> > On Sun, Oct 20, 2024 at 12:14:31PM -0700, Yonghong Song wrote:
> > 
> > SNIP
> > 
> > > +__naked __noinline __used
> > > +static unsigned long loop_callback(void)
> > > +{
> > > +	asm volatile (
> > > +	"call %[bpf_get_prandom_u32];"
> > > +	"r1 = 42;"
> > > +	"*(u64 *)(r10 - 512) = r1;"
> > > +	"call cumulative_stack_depth_subprog;"
> > > +	"r0 = 0;"
> > > +	"exit;"
> > > +	:
> > > +	: __imm(bpf_get_prandom_u32)
> > > +	: __clobber_common);
> > > +}
> > > +
> > > +SEC("raw_tp")
> > > +__description("Private stack, callback")
> > > +__success
> > > +__arch_x86_64
> > > +/* for func loop_callback */
> > > +__jited("func #1")
> > > +__jited("	endbr64")
> > this should fail if CONFIG_X86_KERNEL_IBT is not enabled, right?
> > 
> > hm, but I can see that also in other tests, so I guess it's fine,
> > should we add it to config.x86_64 ?
> 
> The CI has CONFIG_X86_KERNEL_IBT as well.
> 
> I checked x86 kconfig, I see
> 
> config CC_HAS_IBT
>         # GCC >= 9 and binutils >= 2.29
>         # Retpoline check to work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93654
>         # Clang/LLVM >= 14
>         # https://github.com/llvm/llvm-project/commit/e0b89df2e0f0130881bf6c39bf31d7f6aac00e0f
>         # https://github.com/llvm/llvm-project/commit/dfcf69770bc522b9e411c66454934a37c1f35332
>         def_bool ((CC_IS_GCC && $(cc-option, -fcf-protection=branch -mindirect-branch-register)) || \
>                   (CC_IS_CLANG && CLANG_VERSION >= 140000)) && \
>                   $(as-instr,endbr64)
> 
> config X86_KERNEL_IBT
>         prompt "Indirect Branch Tracking"
>         def_bool y
>         depends on X86_64 && CC_HAS_IBT && HAVE_OBJTOOL
>         # https://github.com/llvm/llvm-project/commit/9d7001eba9c4cb311e03cd8cdc231f9e579f2d0f
>         depends on !LD_IS_LLD || LLD_VERSION >= 140000
>         select OBJTOOL
>         select X86_CET
>         help
>           Build the kernel with support for Indirect Branch Tracking, a
>           hardware support course-grain forward-edge Control Flow Integrity
>           protection. It enforces that all indirect calls must land on
>           an ENDBR instruction, as such, the compiler will instrument the
>           code with them to make this happen.
>           In addition to building the kernel with IBT, seal all functions that
>           are not indirect call targets, avoiding them ever becoming one.
>           This requires LTO like objtool runs and will slow down the build. It
>           does significantly reduce the number of ENDBR instructions in the
>           kernel image.
> 
> So CONFIG_X86_KERNEL_IBT will be enabled if clang >= version_14 or newer gcc.

IIUC it's just dependency, no? doesn't mean it'll get enabled automatically

> In my system, the gcc version is 13.1. So there is no need to explicitly add
> CONFIG_X86_KERNEL_IBT to the selftests/bpf/config.x86_64 file.

I had to enable it manualy for gcc 13.3.1

jirka
Yonghong Song Oct. 21, 2024, 4:19 p.m. UTC | #4
On 10/21/24 3:40 AM, Jiri Olsa wrote:
> On Sun, Oct 20, 2024 at 09:32:38PM -0700, Yonghong Song wrote:
>> On 10/20/24 2:59 PM, Jiri Olsa wrote:
>>> On Sun, Oct 20, 2024 at 12:14:31PM -0700, Yonghong Song wrote:
>>>
>>> SNIP
>>>
>>>> +__naked __noinline __used
>>>> +static unsigned long loop_callback(void)
>>>> +{
>>>> +	asm volatile (
>>>> +	"call %[bpf_get_prandom_u32];"
>>>> +	"r1 = 42;"
>>>> +	"*(u64 *)(r10 - 512) = r1;"
>>>> +	"call cumulative_stack_depth_subprog;"
>>>> +	"r0 = 0;"
>>>> +	"exit;"
>>>> +	:
>>>> +	: __imm(bpf_get_prandom_u32)
>>>> +	: __clobber_common);
>>>> +}
>>>> +
>>>> +SEC("raw_tp")
>>>> +__description("Private stack, callback")
>>>> +__success
>>>> +__arch_x86_64
>>>> +/* for func loop_callback */
>>>> +__jited("func #1")
>>>> +__jited("	endbr64")
>>> this should fail if CONFIG_X86_KERNEL_IBT is not enabled, right?
>>>
>>> hm, but I can see that also in other tests, so I guess it's fine,
>>> should we add it to config.x86_64 ?
>> The CI has CONFIG_X86_KERNEL_IBT as well.
>>
>> I checked x86 kconfig, I see
>>
>> config CC_HAS_IBT
>>          # GCC >= 9 and binutils >= 2.29
>>          # Retpoline check to work around https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93654
>>          # Clang/LLVM >= 14
>>          # https://github.com/llvm/llvm-project/commit/e0b89df2e0f0130881bf6c39bf31d7f6aac00e0f
>>          # https://github.com/llvm/llvm-project/commit/dfcf69770bc522b9e411c66454934a37c1f35332
>>          def_bool ((CC_IS_GCC && $(cc-option, -fcf-protection=branch -mindirect-branch-register)) || \
>>                    (CC_IS_CLANG && CLANG_VERSION >= 140000)) && \
>>                    $(as-instr,endbr64)
>>
>> config X86_KERNEL_IBT
>>          prompt "Indirect Branch Tracking"
>>          def_bool y
>>          depends on X86_64 && CC_HAS_IBT && HAVE_OBJTOOL
>>          # https://github.com/llvm/llvm-project/commit/9d7001eba9c4cb311e03cd8cdc231f9e579f2d0f
>>          depends on !LD_IS_LLD || LLD_VERSION >= 140000
>>          select OBJTOOL
>>          select X86_CET
>>          help
>>            Build the kernel with support for Indirect Branch Tracking, a
>>            hardware support course-grain forward-edge Control Flow Integrity
>>            protection. It enforces that all indirect calls must land on
>>            an ENDBR instruction, as such, the compiler will instrument the
>>            code with them to make this happen.
>>            In addition to building the kernel with IBT, seal all functions that
>>            are not indirect call targets, avoiding them ever becoming one.
>>            This requires LTO like objtool runs and will slow down the build. It
>>            does significantly reduce the number of ENDBR instructions in the
>>            kernel image.
>>
>> So CONFIG_X86_KERNEL_IBT will be enabled if clang >= version_14 or newer gcc.
> IIUC it's just dependency, no? doesn't mean it'll get enabled automatically
>
>> In my system, the gcc version is 13.1. So there is no need to explicitly add
>> CONFIG_X86_KERNEL_IBT to the selftests/bpf/config.x86_64 file.
> I had to enable it manualy for gcc 13.3.1

IIUC, the ci config is generated based on config + config.x86_64 + config.vm
in tools/testing/selftests/bpf directory.

In my case .config is generated from config + config.x86_64 + config.vm
With my local gcc 11.5, I did
    make olddefconfig
and I see CONFIG_X86_KERNEL_IBT=y is set.

Maybe your base config is a little bit different from what ci used.
My local config is based on ci config + some more e.g. enabling KASAN etc.

Could you debug a little more on why CONFIG_X86_KERNEL_IBT not enabled
by default in your case? For

config X86_KERNEL_IBT
         prompt "Indirect Branch Tracking"
         def_bool y
         depends on X86_64 && CC_HAS_IBT && HAVE_OBJTOOL
         # https://github.com/llvm/llvm-project/commit/9d7001eba9c4cb311e03cd8cdc231f9e579f2d0f
         depends on !LD_IS_LLD || LLD_VERSION >= 140000
         select OBJTOOL
         select X86_CET

default is 'y' so if all dependencies are met, CONFIG_X86_KERNEL_IBT
is supposed to be on by default.

>
> jirka
Jiri Olsa Oct. 21, 2024, 9:13 p.m. UTC | #5
On Mon, Oct 21, 2024 at 09:19:57AM -0700, Yonghong Song wrote:

SNIP

> > > In my system, the gcc version is 13.1. So there is no need to explicitly add
> > > CONFIG_X86_KERNEL_IBT to the selftests/bpf/config.x86_64 file.
> > I had to enable it manualy for gcc 13.3.1
> 
> IIUC, the ci config is generated based on config + config.x86_64 + config.vm
> in tools/testing/selftests/bpf directory.
> 
> In my case .config is generated from config + config.x86_64 + config.vm
> With my local gcc 11.5, I did
>    make olddefconfig
> and I see CONFIG_X86_KERNEL_IBT=y is set.
> 
> Maybe your base config is a little bit different from what ci used.
> My local config is based on ci config + some more e.g. enabling KASAN etc.
> 
> Could you debug a little more on why CONFIG_X86_KERNEL_IBT not enabled
> by default in your case? For

ok, I think I disabled that manually

> 
> config X86_KERNEL_IBT
>         prompt "Indirect Branch Tracking"
>         def_bool y
>         depends on X86_64 && CC_HAS_IBT && HAVE_OBJTOOL
>         # https://github.com/llvm/llvm-project/commit/9d7001eba9c4cb311e03cd8cdc231f9e579f2d0f
>         depends on !LD_IS_LLD || LLD_VERSION >= 140000
>         select OBJTOOL
>         select X86_CET
> 
> default is 'y' so if all dependencies are met, CONFIG_X86_KERNEL_IBT
> is supposed to be on by default.

ah right, that should work then.. thanks for the details

jirka
diff mbox series

Patch

diff --git a/tools/testing/selftests/bpf/prog_tests/verifier.c b/tools/testing/selftests/bpf/prog_tests/verifier.c
index e26b5150fc43..635ff3509403 100644
--- a/tools/testing/selftests/bpf/prog_tests/verifier.c
+++ b/tools/testing/selftests/bpf/prog_tests/verifier.c
@@ -59,6 +59,7 @@ 
 #include "verifier_or_jmp32_k.skel.h"
 #include "verifier_precision.skel.h"
 #include "verifier_prevent_map_lookup.skel.h"
+#include "verifier_private_stack.skel.h"
 #include "verifier_raw_stack.skel.h"
 #include "verifier_raw_tp_writable.skel.h"
 #include "verifier_reg_equal.skel.h"
@@ -185,6 +186,7 @@  void test_verifier_bpf_fastcall(void)         { RUN(verifier_bpf_fastcall); }
 void test_verifier_or_jmp32_k(void)           { RUN(verifier_or_jmp32_k); }
 void test_verifier_precision(void)            { RUN(verifier_precision); }
 void test_verifier_prevent_map_lookup(void)   { RUN(verifier_prevent_map_lookup); }
+void test_verifier_private_stack(void)        { RUN(verifier_private_stack); }
 void test_verifier_raw_stack(void)            { RUN(verifier_raw_stack); }
 void test_verifier_raw_tp_writable(void)      { RUN(verifier_raw_tp_writable); }
 void test_verifier_reg_equal(void)            { RUN(verifier_reg_equal); }
diff --git a/tools/testing/selftests/bpf/progs/verifier_private_stack.c b/tools/testing/selftests/bpf/progs/verifier_private_stack.c
new file mode 100644
index 000000000000..e8de565f8b34
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/verifier_private_stack.c
@@ -0,0 +1,216 @@ 
+// SPDX-License-Identifier: GPL-2.0
+
+#include <vmlinux.h>
+#include <bpf/bpf_helpers.h>
+#include "bpf_misc.h"
+#include "bpf_experimental.h"
+
+/* From include/linux/filter.h */
+#define MAX_BPF_STACK    512
+
+#if defined(__TARGET_ARCH_x86)
+
+SEC("kprobe")
+__description("Private stack, single prog")
+__success
+__arch_x86_64
+__jited("	movabsq	$0x{{.*}}, %r9")
+__jited("	addq	%gs:0x{{.*}}, %r9")
+__jited("	movl	$0x2a, %edi")
+__jited("	movq	%rdi, -0x100(%r9)")
+__naked void private_stack_single_prog(void)
+{
+	asm volatile (
+	"r1 = 42;"
+	"*(u64 *)(r10 - 256) = r1;"
+	"r0 = 0;"
+	"exit;"
+	:
+	:
+	: __clobber_all);
+}
+
+__used
+__naked static void cumulative_stack_depth_subprog(void)
+{
+        asm volatile (
+	"r1 = 41;"
+        "*(u64 *)(r10 - 32) = r1;"
+        "call %[bpf_get_smp_processor_id];"
+        "exit;"
+        :: __imm(bpf_get_smp_processor_id)
+	: __clobber_all);
+}
+
+SEC("kprobe")
+__description("Private stack, subtree > MAX_BPF_STACK")
+__success
+__arch_x86_64
+/* private stack fp for the main prog */
+__jited("	movabsq	$0x{{.*}}, %r9")
+__jited("	addq	%gs:0x{{.*}}, %r9")
+__jited("	movl	$0x2a, %edi")
+__jited("	movq	%rdi, -0x200(%r9)")
+__jited("	pushq	%r9")
+__jited("	callq	0x{{.*}}")
+__jited("	popq	%r9")
+__jited("	xorl	%eax, %eax")
+__naked void private_stack_nested_1(void)
+{
+	asm volatile (
+	"r1 = 42;"
+	"*(u64 *)(r10 - %[max_bpf_stack]) = r1;"
+	"call cumulative_stack_depth_subprog;"
+	"r0 = 0;"
+	"exit;"
+	:
+	: __imm_const(max_bpf_stack, MAX_BPF_STACK)
+	: __clobber_all);
+}
+
+SEC("kprobe")
+__description("Private stack, subtree > MAX_BPF_STACK")
+__success
+__arch_x86_64
+/* private stack fp for the subprog */
+__jited("	addq	$0x20, %r9")
+__naked void private_stack_nested_2(void)
+{
+	asm volatile (
+	"r1 = 42;"
+	"*(u64 *)(r10 - %[max_bpf_stack]) = r1;"
+	"call cumulative_stack_depth_subprog;"
+	"r0 = 0;"
+	"exit;"
+	:
+	: __imm_const(max_bpf_stack, MAX_BPF_STACK)
+	: __clobber_all);
+}
+
+SEC("raw_tp")
+__description("No private stack, nested")
+__success
+__arch_x86_64
+__jited("	subq	$0x8, %rsp")
+__naked void no_private_stack_nested(void)
+{
+	asm volatile (
+	"r1 = 42;"
+	"*(u64 *)(r10 - 8) = r1;"
+	"call cumulative_stack_depth_subprog;"
+	"r0 = 0;"
+	"exit;"
+	:
+	:
+	: __clobber_all);
+}
+
+__naked __noinline __used
+static unsigned long loop_callback(void)
+{
+	asm volatile (
+	"call %[bpf_get_prandom_u32];"
+	"r1 = 42;"
+	"*(u64 *)(r10 - 512) = r1;"
+	"call cumulative_stack_depth_subprog;"
+	"r0 = 0;"
+	"exit;"
+	:
+	: __imm(bpf_get_prandom_u32)
+	: __clobber_common);
+}
+
+SEC("raw_tp")
+__description("Private stack, callback")
+__success
+__arch_x86_64
+/* for func loop_callback */
+__jited("func #1")
+__jited("	endbr64")
+__jited("	nopl	(%rax,%rax)")
+__jited("	nopl	(%rax)")
+__jited("	pushq	%rbp")
+__jited("	movq	%rsp, %rbp")
+__jited("	endbr64")
+__jited("	movabsq	$0x{{.*}}, %r9")
+__jited("	addq	%gs:0x{{.*}}, %r9")
+__jited("	pushq	%r9")
+__jited("	callq")
+__jited("	popq	%r9")
+__jited("	movl	$0x2a, %edi")
+__jited("	movq	%rdi, -0x200(%r9)")
+__jited("	pushq	%r9")
+__jited("	callq")
+__jited("	popq	%r9")
+__naked void private_stack_callback(void)
+{
+	asm volatile (
+	"r1 = 1;"
+	"r2 = %[loop_callback];"
+	"r3 = 0;"
+	"r4 = 0;"
+	"call %[bpf_loop];"
+	"r0 = 0;"
+	"exit;"
+	:
+	: __imm_ptr(loop_callback),
+	  __imm(bpf_loop)
+	: __clobber_common);
+}
+
+SEC("fentry/bpf_fentry_test9")
+__description("Private stack, exception in main prog")
+__success __retval(0)
+__arch_x86_64
+__jited("	pushq	%r9")
+__jited("	callq")
+__jited("	popq	%r9")
+int private_stack_exception_main_prog(void)
+{
+	asm volatile (
+	"r1 = 42;"
+	"*(u64 *)(r10 - 512) = r1;"
+	::: __clobber_common);
+
+	bpf_throw(0);
+	return 0;
+}
+
+__used static int subprog_exception(void)
+{
+	bpf_throw(0);
+	return 0;
+}
+
+SEC("fentry/bpf_fentry_test9")
+__description("Private stack, exception in subprog")
+__success __retval(0)
+__arch_x86_64
+__jited("	movq	%rdi, -0x200(%r9)")
+__jited("	pushq	%r9")
+__jited("	callq")
+__jited("	popq	%r9")
+int private_stack_exception_sub_prog(void)
+{
+	asm volatile (
+	"r1 = 42;"
+	"*(u64 *)(r10 - 512) = r1;"
+	"call subprog_exception;"
+	::: __clobber_common);
+
+	return 0;
+}
+
+#else
+
+SEC("kprobe")
+__description("private stack is not supported, use a dummy test")
+__success
+int dummy_test(void)
+{
+        return 0;
+}
+
+#endif
+
+char _license[] SEC("license") = "GPL";