Skip to content

Commit 2f69c56

Browse files
aspskAlexei Starovoitov
authored andcommitted
bpf: make bpf_insn_successors to return a pointer
The bpf_insn_successors() function is used to return successors to a BPF instruction. So far, an instruction could have 0, 1 or 2 successors. Prepare the verifier code to introduction of instructions with more than 2 successors (namely, indirect jumps). To do this, introduce a new struct, struct bpf_iarray, containing an array of bpf instruction indexes and make bpf_insn_successors to return a pointer of that type. The storage for all instructions is allocated in the env->succ, which holds an array of size 2, to be used for all instructions. Signed-off-by: Anton Protopopov <[email protected]> Acked-by: Eduard Zingerman <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Alexei Starovoitov <[email protected]>
1 parent 44481e4 commit 2f69c56

File tree

3 files changed

+75
-33
lines changed

3 files changed

+75
-33
lines changed

include/linux/bpf_verifier.h

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -509,6 +509,15 @@ struct bpf_map_ptr_state {
509509
#define BPF_ALU_SANITIZE (BPF_ALU_SANITIZE_SRC | \
510510
BPF_ALU_SANITIZE_DST)
511511

512+
/*
513+
* An array of BPF instructions.
514+
* Primary usage: return value of bpf_insn_successors.
515+
*/
516+
struct bpf_iarray {
517+
int cnt;
518+
u32 items[];
519+
};
520+
512521
struct bpf_insn_aux_data {
513522
union {
514523
enum bpf_reg_type ptr_type; /* pointer type for load/store insns */
@@ -828,6 +837,7 @@ struct bpf_verifier_env {
828837
/* array of pointers to bpf_scc_info indexed by SCC id */
829838
struct bpf_scc_info **scc_info;
830839
u32 scc_cnt;
840+
struct bpf_iarray *succ;
831841
};
832842

833843
static inline struct bpf_func_info_aux *subprog_aux(struct bpf_verifier_env *env, int subprog)
@@ -1050,7 +1060,7 @@ void print_insn_state(struct bpf_verifier_env *env, const struct bpf_verifier_st
10501060

10511061
struct bpf_subprog_info *bpf_find_containing_subprog(struct bpf_verifier_env *env, int off);
10521062
int bpf_jmp_offset(struct bpf_insn *insn);
1053-
int bpf_insn_successors(struct bpf_prog *prog, u32 idx, u32 succ[2]);
1063+
struct bpf_iarray *bpf_insn_successors(struct bpf_verifier_env *env, u32 idx);
10541064
void bpf_fmt_stack_mask(char *buf, ssize_t buf_sz, u64 stack_mask);
10551065
bool bpf_calls_callback(struct bpf_verifier_env *env, int insn_idx);
10561066

kernel/bpf/liveness.c

Lines changed: 24 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
* - read and write marks propagation.
3535
* - The propagation phase is a textbook live variable data flow analysis:
3636
*
37-
* state[cc, i].live_after = U [state[cc, s].live_before for s in insn_successors(i)]
37+
* state[cc, i].live_after = U [state[cc, s].live_before for s in bpf_insn_successors(i)]
3838
* state[cc, i].live_before =
3939
* (state[cc, i].live_after / state[cc, i].must_write) U state[i].may_read
4040
*
@@ -54,7 +54,7 @@
5454
* The equation for "must_write_acc" propagation looks as follows:
5555
*
5656
* state[cc, i].must_write_acc =
57-
* ∩ [state[cc, s].must_write_acc for s in insn_successors(i)]
57+
* ∩ [state[cc, s].must_write_acc for s in bpf_insn_successors(i)]
5858
* U state[cc, i].must_write
5959
*
6060
* (An intersection of all "must_write_acc" for instruction successors
@@ -447,7 +447,12 @@ int bpf_jmp_offset(struct bpf_insn *insn)
447447
__diag_push();
448448
__diag_ignore_all("-Woverride-init", "Allow field initialization overrides for opcode_info_tbl");
449449

450-
inline int bpf_insn_successors(struct bpf_prog *prog, u32 idx, u32 succ[2])
450+
/*
451+
* Returns an array of instructions succ, with succ->items[0], ...,
452+
* succ->items[n-1] with successor instructions, where n=succ->cnt
453+
*/
454+
inline struct bpf_iarray *
455+
bpf_insn_successors(struct bpf_verifier_env *env, u32 idx)
451456
{
452457
static const struct opcode_info {
453458
bool can_jump;
@@ -474,19 +479,25 @@ inline int bpf_insn_successors(struct bpf_prog *prog, u32 idx, u32 succ[2])
474479
_J(BPF_JSET, {.can_jump = true, .can_fallthrough = true}),
475480
#undef _J
476481
};
482+
struct bpf_prog *prog = env->prog;
477483
struct bpf_insn *insn = &prog->insnsi[idx];
478484
const struct opcode_info *opcode_info;
479-
int i = 0, insn_sz;
485+
struct bpf_iarray *succ;
486+
int insn_sz;
487+
488+
/* pre-allocated array of size up to 2; reset cnt, as it may have been used already */
489+
succ = env->succ;
490+
succ->cnt = 0;
480491

481492
opcode_info = &opcode_info_tbl[BPF_CLASS(insn->code) | BPF_OP(insn->code)];
482493
insn_sz = bpf_is_ldimm64(insn) ? 2 : 1;
483494
if (opcode_info->can_fallthrough)
484-
succ[i++] = idx + insn_sz;
495+
succ->items[succ->cnt++] = idx + insn_sz;
485496

486497
if (opcode_info->can_jump)
487-
succ[i++] = idx + bpf_jmp_offset(insn) + 1;
498+
succ->items[succ->cnt++] = idx + bpf_jmp_offset(insn) + 1;
488499

489-
return i;
500+
return succ;
490501
}
491502

492503
__diag_pop();
@@ -548,11 +559,12 @@ static inline bool update_insn(struct bpf_verifier_env *env,
548559
struct bpf_insn_aux_data *aux = env->insn_aux_data;
549560
u64 new_before, new_after, must_write_acc;
550561
struct per_frame_masks *insn, *succ_insn;
551-
u32 succ_num, s, succ[2];
562+
struct bpf_iarray *succ;
563+
u32 s;
552564
bool changed;
553565

554-
succ_num = bpf_insn_successors(env->prog, insn_idx, succ);
555-
if (unlikely(succ_num == 0))
566+
succ = bpf_insn_successors(env, insn_idx);
567+
if (succ->cnt == 0)
556568
return false;
557569

558570
changed = false;
@@ -564,8 +576,8 @@ static inline bool update_insn(struct bpf_verifier_env *env,
564576
* of successors plus all "must_write" slots of instruction itself.
565577
*/
566578
must_write_acc = U64_MAX;
567-
for (s = 0; s < succ_num; ++s) {
568-
succ_insn = get_frame_masks(instance, frame, succ[s]);
579+
for (s = 0; s < succ->cnt; ++s) {
580+
succ_insn = get_frame_masks(instance, frame, succ->items[s]);
569581
new_after |= succ_insn->live_before;
570582
must_write_acc &= succ_insn->must_write_acc;
571583
}

kernel/bpf/verifier.c

Lines changed: 40 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -17805,6 +17805,22 @@ static int mark_fastcall_patterns(struct bpf_verifier_env *env)
1780517805
return 0;
1780617806
}
1780717807

17808+
static struct bpf_iarray *iarray_realloc(struct bpf_iarray *old, size_t n_elem)
17809+
{
17810+
size_t new_size = sizeof(struct bpf_iarray) + n_elem * sizeof(old->items[0]);
17811+
struct bpf_iarray *new;
17812+
17813+
new = kvrealloc(old, new_size, GFP_KERNEL_ACCOUNT);
17814+
if (!new) {
17815+
/* this is what callers always want, so simplify the call site */
17816+
kvfree(old);
17817+
return NULL;
17818+
}
17819+
17820+
new->cnt = n_elem;
17821+
return new;
17822+
}
17823+
1780817824
/* Visits the instruction at index t and returns one of the following:
1780917825
* < 0 - an error occurred
1781017826
* DONE_EXPLORING - the instruction was fully explored
@@ -18025,8 +18041,9 @@ static int check_cfg(struct bpf_verifier_env *env)
1802518041
*/
1802618042
static int compute_postorder(struct bpf_verifier_env *env)
1802718043
{
18028-
u32 cur_postorder, i, top, stack_sz, s, succ_cnt, succ[2];
18044+
u32 cur_postorder, i, top, stack_sz, s;
1802918045
int *stack = NULL, *postorder = NULL, *state = NULL;
18046+
struct bpf_iarray *succ;
1803018047

1803118048
postorder = kvcalloc(env->prog->len, sizeof(int), GFP_KERNEL_ACCOUNT);
1803218049
state = kvcalloc(env->prog->len, sizeof(int), GFP_KERNEL_ACCOUNT);
@@ -18050,11 +18067,11 @@ static int compute_postorder(struct bpf_verifier_env *env)
1805018067
stack_sz--;
1805118068
continue;
1805218069
}
18053-
succ_cnt = bpf_insn_successors(env->prog, top, succ);
18054-
for (s = 0; s < succ_cnt; ++s) {
18055-
if (!state[succ[s]]) {
18056-
stack[stack_sz++] = succ[s];
18057-
state[succ[s]] |= DISCOVERED;
18070+
succ = bpf_insn_successors(env, top);
18071+
for (s = 0; s < succ->cnt; ++s) {
18072+
if (!state[succ->items[s]]) {
18073+
stack[stack_sz++] = succ->items[s];
18074+
state[succ->items[s]] |= DISCOVERED;
1805818075
}
1805918076
}
1806018077
state[top] |= EXPLORED;
@@ -24313,14 +24330,13 @@ static int compute_live_registers(struct bpf_verifier_env *env)
2431324330
for (i = 0; i < env->cfg.cur_postorder; ++i) {
2431424331
int insn_idx = env->cfg.insn_postorder[i];
2431524332
struct insn_live_regs *live = &state[insn_idx];
24316-
int succ_num;
24317-
u32 succ[2];
24333+
struct bpf_iarray *succ;
2431824334
u16 new_out = 0;
2431924335
u16 new_in = 0;
2432024336

24321-
succ_num = bpf_insn_successors(env->prog, insn_idx, succ);
24322-
for (int s = 0; s < succ_num; ++s)
24323-
new_out |= state[succ[s]].in;
24337+
succ = bpf_insn_successors(env, insn_idx);
24338+
for (int s = 0; s < succ->cnt; ++s)
24339+
new_out |= state[succ->items[s]].in;
2432424340
new_in = (new_out & ~live->def) | live->use;
2432524341
if (new_out != live->out || new_in != live->in) {
2432624342
live->in = new_in;
@@ -24373,11 +24389,11 @@ static int compute_scc(struct bpf_verifier_env *env)
2437324389
const u32 insn_cnt = env->prog->len;
2437424390
int stack_sz, dfs_sz, err = 0;
2437524391
u32 *stack, *pre, *low, *dfs;
24376-
u32 succ_cnt, i, j, t, w;
24392+
u32 i, j, t, w;
2437724393
u32 next_preorder_num;
2437824394
u32 next_scc_id;
2437924395
bool assign_scc;
24380-
u32 succ[2];
24396+
struct bpf_iarray *succ;
2438124397

2438224398
next_preorder_num = 1;
2438324399
next_scc_id = 1;
@@ -24484,12 +24500,12 @@ static int compute_scc(struct bpf_verifier_env *env)
2448424500
stack[stack_sz++] = w;
2448524501
}
2448624502
/* Visit 'w' successors */
24487-
succ_cnt = bpf_insn_successors(env->prog, w, succ);
24488-
for (j = 0; j < succ_cnt; ++j) {
24489-
if (pre[succ[j]]) {
24490-
low[w] = min(low[w], low[succ[j]]);
24503+
succ = bpf_insn_successors(env, w);
24504+
for (j = 0; j < succ->cnt; ++j) {
24505+
if (pre[succ->items[j]]) {
24506+
low[w] = min(low[w], low[succ->items[j]]);
2449124507
} else {
24492-
dfs[dfs_sz++] = succ[j];
24508+
dfs[dfs_sz++] = succ->items[j];
2449324509
goto dfs_continue;
2449424510
}
2449524511
}
@@ -24506,8 +24522,8 @@ static int compute_scc(struct bpf_verifier_env *env)
2450624522
* or if component has a self reference.
2450724523
*/
2450824524
assign_scc = stack[stack_sz - 1] != w;
24509-
for (j = 0; j < succ_cnt; ++j) {
24510-
if (succ[j] == w) {
24525+
for (j = 0; j < succ->cnt; ++j) {
24526+
if (succ->items[j] == w) {
2451124527
assign_scc = true;
2451224528
break;
2451324529
}
@@ -24569,6 +24585,9 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3
2456924585
goto err_free_env;
2457024586
for (i = 0; i < len; i++)
2457124587
env->insn_aux_data[i].orig_idx = i;
24588+
env->succ = iarray_realloc(NULL, 2);
24589+
if (!env->succ)
24590+
goto err_free_env;
2457224591
env->prog = *prog;
2457324592
env->ops = bpf_verifier_ops[env->prog->type];
2457424593

@@ -24817,6 +24836,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr, __u3
2481724836
bpf_stack_liveness_free(env);
2481824837
kvfree(env->cfg.insn_postorder);
2481924838
kvfree(env->scc_info);
24839+
kvfree(env->succ);
2482024840
kvfree(env);
2482124841
return ret;
2482224842
}

0 commit comments

Comments
 (0)