Skip to content

Commit 07ae6c1

Browse files
Xu KuohaiAlexei Starovoitov
authored andcommitted
bpf: Add helper to detect indirect jump targets
Introduce helper bpf_insn_is_indirect_target to check whether a BPF instruction is an indirect jump target. Since the verifier knows which instructions are indirect jump targets, add a new flag indirect_target to struct bpf_insn_aux_data to mark them. The verifier sets this flag when verifying an indirect jump target instruction, and the helper checks the flag to determine whether an instruction is an indirect jump target. Reviewed-by: Anton Protopopov <a.s.protopopov@gmail.com> #v8 Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com> #v12 Signed-off-by: Xu Kuohai <xukuohai@huawei.com> Link: https://lore.kernel.org/r/20260416064341.151802-4-xukuohai@huaweicloud.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent d9ef13f commit 07ae6c1

5 files changed

Lines changed: 35 additions & 4 deletions

File tree

include/linux/bpf.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1541,6 +1541,8 @@ bool bpf_has_frame_pointer(unsigned long ip);
15411541
int bpf_jit_charge_modmem(u32 size);
15421542
void bpf_jit_uncharge_modmem(u32 size);
15431543
bool bpf_prog_has_trampoline(const struct bpf_prog *prog);
1544+
bool bpf_insn_is_indirect_target(const struct bpf_verifier_env *env, const struct bpf_prog *prog,
1545+
int insn_idx);
15441546
#else
15451547
static inline int bpf_trampoline_link_prog(struct bpf_tramp_link *link,
15461548
struct bpf_trampoline *tr,

include/linux/bpf_verifier.h

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -630,16 +630,17 @@ struct bpf_insn_aux_data {
630630

631631
/* below fields are initialized once */
632632
unsigned int orig_idx; /* original instruction index */
633-
bool jmp_point;
634-
bool prune_point;
633+
u32 jmp_point:1;
634+
u32 prune_point:1;
635635
/* ensure we check state equivalence and save state checkpoint and
636636
* this instruction, regardless of any heuristics
637637
*/
638-
bool force_checkpoint;
638+
u32 force_checkpoint:1;
639639
/* true if instruction is a call to a helper function that
640640
* accepts callback function as a parameter.
641641
*/
642-
bool calls_callback;
642+
u32 calls_callback:1;
643+
u32 indirect_target:1; /* if it is an indirect jump target */
643644
/*
644645
* CFG strongly connected component this instruction belongs to,
645646
* zero if it is a singleton SCC.

kernel/bpf/core.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1573,6 +1573,15 @@ struct bpf_prog *bpf_jit_blind_constants(struct bpf_verifier_env *env, struct bp
15731573
clone->blinded = 1;
15741574
return clone;
15751575
}
1576+
1577+
bool bpf_insn_is_indirect_target(const struct bpf_verifier_env *env, const struct bpf_prog *prog,
1578+
int insn_idx)
1579+
{
1580+
if (!env)
1581+
return false;
1582+
insn_idx += prog->aux->subprog_start;
1583+
return env->insn_aux_data[insn_idx].indirect_target;
1584+
}
15761585
#endif /* CONFIG_BPF_JIT */
15771586

15781587
/* Base function for offset calculation. Needs to go into .text section,

kernel/bpf/fixups.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,18 @@ static void adjust_insn_aux_data(struct bpf_verifier_env *env,
183183
data[i].seen = old_seen;
184184
data[i].zext_dst = insn_has_def32(insn + i);
185185
}
186+
187+
/*
188+
* The indirect_target flag of the original instruction was moved to the last of the
189+
* new instructions by the above memmove and memset, but the indirect jump target is
190+
* actually the first instruction, so move it back. This also matches with the behavior
191+
* of bpf_insn_array_adjust(), which preserves xlated_off to point to the first new
192+
* instruction.
193+
*/
194+
if (data[off + cnt - 1].indirect_target) {
195+
data[off].indirect_target = 1;
196+
data[off + cnt - 1].indirect_target = 0;
197+
}
186198
}
187199

188200
static void adjust_subprog_starts(struct bpf_verifier_env *env, u32 off, u32 len)

kernel/bpf/verifier.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3497,6 +3497,11 @@ static int insn_stack_access_flags(int frameno, int spi)
34973497
return INSN_F_STACK_ACCESS | (spi << INSN_F_SPI_SHIFT) | frameno;
34983498
}
34993499

3500+
static void mark_indirect_target(struct bpf_verifier_env *env, int idx)
3501+
{
3502+
env->insn_aux_data[idx].indirect_target = true;
3503+
}
3504+
35003505
#define LR_FRAMENO_BITS 3
35013506
#define LR_SPI_BITS 6
35023507
#define LR_ENTRY_BITS (LR_SPI_BITS + LR_FRAMENO_BITS + 1)
@@ -17545,12 +17550,14 @@ static int check_indirect_jump(struct bpf_verifier_env *env, struct bpf_insn *in
1754517550
}
1754617551

1754717552
for (i = 0; i < n - 1; i++) {
17553+
mark_indirect_target(env, env->gotox_tmp_buf->items[i]);
1754817554
other_branch = push_stack(env, env->gotox_tmp_buf->items[i],
1754917555
env->insn_idx, env->cur_state->speculative);
1755017556
if (IS_ERR(other_branch))
1755117557
return PTR_ERR(other_branch);
1755217558
}
1755317559
env->insn_idx = env->gotox_tmp_buf->items[n-1];
17560+
mark_indirect_target(env, env->insn_idx);
1755417561
return INSN_IDX_UPDATED;
1755517562
}
1755617563

0 commit comments

Comments
 (0)