@@ -3516,12 +3516,29 @@ static int push_jmp_history(struct bpf_verifier_env *env,
3516
3516
3517
3517
/* Backtrack one insn at a time. If idx is not at the top of recorded
3518
3518
* history then previous instruction came from straight line execution.
3519
+ * Return -ENOENT if we exhausted all instructions within given state.
3520
+ *
3521
+ * It's legal to have a bit of a looping with the same starting and ending
3522
+ * insn index within the same state, e.g.: 3->4->5->3, so just because current
3523
+ * instruction index is the same as state's first_idx doesn't mean we are
3524
+ * done. If there is still some jump history left, we should keep going. We
3525
+ * need to take into account that we might have a jump history between given
3526
+ * state's parent and itself, due to checkpointing. In this case, we'll have
3527
+ * history entry recording a jump from last instruction of parent state and
3528
+ * first instruction of given state.
3519
3529
*/
3520
3530
static int get_prev_insn_idx(struct bpf_verifier_state *st, int i,
3521
3531
u32 *history)
3522
3532
{
3523
3533
u32 cnt = *history;
3524
3534
3535
+ if (i == st->first_insn_idx) {
3536
+ if (cnt == 0)
3537
+ return -ENOENT;
3538
+ if (cnt == 1 && st->jmp_history[0].idx == i)
3539
+ return -ENOENT;
3540
+ }
3541
+
3525
3542
if (cnt && st->jmp_history[cnt - 1].idx == i) {
3526
3543
i = st->jmp_history[cnt - 1].prev_idx;
3527
3544
(*history)--;
@@ -4401,10 +4418,10 @@ static int __mark_chain_precision(struct bpf_verifier_env *env, int regno)
4401
4418
* Nothing to be tracked further in the parent state.
4402
4419
*/
4403
4420
return 0;
4404
- if (i == first_idx)
4405
- break;
4406
4421
subseq_idx = i;
4407
4422
i = get_prev_insn_idx(st, i, &history);
4423
+ if (i == -ENOENT)
4424
+ break;
4408
4425
if (i >= env->prog->len) {
4409
4426
/* This can happen if backtracking reached insn 0
4410
4427
* and there are still reg_mask or stack_mask
@@ -15439,15 +15456,16 @@ static int visit_func_call_insn(int t, struct bpf_insn *insns,
15439
15456
struct bpf_verifier_env *env,
15440
15457
bool visit_callee)
15441
15458
{
15442
- int ret;
15459
+ int ret, insn_sz ;
15443
15460
15444
- ret = push_insn(t, t + 1, FALLTHROUGH, env, false);
15461
+ insn_sz = bpf_is_ldimm64(&insns[t]) ? 2 : 1;
15462
+ ret = push_insn(t, t + insn_sz, FALLTHROUGH, env, false);
15445
15463
if (ret)
15446
15464
return ret;
15447
15465
15448
- mark_prune_point(env, t + 1 );
15466
+ mark_prune_point(env, t + insn_sz );
15449
15467
/* when we exit from subprog, we need to record non-linear history */
15450
- mark_jmp_point(env, t + 1 );
15468
+ mark_jmp_point(env, t + insn_sz );
15451
15469
15452
15470
if (visit_callee) {
15453
15471
mark_prune_point(env, t);
@@ -15469,15 +15487,17 @@ static int visit_func_call_insn(int t, struct bpf_insn *insns,
15469
15487
static int visit_insn(int t, struct bpf_verifier_env *env)
15470
15488
{
15471
15489
struct bpf_insn *insns = env->prog->insnsi, *insn = &insns[t];
15472
- int ret, off;
15490
+ int ret, off, insn_sz ;
15473
15491
15474
15492
if (bpf_pseudo_func(insn))
15475
15493
return visit_func_call_insn(t, insns, env, true);
15476
15494
15477
15495
/* All non-branch instructions have a single fall-through edge. */
15478
15496
if (BPF_CLASS(insn->code) != BPF_JMP &&
15479
- BPF_CLASS(insn->code) != BPF_JMP32)
15480
- return push_insn(t, t + 1, FALLTHROUGH, env, false);
15497
+ BPF_CLASS(insn->code) != BPF_JMP32) {
15498
+ insn_sz = bpf_is_ldimm64(insn) ? 2 : 1;
15499
+ return push_insn(t, t + insn_sz, FALLTHROUGH, env, false);
15500
+ }
15481
15501
15482
15502
switch (BPF_OP(insn->code)) {
15483
15503
case BPF_EXIT:
@@ -15607,11 +15627,21 @@ static int check_cfg(struct bpf_verifier_env *env)
15607
15627
}
15608
15628
15609
15629
for (i = 0; i < insn_cnt; i++) {
15630
+ struct bpf_insn *insn = &env->prog->insnsi[i];
15631
+
15610
15632
if (insn_state[i] != EXPLORED) {
15611
15633
verbose(env, "unreachable insn %d\n", i);
15612
15634
ret = -EINVAL;
15613
15635
goto err_free;
15614
15636
}
15637
+ if (bpf_is_ldimm64(insn)) {
15638
+ if (insn_state[i + 1] != 0) {
15639
+ verbose(env, "jump into the middle of ldimm64 insn %d\n", i);
15640
+ ret = -EINVAL;
15641
+ goto err_free;
15642
+ }
15643
+ i++; /* skip second half of ldimm64 */
15644
+ }
15615
15645
}
15616
15646
ret = 0; /* cfg looks good */
15617
15647
0 commit comments