> diff --git a/arch/x86/net/bpf_jit_comp32.c b/arch/x86/net/bpf_jit_comp32.c
> index 852baf2e4db4d..017cc9e7e4e2b 100644
> --- a/arch/x86/net/bpf_jit_comp32.c
> +++ b/arch/x86/net/bpf_jit_comp32.c

[ ... ]

> @@ -1620,13 +1620,25 @@ static int emit_kfunc_call(const struct bpf_prog 
> *bpf_prog, u8 *end_addr,
>               /* add esp,"bytes_in_stack" */
>               end_addr -= 3;
>
> -     /* mov dword ptr [ebp+off],edx */
> -     if (fm->ret_size > sizeof(u32))
> -             end_addr -= 3;
> -
> -     /* mov dword ptr [ebp+off],eax */
> -     if (fm->ret_size)
> +     switch (fm->ret_size) {
> +     case 0:
> +             break;
> +     case sizeof(u8):
> +     case sizeof(u16):
> +             /* mov[s|z]x eax,[a]x */
>               end_addr -= 3;
> +             fallthrough;
> +     case sizeof(u32):
> +             /* cdq or xor edx,edx */
> +             end_addr -= fm->ret_flags & BTF_FMODEL_SIGNED_ARG ? 1 : 2;
> +             fallthrough;
> +     case sizeof(u64):
> +             /* Store EDX:EAX in R0. */
> +             end_addr -= 6;
> +             break;
> +     default:
> +             return -EINVAL;
> +     }

The comment above this diff hunk reads:

 * address by figuring out how many jit-insn is generated between
 * the call (0xE8) and the end_addr:
 *      - 0-1 jit-insn (3 bytes each) to restore the esp pointer if there
 *        is arg pushed to the stack.
 *      - 0-2 jit-insns (3 bytes each) to handle the return value.

Should this comment be updated? The new code can emit 0-4 instructions
with varying lengths (1, 2, 3 or 6 bytes) to extend and store the
return value, not just "0-2 jit-insns (3 bytes each)".

>
>       jmp_offset = (u8 *)__bpf_call_base + insn->imm - end_addr;
>       if (!is_simm32(jmp_offset)) {
> @@ -1637,15 +1649,38 @@ static int emit_kfunc_call(const struct bpf_prog 
> *bpf_prog, u8 *end_addr,
>
>       EMIT1_off32(0xE8, jmp_offset);
>
> -     if (fm->ret_size)
> +     switch (fm->ret_size) {
> +     case sizeof(u8):
> +             /* mov[s|z]x eax,al */
> +             EMIT3(0x0F, fm->ret_flags & BTF_FMODEL_SIGNED_ARG ? 0xBE : 0xB6,
> +                   add_2reg(0xC0, IA32_EAX, IA32_EAX));
> +             break;
> +     case sizeof(u16):
> +             /* mov[s|z]x eax,ax */
> +             EMIT3(0x0F, fm->ret_flags & BTF_FMODEL_SIGNED_ARG ? 0xBF : 0xB7,
> +                   add_2reg(0xC0, IA32_EAX, IA32_EAX));
> +             break;
> +     default:
> +             break;
> +     }
> +
> +     if (fm->ret_size && fm->ret_size <= sizeof(u32)) {
> +             if (fm->ret_flags & BTF_FMODEL_SIGNED_ARG)
> +                     /* cdq */
> +                     EMIT1(0x99);
> +             else
> +                     /* xor edx,edx */
> +                     EMIT2(0x31, add_2reg(0xC0, IA32_EDX, IA32_EDX));
> +     }

Does sign-extending narrow signed returns match the documented kfunc
return contract? In kernel/bpf/fixups.c the comment says:

    /* Zero-extension is done by the caller. */
    if (bpf_pseudo_kfunc_call(&insn))
            continue;

This exempts kfunc calls from the usual zero-extension path because
the JIT is responsible for R0's high half. The verifier's
__mark_btf_func_reg_size() marks narrow returns as subregs
specifically to invoke the zero-extension machinery.

For a concrete example with bpf_strcmp() which returns signed int,
if it returns -1:
  - x86-64 leaves R0 = 0x00000000ffffffff (32-bit write zeros upper half)
  - This patch makes x86-32 produce R0 = 0xffffffffffffffff via cdq

The same BPF program would see different R0 values depending on the
architecture. Is this the intended behavior, or should narrow kfunc
returns be zero-extended unconditionally to match the x86-64 path and
the fixups.c contract?

> +
> +     if (fm->ret_size) {
>               /* mov dword ptr [ebp+off],eax */
>               EMIT3(0x89, add_2reg(0x40, IA32_EBP, IA32_EAX),
>                     STACK_VAR(bpf2ia32[BPF_REG_0][0]));
> -
> -     if (fm->ret_size > sizeof(u32))
>               /* mov dword ptr [ebp+off],edx */
>               EMIT3(0x89, add_2reg(0x40, IA32_EBP, IA32_EDX),
>                     STACK_VAR(bpf2ia32[BPF_REG_0][1]));
> +     }

[ ... ]


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/31699378511

Reply via email to