Skip to content

Commit 0460484

Browse files
puranjaymohanAlexei Starovoitov
authored andcommitted
bpf: arm64: simplify exception table handling
BPF loads with BPF_PROBE_MEM(SX) can load from unsafe pointers and the JIT adds an exception table entry for the JITed instruction which allows the exeption handler to set the destination register of the load to zero and continue execution from the next instruction. As all arm64 instructions are AARCH64_INSN_SIZE size, the exception handler can just increment the pc by AARCH64_INSN_SIZE without needing the exact address of the instruction following the the faulting instruction. Simplify the exception table usage in arm64 JIT by only saving the destination register in ex->fixup and drop everything related to the fixup_offset. The fault handler is modified to add AARCH64_INSN_SIZE to the pc. Signed-off-by: Puranjay Mohan <[email protected]> Acked-by: Yonghong Song <[email protected]> Acked-by: Kumar Kartikeya Dwivedi <[email protected]> Acked-by: Xu Kuohai <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 5d87e96 commit 0460484

File tree

1 file changed

+3
-22
lines changed

1 file changed

+3
-22
lines changed

arch/arm64/net/bpf_jit_comp.c

Lines changed: 3 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,19 +1066,18 @@ static void build_epilogue(struct jit_ctx *ctx, bool was_classic)
10661066
emit(A64_RET(A64_LR), ctx);
10671067
}
10681068

1069-
#define BPF_FIXUP_OFFSET_MASK GENMASK(26, 0)
10701069
#define BPF_FIXUP_REG_MASK GENMASK(31, 27)
10711070
#define DONT_CLEAR 5 /* Unused ARM64 register from BPF's POV */
10721071

10731072
bool ex_handler_bpf(const struct exception_table_entry *ex,
10741073
struct pt_regs *regs)
10751074
{
1076-
off_t offset = FIELD_GET(BPF_FIXUP_OFFSET_MASK, ex->fixup);
10771075
int dst_reg = FIELD_GET(BPF_FIXUP_REG_MASK, ex->fixup);
10781076

10791077
if (dst_reg != DONT_CLEAR)
10801078
regs->regs[dst_reg] = 0;
1081-
regs->pc = (unsigned long)&ex->fixup - offset;
1079+
/* Skip the faulting instruction */
1080+
regs->pc += AARCH64_INSN_SIZE;
10821081
return true;
10831082
}
10841083

@@ -1088,7 +1087,6 @@ static int add_exception_handler(const struct bpf_insn *insn,
10881087
int dst_reg)
10891088
{
10901089
off_t ins_offset;
1091-
off_t fixup_offset;
10921090
unsigned long pc;
10931091
struct exception_table_entry *ex;
10941092

@@ -1119,22 +1117,6 @@ static int add_exception_handler(const struct bpf_insn *insn,
11191117
if (WARN_ON_ONCE(ins_offset >= 0 || ins_offset < INT_MIN))
11201118
return -ERANGE;
11211119

1122-
/*
1123-
* Since the extable follows the program, the fixup offset is always
1124-
* negative and limited to BPF_JIT_REGION_SIZE. Store a positive value
1125-
* to keep things simple, and put the destination register in the upper
1126-
* bits. We don't need to worry about buildtime or runtime sort
1127-
* modifying the upper bits because the table is already sorted, and
1128-
* isn't part of the main exception table.
1129-
*
1130-
* The fixup_offset is set to the next instruction from the instruction
1131-
* that may fault. The execution will jump to this after handling the
1132-
* fault.
1133-
*/
1134-
fixup_offset = (long)&ex->fixup - (pc + AARCH64_INSN_SIZE);
1135-
if (!FIELD_FIT(BPF_FIXUP_OFFSET_MASK, fixup_offset))
1136-
return -ERANGE;
1137-
11381120
/*
11391121
* The offsets above have been calculated using the RO buffer but we
11401122
* need to use the R/W buffer for writes.
@@ -1147,8 +1129,7 @@ static int add_exception_handler(const struct bpf_insn *insn,
11471129
if (BPF_CLASS(insn->code) != BPF_LDX)
11481130
dst_reg = DONT_CLEAR;
11491131

1150-
ex->fixup = FIELD_PREP(BPF_FIXUP_OFFSET_MASK, fixup_offset) |
1151-
FIELD_PREP(BPF_FIXUP_REG_MASK, dst_reg);
1132+
ex->fixup = FIELD_PREP(BPF_FIXUP_REG_MASK, dst_reg);
11521133

11531134
ex->type = EX_TYPE_BPF;
11541135

0 commit comments

Comments
 (0)