Skip to content

Commit a91ae3c

Browse files
kkdwivediAlexei Starovoitov
authored andcommitted
bpf, x86: Add support for signed arena loads
Currently, signed load instructions into arena memory are unsupported. The compiler is free to generate these, and on GCC-14 we see a corresponding error when it happens. The hurdle in supporting them is deciding which unused opcode to use to mark them for the JIT's own consumption. After much thinking, it appears 0xc0 / BPF_NOSPEC can be combined with load instructions to identify signed arena loads. Use this to recognize and JIT them appropriately, and remove the verifier side limitation on the program if the JIT supports them. Co-developed-by: Puranjay Mohan <[email protected]> Signed-off-by: Kumar Kartikeya Dwivedi <[email protected]> Signed-off-by: Puranjay Mohan <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 348f611 commit a91ae3c

File tree

6 files changed

+63
-6
lines changed

6 files changed

+63
-6
lines changed

arch/arm64/net/bpf_jit_comp.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3064,6 +3064,11 @@ bool bpf_jit_supports_insn(struct bpf_insn *insn, bool in_arena)
30643064
if (!bpf_atomic_is_load_store(insn) &&
30653065
!cpus_have_cap(ARM64_HAS_LSE_ATOMICS))
30663066
return false;
3067+
break;
3068+
case BPF_LDX | BPF_MEMSX | BPF_B:
3069+
case BPF_LDX | BPF_MEMSX | BPF_H:
3070+
case BPF_LDX | BPF_MEMSX | BPF_W:
3071+
return false;
30673072
}
30683073
return true;
30693074
}

arch/riscv/net/bpf_jit_comp64.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2066,6 +2066,11 @@ bool bpf_jit_supports_insn(struct bpf_insn *insn, bool in_arena)
20662066
case BPF_STX | BPF_ATOMIC | BPF_DW:
20672067
if (insn->imm == BPF_CMPXCHG)
20682068
return rv_ext_enabled(ZACAS);
2069+
break;
2070+
case BPF_LDX | BPF_MEMSX | BPF_B:
2071+
case BPF_LDX | BPF_MEMSX | BPF_H:
2072+
case BPF_LDX | BPF_MEMSX | BPF_W:
2073+
return false;
20692074
}
20702075
}
20712076

arch/s390/net/bpf_jit_comp.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2967,6 +2967,11 @@ bool bpf_jit_supports_insn(struct bpf_insn *insn, bool in_arena)
29672967
case BPF_STX | BPF_ATOMIC | BPF_DW:
29682968
if (bpf_atomic_is_load_store(insn))
29692969
return false;
2970+
break;
2971+
case BPF_LDX | BPF_MEMSX | BPF_B:
2972+
case BPF_LDX | BPF_MEMSX | BPF_H:
2973+
case BPF_LDX | BPF_MEMSX | BPF_W:
2974+
return false;
29702975
}
29712976
return true;
29722977
}

arch/x86/net/bpf_jit_comp.c

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1152,11 +1152,38 @@ static void emit_ldx_index(u8 **pprog, u32 size, u32 dst_reg, u32 src_reg, u32 i
11521152
*pprog = prog;
11531153
}
11541154

1155+
static void emit_ldsx_index(u8 **pprog, u32 size, u32 dst_reg, u32 src_reg, u32 index_reg, int off)
1156+
{
1157+
u8 *prog = *pprog;
1158+
1159+
switch (size) {
1160+
case BPF_B:
1161+
/* movsx rax, byte ptr [rax + r12 + off] */
1162+
EMIT3(add_3mod(0x48, src_reg, dst_reg, index_reg), 0x0F, 0xBE);
1163+
break;
1164+
case BPF_H:
1165+
/* movsx rax, word ptr [rax + r12 + off] */
1166+
EMIT3(add_3mod(0x48, src_reg, dst_reg, index_reg), 0x0F, 0xBF);
1167+
break;
1168+
case BPF_W:
1169+
/* movsx rax, dword ptr [rax + r12 + off] */
1170+
EMIT2(add_3mod(0x48, src_reg, dst_reg, index_reg), 0x63);
1171+
break;
1172+
}
1173+
emit_insn_suffix_SIB(&prog, src_reg, dst_reg, index_reg, off);
1174+
*pprog = prog;
1175+
}
1176+
11551177
static void emit_ldx_r12(u8 **pprog, u32 size, u32 dst_reg, u32 src_reg, int off)
11561178
{
11571179
emit_ldx_index(pprog, size, dst_reg, src_reg, X86_REG_R12, off);
11581180
}
11591181

1182+
static void emit_ldsx_r12(u8 **prog, u32 size, u32 dst_reg, u32 src_reg, int off)
1183+
{
1184+
emit_ldsx_index(prog, size, dst_reg, src_reg, X86_REG_R12, off);
1185+
}
1186+
11601187
/* STX: *(u8*)(dst_reg + off) = src_reg */
11611188
static void emit_stx(u8 **pprog, u32 size, u32 dst_reg, u32 src_reg, int off)
11621189
{
@@ -2109,15 +2136,22 @@ st: if (is_imm8(insn->off))
21092136
case BPF_LDX | BPF_PROBE_MEM32 | BPF_H:
21102137
case BPF_LDX | BPF_PROBE_MEM32 | BPF_W:
21112138
case BPF_LDX | BPF_PROBE_MEM32 | BPF_DW:
2139+
case BPF_LDX | BPF_PROBE_MEM32SX | BPF_B:
2140+
case BPF_LDX | BPF_PROBE_MEM32SX | BPF_H:
2141+
case BPF_LDX | BPF_PROBE_MEM32SX | BPF_W:
21122142
case BPF_STX | BPF_PROBE_MEM32 | BPF_B:
21132143
case BPF_STX | BPF_PROBE_MEM32 | BPF_H:
21142144
case BPF_STX | BPF_PROBE_MEM32 | BPF_W:
21152145
case BPF_STX | BPF_PROBE_MEM32 | BPF_DW:
21162146
start_of_ldx = prog;
2117-
if (BPF_CLASS(insn->code) == BPF_LDX)
2118-
emit_ldx_r12(&prog, BPF_SIZE(insn->code), dst_reg, src_reg, insn->off);
2119-
else
2147+
if (BPF_CLASS(insn->code) == BPF_LDX) {
2148+
if (BPF_MODE(insn->code) == BPF_PROBE_MEM32SX)
2149+
emit_ldsx_r12(&prog, BPF_SIZE(insn->code), dst_reg, src_reg, insn->off);
2150+
else
2151+
emit_ldx_r12(&prog, BPF_SIZE(insn->code), dst_reg, src_reg, insn->off);
2152+
} else {
21202153
emit_stx_r12(&prog, BPF_SIZE(insn->code), dst_reg, src_reg, insn->off);
2154+
}
21212155
populate_extable:
21222156
{
21232157
struct exception_table_entry *ex;

include/linux/filter.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ struct ctl_table_header;
7878
/* unused opcode to mark special atomic instruction */
7979
#define BPF_PROBE_ATOMIC 0xe0
8080

81+
/* unused opcode to mark special ldsx instruction. Same as BPF_NOSPEC */
82+
#define BPF_PROBE_MEM32SX 0xc0
83+
8184
/* unused opcode to mark call to interpreter with arguments */
8285
#define BPF_CALL_ARGS 0xe0
8386

kernel/bpf/verifier.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21379,10 +21379,14 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
2137921379
continue;
2138021380
case PTR_TO_ARENA:
2138121381
if (BPF_MODE(insn->code) == BPF_MEMSX) {
21382-
verbose(env, "sign extending loads from arena are not supported yet\n");
21383-
return -EOPNOTSUPP;
21382+
if (!bpf_jit_supports_insn(insn, true)) {
21383+
verbose(env, "sign extending loads from arena are not supported yet\n");
21384+
return -EOPNOTSUPP;
21385+
}
21386+
insn->code = BPF_CLASS(insn->code) | BPF_PROBE_MEM32SX | BPF_SIZE(insn->code);
21387+
} else {
21388+
insn->code = BPF_CLASS(insn->code) | BPF_PROBE_MEM32 | BPF_SIZE(insn->code);
2138421389
}
21385-
insn->code = BPF_CLASS(insn->code) | BPF_PROBE_MEM32 | BPF_SIZE(insn->code);
2138621390
env->prog->aux->num_exentries++;
2138721391
continue;
2138821392
default:
@@ -21588,6 +21592,7 @@ static int jit_subprogs(struct bpf_verifier_env *env)
2158821592
if (BPF_CLASS(insn->code) == BPF_LDX &&
2158921593
(BPF_MODE(insn->code) == BPF_PROBE_MEM ||
2159021594
BPF_MODE(insn->code) == BPF_PROBE_MEM32 ||
21595+
BPF_MODE(insn->code) == BPF_PROBE_MEM32SX ||
2159121596
BPF_MODE(insn->code) == BPF_PROBE_MEMSX))
2159221597
num_exentries++;
2159321598
if ((BPF_CLASS(insn->code) == BPF_STX ||

0 commit comments

Comments
 (0)