@@ -362,20 +362,23 @@ __printf(2, 3) static void verbose(void *private_data, const char *fmt, ...)
362
362
363
363
static void verbose_invalid_scalar(struct bpf_verifier_env *env,
364
364
struct bpf_reg_state *reg,
365
- struct tnum * range, const char *ctx,
365
+ struct bpf_retval_range range, const char *ctx,
366
366
const char *reg_name)
367
367
{
368
- char tn_buf[48] ;
368
+ bool unknown = true ;
369
369
370
- verbose(env, "At %s the register %s ", ctx, reg_name);
371
- if (!tnum_is_unknown(reg->var_off)) {
372
- tnum_strn(tn_buf, sizeof(tn_buf), reg->var_off);
373
- verbose(env, "has value %s", tn_buf);
374
- } else {
375
- verbose(env, "has unknown scalar value");
370
+ verbose(env, "%s the register %s has", ctx, reg_name);
371
+ if (reg->smin_value > S64_MIN) {
372
+ verbose(env, " smin=%lld", reg->smin_value);
373
+ unknown = false;
376
374
}
377
- tnum_strn(tn_buf, sizeof(tn_buf), *range);
378
- verbose(env, " should have been in %s\n", tn_buf);
375
+ if (reg->smax_value < S64_MAX) {
376
+ verbose(env, " smax=%lld", reg->smax_value);
377
+ unknown = false;
378
+ }
379
+ if (unknown)
380
+ verbose(env, " unknown scalar value");
381
+ verbose(env, " should have been in [%d, %d]\n", range.minval, range.maxval);
379
382
}
380
383
381
384
static bool type_may_be_null(u32 type)
@@ -2305,6 +2308,11 @@ static void init_reg_state(struct bpf_verifier_env *env,
2305
2308
regs[BPF_REG_FP].frameno = state->frameno;
2306
2309
}
2307
2310
2311
+ static struct bpf_retval_range retval_range(s32 minval, s32 maxval)
2312
+ {
2313
+ return (struct bpf_retval_range){ minval, maxval };
2314
+ }
2315
+
2308
2316
#define BPF_MAIN_FUNC (-1)
2309
2317
static void init_func_state(struct bpf_verifier_env *env,
2310
2318
struct bpf_func_state *state,
@@ -2313,7 +2321,7 @@ static void init_func_state(struct bpf_verifier_env *env,
2313
2321
state->callsite = callsite;
2314
2322
state->frameno = frameno;
2315
2323
state->subprogno = subprogno;
2316
- state->callback_ret_range = tnum_range (0, 0);
2324
+ state->callback_ret_range = retval_range (0, 0);
2317
2325
init_reg_state(env, state);
2318
2326
mark_verifier_state_scratched(env);
2319
2327
}
@@ -9396,7 +9404,7 @@ static int set_map_elem_callback_state(struct bpf_verifier_env *env,
9396
9404
return err;
9397
9405
9398
9406
callee->in_callback_fn = true;
9399
- callee->callback_ret_range = tnum_range (0, 1);
9407
+ callee->callback_ret_range = retval_range (0, 1);
9400
9408
return 0;
9401
9409
}
9402
9410
@@ -9418,7 +9426,7 @@ static int set_loop_callback_state(struct bpf_verifier_env *env,
9418
9426
__mark_reg_not_init(env, &callee->regs[BPF_REG_5]);
9419
9427
9420
9428
callee->in_callback_fn = true;
9421
- callee->callback_ret_range = tnum_range (0, 1);
9429
+ callee->callback_ret_range = retval_range (0, 1);
9422
9430
return 0;
9423
9431
}
9424
9432
@@ -9448,7 +9456,7 @@ static int set_timer_callback_state(struct bpf_verifier_env *env,
9448
9456
__mark_reg_not_init(env, &callee->regs[BPF_REG_4]);
9449
9457
__mark_reg_not_init(env, &callee->regs[BPF_REG_5]);
9450
9458
callee->in_async_callback_fn = true;
9451
- callee->callback_ret_range = tnum_range (0, 1);
9459
+ callee->callback_ret_range = retval_range (0, 1);
9452
9460
return 0;
9453
9461
}
9454
9462
@@ -9476,7 +9484,7 @@ static int set_find_vma_callback_state(struct bpf_verifier_env *env,
9476
9484
__mark_reg_not_init(env, &callee->regs[BPF_REG_4]);
9477
9485
__mark_reg_not_init(env, &callee->regs[BPF_REG_5]);
9478
9486
callee->in_callback_fn = true;
9479
- callee->callback_ret_range = tnum_range (0, 1);
9487
+ callee->callback_ret_range = retval_range (0, 1);
9480
9488
return 0;
9481
9489
}
9482
9490
@@ -9499,7 +9507,7 @@ static int set_user_ringbuf_callback_state(struct bpf_verifier_env *env,
9499
9507
__mark_reg_not_init(env, &callee->regs[BPF_REG_5]);
9500
9508
9501
9509
callee->in_callback_fn = true;
9502
- callee->callback_ret_range = tnum_range (0, 1);
9510
+ callee->callback_ret_range = retval_range (0, 1);
9503
9511
return 0;
9504
9512
}
9505
9513
@@ -9531,7 +9539,7 @@ static int set_rbtree_add_callback_state(struct bpf_verifier_env *env,
9531
9539
__mark_reg_not_init(env, &callee->regs[BPF_REG_4]);
9532
9540
__mark_reg_not_init(env, &callee->regs[BPF_REG_5]);
9533
9541
callee->in_callback_fn = true;
9534
- callee->callback_ret_range = tnum_range (0, 1);
9542
+ callee->callback_ret_range = retval_range (0, 1);
9535
9543
return 0;
9536
9544
}
9537
9545
@@ -9560,6 +9568,11 @@ static bool in_rbtree_lock_required_cb(struct bpf_verifier_env *env)
9560
9568
return is_rbtree_lock_required_kfunc(kfunc_btf_id);
9561
9569
}
9562
9570
9571
+ static bool retval_range_within(struct bpf_retval_range range, const struct bpf_reg_state *reg)
9572
+ {
9573
+ return range.minval <= reg->smin_value && reg->smax_value <= range.maxval;
9574
+ }
9575
+
9563
9576
static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx)
9564
9577
{
9565
9578
struct bpf_verifier_state *state = env->cur_state, *prev_st;
@@ -9583,15 +9596,21 @@ static int prepare_func_exit(struct bpf_verifier_env *env, int *insn_idx)
9583
9596
9584
9597
caller = state->frame[state->curframe - 1];
9585
9598
if (callee->in_callback_fn) {
9586
- /* enforce R0 return value range [0, 1]. */
9587
- struct tnum range = callee->callback_ret_range;
9588
-
9589
9599
if (r0->type != SCALAR_VALUE) {
9590
9600
verbose(env, "R0 not a scalar value\n");
9591
9601
return -EACCES;
9592
9602
}
9593
- if (!tnum_in(range, r0->var_off)) {
9594
- verbose_invalid_scalar(env, r0, &range, "callback return", "R0");
9603
+
9604
+ /* we are going to rely on register's precise value */
9605
+ err = mark_reg_read(env, r0, r0->parent, REG_LIVE_READ64);
9606
+ err = err ?: mark_chain_precision(env, BPF_REG_0);
9607
+ if (err)
9608
+ return err;
9609
+
9610
+ /* enforce R0 return value range */
9611
+ if (!retval_range_within(callee->callback_ret_range, r0)) {
9612
+ verbose_invalid_scalar(env, r0, callee->callback_ret_range,
9613
+ "At callback return", "R0");
9595
9614
return -EINVAL;
9596
9615
}
9597
9616
if (!calls_callback(env, callee->callsite)) {
@@ -11805,7 +11824,7 @@ static int fetch_kfunc_meta(struct bpf_verifier_env *env,
11805
11824
return 0;
11806
11825
}
11807
11826
11808
- static int check_return_code(struct bpf_verifier_env *env, int regno);
11827
+ static int check_return_code(struct bpf_verifier_env *env, int regno, const char *reg_name );
11809
11828
11810
11829
static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
11811
11830
int *insn_idx_p)
@@ -11942,7 +11961,7 @@ static int check_kfunc_call(struct bpf_verifier_env *env, struct bpf_insn *insn,
11942
11961
* to bpf_throw becomes the return value of the program.
11943
11962
*/
11944
11963
if (!env->exception_callback_subprog) {
11945
- err = check_return_code(env, BPF_REG_1);
11964
+ err = check_return_code(env, BPF_REG_1, "R1" );
11946
11965
if (err < 0)
11947
11966
return err;
11948
11967
}
@@ -14972,12 +14991,13 @@ static int check_ld_abs(struct bpf_verifier_env *env, struct bpf_insn *insn)
14972
14991
return 0;
14973
14992
}
14974
14993
14975
- static int check_return_code(struct bpf_verifier_env *env, int regno)
14994
+ static int check_return_code(struct bpf_verifier_env *env, int regno, const char *reg_name )
14976
14995
{
14996
+ const char *exit_ctx = "At program exit";
14977
14997
struct tnum enforce_attach_type_range = tnum_unknown;
14978
14998
const struct bpf_prog *prog = env->prog;
14979
14999
struct bpf_reg_state *reg;
14980
- struct tnum range = tnum_range (0, 1), const_0 = tnum_const(0 );
15000
+ struct bpf_retval_range range = retval_range (0, 1);
14981
15001
enum bpf_prog_type prog_type = resolve_prog_type(env->prog);
14982
15002
int err;
14983
15003
struct bpf_func_state *frame = env->cur_state->frame[0];
@@ -15019,17 +15039,9 @@ static int check_return_code(struct bpf_verifier_env *env, int regno)
15019
15039
15020
15040
if (frame->in_async_callback_fn) {
15021
15041
/* enforce return zero from async callbacks like timer */
15022
- if (reg->type != SCALAR_VALUE) {
15023
- verbose(env, "In async callback the register R%d is not a known value (%s)\n",
15024
- regno, reg_type_str(env, reg->type));
15025
- return -EINVAL;
15026
- }
15027
-
15028
- if (!tnum_in(const_0, reg->var_off)) {
15029
- verbose_invalid_scalar(env, reg, &const_0, "async callback", "R0");
15030
- return -EINVAL;
15031
- }
15032
- return 0;
15042
+ exit_ctx = "At async callback return";
15043
+ range = retval_range(0, 0);
15044
+ goto enforce_retval;
15033
15045
}
15034
15046
15035
15047
if (is_subprog && !frame->in_exception_callback_fn) {
@@ -15052,14 +15064,14 @@ static int check_return_code(struct bpf_verifier_env *env, int regno)
15052
15064
env->prog->expected_attach_type == BPF_CGROUP_INET4_GETSOCKNAME ||
15053
15065
env->prog->expected_attach_type == BPF_CGROUP_INET6_GETSOCKNAME ||
15054
15066
env->prog->expected_attach_type == BPF_CGROUP_UNIX_GETSOCKNAME)
15055
- range = tnum_range (1, 1);
15067
+ range = retval_range (1, 1);
15056
15068
if (env->prog->expected_attach_type == BPF_CGROUP_INET4_BIND ||
15057
15069
env->prog->expected_attach_type == BPF_CGROUP_INET6_BIND)
15058
- range = tnum_range (0, 3);
15070
+ range = retval_range (0, 3);
15059
15071
break;
15060
15072
case BPF_PROG_TYPE_CGROUP_SKB:
15061
15073
if (env->prog->expected_attach_type == BPF_CGROUP_INET_EGRESS) {
15062
- range = tnum_range (0, 3);
15074
+ range = retval_range (0, 3);
15063
15075
enforce_attach_type_range = tnum_range(2, 3);
15064
15076
}
15065
15077
break;
@@ -15072,13 +15084,13 @@ static int check_return_code(struct bpf_verifier_env *env, int regno)
15072
15084
case BPF_PROG_TYPE_RAW_TRACEPOINT:
15073
15085
if (!env->prog->aux->attach_btf_id)
15074
15086
return 0;
15075
- range = tnum_const( 0);
15087
+ range = retval_range(0, 0);
15076
15088
break;
15077
15089
case BPF_PROG_TYPE_TRACING:
15078
15090
switch (env->prog->expected_attach_type) {
15079
15091
case BPF_TRACE_FENTRY:
15080
15092
case BPF_TRACE_FEXIT:
15081
- range = tnum_const( 0);
15093
+ range = retval_range(0, 0);
15082
15094
break;
15083
15095
case BPF_TRACE_RAW_TP:
15084
15096
case BPF_MODIFY_RETURN:
@@ -15090,7 +15102,7 @@ static int check_return_code(struct bpf_verifier_env *env, int regno)
15090
15102
}
15091
15103
break;
15092
15104
case BPF_PROG_TYPE_SK_LOOKUP:
15093
- range = tnum_range (SK_DROP, SK_PASS);
15105
+ range = retval_range (SK_DROP, SK_PASS);
15094
15106
break;
15095
15107
15096
15108
case BPF_PROG_TYPE_LSM:
@@ -15104,12 +15116,12 @@ static int check_return_code(struct bpf_verifier_env *env, int regno)
15104
15116
/* Make sure programs that attach to void
15105
15117
* hooks don't try to modify return value.
15106
15118
*/
15107
- range = tnum_range (1, 1);
15119
+ range = retval_range (1, 1);
15108
15120
}
15109
15121
break;
15110
15122
15111
15123
case BPF_PROG_TYPE_NETFILTER:
15112
- range = tnum_range (NF_DROP, NF_ACCEPT);
15124
+ range = retval_range (NF_DROP, NF_ACCEPT);
15113
15125
break;
15114
15126
case BPF_PROG_TYPE_EXT:
15115
15127
/* freplace program can return anything as its return value
@@ -15119,15 +15131,21 @@ static int check_return_code(struct bpf_verifier_env *env, int regno)
15119
15131
return 0;
15120
15132
}
15121
15133
15134
+ enforce_retval:
15122
15135
if (reg->type != SCALAR_VALUE) {
15123
- verbose(env, "At program exit the register R%d is not a known value (%s)\n",
15124
- regno, reg_type_str(env, reg->type));
15136
+ verbose(env, "%s the register R%d is not a known value (%s)\n",
15137
+ exit_ctx, regno, reg_type_str(env, reg->type));
15125
15138
return -EINVAL;
15126
15139
}
15127
15140
15128
- if (!tnum_in(range, reg->var_off)) {
15129
- verbose_invalid_scalar(env, reg, &range, "program exit", "R0");
15130
- if (prog->expected_attach_type == BPF_LSM_CGROUP &&
15141
+ err = mark_chain_precision(env, regno);
15142
+ if (err)
15143
+ return err;
15144
+
15145
+ if (!retval_range_within(range, reg)) {
15146
+ verbose_invalid_scalar(env, reg, range, exit_ctx, reg_name);
15147
+ if (!is_subprog &&
15148
+ prog->expected_attach_type == BPF_LSM_CGROUP &&
15131
15149
prog_type == BPF_PROG_TYPE_LSM &&
15132
15150
!prog->aux->attach_func_proto->type)
15133
15151
verbose(env, "Note, BPF_LSM_CGROUP that attach to void LSM hooks can't modify return value!\n");
@@ -17410,7 +17428,7 @@ static int do_check(struct bpf_verifier_env *env)
17410
17428
continue;
17411
17429
}
17412
17430
17413
- err = check_return_code(env, BPF_REG_0);
17431
+ err = check_return_code(env, BPF_REG_0, "R0" );
17414
17432
if (err)
17415
17433
return err;
17416
17434
process_bpf_exit:
0 commit comments