Re: [PATCH bpf] bpf: fix BPF_F_CPU validation for sparse CPU IDs

Leon Hwang <[email protected]>
Newsgroups org.kernel.vger.bpf,org.kernel.vger.linux-kernel
Message-ID <[email protected]>
Hi Hui,

On 2026/8/13 18:12, Hui Su wrote:
> BPF_F_CPU stores the target CPU ID in the upper 32 bits of the map
> operation flags. bpf_map_check_op_flags() currently compares that ID
> with num_possible_cpus(), which is the number of possible CPUs rather
> than a bound on CPU IDs.
> 
> On an arm64 QEMU guest with a CPU device-tree hole, the possible CPU

TIL about the possible CPU hole.

> mask was 0,2-3. A userspace program using raw bpf() syscalls creates
> a BPF_MAP_TYPE_PERCPU_ARRAY and performs update and lookup operations
> for each CPU by setting BPF_F_CPU and the CPU ID in the flags.
> 
> With the old check, CPU 1 is incorrectly accepted while valid CPU 3 is
> rejected with -ERANGE. The CPU 1 update then reaches the per-CPU map
> access path and triggers:
> 
>   Unable to handle kernel paging request at virtual address ...
>   pc : __pi_memcpy_generic+0x5c/0x22c
>   lr : bpf_percpu_array_update+0x2dc/0x2e8
>   Call trace:
>     __pi_memcpy_generic
>     bpf_map_update_value
>     map_update_elem
>     __sys_bpf
> 
> Check the CPU ID against nr_cpu_ids and cpu_possible() instead. This
> rejects CPU IDs outside the valid range and CPUs absent from the
> possible mask, while allowing valid sparse CPU IDs.
> 
> Fixes: 2b421662c788 ("bpf: Introduce BPF_F_CPU and BPF_F_ALL_CPUS flags")
> Signed-off-by: Hui Su <[email protected]>
> ---
>  include/linux/bpf.h | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/include/linux/bpf.h b/include/linux/bpf.h
> index 7719f6528445..282f7022d984 100644
> --- a/include/linux/bpf.h
> +++ b/include/linux/bpf.h
> @@ -4202,7 +4202,8 @@ static inline int bpf_map_check_op_flags(struct bpf_map *map, u64 flags, u64 all
>  			return -EINVAL;
>  
>  		cpu = flags >> 32;
> -		if ((flags & BPF_F_CPU) && cpu >= num_possible_cpus())
> +		if ((flags & BPF_F_CPU) &&
> +		    (cpu >= nr_cpu_ids || !cpu_possible(cpu)))

NIT: no need to put the cpu check on a new line, as 100 chars per line
are allowed.

Other than the NIT,

Acked-by: Leon Hwang <[email protected]>

>  			return -ERANGE;
>  	}
>
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.