@@ -3743,6 +3743,11 @@ static int check_reg_arg(struct bpf_verifier_env *env, u32 regno,
3743
3743
return __check_reg_arg(env, state->regs, regno, t);
3744
3744
}
3745
3745
3746
+ static int insn_reg_with_access_flag(int reg)
3747
+ {
3748
+ return INSN_F_REG_ACCESS | reg;
3749
+ }
3750
+
3746
3751
static int insn_stack_access_flags(int frameno, int spi)
3747
3752
{
3748
3753
return INSN_F_STACK_ACCESS | (spi << INSN_F_SPI_SHIFT) | frameno;
@@ -3848,7 +3853,7 @@ static void linked_regs_unpack(u64 val, struct linked_regs *s)
3848
3853
3849
3854
/* for any branch, call, exit record the history of jmps in the given state */
3850
3855
static int push_insn_history(struct bpf_verifier_env *env, struct bpf_verifier_state *cur,
3851
- int insn_flags, u64 linked_regs)
3856
+ int insn_flags, u64 linked_regs, u8 sreg_flag, u8 dreg_flag )
3852
3857
{
3853
3858
struct bpf_insn_hist_entry *p;
3854
3859
size_t alloc_size;
@@ -3867,6 +3872,8 @@ static int push_insn_history(struct bpf_verifier_env *env, struct bpf_verifier_s
3867
3872
"verifier insn history bug: insn_idx %d linked_regs != 0: %#llx\n",
3868
3873
env->insn_idx, env->cur_hist_ent->linked_regs);
3869
3874
env->cur_hist_ent->linked_regs = linked_regs;
3875
+ env->cur_hist_ent->sreg_flag = sreg_flag;
3876
+ env->cur_hist_ent->dreg_flag = dreg_flag;
3870
3877
return 0;
3871
3878
}
3872
3879
@@ -3884,6 +3891,8 @@ static int push_insn_history(struct bpf_verifier_env *env, struct bpf_verifier_s
3884
3891
p->prev_idx = env->prev_insn_idx;
3885
3892
p->flags = insn_flags;
3886
3893
p->linked_regs = linked_regs;
3894
+ p->sreg_flag = sreg_flag;
3895
+ p->dreg_flag = dreg_flag;
3887
3896
3888
3897
cur->insn_hist_end++;
3889
3898
env->cur_hist_ent = p;
@@ -4406,6 +4415,8 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx,
4406
4415
*/
4407
4416
return 0;
4408
4417
} else if (BPF_SRC(insn->code) == BPF_X) {
4418
+ bool dreg_precise, sreg_precise;
4419
+
4409
4420
if (!bt_is_reg_set(bt, dreg) && !bt_is_reg_set(bt, sreg))
4410
4421
return 0;
4411
4422
/* dreg <cond> sreg
@@ -4414,8 +4425,16 @@ static int backtrack_insn(struct bpf_verifier_env *env, int idx, int subseq_idx,
4414
4425
* before it would be equally necessary to
4415
4426
* propagate it to dreg.
4416
4427
*/
4417
- bt_set_reg(bt, dreg);
4418
- bt_set_reg(bt, sreg);
4428
+ if (!hist)
4429
+ return 0;
4430
+ dreg_precise = hist->dreg_flag == insn_reg_with_access_flag(dreg);
4431
+ sreg_precise = hist->sreg_flag == insn_reg_with_access_flag(sreg);
4432
+ if (!dreg_precise && !sreg_precise)
4433
+ return 0;
4434
+ if (dreg_precise)
4435
+ bt_set_reg(bt, dreg);
4436
+ if (sreg_precise)
4437
+ bt_set_reg(bt, sreg);
4419
4438
} else if (BPF_SRC(insn->code) == BPF_K) {
4420
4439
/* dreg <cond> K
4421
4440
* Only dreg still needs precision before
@@ -5115,7 +5134,7 @@ static int check_stack_write_fixed_off(struct bpf_verifier_env *env,
5115
5134
}
5116
5135
5117
5136
if (insn_flags)
5118
- return push_insn_history(env, env->cur_state, insn_flags, 0);
5137
+ return push_insn_history(env, env->cur_state, insn_flags, 0, 0, 0 );
5119
5138
return 0;
5120
5139
}
5121
5140
@@ -5422,7 +5441,7 @@ static int check_stack_read_fixed_off(struct bpf_verifier_env *env,
5422
5441
insn_flags = 0; /* we are not restoring spilled register */
5423
5442
}
5424
5443
if (insn_flags)
5425
- return push_insn_history(env, env->cur_state, insn_flags, 0);
5444
+ return push_insn_history(env, env->cur_state, insn_flags, 0, 0, 0 );
5426
5445
return 0;
5427
5446
}
5428
5447
@@ -16414,6 +16433,27 @@ static void sync_linked_regs(struct bpf_verifier_state *vstate, struct bpf_reg_s
16414
16433
}
16415
16434
}
16416
16435
16436
+ static int push_cond_jmp_history(struct bpf_verifier_env *env, struct bpf_verifier_state *state,
16437
+ struct bpf_insn *insn, u64 linked_regs)
16438
+ {
16439
+ int err;
16440
+
16441
+ if ((BPF_SRC(insn->code) != BPF_X ||
16442
+ (insn->src_reg == BPF_REG_FP && insn->dst_reg == BPF_REG_FP)) &&
16443
+ !linked_regs)
16444
+ return 0;
16445
+
16446
+ err = push_insn_history(env, state, 0, linked_regs,
16447
+ BPF_SRC(insn->code) == BPF_X && insn->src_reg != BPF_REG_FP
16448
+ ? insn_reg_with_access_flag(insn->src_reg)
16449
+ : 0,
16450
+ BPF_SRC(insn->code) == BPF_X && insn->dst_reg != BPF_REG_FP
16451
+ ? insn_reg_with_access_flag(insn->dst_reg)
16452
+ : 0);
16453
+
16454
+ return err;
16455
+ }
16456
+
16417
16457
static int check_cond_jmp_op(struct bpf_verifier_env *env,
16418
16458
struct bpf_insn *insn, int *insn_idx)
16419
16459
{
@@ -16517,6 +16557,9 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env,
16517
16557
!sanitize_speculative_path(env, insn, *insn_idx + 1,
16518
16558
*insn_idx))
16519
16559
return -EFAULT;
16560
+ err = push_cond_jmp_history(env, this_branch, insn, 0);
16561
+ if (err)
16562
+ return err;
16520
16563
if (env->log.level & BPF_LOG_LEVEL)
16521
16564
print_insn_state(env, this_branch, this_branch->curframe);
16522
16565
*insn_idx += insn->off;
@@ -16531,6 +16574,9 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env,
16531
16574
*insn_idx + insn->off + 1,
16532
16575
*insn_idx))
16533
16576
return -EFAULT;
16577
+ err = push_cond_jmp_history(env, this_branch, insn, 0);
16578
+ if (err)
16579
+ return err;
16534
16580
if (env->log.level & BPF_LOG_LEVEL)
16535
16581
print_insn_state(env, this_branch, this_branch->curframe);
16536
16582
return 0;
@@ -16545,11 +16591,10 @@ static int check_cond_jmp_op(struct bpf_verifier_env *env,
16545
16591
collect_linked_regs(this_branch, src_reg->id, &linked_regs);
16546
16592
if (dst_reg->type == SCALAR_VALUE && dst_reg->id)
16547
16593
collect_linked_regs(this_branch, dst_reg->id, &linked_regs);
16548
- if (linked_regs.cnt > 1) {
16549
- err = push_insn_history(env, this_branch, 0, linked_regs_pack(&linked_regs));
16550
- if (err)
16551
- return err;
16552
- }
16594
+ err = push_cond_jmp_history(env, this_branch, insn,
16595
+ linked_regs.cnt > 1 ? linked_regs_pack(&linked_regs) : 0);
16596
+ if (err)
16597
+ return err;
16553
16598
16554
16599
other_branch = push_stack(env, *insn_idx + insn->off + 1, *insn_idx,
16555
16600
false);
@@ -19243,7 +19288,7 @@ static int is_state_visited(struct bpf_verifier_env *env, int insn_idx)
19243
19288
* the current state.
19244
19289
*/
19245
19290
if (is_jmp_point(env, env->insn_idx))
19246
- err = err ? : push_insn_history(env, cur, 0, 0);
19291
+ err = err ? : push_insn_history(env, cur, 0, 0, 0, 0 );
19247
19292
err = err ? : propagate_precision(env, &sl->state);
19248
19293
if (err)
19249
19294
return err;
@@ -19494,7 +19539,7 @@ static int do_check(struct bpf_verifier_env *env)
19494
19539
}
19495
19540
19496
19541
if (is_jmp_point(env, env->insn_idx)) {
19497
- err = push_insn_history(env, state, 0, 0);
19542
+ err = push_insn_history(env, state, 0, 0, 0, 0 );
19498
19543
if (err)
19499
19544
return err;
19500
19545
}
0 commit comments