Skip to content

Commit 48f862d

Browse files
bpf: Add MEM_RDONLY for helper args that are pointers to rdonly mem.
jira VULN-132 cve CVE-2022-0500 commit-author Hao Luo <haoluo@google.com> commit 216e3cd upstream-diff A merge confict arised because several commits were introduced since linux-4.18.y untill this commit (216e3cd ("bpf: Add MEM_RDONLY for helper args that are pointers to rdonly mem.")) was merged upstream. Not listing all commits because there are 20+ such commits. Some helper functions may modify its arguments, for example, bpf_d_path, bpf_get_stack etc. Previously, their argument types were marked as ARG_PTR_TO_MEM, which is compatible with read-only mem types, such as PTR_TO_RDONLY_BUF. Therefore it's legitimate, but technically incorrect, to modify a read-only memory by passing it into one of such helper functions. This patch tags the bpf_args compatible with immutable memory with MEM_RDONLY flag. The arguments that don't have this flag will be only compatible with mutable memory types, preventing the helper from modifying a read-only memory. The bpf_args that have MEM_RDONLY are compatible with both mutable memory and immutable memory. Signed-off-by: Hao Luo <haoluo@google.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Link: https://lore.kernel.org/bpf/20211217003152.48334-9-haoluo@google.com (cherry picked from commit 216e3cd) Signed-off-by: Pratham Patel <ppatel@ciq.com>
1 parent 8cdf7b6 commit 48f862d

File tree

7 files changed

+68
-52
lines changed

7 files changed

+68
-52
lines changed

include/linux/bpf.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -291,7 +291,9 @@ enum bpf_type_flag {
291291
/* PTR may be NULL. */
292292
PTR_MAYBE_NULL = BIT(0 + BPF_BASE_TYPE_BITS),
293293

294-
/* MEM is read-only. */
294+
/* MEM is read-only. When applied on bpf_arg, it indicates the arg is
295+
* compatible with both mutable and immutable memory.
296+
*/
295297
MEM_RDONLY = BIT(1 + BPF_BASE_TYPE_BITS),
296298

297299
__BPF_TYPE_LAST_FLAG = MEM_RDONLY,

kernel/bpf/cgroup.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1738,7 +1738,7 @@ static const struct bpf_func_proto bpf_sysctl_set_new_value_proto = {
17381738
.gpl_only = false,
17391739
.ret_type = RET_INTEGER,
17401740
.arg1_type = ARG_PTR_TO_CTX,
1741-
.arg2_type = ARG_PTR_TO_MEM,
1741+
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
17421742
.arg3_type = ARG_CONST_SIZE,
17431743
};
17441744

kernel/bpf/helpers.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -523,7 +523,7 @@ const struct bpf_func_proto bpf_strtol_proto = {
523523
.func = bpf_strtol,
524524
.gpl_only = false,
525525
.ret_type = RET_INTEGER,
526-
.arg1_type = ARG_PTR_TO_MEM,
526+
.arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY,
527527
.arg2_type = ARG_CONST_SIZE,
528528
.arg3_type = ARG_ANYTHING,
529529
.arg4_type = ARG_PTR_TO_LONG,
@@ -551,7 +551,7 @@ const struct bpf_func_proto bpf_strtoul_proto = {
551551
.func = bpf_strtoul,
552552
.gpl_only = false,
553553
.ret_type = RET_INTEGER,
554-
.arg1_type = ARG_PTR_TO_MEM,
554+
.arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY,
555555
.arg2_type = ARG_CONST_SIZE,
556556
.arg3_type = ARG_ANYTHING,
557557
.arg4_type = ARG_PTR_TO_LONG,
@@ -623,7 +623,7 @@ const struct bpf_func_proto bpf_event_output_data_proto = {
623623
.arg1_type = ARG_PTR_TO_CTX,
624624
.arg2_type = ARG_CONST_MAP_PTR,
625625
.arg3_type = ARG_ANYTHING,
626-
.arg4_type = ARG_PTR_TO_MEM,
626+
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
627627
.arg5_type = ARG_CONST_SIZE_OR_ZERO,
628628
};
629629

@@ -992,7 +992,7 @@ const struct bpf_func_proto bpf_snprintf_proto = {
992992
.arg1_type = ARG_PTR_TO_MEM_OR_NULL,
993993
.arg2_type = ARG_CONST_SIZE_OR_ZERO,
994994
.arg3_type = ARG_PTR_TO_CONST_STR,
995-
.arg4_type = ARG_PTR_TO_MEM_OR_NULL,
995+
.arg4_type = ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY,
996996
.arg5_type = ARG_CONST_SIZE_OR_ZERO,
997997
};
998998

kernel/bpf/ringbuf.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -442,7 +442,7 @@ const struct bpf_func_proto bpf_ringbuf_output_proto = {
442442
.func = bpf_ringbuf_output,
443443
.ret_type = RET_INTEGER,
444444
.arg1_type = ARG_CONST_MAP_PTR,
445-
.arg2_type = ARG_PTR_TO_MEM,
445+
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
446446
.arg3_type = ARG_CONST_SIZE_OR_ZERO,
447447
.arg4_type = ARG_ANYTHING,
448448
};

kernel/bpf/verifier.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4739,7 +4739,6 @@ static const struct bpf_reg_types mem_types = {
47394739
PTR_TO_MAP_VALUE,
47404740
PTR_TO_MEM,
47414741
PTR_TO_BUF,
4742-
PTR_TO_BUF | MEM_RDONLY,
47434742
},
47444743
};
47454744

@@ -4807,6 +4806,21 @@ static int check_reg_type(struct bpf_verifier_env *env, u32 regno,
48074806
return -EFAULT;
48084807
}
48094808

4809+
/* ARG_PTR_TO_MEM + RDONLY is compatible with PTR_TO_MEM and PTR_TO_MEM + RDONLY,
4810+
* but ARG_PTR_TO_MEM is compatible only with PTR_TO_MEM and NOT with PTR_TO_MEM + RDONLY
4811+
*
4812+
* Same for MAYBE_NULL:
4813+
*
4814+
* ARG_PTR_TO_MEM + MAYBE_NULL is compatible with PTR_TO_MEM and PTR_TO_MEM + MAYBE_NULL,
4815+
* but ARG_PTR_TO_MEM is compatible only with PTR_TO_MEM but NOT with PTR_TO_MEM + MAYBE_NULL
4816+
*
4817+
* Therefore we fold these flags depending on the arg_type before comparison.
4818+
*/
4819+
if (arg_type & MEM_RDONLY)
4820+
type &= ~MEM_RDONLY;
4821+
if (arg_type & PTR_MAYBE_NULL)
4822+
type &= ~PTR_MAYBE_NULL;
4823+
48104824
for (i = 0; i < ARRAY_SIZE(compatible->types); i++) {
48114825
expected = compatible->types[i];
48124826
if (expected == NOT_INIT)
@@ -4816,14 +4830,14 @@ static int check_reg_type(struct bpf_verifier_env *env, u32 regno,
48164830
goto found;
48174831
}
48184832

4819-
verbose(env, "R%d type=%s expected=", regno, reg_type_str(env, type));
4833+
verbose(env, "R%d type=%s expected=", regno, reg_type_str(env, reg->type));
48204834
for (j = 0; j + 1 < i; j++)
48214835
verbose(env, "%s, ", reg_type_str(env, compatible->types[j]));
48224836
verbose(env, "%s\n", reg_type_str(env, compatible->types[j]));
48234837
return -EACCES;
48244838

48254839
found:
4826-
if (type == PTR_TO_BTF_ID) {
4840+
if (reg->type == PTR_TO_BTF_ID) {
48274841
if (!arg_btf_id) {
48284842
if (!compatible->btf_id) {
48294843
verbose(env, "verifier internal error: missing arg compatible BTF ID\n");

kernel/trace/bpf_trace.c

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -347,7 +347,7 @@ static const struct bpf_func_proto bpf_probe_write_user_proto = {
347347
.gpl_only = true,
348348
.ret_type = RET_INTEGER,
349349
.arg1_type = ARG_ANYTHING,
350-
.arg2_type = ARG_PTR_TO_MEM,
350+
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
351351
.arg3_type = ARG_CONST_SIZE,
352352
};
353353

@@ -396,7 +396,7 @@ static const struct bpf_func_proto bpf_trace_printk_proto = {
396396
.func = bpf_trace_printk,
397397
.gpl_only = true,
398398
.ret_type = RET_INTEGER,
399-
.arg1_type = ARG_PTR_TO_MEM,
399+
.arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY,
400400
.arg2_type = ARG_CONST_SIZE,
401401
};
402402

@@ -448,9 +448,9 @@ static const struct bpf_func_proto bpf_seq_printf_proto = {
448448
.ret_type = RET_INTEGER,
449449
.arg1_type = ARG_PTR_TO_BTF_ID,
450450
.arg1_btf_id = &btf_seq_file_ids[0],
451-
.arg2_type = ARG_PTR_TO_MEM,
451+
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
452452
.arg3_type = ARG_CONST_SIZE,
453-
.arg4_type = ARG_PTR_TO_MEM_OR_NULL,
453+
.arg4_type = ARG_PTR_TO_MEM | PTR_MAYBE_NULL | MEM_RDONLY,
454454
.arg5_type = ARG_CONST_SIZE_OR_ZERO,
455455
};
456456

@@ -465,7 +465,7 @@ static const struct bpf_func_proto bpf_seq_write_proto = {
465465
.ret_type = RET_INTEGER,
466466
.arg1_type = ARG_PTR_TO_BTF_ID,
467467
.arg1_btf_id = &btf_seq_file_ids[0],
468-
.arg2_type = ARG_PTR_TO_MEM,
468+
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
469469
.arg3_type = ARG_CONST_SIZE_OR_ZERO,
470470
};
471471

@@ -489,7 +489,7 @@ static const struct bpf_func_proto bpf_seq_printf_btf_proto = {
489489
.ret_type = RET_INTEGER,
490490
.arg1_type = ARG_PTR_TO_BTF_ID,
491491
.arg1_btf_id = &btf_seq_file_ids[0],
492-
.arg2_type = ARG_PTR_TO_MEM,
492+
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
493493
.arg3_type = ARG_CONST_SIZE_OR_ZERO,
494494
.arg4_type = ARG_ANYTHING,
495495
};
@@ -650,7 +650,7 @@ static const struct bpf_func_proto bpf_perf_event_output_proto = {
650650
.arg1_type = ARG_PTR_TO_CTX,
651651
.arg2_type = ARG_CONST_MAP_PTR,
652652
.arg3_type = ARG_ANYTHING,
653-
.arg4_type = ARG_PTR_TO_MEM,
653+
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
654654
.arg5_type = ARG_CONST_SIZE_OR_ZERO,
655655
};
656656

@@ -945,7 +945,7 @@ const struct bpf_func_proto bpf_snprintf_btf_proto = {
945945
.ret_type = RET_INTEGER,
946946
.arg1_type = ARG_PTR_TO_MEM,
947947
.arg2_type = ARG_CONST_SIZE,
948-
.arg3_type = ARG_PTR_TO_MEM,
948+
.arg3_type = ARG_PTR_TO_MEM | MEM_RDONLY,
949949
.arg4_type = ARG_CONST_SIZE,
950950
.arg5_type = ARG_ANYTHING,
951951
};
@@ -1123,7 +1123,7 @@ static const struct bpf_func_proto bpf_perf_event_output_proto_tp = {
11231123
.arg1_type = ARG_PTR_TO_CTX,
11241124
.arg2_type = ARG_CONST_MAP_PTR,
11251125
.arg3_type = ARG_ANYTHING,
1126-
.arg4_type = ARG_PTR_TO_MEM,
1126+
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
11271127
.arg5_type = ARG_CONST_SIZE_OR_ZERO,
11281128
};
11291129

@@ -1345,7 +1345,7 @@ static const struct bpf_func_proto bpf_perf_event_output_proto_raw_tp = {
13451345
.arg1_type = ARG_PTR_TO_CTX,
13461346
.arg2_type = ARG_CONST_MAP_PTR,
13471347
.arg3_type = ARG_ANYTHING,
1348-
.arg4_type = ARG_PTR_TO_MEM,
1348+
.arg4_type = ARG_PTR_TO_MEM | MEM_RDONLY,
13491349
.arg5_type = ARG_CONST_SIZE_OR_ZERO,
13501350
};
13511351

@@ -1399,7 +1399,7 @@ static const struct bpf_func_proto bpf_get_stack_proto_raw_tp = {
13991399
.gpl_only = true,
14001400
.ret_type = RET_INTEGER,
14011401
.arg1_type = ARG_PTR_TO_CTX,
1402-
.arg2_type = ARG_PTR_TO_MEM,
1402+
.arg2_type = ARG_PTR_TO_MEM | MEM_RDONLY,
14031403
.arg3_type = ARG_CONST_SIZE_OR_ZERO,
14041404
.arg4_type = ARG_ANYTHING,
14051405
};

0 commit comments

Comments
 (0)