mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-12-29 09:16:33 +00:00
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 4b3786a6c5
("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>
This commit is contained in:
parent
1f97c03f43
commit
6fad274f06
@ -635,6 +635,7 @@ enum bpf_type_flag {
|
|||||||
*/
|
*/
|
||||||
PTR_UNTRUSTED = BIT(6 + BPF_BASE_TYPE_BITS),
|
PTR_UNTRUSTED = BIT(6 + BPF_BASE_TYPE_BITS),
|
||||||
|
|
||||||
|
/* MEM can be uninitialized. */
|
||||||
MEM_UNINIT = BIT(7 + BPF_BASE_TYPE_BITS),
|
MEM_UNINIT = BIT(7 + BPF_BASE_TYPE_BITS),
|
||||||
|
|
||||||
/* DYNPTR points to memory local to the bpf program. */
|
/* DYNPTR points to memory local to the bpf program. */
|
||||||
@ -700,6 +701,13 @@ enum bpf_type_flag {
|
|||||||
*/
|
*/
|
||||||
MEM_ALIGNED = BIT(17 + BPF_BASE_TYPE_BITS),
|
MEM_ALIGNED = BIT(17 + BPF_BASE_TYPE_BITS),
|
||||||
|
|
||||||
|
/* MEM is being written to, often combined with MEM_UNINIT. Non-presence
|
||||||
|
* of MEM_WRITE means that MEM is only being read. MEM_WRITE without the
|
||||||
|
* MEM_UNINIT means that memory needs to be initialized since it is also
|
||||||
|
* read.
|
||||||
|
*/
|
||||||
|
MEM_WRITE = BIT(18 + BPF_BASE_TYPE_BITS),
|
||||||
|
|
||||||
__BPF_TYPE_FLAG_MAX,
|
__BPF_TYPE_FLAG_MAX,
|
||||||
__BPF_TYPE_LAST_FLAG = __BPF_TYPE_FLAG_MAX - 1,
|
__BPF_TYPE_LAST_FLAG = __BPF_TYPE_FLAG_MAX - 1,
|
||||||
};
|
};
|
||||||
@ -758,10 +766,10 @@ enum bpf_arg_type {
|
|||||||
ARG_PTR_TO_SOCKET_OR_NULL = PTR_MAYBE_NULL | ARG_PTR_TO_SOCKET,
|
ARG_PTR_TO_SOCKET_OR_NULL = PTR_MAYBE_NULL | ARG_PTR_TO_SOCKET,
|
||||||
ARG_PTR_TO_STACK_OR_NULL = PTR_MAYBE_NULL | ARG_PTR_TO_STACK,
|
ARG_PTR_TO_STACK_OR_NULL = PTR_MAYBE_NULL | ARG_PTR_TO_STACK,
|
||||||
ARG_PTR_TO_BTF_ID_OR_NULL = PTR_MAYBE_NULL | ARG_PTR_TO_BTF_ID,
|
ARG_PTR_TO_BTF_ID_OR_NULL = PTR_MAYBE_NULL | ARG_PTR_TO_BTF_ID,
|
||||||
/* pointer to memory does not need to be initialized, helper function must fill
|
/* Pointer to memory does not need to be initialized, since helper function
|
||||||
* all bytes or clear them in error case.
|
* fills all bytes or clears them in error case.
|
||||||
*/
|
*/
|
||||||
ARG_PTR_TO_UNINIT_MEM = MEM_UNINIT | ARG_PTR_TO_MEM,
|
ARG_PTR_TO_UNINIT_MEM = MEM_UNINIT | MEM_WRITE | ARG_PTR_TO_MEM,
|
||||||
/* Pointer to valid memory of size known at compile time. */
|
/* Pointer to valid memory of size known at compile time. */
|
||||||
ARG_PTR_TO_FIXED_SIZE_MEM = MEM_FIXED_SIZE | ARG_PTR_TO_MEM,
|
ARG_PTR_TO_FIXED_SIZE_MEM = MEM_FIXED_SIZE | ARG_PTR_TO_MEM,
|
||||||
|
|
||||||
|
@ -111,7 +111,7 @@ const struct bpf_func_proto bpf_map_pop_elem_proto = {
|
|||||||
.gpl_only = false,
|
.gpl_only = false,
|
||||||
.ret_type = RET_INTEGER,
|
.ret_type = RET_INTEGER,
|
||||||
.arg1_type = ARG_CONST_MAP_PTR,
|
.arg1_type = ARG_CONST_MAP_PTR,
|
||||||
.arg2_type = ARG_PTR_TO_MAP_VALUE | MEM_UNINIT,
|
.arg2_type = ARG_PTR_TO_MAP_VALUE | MEM_UNINIT | MEM_WRITE,
|
||||||
};
|
};
|
||||||
|
|
||||||
BPF_CALL_2(bpf_map_peek_elem, struct bpf_map *, map, void *, value)
|
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 = {
|
|||||||
.gpl_only = false,
|
.gpl_only = false,
|
||||||
.ret_type = RET_INTEGER,
|
.ret_type = RET_INTEGER,
|
||||||
.arg1_type = ARG_CONST_MAP_PTR,
|
.arg1_type = ARG_CONST_MAP_PTR,
|
||||||
.arg2_type = ARG_PTR_TO_MAP_VALUE | MEM_UNINIT,
|
.arg2_type = ARG_PTR_TO_MAP_VALUE | MEM_UNINIT | MEM_WRITE,
|
||||||
};
|
};
|
||||||
|
|
||||||
BPF_CALL_3(bpf_map_lookup_percpu_elem, struct bpf_map *, map, void *, key, u32, cpu)
|
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 = {
|
|||||||
.arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY,
|
.arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY,
|
||||||
.arg2_type = ARG_CONST_SIZE,
|
.arg2_type = ARG_CONST_SIZE,
|
||||||
.arg3_type = ARG_ANYTHING,
|
.arg3_type = ARG_ANYTHING,
|
||||||
.arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
|
.arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
|
||||||
.arg4_size = sizeof(s64),
|
.arg4_size = sizeof(s64),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -566,7 +566,7 @@ const struct bpf_func_proto bpf_strtoul_proto = {
|
|||||||
.arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY,
|
.arg1_type = ARG_PTR_TO_MEM | MEM_RDONLY,
|
||||||
.arg2_type = ARG_CONST_SIZE,
|
.arg2_type = ARG_CONST_SIZE,
|
||||||
.arg3_type = ARG_ANYTHING,
|
.arg3_type = ARG_ANYTHING,
|
||||||
.arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
|
.arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
|
||||||
.arg4_size = sizeof(u64),
|
.arg4_size = sizeof(u64),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1742,7 +1742,7 @@ static const struct bpf_func_proto bpf_dynptr_from_mem_proto = {
|
|||||||
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
|
.arg1_type = ARG_PTR_TO_UNINIT_MEM,
|
||||||
.arg2_type = ARG_CONST_SIZE_OR_ZERO,
|
.arg2_type = ARG_CONST_SIZE_OR_ZERO,
|
||||||
.arg3_type = ARG_ANYTHING,
|
.arg3_type = ARG_ANYTHING,
|
||||||
.arg4_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_LOCAL | MEM_UNINIT,
|
.arg4_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_LOCAL | MEM_UNINIT | MEM_WRITE,
|
||||||
};
|
};
|
||||||
|
|
||||||
BPF_CALL_5(bpf_dynptr_read, void *, dst, u32, len, const struct bpf_dynptr_kern *, src,
|
BPF_CALL_5(bpf_dynptr_read, void *, dst, u32, len, const struct bpf_dynptr_kern *, src,
|
||||||
|
@ -632,7 +632,7 @@ const struct bpf_func_proto bpf_ringbuf_reserve_dynptr_proto = {
|
|||||||
.arg1_type = ARG_CONST_MAP_PTR,
|
.arg1_type = ARG_CONST_MAP_PTR,
|
||||||
.arg2_type = ARG_ANYTHING,
|
.arg2_type = ARG_ANYTHING,
|
||||||
.arg3_type = ARG_ANYTHING,
|
.arg3_type = ARG_ANYTHING,
|
||||||
.arg4_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_RINGBUF | MEM_UNINIT,
|
.arg4_type = ARG_PTR_TO_DYNPTR | DYNPTR_TYPE_RINGBUF | MEM_UNINIT | MEM_WRITE,
|
||||||
};
|
};
|
||||||
|
|
||||||
BPF_CALL_2(bpf_ringbuf_submit_dynptr, struct bpf_dynptr_kern *, ptr, u64, flags)
|
BPF_CALL_2(bpf_ringbuf_submit_dynptr, struct bpf_dynptr_kern *, ptr, u64, flags)
|
||||||
|
@ -5892,7 +5892,7 @@ static const struct bpf_func_proto bpf_kallsyms_lookup_name_proto = {
|
|||||||
.arg1_type = ARG_PTR_TO_MEM,
|
.arg1_type = ARG_PTR_TO_MEM,
|
||||||
.arg2_type = ARG_CONST_SIZE_OR_ZERO,
|
.arg2_type = ARG_CONST_SIZE_OR_ZERO,
|
||||||
.arg3_type = ARG_ANYTHING,
|
.arg3_type = ARG_ANYTHING,
|
||||||
.arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
|
.arg4_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
|
||||||
.arg4_size = sizeof(u64),
|
.arg4_size = sizeof(u64),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1202,7 +1202,7 @@ static const struct bpf_func_proto bpf_get_func_arg_proto = {
|
|||||||
.ret_type = RET_INTEGER,
|
.ret_type = RET_INTEGER,
|
||||||
.arg1_type = ARG_PTR_TO_CTX,
|
.arg1_type = ARG_PTR_TO_CTX,
|
||||||
.arg2_type = ARG_ANYTHING,
|
.arg2_type = ARG_ANYTHING,
|
||||||
.arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
|
.arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
|
||||||
.arg3_size = sizeof(u64),
|
.arg3_size = sizeof(u64),
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1219,7 +1219,7 @@ static const struct bpf_func_proto bpf_get_func_ret_proto = {
|
|||||||
.func = get_func_ret,
|
.func = get_func_ret,
|
||||||
.ret_type = RET_INTEGER,
|
.ret_type = RET_INTEGER,
|
||||||
.arg1_type = ARG_PTR_TO_CTX,
|
.arg1_type = ARG_PTR_TO_CTX,
|
||||||
.arg2_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
|
.arg2_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
|
||||||
.arg2_size = sizeof(u64),
|
.arg2_size = sizeof(u64),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -6368,7 +6368,7 @@ static const struct bpf_func_proto bpf_skb_check_mtu_proto = {
|
|||||||
.ret_type = RET_INTEGER,
|
.ret_type = RET_INTEGER,
|
||||||
.arg1_type = ARG_PTR_TO_CTX,
|
.arg1_type = ARG_PTR_TO_CTX,
|
||||||
.arg2_type = ARG_ANYTHING,
|
.arg2_type = ARG_ANYTHING,
|
||||||
.arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
|
.arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
|
||||||
.arg3_size = sizeof(u32),
|
.arg3_size = sizeof(u32),
|
||||||
.arg4_type = ARG_ANYTHING,
|
.arg4_type = ARG_ANYTHING,
|
||||||
.arg5_type = ARG_ANYTHING,
|
.arg5_type = ARG_ANYTHING,
|
||||||
@ -6380,7 +6380,7 @@ static const struct bpf_func_proto bpf_xdp_check_mtu_proto = {
|
|||||||
.ret_type = RET_INTEGER,
|
.ret_type = RET_INTEGER,
|
||||||
.arg1_type = ARG_PTR_TO_CTX,
|
.arg1_type = ARG_PTR_TO_CTX,
|
||||||
.arg2_type = ARG_ANYTHING,
|
.arg2_type = ARG_ANYTHING,
|
||||||
.arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_ALIGNED,
|
.arg3_type = ARG_PTR_TO_FIXED_SIZE_MEM | MEM_UNINIT | MEM_WRITE | MEM_ALIGNED,
|
||||||
.arg3_size = sizeof(u32),
|
.arg3_size = sizeof(u32),
|
||||||
.arg4_type = ARG_ANYTHING,
|
.arg4_type = ARG_ANYTHING,
|
||||||
.arg5_type = ARG_ANYTHING,
|
.arg5_type = ARG_ANYTHING,
|
||||||
|
Loading…
Reference in New Issue
Block a user