Skip to content

Commit 20b2aff

Browse files
haoluo1022Alexei Starovoitov
authored and
Alexei Starovoitov
committed
bpf: Introduce MEM_RDONLY flag
This patch introduce a flag MEM_RDONLY to tag a reg value pointing to read-only memory. It makes the following changes: 1. PTR_TO_RDWR_BUF -> PTR_TO_BUF 2. PTR_TO_RDONLY_BUF -> PTR_TO_BUF | MEM_RDONLY Signed-off-by: Hao Luo <[email protected]> Signed-off-by: Alexei Starovoitov <[email protected]> Link: https://lore.kernel.org/bpf/[email protected]
1 parent c25b2ae commit 20b2aff

File tree

6 files changed

+60
-43
lines changed

6 files changed

+60
-43
lines changed

include/linux/bpf.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -311,7 +311,10 @@ enum bpf_type_flag {
311311
/* PTR may be NULL. */
312312
PTR_MAYBE_NULL = BIT(0 + BPF_BASE_TYPE_BITS),
313313

314-
__BPF_TYPE_LAST_FLAG = PTR_MAYBE_NULL,
314+
/* MEM is read-only. */
315+
MEM_RDONLY = BIT(1 + BPF_BASE_TYPE_BITS),
316+
317+
__BPF_TYPE_LAST_FLAG = MEM_RDONLY,
315318
};
316319

317320
/* Max number of base types. */
@@ -492,8 +495,7 @@ enum bpf_reg_type {
492495
* an explicit null check is required for this struct.
493496
*/
494497
PTR_TO_MEM, /* reg points to valid memory region */
495-
PTR_TO_RDONLY_BUF, /* reg points to a readonly buffer */
496-
PTR_TO_RDWR_BUF, /* reg points to a read/write buffer */
498+
PTR_TO_BUF, /* reg points to a read/write buffer */
497499
PTR_TO_PERCPU_BTF_ID, /* reg points to a percpu kernel variable */
498500
PTR_TO_FUNC, /* reg points to a bpf program function */
499501
__BPF_REG_TYPE_MAX,

kernel/bpf/btf.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4944,8 +4944,7 @@ bool btf_ctx_access(int off, int size, enum bpf_access_type type,
49444944

49454945
type = base_type(ctx_arg_info->reg_type);
49464946
flag = type_flag(ctx_arg_info->reg_type);
4947-
if (ctx_arg_info->offset == off &&
4948-
(type == PTR_TO_RDWR_BUF || type == PTR_TO_RDONLY_BUF) &&
4947+
if (ctx_arg_info->offset == off && type == PTR_TO_BUF &&
49494948
(flag & PTR_MAYBE_NULL)) {
49504949
info->reg_type = ctx_arg_info->reg_type;
49514950
return true;

kernel/bpf/map_iter.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -174,9 +174,9 @@ static const struct bpf_iter_reg bpf_map_elem_reg_info = {
174174
.ctx_arg_info_size = 2,
175175
.ctx_arg_info = {
176176
{ offsetof(struct bpf_iter__bpf_map_elem, key),
177-
PTR_TO_RDONLY_BUF | PTR_MAYBE_NULL },
177+
PTR_TO_BUF | PTR_MAYBE_NULL | MEM_RDONLY },
178178
{ offsetof(struct bpf_iter__bpf_map_elem, value),
179-
PTR_TO_RDWR_BUF | PTR_MAYBE_NULL },
179+
PTR_TO_BUF | PTR_MAYBE_NULL },
180180
},
181181
};
182182

kernel/bpf/verifier.c

Lines changed: 50 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -455,6 +455,11 @@ static bool reg_type_may_be_refcounted_or_null(enum bpf_reg_type type)
455455
base_type(type) == PTR_TO_MEM;
456456
}
457457

458+
static bool type_is_rdonly_mem(u32 type)
459+
{
460+
return type & MEM_RDONLY;
461+
}
462+
458463
static bool arg_type_may_be_refcounted(enum bpf_arg_type type)
459464
{
460465
return type == ARG_PTR_TO_SOCK_COMMON;
@@ -530,7 +535,7 @@ static bool is_cmpxchg_insn(const struct bpf_insn *insn)
530535
static const char *reg_type_str(struct bpf_verifier_env *env,
531536
enum bpf_reg_type type)
532537
{
533-
char postfix[16] = {0};
538+
char postfix[16] = {0}, prefix[16] = {0};
534539
static const char * const str[] = {
535540
[NOT_INIT] = "?",
536541
[SCALAR_VALUE] = "inv",
@@ -550,8 +555,7 @@ static const char *reg_type_str(struct bpf_verifier_env *env,
550555
[PTR_TO_BTF_ID] = "ptr_",
551556
[PTR_TO_PERCPU_BTF_ID] = "percpu_ptr_",
552557
[PTR_TO_MEM] = "mem",
553-
[PTR_TO_RDONLY_BUF] = "rdonly_buf",
554-
[PTR_TO_RDWR_BUF] = "rdwr_buf",
558+
[PTR_TO_BUF] = "buf",
555559
[PTR_TO_FUNC] = "func",
556560
[PTR_TO_MAP_KEY] = "map_key",
557561
};
@@ -564,8 +568,11 @@ static const char *reg_type_str(struct bpf_verifier_env *env,
564568
strncpy(postfix, "_or_null", 16);
565569
}
566570

567-
snprintf(env->type_str_buf, TYPE_STR_BUF_LEN, "%s%s",
568-
str[base_type(type)], postfix);
571+
if (type & MEM_RDONLY)
572+
strncpy(prefix, "rdonly_", 16);
573+
574+
snprintf(env->type_str_buf, TYPE_STR_BUF_LEN, "%s%s%s",
575+
prefix, str[base_type(type)], postfix);
569576
return env->type_str_buf;
570577
}
571578

@@ -2755,8 +2762,7 @@ static bool is_spillable_regtype(enum bpf_reg_type type)
27552762
case PTR_TO_TCP_SOCK:
27562763
case PTR_TO_XDP_SOCK:
27572764
case PTR_TO_BTF_ID:
2758-
case PTR_TO_RDONLY_BUF:
2759-
case PTR_TO_RDWR_BUF:
2765+
case PTR_TO_BUF:
27602766
case PTR_TO_PERCPU_BTF_ID:
27612767
case PTR_TO_MEM:
27622768
case PTR_TO_FUNC:
@@ -4508,22 +4514,28 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
45084514
} else if (reg->type == CONST_PTR_TO_MAP) {
45094515
err = check_ptr_to_map_access(env, regs, regno, off, size, t,
45104516
value_regno);
4511-
} else if (reg->type == PTR_TO_RDONLY_BUF) {
4512-
if (t == BPF_WRITE) {
4513-
verbose(env, "R%d cannot write into %s\n",
4514-
regno, reg_type_str(env, reg->type));
4515-
return -EACCES;
4517+
} else if (base_type(reg->type) == PTR_TO_BUF) {
4518+
bool rdonly_mem = type_is_rdonly_mem(reg->type);
4519+
const char *buf_info;
4520+
u32 *max_access;
4521+
4522+
if (rdonly_mem) {
4523+
if (t == BPF_WRITE) {
4524+
verbose(env, "R%d cannot write into %s\n",
4525+
regno, reg_type_str(env, reg->type));
4526+
return -EACCES;
4527+
}
4528+
buf_info = "rdonly";
4529+
max_access = &env->prog->aux->max_rdonly_access;
4530+
} else {
4531+
buf_info = "rdwr";
4532+
max_access = &env->prog->aux->max_rdwr_access;
45164533
}
4534+
45174535
err = check_buffer_access(env, reg, regno, off, size, false,
4518-
"rdonly",
4519-
&env->prog->aux->max_rdonly_access);
4520-
if (!err && value_regno >= 0)
4521-
mark_reg_unknown(env, regs, value_regno);
4522-
} else if (reg->type == PTR_TO_RDWR_BUF) {
4523-
err = check_buffer_access(env, reg, regno, off, size, false,
4524-
"rdwr",
4525-
&env->prog->aux->max_rdwr_access);
4526-
if (!err && t == BPF_READ && value_regno >= 0)
4536+
buf_info, max_access);
4537+
4538+
if (!err && value_regno >= 0 && (rdonly_mem || t == BPF_READ))
45274539
mark_reg_unknown(env, regs, value_regno);
45284540
} else {
45294541
verbose(env, "R%d invalid mem access '%s'\n", regno,
@@ -4771,8 +4783,10 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, int regno,
47714783
struct bpf_call_arg_meta *meta)
47724784
{
47734785
struct bpf_reg_state *regs = cur_regs(env), *reg = &regs[regno];
4786+
const char *buf_info;
4787+
u32 *max_access;
47744788

4775-
switch (reg->type) {
4789+
switch (base_type(reg->type)) {
47764790
case PTR_TO_PACKET:
47774791
case PTR_TO_PACKET_META:
47784792
return check_packet_access(env, regno, reg->off, access_size,
@@ -4791,18 +4805,20 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, int regno,
47914805
return check_mem_region_access(env, regno, reg->off,
47924806
access_size, reg->mem_size,
47934807
zero_size_allowed);
4794-
case PTR_TO_RDONLY_BUF:
4795-
if (meta && meta->raw_mode)
4796-
return -EACCES;
4797-
return check_buffer_access(env, reg, regno, reg->off,
4798-
access_size, zero_size_allowed,
4799-
"rdonly",
4800-
&env->prog->aux->max_rdonly_access);
4801-
case PTR_TO_RDWR_BUF:
4808+
case PTR_TO_BUF:
4809+
if (type_is_rdonly_mem(reg->type)) {
4810+
if (meta && meta->raw_mode)
4811+
return -EACCES;
4812+
4813+
buf_info = "rdonly";
4814+
max_access = &env->prog->aux->max_rdonly_access;
4815+
} else {
4816+
buf_info = "rdwr";
4817+
max_access = &env->prog->aux->max_rdwr_access;
4818+
}
48024819
return check_buffer_access(env, reg, regno, reg->off,
48034820
access_size, zero_size_allowed,
4804-
"rdwr",
4805-
&env->prog->aux->max_rdwr_access);
4821+
buf_info, max_access);
48064822
case PTR_TO_STACK:
48074823
return check_stack_range_initialized(
48084824
env,
@@ -5081,8 +5097,8 @@ static const struct bpf_reg_types mem_types = {
50815097
PTR_TO_MAP_KEY,
50825098
PTR_TO_MAP_VALUE,
50835099
PTR_TO_MEM,
5084-
PTR_TO_RDONLY_BUF,
5085-
PTR_TO_RDWR_BUF,
5100+
PTR_TO_BUF,
5101+
PTR_TO_BUF | MEM_RDONLY,
50865102
},
50875103
};
50885104

net/core/bpf_sk_storage.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -929,7 +929,7 @@ static struct bpf_iter_reg bpf_sk_storage_map_reg_info = {
929929
{ offsetof(struct bpf_iter__bpf_sk_storage_map, sk),
930930
PTR_TO_BTF_ID_OR_NULL },
931931
{ offsetof(struct bpf_iter__bpf_sk_storage_map, value),
932-
PTR_TO_RDWR_BUF | PTR_MAYBE_NULL },
932+
PTR_TO_BUF | PTR_MAYBE_NULL },
933933
},
934934
.seq_info = &iter_seq_info,
935935
};

net/core/sock_map.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1564,7 +1564,7 @@ static struct bpf_iter_reg sock_map_iter_reg = {
15641564
.ctx_arg_info_size = 2,
15651565
.ctx_arg_info = {
15661566
{ offsetof(struct bpf_iter__sockmap, key),
1567-
PTR_TO_RDONLY_BUF | PTR_MAYBE_NULL },
1567+
PTR_TO_BUF | PTR_MAYBE_NULL | MEM_RDONLY },
15681568
{ offsetof(struct bpf_iter__sockmap, sk),
15691569
PTR_TO_BTF_ID_OR_NULL },
15701570
},

0 commit comments

Comments
 (0)