Skip to content

Commit 6fad274

Browse files
borkmannAlexei Starovoitov
authored andcommitted
bpf: Add MEM_WRITE attribute
Add a MEM_WRITE attribute for BPF helper functions which can be used in bpf_func_proto to annotate an argument type in order to let the verifier know that the helper writes into the memory passed as an argument. In the past MEM_UNINIT has been (ab)used for this function, but the latter merely tells the verifier that the passed memory can be uninitialized. There have been bugs with overloading the latter but aside from that there are also cases where the passed memory is read + written which currently cannot be expressed, see also 4b3786a ("bpf: Zero former ARG_PTR_TO_{LONG,INT} args in case of error"). Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Acked-by: Kumar Kartikeya Dwivedi <memxor@gmail.com> Link: https://lore.kernel.org/r/20241021152809.33343-1-daniel@iogearbox.net Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent 1f97c03 commit 6fad274

6 files changed

Lines changed: 22 additions & 14 deletions

File tree

include/linux/bpf.h

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -635,6 +635,7 @@ enum bpf_type_flag {
635635
*/
636636
PTR_UNTRUSTED = BIT(6 + BPF_BASE_TYPE_BITS),
637637

638+
/* MEM can be uninitialized. */
638639
MEM_UNINIT = BIT(7 + BPF_BASE_TYPE_BITS),
639640

640641
/* DYNPTR points to memory local to the bpf program. */
@@ -700,6 +701,13 @@ enum bpf_type_flag {
700701
*/
701702
MEM_ALIGNED = BIT(17 + BPF_BASE_TYPE_BITS),
702703

704+
/* MEM is being written to, often combined with MEM_UNINIT. Non-presence
705+
* of MEM_WRITE means that MEM is only being read. MEM_WRITE without the
706+
* MEM_UNINIT means that memory needs to be initialized since it is also
707+
* read.
708+
*/
709+
MEM_WRITE = BIT(18 + BPF_BASE_TYPE_BITS),
710+
703711
__BPF_TYPE_FLAG_MAX,
704712
__BPF_TYPE_LAST_FLAG = __BPF_TYPE_FLAG_MAX - 1,
705713
};
@@ -758,10 +766,10 @@ enum bpf_arg_type {
758766
ARG_PTR_TO_SOCKET_OR_NULL = PTR_MAYBE_NULL | ARG_PTR_TO_SOCKET,
759767
ARG_PTR_TO_STACK_OR_NULL = PTR_MAYBE_NULL | ARG_PTR_TO_STACK,
760768
ARG_PTR_TO_BTF_ID_OR_NULL = PTR_MAYBE_NULL | ARG_PTR_TO_BTF_ID,
761-
/* pointer to memory does not need to be initialized, helper function must fill
762-
* all bytes or clear them in error case.
769+
/* Pointer to memory does not need to be initialized, since helper function
770+
* fills all bytes or clears them in error case.
763771
*/
764-
ARG_PTR_TO_UNINIT_MEM = MEM_UNINIT | ARG_PTR_TO_MEM,
772+
ARG_PTR_TO_UNINIT_MEM = MEM_UNINIT | MEM_WRITE | ARG_PTR_TO_MEM,
765773
/* Pointer to valid memory of size known at compile time. */
766774
ARG_PTR_TO_FIXED_SIZE_MEM = MEM_FIXED_SIZE | ARG_PTR_TO_MEM,
767775

kernel/bpf/helpers.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,7 @@ const struct bpf_func_proto bpf_map_pop_elem_proto = {
111111
.gpl_only = false,
112112
.ret_type = RET_INTEGER,
113113
.arg1_type = ARG_CONST_MAP_PTR,
114-
.arg2_type = ARG_PTR_TO_MAP_VALUE | MEM_UNINIT,
114+
.arg2_type = ARG_PTR_TO_MAP_VALUE | MEM_UNINIT | MEM_WRITE,
115115
};
116116

117117
BPF_CALL_2(bpf_map_peek_elem, struct bpf_map *, map, void *, value)
@@ -124,7 +124,7 @@ const struct bpf_func_proto bpf_map_peek_elem_proto = {
124124
.gpl_only = false,
125125
.ret_type = RET_INTEGER,
126126
.arg1_type = ARG_CONST_MAP_PTR,
127-
.arg2_type = ARG_PTR_TO_MAP_VALUE | MEM_UNINIT,
127+
.arg2_type = ARG_PTR_TO_MAP_VALUE | MEM_UNINIT | MEM_WRITE,
128128
};
129129

130130
BPF_CALL_3(bpf_map_lookup_percpu_elem, struct bpf_map *, map, void *, key, u32, cpu)
@@ -538,7 +538,7 @@ const struct bpf_func_proto bpf_strtol_proto = {
538538
.arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY,
539539
.arg2_type = ARG_CONST_SIZE,
540540
.arg3_type = ARG_ANYTHING,
541-
.arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
541+
.arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
542542
.arg4_size = sizeof(s64),
543543
};
544544

@@ -566,7 +566,7 @@ const struct bpf_func_proto bpf_strtoul_proto = {
566566
.arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY,
567567
.arg2_type = ARG_CONST_SIZE,
568568
.arg3_type = ARG_ANYTHING,
569-
.arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
569+
.arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
570570
.arg4_size = sizeof(u64),
571571
};
572572

@@ -1742,7 +1742,7 @@ static const struct bpf_func_proto bpf_dynptr_from_mem_proto = {
17421742
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
17431743
.arg2_type = ARG_CONST_SIZE_OR_ZERO,
17441744
.arg3_type = ARG_ANYTHING,
1745-
.arg4_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_LOCAL | MEM_UNINIT,
1745+
.arg4_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_LOCAL | MEM_UNINIT | MEM_WRITE,
17461746
};
17471747

17481748
BPF_CALL_5(bpf_dynptr_read, void *, dst, u32, len, const struct bpf_dynptr_kern *, src,

kernel/bpf/ringbuf.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -632,7 +632,7 @@ const struct bpf_func_proto bpf_ringbuf_reserve_dynptr_proto = {
632632
.arg1_type = ARG_CONST_MAP_PTR,
633633
.arg2_type = ARG_ANYTHING,
634634
.arg3_type = ARG_ANYTHING,
635-
.arg4_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_RINGBUF | MEM_UNINIT,
635+
.arg4_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_RINGBUF | MEM_UNINIT | MEM_WRITE,
636636
};
637637

638638
BPF_CALL_2(bpf_ringbuf_submit_dynptr, struct bpf_dynptr_kern *, ptr, u64, flags)

kernel/bpf/syscall.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5892,7 +5892,7 @@ static const struct bpf_func_proto bpf_kallsyms_lookup_name_proto = {
58925892
.arg1_type = ARG_PTR_TO_MEM,
58935893
.arg2_type = ARG_CONST_SIZE_OR_ZERO,
58945894
.arg3_type = ARG_ANYTHING,
5895-
.arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
5895+
.arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
58965896
.arg4_size = sizeof(u64),
58975897
};
58985898

kernel/trace/bpf_trace.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1202,7 +1202,7 @@ static const struct bpf_func_proto bpf_get_func_arg_proto = {
12021202
.ret_type = RET_INTEGER,
12031203
.arg1_type = ARG_PTR_TO_CTX,
12041204
.arg2_type = ARG_ANYTHING,
1205-
.arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
1205+
.arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
12061206
.arg3_size = sizeof(u64),
12071207
};
12081208

@@ -1219,7 +1219,7 @@ static const struct bpf_func_proto bpf_get_func_ret_proto = {
12191219
.func = get_func_ret,
12201220
.ret_type = RET_INTEGER,
12211221
.arg1_type = ARG_PTR_TO_CTX,
1222-
.arg2_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
1222+
.arg2_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
12231223
.arg2_size = sizeof(u64),
12241224
};
12251225

net/core/filter.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6368,7 +6368,7 @@ static const struct bpf_func_proto bpf_skb_check_mtu_proto = {
63686368
.ret_type = RET_INTEGER,
63696369
.arg1_type = ARG_PTR_TO_CTX,
63706370
.arg2_type = ARG_ANYTHING,
6371-
.arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
6371+
.arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
63726372
.arg3_size = sizeof(u32),
63736373
.arg4_type = ARG_ANYTHING,
63746374
.arg5_type = ARG_ANYTHING,
@@ -6380,7 +6380,7 @@ static const struct bpf_func_proto bpf_xdp_check_mtu_proto = {
63806380
.ret_type = RET_INTEGER,
63816381
.arg1_type = ARG_PTR_TO_CTX,
63826382
.arg2_type = ARG_ANYTHING,
6383-
.arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
6383+
.arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
63846384
.arg3_size = sizeof(u32),
63856385
.arg4_type = ARG_ANYTHING,
63866386
.arg5_type = ARG_ANYTHING,

0 commit comments

Comments
 (0)