* [PATCH bpf] bpf: Zero-fill non-target CPU slots on BPF_F_CPU insert of new per-CPU element
@ 2026-09-28 21:47 Ömer Mete Kaya
2026-09-28 22:03 ` sashiko-bot
2026-09-29 5:04 ` Leon Hwang
0 siblings, 2 replies; 4+ messages in thread
From: Ömer Mete Kaya @ 2026-09-28 21:47 UTC (permalink / raw)
To: ast, daniel
Cc: andrii, eddyz87, memxor, martin.lau, song, yonghong.song, jolsa,
emil, ihor.solodrai, leon.hwang, bpf, linux-kernel,
Ömer Mete Kaya
pcpu_copy_value() with BPF_F_CPU copies the value only to the target
CPU's slot and returns immediately, leaving all other CPUs untouched.
When inserting a *new* element, the backing per-CPU area may be reused
from bpf_mem_cache or a prealloc freelist without being zero-initialized,
so non-target CPUs retain stale contents of a previously-deleted
element in the same map — a same-map information disclosure.
pcpu_init_value() is used to initialize newly allocated elements, while
updates to existing elements call pcpu_copy_value() directly; non-target
CPU slots intentionally retain their previous values there.
The onallcpus=false path in pcpu_init_value() already handles new
element initialization correctly by explicitly zeroing non-current CPUs:
if (cpu == current_cpu)
copy_map_value(..., value);
else
zero_map_value(...);
Fix by adding a zero-fill pass in pcpu_init_value() after
pcpu_copy_value() returns, covering only the BPF_F_CPU new-element
path: iterate all CPUs and zero-fill every slot except the target.
This leaves pcpu_copy_value() unchanged so the update-existing-element
semantics are not affected.
Fixes: c6936161fd55 ("bpf: Add BPF_F_CPU and BPF_F_ALL_CPUS flags support for percpu_hash and lru_percpu_hash maps")
Signed-off-by: Ömer Mete Kaya <omermetekaya0@gmail.com>
---
Tested with a reproducer:
- Before the fix: CPU 1 retained 0xDEADBEEFCAFEBABE from the deleted
element.
- After the fix: the non-target CPU read back zero.
kernel/bpf/hashtab.c | 10 ++++++++++
1 file changed, 10 insertions(+)
diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c
index 8cc07e54daaa..dff4321f2828 100644
--- a/kernel/bpf/hashtab.c
+++ b/kernel/bpf/hashtab.c
@@ -1099,6 +1099,16 @@ static void pcpu_init_value(struct bpf_htab *htab, void __percpu *pptr,
}
} else {
pcpu_copy_value(htab, pptr, value, onallcpus, map_flags);
+ if (map_flags & BPF_F_CPU) {
+ int target = map_flags >> 32;
+ int cpu;
+
+ for_each_possible_cpu(cpu) {
+ if (cpu != target)
+ zero_map_value(&htab->map,
+ per_cpu_ptr(pptr, cpu));
+ }
+ }
}
}
--
2.55.0
^ permalink raw reply related [flat|nested] 4+ messages in thread
* Re: [PATCH bpf] bpf: Zero-fill non-target CPU slots on BPF_F_CPU insert of new per-CPU element
2026-09-28 21:47 [PATCH bpf] bpf: Zero-fill non-target CPU slots on BPF_F_CPU insert of new per-CPU element Ömer Mete Kaya
@ 2026-09-28 22:03 ` sashiko-bot
2026-09-29 5:04 ` Leon Hwang
1 sibling, 0 replies; 4+ messages in thread
From: sashiko-bot @ 2026-09-28 22:03 UTC (permalink / raw)
To: Ömer Mete Kaya; +Cc: bpf
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [Low] bpf: unreachable dead code added in pcpu_init_value()
--
commit aa9c1147874e7681c03a2eaf750ae6f2bf2a633a
Author: Ömer Mete Kaya <omermetekaya0@gmail.com>
bpf: Zero-fill non-target CPU slots on BPF_F_CPU insert of new per-CPU element
pcpu_copy_value() with BPF_F_CPU copies the value only to the target
CPU's slot and returns immediately, leaving all other CPUs untouched.
When inserting a *new* element, the backing per-CPU area may be reused
from bpf_mem_cache or a prealloc freelist without being zero-initialized,
so non-target CPUs retain stale contents of a previously-deleted
element in the same map — a same-map information disclosure.
> diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c
> index 548eb1cc7c45c..f426d4c00bdc8 100644
> --- a/kernel/bpf/hashtab.c
> +++ b/kernel/bpf/hashtab.c
> @@ -1086,6 +1086,16 @@ static void pcpu_init_value(struct bpf_htab *htab, void __percpu *pptr,
> }
> } else {
> pcpu_copy_value(htab, pptr, value, onallcpus, map_flags);
> + if (map_flags & BPF_F_CPU) {
[Severity: Low]
Is this block reachable?
Since the preceding if statement in pcpu_init_value() evaluates
"if (!onallcpus || (map_flags & BPF_F_CPU))", the else branch will only
execute if "(map_flags & BPF_F_CPU)" evaluates to false.
This makes the newly added code here unreachable. Furthermore, the new
element initialization issue mentioned in the commit message appears to
already be handled correctly in the first branch, which already zeroes out
non-target CPUs via zero_map_value().
> + int target = map_flags >> 32;
> + int cpu;
> +
> + for_each_possible_cpu(cpu) {
> + if (cpu != target)
> + zero_map_value(&htab->map,
> + per_cpu_ptr(pptr, cpu));
> + }
> + }
> }
> }
--
Sashiko AI review · https://sashiko.dev/#/patchset/20260928214932.544124-1-omermetekaya0@gmail.com?part=1
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH bpf] bpf: Zero-fill non-target CPU slots on BPF_F_CPU insert of new per-CPU element
2026-09-28 21:47 [PATCH bpf] bpf: Zero-fill non-target CPU slots on BPF_F_CPU insert of new per-CPU element Ömer Mete Kaya
2026-09-28 22:03 ` sashiko-bot
@ 2026-09-29 5:04 ` Leon Hwang
2026-09-29 7:58 ` Ömer Mete Kaya
1 sibling, 1 reply; 4+ messages in thread
From: Leon Hwang @ 2026-09-29 5:04 UTC (permalink / raw)
To: Ömer Mete Kaya, ast, daniel
Cc: andrii, eddyz87, memxor, martin.lau, song, yonghong.song, jolsa,
emil, ihor.solodrai, bpf, linux-kernel
On 29/9/26 05:47, Ömer Mete Kaya wrote:
> pcpu_copy_value() with BPF_F_CPU copies the value only to the target
> CPU's slot and returns immediately, leaving all other CPUs untouched.
> When inserting a *new* element, the backing per-CPU area may be reused
> from bpf_mem_cache or a prealloc freelist without being zero-initialized,
> so non-target CPUs retain stale contents of a previously-deleted
> element in the same map — a same-map information disclosure.
>
> pcpu_init_value() is used to initialize newly allocated elements, while
> updates to existing elements call pcpu_copy_value() directly; non-target
> CPU slots intentionally retain their previous values there.
>
> The onallcpus=false path in pcpu_init_value() already handles new
> element initialization correctly by explicitly zeroing non-current CPUs:
>
> if (cpu == current_cpu)
> copy_map_value(..., value);
> else
> zero_map_value(...);
>
> Fix by adding a zero-fill pass in pcpu_init_value() after
> pcpu_copy_value() returns, covering only the BPF_F_CPU new-element
> path: iterate all CPUs and zero-fill every slot except the target.
> This leaves pcpu_copy_value() unchanged so the update-existing-element
> semantics are not affected.
>
> Fixes: c6936161fd55 ("bpf: Add BPF_F_CPU and BPF_F_ALL_CPUS flags support for percpu_hash and lru_percpu_hash maps")
> Signed-off-by: Ömer Mete Kaya <omermetekaya0@gmail.com>
> ---
> Tested with a reproducer:
> - Before the fix: CPU 1 retained 0xDEADBEEFCAFEBABE from the deleted
> element.
> - After the fix: the non-target CPU read back zero.
Could you add a selftest to prove the issue?
You said a reproducer. But, I don't know what it looks like.
>
> kernel/bpf/hashtab.c | 10 ++++++++++
> 1 file changed, 10 insertions(+)
>
> diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c
> index 8cc07e54daaa..dff4321f2828 100644
> --- a/kernel/bpf/hashtab.c
> +++ b/kernel/bpf/hashtab.c
> @@ -1099,6 +1099,16 @@ static void pcpu_init_value(struct bpf_htab *htab, void __percpu *pptr,
> }
> } else {
> pcpu_copy_value(htab, pptr, value, onallcpus, map_flags);
> + if (map_flags & BPF_F_CPU) {
> + int target = map_flags >> 32;
> + int cpu;
> +
> + for_each_possible_cpu(cpu) {
But wait, the 'map_flags & BPF_F_CPU' has been check in the first 'if
()' condition in pcpu_init_value(). See the previous fix:
https://lore.kernel.org/bpf/20260924102321.2120434-1-donggeunyoo.kernel@gmail.com/
Thanks,
Leon
> + if (cpu != target)
> + zero_map_value(&htab->map,
> + per_cpu_ptr(pptr, cpu));
> + }
> + }
> }
> }
>
> --
> 2.55.0
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH bpf] bpf: Zero-fill non-target CPU slots on BPF_F_CPU insert of new per-CPU element
2026-09-29 5:04 ` Leon Hwang
@ 2026-09-29 7:58 ` Ömer Mete Kaya
0 siblings, 0 replies; 4+ messages in thread
From: Ömer Mete Kaya @ 2026-09-29 7:58 UTC (permalink / raw)
To: Leon Hwang, ast, daniel
Cc: andrii, eddyz87, memxor, martin.lau, song, yonghong.song, jolsa,
emil, ihor.solodrai, bpf, linux-kernel
On 9/29/26 08:04, Leon Hwang wrote:
> On 29/9/26 05:47, Ömer Mete Kaya wrote:
>> pcpu_copy_value() with BPF_F_CPU copies the value only to the target
>> CPU's slot and returns immediately, leaving all other CPUs untouched.
>> When inserting a *new* element, the backing per-CPU area may be reused
>> from bpf_mem_cache or a prealloc freelist without being zero-initialized,
>> so non-target CPUs retain stale contents of a previously-deleted
>> element in the same map — a same-map information disclosure.
>>
>> pcpu_init_value() is used to initialize newly allocated elements, while
>> updates to existing elements call pcpu_copy_value() directly; non-target
>> CPU slots intentionally retain their previous values there.
>>
>> The onallcpus=false path in pcpu_init_value() already handles new
>> element initialization correctly by explicitly zeroing non-current CPUs:
>>
>> if (cpu == current_cpu)
>> copy_map_value(..., value);
>> else
>> zero_map_value(...);
>>
>> Fix by adding a zero-fill pass in pcpu_init_value() after
>> pcpu_copy_value() returns, covering only the BPF_F_CPU new-element
>> path: iterate all CPUs and zero-fill every slot except the target.
>> This leaves pcpu_copy_value() unchanged so the update-existing-element
>> semantics are not affected.
>>
>> Fixes: c6936161fd55 ("bpf: Add BPF_F_CPU and BPF_F_ALL_CPUS flags support for percpu_hash and lru_percpu_hash maps")
>> Signed-off-by: Ömer Mete Kaya <omermetekaya0@gmail.com>
>> ---
>> Tested with a reproducer:
>> - Before the fix: CPU 1 retained 0xDEADBEEFCAFEBABE from the deleted
>> element.
>> - After the fix: the non-target CPU read back zero.
>
> Could you add a selftest to prove the issue?
>
> You said a reproducer. But, I don't know what it looks like.
>
>>
>> kernel/bpf/hashtab.c | 10 ++++++++++
>> 1 file changed, 10 insertions(+)
>>
>> diff --git a/kernel/bpf/hashtab.c b/kernel/bpf/hashtab.c
>> index 8cc07e54daaa..dff4321f2828 100644
>> --- a/kernel/bpf/hashtab.c
>> +++ b/kernel/bpf/hashtab.c
>> @@ -1099,6 +1099,16 @@ static void pcpu_init_value(struct bpf_htab *htab, void __percpu *pptr,
>> }
>> } else {
>> pcpu_copy_value(htab, pptr, value, onallcpus, map_flags);
>> + if (map_flags & BPF_F_CPU) {
>> + int target = map_flags >> 32;
>> + int cpu;
>> +
>> + for_each_possible_cpu(cpu) {
>
> But wait, the 'map_flags & BPF_F_CPU' has been check in the first 'if
> ()' condition in pcpu_init_value(). See the previous fix:
> https://lore.kernel.org/bpf/20260924102321.2120434-1-donggeunyoo.kernel@gmail.com/
Ah yes didn't see his fix, and it looks much cleaner.I think mine is no
longer necessary.
Thanks,
Ömer
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2026-09-29 7:58 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-28 21:47 [PATCH bpf] bpf: Zero-fill non-target CPU slots on BPF_F_CPU insert of new per-CPU element Ömer Mete Kaya
2026-09-28 22:03 ` sashiko-bot
2026-09-29 5:04 ` Leon Hwang
2026-09-29 7:58 ` Ömer Mete Kaya
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox