* [PATCH bpf] bpf: Fix out-of-bounds read in bpf_obj_memcpy
@ 2026-04-08 10:04 Jiayuan Chen
2026-04-08 10:52 ` Jiayuan Chen
0 siblings, 1 reply; 2+ messages in thread
From: Jiayuan Chen @ 2026-04-08 10:04 UTC (permalink / raw)
To: bpf
Cc: Jiayuan Chen, Kaiyan Mei, Yinhao Hu, Dongliang Mu,
Alexei Starovoitov, Daniel Borkmann, Andrii Nakryiko,
Martin KaFai Lau, Eduard Zingerman, Kumar Kartikeya Dwivedi,
Song Liu, Yonghong Song, Jiri Olsa, John Fastabend,
Matthieu Baerts, David Verbeiren, linux-kernel
When copying map value between two maps in BPF program, an out-of-bounds
read can occur in bpf_obj_memcpy(). Consider the following scenario:
// map1: BPF_MAP_TYPE_CGROUP_STORAGE, value_size = 4
// map2: BPF_MAP_TYPE_LRU_PERCPU_HASH, value_size = 4
void *src = bpf_get_local_storage(&map1, 0); // 4-byte buffer
bpf_map_update_elem(&map2, &key, src, 0); // copy src to map2
The verifier validates that source buffer size >= destination map's
value_size through check_helper_mem_access(). Since both maps have
value_size=4, verification passes.
However, at runtime bpf_obj_memcpy() rounds up the copy size to 8 bytes
for long-aligned atomic copy:
bpf_long_memcpy(dst, src, round_up(size, 8)); // reads 8 bytes
This causes a 4-byte over-read from the source buffer. Fix this by using
round_down() to only copy complete 8-byte chunks with bpf_long_memcpy(),
then copy any remaining bytes with regular memcpy().
This ensures we never read beyond the validated buffer size while still
maintaining atomic operations where possible.
Fixes: d3bec0138bfbe ("bpf: Zero-fill re-used per-cpu map element")
Closes: https://lore.kernel.org/bpf/14e6c70c.6c121.19c0399d948.Coremail.kaiyanm@hust.edu.cn/
Reported-by: Kaiyan Mei <M202472210@hust.edu.cn>
Reported-by: Yinhao Hu <dddddd@hust.edu.cn>
Reviewed-by: Dongliang Mu <dzm91@hust.edu.cn>
Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
---
include/linux/bpf.h | 11 ++++++++---
1 file changed, 8 insertions(+), 3 deletions(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 05b34a6355b03..1b789f9f8a095 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -535,10 +535,15 @@ static inline void bpf_obj_memcpy(struct btf_record *rec,
int i;
if (IS_ERR_OR_NULL(rec)) {
- if (long_memcpy)
- bpf_long_memcpy(dst, src, round_up(size, 8));
- else
+ u32 aligned = round_down(size, 8);
+
+ if (long_memcpy && aligned) {
+ bpf_long_memcpy(dst, src, aligned);
+ if (size > aligned)
+ memcpy(dst + aligned, src + aligned, size - aligned);
+ } else {
memcpy(dst, src, size);
+ }
return;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH bpf] bpf: Fix out-of-bounds read in bpf_obj_memcpy
2026-04-08 10:04 [PATCH bpf] bpf: Fix out-of-bounds read in bpf_obj_memcpy Jiayuan Chen
@ 2026-04-08 10:52 ` Jiayuan Chen
0 siblings, 0 replies; 2+ messages in thread
From: Jiayuan Chen @ 2026-04-08 10:52 UTC (permalink / raw)
To: Jiayuan Chen, bpf
Cc: Kaiyan Mei, Yinhao Hu, Dongliang Mu, Alexei Starovoitov,
Daniel Borkmann, Andrii Nakryiko, Martin KaFai Lau,
Eduard Zingerman, Kumar Kartikeya Dwivedi, Song Liu,
Yonghong Song, Jiri Olsa, John Fastabend, Matthieu Baerts,
David Verbeiren, linux-kernel
On 4/8/26 6:04 PM, Jiayuan Chen wrote:
> When copying map value between two maps in BPF program, an out-of-bounds
> read can occur in bpf_obj_memcpy(). Consider the following scenario:
> // map1: BPF_MAP_TYPE_CGROUP_STORAGE, value_size = 4
> // map2: BPF_MAP_TYPE_LRU_PERCPU_HASH, value_size = 4
> void *src = bpf_get_local_storage(&map1, 0); // 4-byte buffer
> bpf_map_update_elem(&map2, &key, src, 0); // copy src to map2
>
> The verifier validates that source buffer size >= destination map's
> value_size through check_helper_mem_access(). Since both maps have
> value_size=4, verification passes.
>
> However, at runtime bpf_obj_memcpy() rounds up the copy size to 8 bytes
> for long-aligned atomic copy:
> bpf_long_memcpy(dst, src, round_up(size, 8)); // reads 8 bytes
>
> This causes a 4-byte over-read from the source buffer. Fix this by using
> round_down() to only copy complete 8-byte chunks with bpf_long_memcpy(),
> then copy any remaining bytes with regular memcpy().
>
> This ensures we never read beyond the validated buffer size while still
> maintaining atomic operations where possible.
>
> Fixes: d3bec0138bfbe ("bpf: Zero-fill re-used per-cpu map element")
> Closes: https://lore.kernel.org/bpf/14e6c70c.6c121.19c0399d948.Coremail.kaiyanm@hust.edu.cn/
> Reported-by: Kaiyan Mei <M202472210@hust.edu.cn>
> Reported-by: Yinhao Hu <dddddd@hust.edu.cn>
> Reviewed-by: Dongliang Mu <dzm91@hust.edu.cn>
> Signed-off-by: Jiayuan Chen <jiayuan.chen@linux.dev>
> ---
> include/linux/bpf.h | 11 ++++++++---
> 1 file changed, 8 insertions(+), 3 deletions(-)
>
> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> index 05b34a6355b03..1b789f9f8a095 100644
> --- a/include/linux/bpf.h
> +++ b/include/linux/bpf.h
> @@ -535,10 +535,15 @@ static inline void bpf_obj_memcpy(struct btf_record *rec,
> int i;
>
> if (IS_ERR_OR_NULL(rec)) {
> - if (long_memcpy)
> - bpf_long_memcpy(dst, src, round_up(size, 8));
> - else
> + u32 aligned = round_down(size, 8);
> +
> + if (long_memcpy && aligned) {
> + bpf_long_memcpy(dst, src, aligned);
> + if (size > aligned)
> + memcpy(dst + aligned, src + aligned, size - aligned);
> + } else {
> memcpy(dst, src, size);
> + }
> return;
> }
>
This seems to already exist....
https://lore.kernel.org/bpf/7653EEEC2BAB17DF+20260402073948.2185396-1-xulang@uniontech.com/
pw-bot: cr
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2026-04-08 10:53 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-04-08 10:04 [PATCH bpf] bpf: Fix out-of-bounds read in bpf_obj_memcpy Jiayuan Chen
2026-04-08 10:52 ` Jiayuan Chen
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox