bpf.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH bpf-next 0/2] s390/bpf: Remove the orig_call NULL check
@ 2025-05-12 20:57 Ilya Leoshkevich
  2025-05-12 20:57 ` [PATCH bpf-next 1/2] bpf: Pass the same orig_call value to trampoline functions Ilya Leoshkevich
                   ` (2 more replies)
  0 siblings, 3 replies; 7+ messages in thread
From: Ilya Leoshkevich @ 2025-05-12 20:57 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
  Cc: bpf, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Ilya Leoshkevich

Hi,

I've been looking at fixing the tailcall_bpf2bpf_hierarchy failures on
s390. One of the challenges is that when a BPF trampoline calls a BPF
prog A, the prologue of A sets the tail call count to 0. Therefore it
would be useful to know whether the trampoline is attached to some
other BPF prog B, in which case A should be called using an offset
equal to tail_call_start, bypassing the tail call count initialization.

The trampoline attachment point is passed to trampoline functions via
the orig_call variable. Unfortunately in the case of calculating the
size of a struct_ops trampoline it's NULL, and I could not think of a
good reason to have it this way. This series makes it always non-NULL.

Best regards,
Ilya

Ilya Leoshkevich (2):
  bpf: Pass the same orig_call value to trampoline functions
  s390/bpf: Remove the orig_call NULL check

 arch/s390/net/bpf_jit_comp.c | 5 ++---
 kernel/bpf/bpf_struct_ops.c  | 2 +-
 2 files changed, 3 insertions(+), 4 deletions(-)

-- 
2.49.0


^ permalink raw reply	[flat|nested] 7+ messages in thread

* [PATCH bpf-next 1/2] bpf: Pass the same orig_call value to trampoline functions
  2025-05-12 20:57 [PATCH bpf-next 0/2] s390/bpf: Remove the orig_call NULL check Ilya Leoshkevich
@ 2025-05-12 20:57 ` Ilya Leoshkevich
  2025-05-14 21:26   ` Martin KaFai Lau
  2025-05-12 20:57 ` [PATCH bpf-next 2/2] s390/bpf: Remove the orig_call NULL check Ilya Leoshkevich
  2025-05-15  1:00 ` [PATCH bpf-next 0/2] " patchwork-bot+netdevbpf
  2 siblings, 1 reply; 7+ messages in thread
From: Ilya Leoshkevich @ 2025-05-12 20:57 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
  Cc: bpf, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Ilya Leoshkevich

There is currently some confusion in the s390x JIT regarding whether
orig_call can be NULL and what that means. Originally the NULL value
was used to distinguish the struct_ops case, but this was superseded by
BPF_TRAMP_F_INDIRECT (see commit 0c970ed2f87c ("s390/bpf: Fix indirect
trampoline generation").

The remaining reason to have this check is that NULL can actually be
passed to the arch_bpf_trampoline_size() call - but not to the
respective arch_prepare_bpf_trampoline()! call - by
bpf_struct_ops_prepare_trampoline().

Remove this asymmetry by passing stub_func to both functions, so that
JITs may rely on orig_call never being NULL.

Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
 kernel/bpf/bpf_struct_ops.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c
index db13ee70d94d..96113633e391 100644
--- a/kernel/bpf/bpf_struct_ops.c
+++ b/kernel/bpf/bpf_struct_ops.c
@@ -601,7 +601,7 @@ int bpf_struct_ops_prepare_trampoline(struct bpf_tramp_links *tlinks,
 	if (model->ret_size > 0)
 		flags |= BPF_TRAMP_F_RET_FENTRY_RET;
 
-	size = arch_bpf_trampoline_size(model, flags, tlinks, NULL);
+	size = arch_bpf_trampoline_size(model, flags, tlinks, stub_func);
 	if (size <= 0)
 		return size ? : -EFAULT;
 
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH bpf-next 2/2] s390/bpf: Remove the orig_call NULL check
  2025-05-12 20:57 [PATCH bpf-next 0/2] s390/bpf: Remove the orig_call NULL check Ilya Leoshkevich
  2025-05-12 20:57 ` [PATCH bpf-next 1/2] bpf: Pass the same orig_call value to trampoline functions Ilya Leoshkevich
@ 2025-05-12 20:57 ` Ilya Leoshkevich
  2025-05-15  1:00 ` [PATCH bpf-next 0/2] " patchwork-bot+netdevbpf
  2 siblings, 0 replies; 7+ messages in thread
From: Ilya Leoshkevich @ 2025-05-12 20:57 UTC (permalink / raw)
  To: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko
  Cc: bpf, Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Ilya Leoshkevich

Now that orig_call can never be NULL, remove the respective check.

Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
---
 arch/s390/net/bpf_jit_comp.c | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/arch/s390/net/bpf_jit_comp.c b/arch/s390/net/bpf_jit_comp.c
index 0776dfde2dba..4618f706067d 100644
--- a/arch/s390/net/bpf_jit_comp.c
+++ b/arch/s390/net/bpf_jit_comp.c
@@ -2585,9 +2585,8 @@ static int __arch_prepare_bpf_trampoline(struct bpf_tramp_image *im,
 	if (nr_stack_args > MAX_NR_STACK_ARGS)
 		return -ENOTSUPP;
 
-	/* Return to %r14, since func_addr and %r0 are not available. */
-	if ((!func_addr && !(flags & BPF_TRAMP_F_ORIG_STACK)) ||
-	    (flags & BPF_TRAMP_F_INDIRECT))
+	/* Return to %r14 in the struct_ops case. */
+	if (flags & BPF_TRAMP_F_INDIRECT)
 		flags |= BPF_TRAMP_F_SKIP_FRAME;
 
 	/*
-- 
2.49.0


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH bpf-next 1/2] bpf: Pass the same orig_call value to trampoline functions
  2025-05-12 20:57 ` [PATCH bpf-next 1/2] bpf: Pass the same orig_call value to trampoline functions Ilya Leoshkevich
@ 2025-05-14 21:26   ` Martin KaFai Lau
  2025-05-14 22:46     ` Ilya Leoshkevich
  0 siblings, 1 reply; 7+ messages in thread
From: Martin KaFai Lau @ 2025-05-14 21:26 UTC (permalink / raw)
  To: Ilya Leoshkevich
  Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, bpf,
	Heiko Carstens, Vasily Gorbik, Alexander Gordeev

On 5/12/25 1:57 PM, Ilya Leoshkevich wrote:
> There is currently some confusion in the s390x JIT regarding whether
> orig_call can be NULL and what that means. Originally the NULL value
> was used to distinguish the struct_ops case, but this was superseded by
> BPF_TRAMP_F_INDIRECT (see commit 0c970ed2f87c ("s390/bpf: Fix indirect
> trampoline generation").
> 
> The remaining reason to have this check is that NULL can actually be
> passed to the arch_bpf_trampoline_size() call - but not to the
> respective arch_prepare_bpf_trampoline()! call - by
> bpf_struct_ops_prepare_trampoline().
> 
> Remove this asymmetry by passing stub_func to both functions, so that
> JITs may rely on orig_call never being NULL.
> 
> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
> ---
>   kernel/bpf/bpf_struct_ops.c | 2 +-
>   1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/kernel/bpf/bpf_struct_ops.c b/kernel/bpf/bpf_struct_ops.c
> index db13ee70d94d..96113633e391 100644
> --- a/kernel/bpf/bpf_struct_ops.c
> +++ b/kernel/bpf/bpf_struct_ops.c
> @@ -601,7 +601,7 @@ int bpf_struct_ops_prepare_trampoline(struct bpf_tramp_links *tlinks,
>   	if (model->ret_size > 0)
>   		flags |= BPF_TRAMP_F_RET_FENTRY_RET;
>   
> -	size = arch_bpf_trampoline_size(model, flags, tlinks, NULL);
> +	size = arch_bpf_trampoline_size(model, flags, tlinks, stub_func);

The change looks ok but not sure why it is needed.

I can see why stub_func is needed to generate the final image in 
arch_prepare_bpf_trampoline() in x86. The "arch_bpf_trampoline_size()" here is 
generating a temporary image, so NULL or not doesn't seem to matter.

Does the s390 jit need to use the actual stub_func address somewhere in the 
temporary and/or final image?


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH bpf-next 1/2] bpf: Pass the same orig_call value to trampoline functions
  2025-05-14 21:26   ` Martin KaFai Lau
@ 2025-05-14 22:46     ` Ilya Leoshkevich
  2025-05-14 23:30       ` Martin KaFai Lau
  0 siblings, 1 reply; 7+ messages in thread
From: Ilya Leoshkevich @ 2025-05-14 22:46 UTC (permalink / raw)
  To: Martin KaFai Lau
  Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, bpf,
	Heiko Carstens, Vasily Gorbik, Alexander Gordeev

On Wed, 2025-05-14 at 14:26 -0700, Martin KaFai Lau wrote:
> On 5/12/25 1:57 PM, Ilya Leoshkevich wrote:
> > There is currently some confusion in the s390x JIT regarding
> > whether
> > orig_call can be NULL and what that means. Originally the NULL
> > value
> > was used to distinguish the struct_ops case, but this was
> > superseded by
> > BPF_TRAMP_F_INDIRECT (see commit 0c970ed2f87c ("s390/bpf: Fix
> > indirect
> > trampoline generation").
> > 
> > The remaining reason to have this check is that NULL can actually
> > be
> > passed to the arch_bpf_trampoline_size() call - but not to the
> > respective arch_prepare_bpf_trampoline()! call - by
> > bpf_struct_ops_prepare_trampoline().
> > 
> > Remove this asymmetry by passing stub_func to both functions, so
> > that
> > JITs may rely on orig_call never being NULL.
> > 
> > Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
> > ---
> >   kernel/bpf/bpf_struct_ops.c | 2 +-
> >   1 file changed, 1 insertion(+), 1 deletion(-)
> > 
> > diff --git a/kernel/bpf/bpf_struct_ops.c
> > b/kernel/bpf/bpf_struct_ops.c
> > index db13ee70d94d..96113633e391 100644
> > --- a/kernel/bpf/bpf_struct_ops.c
> > +++ b/kernel/bpf/bpf_struct_ops.c
> > @@ -601,7 +601,7 @@ int bpf_struct_ops_prepare_trampoline(struct
> > bpf_tramp_links *tlinks,
> >   	if (model->ret_size > 0)
> >   		flags |= BPF_TRAMP_F_RET_FENTRY_RET;
> >   
> > -	size = arch_bpf_trampoline_size(model, flags, tlinks,
> > NULL);
> > +	size = arch_bpf_trampoline_size(model, flags, tlinks,
> > stub_func);
> 
> The change looks ok but not sure why it is needed.
> 
> I can see why stub_func is needed to generate the final image in 
> arch_prepare_bpf_trampoline() in x86. The
> "arch_bpf_trampoline_size()" here is 
> generating a temporary image, so NULL or not doesn't seem to matter.
> 
> Does the s390 jit need to use the actual stub_func address somewhere
> in the 
> temporary and/or final image?

Not right now, however, in the future I would like to check whether
orig_call points to a BPF prog. I have explained the rationale behind
this in the series description.

Purely practical issues aside, currently it's unclear what
orig_func == NULL means. It had meaning in the past, but not anymore.
I think it would be good to remove this uncertainty and state that
today orig_func is never NULL.

Furthermore, a hypothetical JIT may produce different instruction
sequences for loading certain constants. Suppose we wanted to load
the value of orig_call into a register. Then in the NULL case a JIT
could generate:

  xgr %r1,%r1

and in the non-NULL case:

  llihf %r1,<high>
  oilf %r1,<low>

As you mentioned, arch_bpf_trampoline_size() generates a temporary
image, and in this case it would have a different size. So this
asymmetry can be a potential footgun.

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH bpf-next 1/2] bpf: Pass the same orig_call value to trampoline functions
  2025-05-14 22:46     ` Ilya Leoshkevich
@ 2025-05-14 23:30       ` Martin KaFai Lau
  0 siblings, 0 replies; 7+ messages in thread
From: Martin KaFai Lau @ 2025-05-14 23:30 UTC (permalink / raw)
  To: Ilya Leoshkevich
  Cc: Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko, bpf,
	Heiko Carstens, Vasily Gorbik, Alexander Gordeev

On 5/14/25 3:46 PM, Ilya Leoshkevich wrote:
> On Wed, 2025-05-14 at 14:26 -0700, Martin KaFai Lau wrote:
>> On 5/12/25 1:57 PM, Ilya Leoshkevich wrote:
>>> There is currently some confusion in the s390x JIT regarding
>>> whether
>>> orig_call can be NULL and what that means. Originally the NULL
>>> value
>>> was used to distinguish the struct_ops case, but this was
>>> superseded by
>>> BPF_TRAMP_F_INDIRECT (see commit 0c970ed2f87c ("s390/bpf: Fix
>>> indirect
>>> trampoline generation").
>>>
>>> The remaining reason to have this check is that NULL can actually
>>> be
>>> passed to the arch_bpf_trampoline_size() call - but not to the
>>> respective arch_prepare_bpf_trampoline()! call - by
>>> bpf_struct_ops_prepare_trampoline().
>>>
>>> Remove this asymmetry by passing stub_func to both functions, so
>>> that
>>> JITs may rely on orig_call never being NULL.
>>>
>>> Signed-off-by: Ilya Leoshkevich <iii@linux.ibm.com>
>>> ---
>>>    kernel/bpf/bpf_struct_ops.c | 2 +-
>>>    1 file changed, 1 insertion(+), 1 deletion(-)
>>>
>>> diff --git a/kernel/bpf/bpf_struct_ops.c
>>> b/kernel/bpf/bpf_struct_ops.c
>>> index db13ee70d94d..96113633e391 100644
>>> --- a/kernel/bpf/bpf_struct_ops.c
>>> +++ b/kernel/bpf/bpf_struct_ops.c
>>> @@ -601,7 +601,7 @@ int bpf_struct_ops_prepare_trampoline(struct
>>> bpf_tramp_links *tlinks,
>>>    	if (model->ret_size > 0)
>>>    		flags |= BPF_TRAMP_F_RET_FENTRY_RET;
>>>    
>>> -	size = arch_bpf_trampoline_size(model, flags, tlinks,
>>> NULL);
>>> +	size = arch_bpf_trampoline_size(model, flags, tlinks,
>>> stub_func);
>>
>> The change looks ok but not sure why it is needed.
>>
>> I can see why stub_func is needed to generate the final image in
>> arch_prepare_bpf_trampoline() in x86. The
>> "arch_bpf_trampoline_size()" here is
>> generating a temporary image, so NULL or not doesn't seem to matter.
>>
>> Does the s390 jit need to use the actual stub_func address somewhere
>> in the
>> temporary and/or final image?
> 
> Not right now, however, in the future I would like to check whether
> orig_call points to a BPF prog. I have explained the rationale behind
> this in the series description.
> 
> Purely practical issues aside, currently it's unclear what
> orig_func == NULL means. It had meaning in the past, but not anymore.
> I think it would be good to remove this uncertainty and state that
> today orig_func is never NULL.

For the bpf_struct_ops trampoline image, there is no need to invoke the 
orig_call, so it had been NULL for both temporary and final image cases until 
the recent cfi fix in x86.

I was asking because it feels like the jit might be doing something incorrect 
(or at least unnecessary) for the bpf_struct_ops if it needs to use the 
orig_call address. I don't know much of the s390 jit though.

The change looks fine from the bpf_struct_ops pov. Always pass "stub_func" is 
more consistent also, so

Acked-by: Martin KaFai Lau <martin.lau@kernel.org>

I don't know enough about the tailcall_bpf2bpf_hierarchy as stated in the commit 
message, so I will defer to others to comment.

> Furthermore, a hypothetical JIT may produce different instruction
> sequences for loading certain constants. Suppose we wanted to load
> the value of orig_call into a register. Then in the NULL case a JIT
> could generate:
> 
>    xgr %r1,%r1
> 
> and in the non-NULL case:
> 
>    llihf %r1,<high>
>    oilf %r1,<low>
> 
> As you mentioned, arch_bpf_trampoline_size() generates a temporary
> image, and in this case it would have a different size. So this
> asymmetry can be a potential footgun.


^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH bpf-next 0/2] s390/bpf: Remove the orig_call NULL check
  2025-05-12 20:57 [PATCH bpf-next 0/2] s390/bpf: Remove the orig_call NULL check Ilya Leoshkevich
  2025-05-12 20:57 ` [PATCH bpf-next 1/2] bpf: Pass the same orig_call value to trampoline functions Ilya Leoshkevich
  2025-05-12 20:57 ` [PATCH bpf-next 2/2] s390/bpf: Remove the orig_call NULL check Ilya Leoshkevich
@ 2025-05-15  1:00 ` patchwork-bot+netdevbpf
  2 siblings, 0 replies; 7+ messages in thread
From: patchwork-bot+netdevbpf @ 2025-05-15  1:00 UTC (permalink / raw)
  To: Ilya Leoshkevich; +Cc: ast, daniel, andrii, bpf, hca, gor, agordeev

Hello:

This series was applied to bpf/bpf-next.git (master)
by Alexei Starovoitov <ast@kernel.org>:

On Mon, 12 May 2025 22:57:29 +0200 you wrote:
> Hi,
> 
> I've been looking at fixing the tailcall_bpf2bpf_hierarchy failures on
> s390. One of the challenges is that when a BPF trampoline calls a BPF
> prog A, the prologue of A sets the tail call count to 0. Therefore it
> would be useful to know whether the trampoline is attached to some
> other BPF prog B, in which case A should be called using an offset
> equal to tail_call_start, bypassing the tail call count initialization.
> 
> [...]

Here is the summary with links:
  - [bpf-next,1/2] bpf: Pass the same orig_call value to trampoline functions
    https://git.kernel.org/bpf/bpf-next/c/94bde253d3ae
  - [bpf-next,2/2] s390/bpf: Remove the orig_call NULL check
    https://git.kernel.org/bpf/bpf-next/c/8e57cf09c84c

You are awesome, thank you!
-- 
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html



^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2025-05-15  0:59 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-05-12 20:57 [PATCH bpf-next 0/2] s390/bpf: Remove the orig_call NULL check Ilya Leoshkevich
2025-05-12 20:57 ` [PATCH bpf-next 1/2] bpf: Pass the same orig_call value to trampoline functions Ilya Leoshkevich
2025-05-14 21:26   ` Martin KaFai Lau
2025-05-14 22:46     ` Ilya Leoshkevich
2025-05-14 23:30       ` Martin KaFai Lau
2025-05-12 20:57 ` [PATCH bpf-next 2/2] s390/bpf: Remove the orig_call NULL check Ilya Leoshkevich
2025-05-15  1:00 ` [PATCH bpf-next 0/2] " patchwork-bot+netdevbpf

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).