Skip to content

Commit c00d738

Browse files
kkdwivediAlexei Starovoitov
authored and
Alexei Starovoitov
committed
bpf: Revert "bpf: Mark raw_tp arguments with PTR_MAYBE_NULL"
This patch reverts commit cb4158c ("bpf: Mark raw_tp arguments with PTR_MAYBE_NULL"). The patch was well-intended and meant to be as a stop-gap fixing branch prediction when the pointer may actually be NULL at runtime. Eventually, it was supposed to be replaced by an automated script or compiler pass detecting possibly NULL arguments and marking them accordingly. However, it caused two main issues observed for production programs and failed to preserve backwards compatibility. First, programs relied on the verifier not exploring == NULL branch when pointer is not NULL, thus they started failing with a 'dereference of scalar' error. Next, allowing raw_tp arguments to be modified surfaced the warning in the verifier that warns against reg->off when PTR_MAYBE_NULL is set. More information, context, and discusson on both problems is available in [0]. Overall, this approach had several shortcomings, and the fixes would further complicate the verifier's logic, and the entire masking scheme would have to be removed eventually anyway. Hence, revert the patch in preparation of a better fix avoiding these issues to replace this commit. [0]: https://lore.kernel.org/bpf/20241206161053.809580-1-memxor@gmail.com Reported-by: Manu Bretelle <chantra@meta.com> Fixes: cb4158c ("bpf: Mark raw_tp arguments with PTR_MAYBE_NULL") Signed-off-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Link: https://lore.kernel.org/r/20241213221929.3495062-2-memxor@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent e4c80f6 commit c00d738

File tree

4 files changed

+9
-87
lines changed

4 files changed

+9
-87
lines changed

include/linux/bpf.h

-6
Original file line numberDiff line numberDiff line change
@@ -3514,10 +3514,4 @@ static inline bool bpf_is_subprog(const struct bpf_prog *prog)
35143514
return prog->aux->func_idx != 0;
35153515
}
35163516

3517-
static inline bool bpf_prog_is_raw_tp(const struct bpf_prog *prog)
3518-
{
3519-
return prog->type == BPF_PROG_TYPE_TRACING &&
3520-
prog->expected_attach_type == BPF_TRACE_RAW_TP;
3521-
}
3522-
35233517
#endif /* _LINUX_BPF_H */

kernel/bpf/btf.c

+1-4
Original file line numberDiff line numberDiff line change
@@ -6594,10 +6594,7 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type,
65946594
if (prog_args_trusted(prog))
65956595
info->reg_type |= PTR_TRUSTED;
65966596

6597-
/* Raw tracepoint arguments always get marked as maybe NULL */
6598-
if (bpf_prog_is_raw_tp(prog))
6599-
info->reg_type |= PTR_MAYBE_NULL;
6600-
else if (btf_param_match_suffix(btf, &args[arg], "__nullable"))
6597+
if (btf_param_match_suffix(btf, &args[arg], "__nullable"))
66016598
info->reg_type |= PTR_MAYBE_NULL;
66026599

66036600
if (tgt_prog) {

kernel/bpf/verifier.c

+7-72
Original file line numberDiff line numberDiff line change
@@ -420,25 +420,6 @@ static struct btf_record *reg_btf_record(const struct bpf_reg_state *reg)
420420
return rec;
421421
}
422422

423-
static bool mask_raw_tp_reg_cond(const struct bpf_verifier_env *env, struct bpf_reg_state *reg) {
424-
return reg->type == (PTR_TO_BTF_ID | PTR_TRUSTED | PTR_MAYBE_NULL) &&
425-
bpf_prog_is_raw_tp(env->prog) && !reg->ref_obj_id;
426-
}
427-
428-
static bool mask_raw_tp_reg(const struct bpf_verifier_env *env, struct bpf_reg_state *reg)
429-
{
430-
if (!mask_raw_tp_reg_cond(env, reg))
431-
return false;
432-
reg->type &= ~PTR_MAYBE_NULL;
433-
return true;
434-
}
435-
436-
static void unmask_raw_tp_reg(struct bpf_reg_state *reg, bool result)
437-
{
438-
if (result)
439-
reg->type |= PTR_MAYBE_NULL;
440-
}
441-
442423
static bool subprog_is_global(const struct bpf_verifier_env *env, int subprog)
443424
{
444425
struct bpf_func_info_aux *aux = env->prog->aux->func_info_aux;
@@ -6801,7 +6782,6 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
68016782
const char *field_name = NULL;
68026783
enum bpf_type_flag flag = 0;
68036784
u32 btf_id = 0;
6804-
bool mask;
68056785
int ret;
68066786

68076787
if (!env->allow_ptr_leaks) {
@@ -6873,21 +6853,7 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
68736853

68746854
if (ret < 0)
68756855
return ret;
6876-
/* For raw_tp progs, we allow dereference of PTR_MAYBE_NULL
6877-
* trusted PTR_TO_BTF_ID, these are the ones that are possibly
6878-
* arguments to the raw_tp. Since internal checks in for trusted
6879-
* reg in check_ptr_to_btf_access would consider PTR_MAYBE_NULL
6880-
* modifier as problematic, mask it out temporarily for the
6881-
* check. Don't apply this to pointers with ref_obj_id > 0, as
6882-
* those won't be raw_tp args.
6883-
*
6884-
* We may end up applying this relaxation to other trusted
6885-
* PTR_TO_BTF_ID with maybe null flag, since we cannot
6886-
* distinguish PTR_MAYBE_NULL tagged for arguments vs normal
6887-
* tagging, but that should expand allowed behavior, and not
6888-
* cause regression for existing behavior.
6889-
*/
6890-
mask = mask_raw_tp_reg(env, reg);
6856+
68916857
if (ret != PTR_TO_BTF_ID) {
68926858
/* just mark; */
68936859

@@ -6948,13 +6914,8 @@ static int check_ptr_to_btf_access(struct bpf_verifier_env *env,
69486914
clear_trusted_flags(&flag);
69496915
}
69506916

6951-
if (atype == BPF_READ && value_regno >= 0) {
6917+
if (atype == BPF_READ && value_regno >= 0)
69526918
mark_btf_ld_reg(env, regs, value_regno, ret, reg->btf, btf_id, flag);
6953-
/* We've assigned a new type to regno, so don't undo masking. */
6954-
if (regno == value_regno)
6955-
mask = false;
6956-
}
6957-
unmask_raw_tp_reg(reg, mask);
69586919

69596920
return 0;
69606921
}
@@ -7329,7 +7290,7 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
73297290
if (!err && t == BPF_READ && value_regno >= 0)
73307291
mark_reg_unknown(env, regs, value_regno);
73317292
} else if (base_type(reg->type) == PTR_TO_BTF_ID &&
7332-
(mask_raw_tp_reg_cond(env, reg) || !type_may_be_null(reg->type))) {
7293+
!type_may_be_null(reg->type)) {
73337294
err = check_ptr_to_btf_access(env, regs, regno, off, size, t,
73347295
value_regno);
73357296
} else if (reg->type == CONST_PTR_TO_MAP) {
@@ -9032,7 +8993,6 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
90328993
enum bpf_reg_type type = reg->type;
90338994
u32 *arg_btf_id = NULL;
90348995
int err = 0;
9035-
bool mask;
90368996

90378997
if (arg_type == ARG_DONTCARE)
90388998
return 0;
@@ -9073,11 +9033,11 @@ static int check_func_arg(struct bpf_verifier_env *env, u32 arg,
90739033
base_type(arg_type) == ARG_PTR_TO_SPIN_LOCK)
90749034
arg_btf_id = fn->arg_btf_id[arg];
90759035

9076-
mask = mask_raw_tp_reg(env, reg);
90779036
err = check_reg_type(env, regno, arg_type, arg_btf_id, meta);
9037+
if (err)
9038+
return err;
90789039

9079-
err = err ?: check_func_arg_reg_off(env, reg, regno, arg_type);
9080-
unmask_raw_tp_reg(reg, mask);
9040+
err = check_func_arg_reg_off(env, reg, regno, arg_type);
90819041
if (err)
90829042
return err;
90839043

@@ -9872,17 +9832,14 @@ static int btf_check_func_arg_match(struct bpf_verifier_env *env, int subprog,
98729832
return ret;
98739833
} else if (base_type(arg->arg_type) == ARG_PTR_TO_BTF_ID) {
98749834
struct bpf_call_arg_meta meta;
9875-
bool mask;
98769835
int err;
98779836

98789837
if (register_is_null(reg) && type_may_be_null(arg->arg_type))
98799838
continue;
98809839

98819840
memset(&meta, 0, sizeof(meta)); /* leave func_id as zero */
9882-
mask = mask_raw_tp_reg(env, reg);
98839841
err = check_reg_type(env, regno, arg->arg_type, &arg->btf_id, &meta);
98849842
err = err ?: check_func_arg_reg_off(env, reg, regno, arg->arg_type);
9885-
unmask_raw_tp_reg(reg, mask);
98869843
if (err)
98879844
return err;
98889845
} else {
@@ -12205,7 +12162,6 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
1220512162
enum bpf_arg_type arg_type = ARG_DONTCARE;
1220612163
u32 regno = i + 1, ref_id, type_size;
1220712164
bool is_ret_buf_sz = false;
12208-
bool mask = false;
1220912165
int kf_arg_type;
1221012166

1221112167
t = btf_type_skip_modifiers(btf, args[i].type, NULL);
@@ -12264,15 +12220,12 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
1226412220
return -EINVAL;
1226512221
}
1226612222

12267-
mask = mask_raw_tp_reg(env, reg);
1226812223
if ((is_kfunc_trusted_args(meta) || is_kfunc_rcu(meta)) &&
1226912224
(register_is_null(reg) || type_may_be_null(reg->type)) &&
1227012225
!is_kfunc_arg_nullable(meta->btf, &args[i])) {
1227112226
verbose(env, "Possibly NULL pointer passed to trusted arg%d\n", i);
12272-
unmask_raw_tp_reg(reg, mask);
1227312227
return -EACCES;
1227412228
}
12275-
unmask_raw_tp_reg(reg, mask);
1227612229

1227712230
if (reg->ref_obj_id) {
1227812231
if (is_kfunc_release(meta) && meta->ref_obj_id) {
@@ -12330,24 +12283,16 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
1233012283
if (!is_kfunc_trusted_args(meta) && !is_kfunc_rcu(meta))
1233112284
break;
1233212285

12333-
/* Allow passing maybe NULL raw_tp arguments to
12334-
* kfuncs for compatibility. Don't apply this to
12335-
* arguments with ref_obj_id > 0.
12336-
*/
12337-
mask = mask_raw_tp_reg(env, reg);
1233812286
if (!is_trusted_reg(reg)) {
1233912287
if (!is_kfunc_rcu(meta)) {
1234012288
verbose(env, "R%d must be referenced or trusted\n", regno);
12341-
unmask_raw_tp_reg(reg, mask);
1234212289
return -EINVAL;
1234312290
}
1234412291
if (!is_rcu_reg(reg)) {
1234512292
verbose(env, "R%d must be a rcu pointer\n", regno);
12346-
unmask_raw_tp_reg(reg, mask);
1234712293
return -EINVAL;
1234812294
}
1234912295
}
12350-
unmask_raw_tp_reg(reg, mask);
1235112296
fallthrough;
1235212297
case KF_ARG_PTR_TO_CTX:
1235312298
case KF_ARG_PTR_TO_DYNPTR:
@@ -12370,9 +12315,7 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
1237012315

1237112316
if (is_kfunc_release(meta) && reg->ref_obj_id)
1237212317
arg_type |= OBJ_RELEASE;
12373-
mask = mask_raw_tp_reg(env, reg);
1237412318
ret = check_func_arg_reg_off(env, reg, regno, arg_type);
12375-
unmask_raw_tp_reg(reg, mask);
1237612319
if (ret < 0)
1237712320
return ret;
1237812321

@@ -12549,7 +12492,6 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
1254912492
ref_tname = btf_name_by_offset(btf, ref_t->name_off);
1255012493
fallthrough;
1255112494
case KF_ARG_PTR_TO_BTF_ID:
12552-
mask = mask_raw_tp_reg(env, reg);
1255312495
/* Only base_type is checked, further checks are done here */
1255412496
if ((base_type(reg->type) != PTR_TO_BTF_ID ||
1255512497
(bpf_type_has_unsafe_modifiers(reg->type) && !is_rcu_reg(reg))) &&
@@ -12558,11 +12500,9 @@ static int check_kfunc_args(struct bpf_verifier_env *env, struct bpf_kfunc_call_
1255812500
verbose(env, "expected %s or socket\n",
1255912501
reg_type_str(env, base_type(reg->type) |
1256012502
(type_flag(reg->type) & BPF_REG_TRUSTED_MODIFIERS)));
12561-
unmask_raw_tp_reg(reg, mask);
1256212503
return -EINVAL;
1256312504
}
1256412505
ret = process_kf_arg_ptr_to_btf_id(env, reg, ref_t, ref_tname, ref_id, meta, i);
12565-
unmask_raw_tp_reg(reg, mask);
1256612506
if (ret < 0)
1256712507
return ret;
1256812508
break;
@@ -13535,7 +13475,7 @@ static int sanitize_check_bounds(struct bpf_verifier_env *env,
1353513475
*/
1353613476
static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
1353713477
struct bpf_insn *insn,
13538-
struct bpf_reg_state *ptr_reg,
13478+
const struct bpf_reg_state *ptr_reg,
1353913479
const struct bpf_reg_state *off_reg)
1354013480
{
1354113481
struct bpf_verifier_state *vstate = env->cur_state;
@@ -13549,7 +13489,6 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
1354913489
struct bpf_sanitize_info info = {};
1355013490
u8 opcode = BPF_OP(insn->code);
1355113491
u32 dst = insn->dst_reg;
13552-
bool mask;
1355313492
int ret;
1355413493

1355513494
dst_reg = &regs[dst];
@@ -13576,14 +13515,11 @@ static int adjust_ptr_min_max_vals(struct bpf_verifier_env *env,
1357613515
return -EACCES;
1357713516
}
1357813517

13579-
mask = mask_raw_tp_reg(env, ptr_reg);
1358013518
if (ptr_reg->type & PTR_MAYBE_NULL) {
1358113519
verbose(env, "R%d pointer arithmetic on %s prohibited, null-check it first\n",
1358213520
dst, reg_type_str(env, ptr_reg->type));
13583-
unmask_raw_tp_reg(ptr_reg, mask);
1358413521
return -EACCES;
1358513522
}
13586-
unmask_raw_tp_reg(ptr_reg, mask);
1358713523

1358813524
switch (base_type(ptr_reg->type)) {
1358913525
case PTR_TO_CTX:
@@ -20126,7 +20062,6 @@ static int convert_ctx_accesses(struct bpf_verifier_env *env)
2012620062
* for this case.
2012720063
*/
2012820064
case PTR_TO_BTF_ID | MEM_ALLOC | PTR_UNTRUSTED:
20129-
case PTR_TO_BTF_ID | PTR_TRUSTED | PTR_MAYBE_NULL:
2013020065
if (type == BPF_READ) {
2013120066
if (BPF_MODE(insn->code) == BPF_MEM)
2013220067
insn->code = BPF_LDX | BPF_PROBE_MEM |

tools/testing/selftests/bpf/progs/test_tp_btf_nullable.c

+1-5
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,7 @@
77
#include "bpf_misc.h"
88

99
SEC("tp_btf/bpf_testmod_test_nullable_bare")
10-
/* This used to be a failure test, but raw_tp nullable arguments can now
11-
* directly be dereferenced, whether they have nullable annotation or not,
12-
* and don't need to be explicitly checked.
13-
*/
14-
__success
10+
__failure __msg("R1 invalid mem access 'trusted_ptr_or_null_'")
1511
int BPF_PROG(handle_tp_btf_nullable_bare1, struct bpf_testmod_test_read_ctx *nullable_ctx)
1612
{
1713
return nullable_ctx->len;

0 commit comments

Comments
 (0)