Skip to content

Commit 9d2bd80

Browse files
bpf: Introduce MEM_RDONLY flag
jira VULN-140 pre-cve CVE-2022-23222 commit-author Hao Luo <[email protected]> commit 20b2aff 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] (cherry picked from commit 20b2aff) Signed-off-by: Pratham Patel <[email protected]>
1 parent 84a49f7 commit 9d2bd80

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
@@ -291,7 +291,10 @@ enum bpf_type_flag {
291291
/* PTR may be NULL. */
292292
PTR_MAYBE_NULL = BIT(0 + BPF_BASE_TYPE_BITS),
293293

294-
__BPF_TYPE_LAST_FLAG = PTR_MAYBE_NULL,
294+
/* MEM is read-only. */
295+
MEM_RDONLY = BIT(1 + BPF_BASE_TYPE_BITS),
296+
297+
__BPF_TYPE_LAST_FLAG = MEM_RDONLY,
295298
};
296299

297300
/* Max number of base types. */
@@ -471,8 +474,7 @@ enum bpf_reg_type {
471474
* an explicit null check is required for this struct.
472475
*/
473476
PTR_TO_MEM, /* reg points to valid memory region */
474-
PTR_TO_RDONLY_BUF, /* reg points to a readonly buffer */
475-
PTR_TO_RDWR_BUF, /* reg points to a read/write buffer */
477+
PTR_TO_BUF, /* reg points to a read/write buffer */
476478
PTR_TO_PERCPU_BTF_ID, /* reg points to a percpu kernel variable */
477479
PTR_TO_FUNC, /* reg points to a bpf program function */
478480
__BPF_REG_TYPE_MAX,

kernel/bpf/btf.c

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

47584758
type = base_type(ctx_arg_info->reg_type);
47594759
flag = type_flag(ctx_arg_info->reg_type);
4760-
if (ctx_arg_info->offset == off &&
4761-
(type == PTR_TO_RDWR_BUF || type == PTR_TO_RDONLY_BUF) &&
4760+
if (ctx_arg_info->offset == off && type == PTR_TO_BUF &&
47624761
(flag & PTR_MAYBE_NULL)) {
47634762
info->reg_type = ctx_arg_info->reg_type;
47644763
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
@@ -459,6 +459,11 @@ static bool reg_type_may_be_refcounted_or_null(enum bpf_reg_type type)
459459
base_type(type) == PTR_TO_MEM;
460460
}
461461

462+
static bool type_is_rdonly_mem(u32 type)
463+
{
464+
return type & MEM_RDONLY;
465+
}
466+
462467
static bool arg_type_may_be_refcounted(enum bpf_arg_type type)
463468
{
464469
return type == ARG_PTR_TO_SOCK_COMMON;
@@ -534,7 +539,7 @@ static bool is_cmpxchg_insn(const struct bpf_insn *insn)
534539
static const char *reg_type_str(struct bpf_verifier_env *env,
535540
enum bpf_reg_type type)
536541
{
537-
char postfix[16] = {0};
542+
char postfix[16] = {0}, prefix[16] = {0};
538543
static const char * const str[] = {
539544
[NOT_INIT] = "?",
540545
[SCALAR_VALUE] = "inv",
@@ -554,8 +559,7 @@ static const char *reg_type_str(struct bpf_verifier_env *env,
554559
[PTR_TO_BTF_ID] = "ptr_",
555560
[PTR_TO_PERCPU_BTF_ID] = "percpu_ptr_",
556561
[PTR_TO_MEM] = "mem",
557-
[PTR_TO_RDONLY_BUF] = "rdonly_buf",
558-
[PTR_TO_RDWR_BUF] = "rdwr_buf",
562+
[PTR_TO_BUF] = "buf",
559563
[PTR_TO_FUNC] = "func",
560564
[PTR_TO_MAP_KEY] = "map_key",
561565
};
@@ -568,8 +572,11 @@ static const char *reg_type_str(struct bpf_verifier_env *env,
568572
strncpy(postfix, "_or_null", 16);
569573
}
570574

571-
snprintf(env->type_str_buf, TYPE_STR_BUF_LEN, "%s%s",
572-
str[base_type(type)], postfix);
575+
if (type & MEM_RDONLY)
576+
strncpy(prefix, "rdonly_", 16);
577+
578+
snprintf(env->type_str_buf, TYPE_STR_BUF_LEN, "%s%s%s",
579+
prefix, str[base_type(type)], postfix);
573580
return env->type_str_buf;
574581
}
575582

@@ -2489,8 +2496,7 @@ static bool is_spillable_regtype(enum bpf_reg_type type)
24892496
case PTR_TO_TCP_SOCK:
24902497
case PTR_TO_XDP_SOCK:
24912498
case PTR_TO_BTF_ID:
2492-
case PTR_TO_RDONLY_BUF:
2493-
case PTR_TO_RDWR_BUF:
2499+
case PTR_TO_BUF:
24942500
case PTR_TO_PERCPU_BTF_ID:
24952501
case PTR_TO_MEM:
24962502
case PTR_TO_FUNC:
@@ -4185,22 +4191,28 @@ static int check_mem_access(struct bpf_verifier_env *env, int insn_idx, u32 regn
41854191
} else if (reg->type == CONST_PTR_TO_MAP) {
41864192
err = check_ptr_to_map_access(env, regs, regno, off, size, t,
41874193
value_regno);
4188-
} else if (reg->type == PTR_TO_RDONLY_BUF) {
4189-
if (t == BPF_WRITE) {
4190-
verbose(env, "R%d cannot write into %s\n",
4191-
regno, reg_type_str(env, reg->type));
4192-
return -EACCES;
4194+
} else if (base_type(reg->type) == PTR_TO_BUF) {
4195+
bool rdonly_mem = type_is_rdonly_mem(reg->type);
4196+
const char *buf_info;
4197+
u32 *max_access;
4198+
4199+
if (rdonly_mem) {
4200+
if (t == BPF_WRITE) {
4201+
verbose(env, "R%d cannot write into %s\n",
4202+
regno, reg_type_str(env, reg->type));
4203+
return -EACCES;
4204+
}
4205+
buf_info = "rdonly";
4206+
max_access = &env->prog->aux->max_rdonly_access;
4207+
} else {
4208+
buf_info = "rdwr";
4209+
max_access = &env->prog->aux->max_rdwr_access;
41934210
}
4211+
41944212
err = check_buffer_access(env, reg, regno, off, size, false,
4195-
"rdonly",
4196-
&env->prog->aux->max_rdonly_access);
4197-
if (!err && value_regno >= 0)
4198-
mark_reg_unknown(env, regs, value_regno);
4199-
} else if (reg->type == PTR_TO_RDWR_BUF) {
4200-
err = check_buffer_access(env, reg, regno, off, size, false,
4201-
"rdwr",
4202-
&env->prog->aux->max_rdwr_access);
4203-
if (!err && t == BPF_READ && value_regno >= 0)
4213+
buf_info, max_access);
4214+
4215+
if (!err && value_regno >= 0 && (rdonly_mem || t == BPF_READ))
42044216
mark_reg_unknown(env, regs, value_regno);
42054217
} else {
42064218
verbose(env, "R%d invalid mem access '%s'\n", regno,
@@ -4448,8 +4460,10 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, int regno,
44484460
struct bpf_call_arg_meta *meta)
44494461
{
44504462
struct bpf_reg_state *regs = cur_regs(env), *reg = &regs[regno];
4463+
const char *buf_info;
4464+
u32 *max_access;
44514465

4452-
switch (reg->type) {
4466+
switch (base_type(reg->type)) {
44534467
case PTR_TO_PACKET:
44544468
case PTR_TO_PACKET_META:
44554469
return check_packet_access(env, regno, reg->off, access_size,
@@ -4468,18 +4482,20 @@ static int check_helper_mem_access(struct bpf_verifier_env *env, int regno,
44684482
return check_mem_region_access(env, regno, reg->off,
44694483
access_size, reg->mem_size,
44704484
zero_size_allowed);
4471-
case PTR_TO_RDONLY_BUF:
4472-
if (meta && meta->raw_mode)
4473-
return -EACCES;
4474-
return check_buffer_access(env, reg, regno, reg->off,
4475-
access_size, zero_size_allowed,
4476-
"rdonly",
4477-
&env->prog->aux->max_rdonly_access);
4478-
case PTR_TO_RDWR_BUF:
4485+
case PTR_TO_BUF:
4486+
if (type_is_rdonly_mem(reg->type)) {
4487+
if (meta && meta->raw_mode)
4488+
return -EACCES;
4489+
4490+
buf_info = "rdonly";
4491+
max_access = &env->prog->aux->max_rdonly_access;
4492+
} else {
4493+
buf_info = "rdwr";
4494+
max_access = &env->prog->aux->max_rdwr_access;
4495+
}
44794496
return check_buffer_access(env, reg, regno, reg->off,
44804497
access_size, zero_size_allowed,
4481-
"rdwr",
4482-
&env->prog->aux->max_rdwr_access);
4498+
buf_info, max_access);
44834499
case PTR_TO_STACK:
44844500
return check_stack_range_initialized(
44854501
env,
@@ -4707,8 +4723,8 @@ static const struct bpf_reg_types mem_types = {
47074723
PTR_TO_MAP_KEY,
47084724
PTR_TO_MAP_VALUE,
47094725
PTR_TO_MEM,
4710-
PTR_TO_RDONLY_BUF,
4711-
PTR_TO_RDWR_BUF,
4726+
PTR_TO_BUF,
4727+
PTR_TO_BUF | MEM_RDONLY,
47124728
},
47134729
};
47144730

net/core/bpf_sk_storage.c

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

net/core/sock_map.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1586,7 +1586,7 @@ static struct bpf_iter_reg sock_map_iter_reg = {
15861586
.ctx_arg_info_size = 2,
15871587
.ctx_arg_info = {
15881588
{ offsetof(struct bpf_iter__sockmap, key),
1589-
PTR_TO_RDONLY_BUF | PTR_MAYBE_NULL },
1589+
PTR_TO_BUF | PTR_MAYBE_NULL | MEM_RDONLY },
15901590
{ offsetof(struct bpf_iter__sockmap, sk),
15911591
PTR_TO_BTF_ID_OR_NULL },
15921592
},

0 commit comments

Comments
 (0)