mirror of
https://github.com/torvalds/linux.git
synced 2026-09-13 15:40:03 +02:00
bpf: Fix percpu map update indexing with sparse CPU IDs
Per-CPU array, hash, and cgroup storage map updates without BPF_F_CPU or BPF_F_ALL_CPUS use a value buffer whose per-CPU slots are packed in possible-CPU order. The buffer is sized as: round_up(value_size, 8) * num_possible_cpus() The update paths iterate over possible CPUs, but use the logical CPU ID to calculate the source offset: value + size * cpu This only works when possible CPU IDs are contiguous starting at zero. For example, with a possible CPU mask of 0,2-3, the buffer contains three slots corresponding to CPUs 0, 2, and 3. CPU2 is therefore expected to use slot 1 and CPU3 slot 2. Instead, the current code uses slots 2 and 3 respectively, causing incorrect per-CPU values and an out-of-bounds read from the update buffer for CPU3. The corresponding lookup paths already use a dense offset while iterating over possible CPUs. Do the same for the array, hash, and cgroup storage update paths, advancing the source offset once for each possible CPU. BPF_F_ALL_CPUS continues to use the same value for every CPU. Fixes:8eb76cb03f("bpf: Add BPF_F_CPU and BPF_F_ALL_CPUS flags support for percpu_array maps") Fixes:c6936161fd("bpf: Add BPF_F_CPU and BPF_F_ALL_CPUS flags support for percpu_hash and lru_percpu_hash maps") Fixes:47c79f05aa("bpf: Add BPF_F_CPU and BPF_F_ALL_CPUS flags support for percpu_cgroup_storage maps") Signed-off-by: Hui Su <sh_def@163.com> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Acked-by: Leon Hwang <leon.hwang@linux.dev> Link: https://lore.kernel.org/bpf/20260813155131.1022745-3-sh_def@163.com
This commit is contained in:
parent
ed54bf564a
commit
75b0a6db43
|
|
@ -436,7 +436,7 @@ int bpf_percpu_array_update(struct bpf_map *map, void *key, void *value,
|
|||
void __percpu *pptr;
|
||||
void *ptr, *val;
|
||||
u32 size;
|
||||
int cpu;
|
||||
int cpu, off = 0;
|
||||
|
||||
if (unlikely((map_flags & BPF_F_LOCK) || (u32)map_flags > BPF_F_ALL_CPUS))
|
||||
/* unknown flags */
|
||||
|
|
@ -468,9 +468,10 @@ int bpf_percpu_array_update(struct bpf_map *map, void *key, void *value,
|
|||
}
|
||||
for_each_possible_cpu(cpu) {
|
||||
ptr = per_cpu_ptr(pptr, cpu);
|
||||
val = (map_flags & BPF_F_ALL_CPUS) ? value : value + size * cpu;
|
||||
val = (map_flags & BPF_F_ALL_CPUS) ? value : value + off;
|
||||
copy_map_value(map, ptr, val);
|
||||
bpf_obj_cancel_fields(map, ptr);
|
||||
off += size;
|
||||
}
|
||||
unlock:
|
||||
rcu_read_unlock();
|
||||
|
|
|
|||
|
|
@ -1025,7 +1025,7 @@ static void pcpu_copy_value(struct bpf_htab *htab, void __percpu *pptr,
|
|||
} else {
|
||||
u32 size = round_up(htab->map.value_size, 8);
|
||||
void *val;
|
||||
int cpu;
|
||||
int cpu, off = 0;
|
||||
|
||||
if (map_flags & BPF_F_CPU) {
|
||||
cpu = map_flags >> 32;
|
||||
|
|
@ -1037,9 +1037,10 @@ static void pcpu_copy_value(struct bpf_htab *htab, void __percpu *pptr,
|
|||
|
||||
for_each_possible_cpu(cpu) {
|
||||
ptr = per_cpu_ptr(pptr, cpu);
|
||||
val = (map_flags & BPF_F_ALL_CPUS) ? value : value + size * cpu;
|
||||
val = (map_flags & BPF_F_ALL_CPUS) ? value : value + off;
|
||||
copy_map_value(&htab->map, ptr, val);
|
||||
bpf_obj_cancel_fields(&htab->map, ptr);
|
||||
off += size;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -220,7 +220,7 @@ int bpf_percpu_cgroup_storage_update(struct bpf_map *_map, void *key,
|
|||
struct bpf_cgroup_storage *storage;
|
||||
void *val;
|
||||
u32 size;
|
||||
int cpu;
|
||||
int cpu, off = 0;
|
||||
|
||||
if ((u32)map_flags & ~(BPF_ANY | BPF_EXIST | BPF_F_CPU | BPF_F_ALL_CPUS))
|
||||
return -EINVAL;
|
||||
|
|
@ -245,8 +245,9 @@ int bpf_percpu_cgroup_storage_update(struct bpf_map *_map, void *key,
|
|||
}
|
||||
size = round_up(_map->value_size, 8);
|
||||
for_each_possible_cpu(cpu) {
|
||||
val = (map_flags & BPF_F_ALL_CPUS) ? value : value + size * cpu;
|
||||
val = (map_flags & BPF_F_ALL_CPUS) ? value : value + off;
|
||||
copy_map_value(_map, per_cpu_ptr(storage->percpu_buf, cpu), val);
|
||||
off += size;
|
||||
}
|
||||
unlock:
|
||||
rcu_read_unlock();
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user