BPF_MAP_TYPE_PROG_ARRAY (and other array maps) take max_entries as a u32 from userspace via bpf(BPF_MAP_CREATE), but array_map_alloc_check() only guards value_size > INT_MAX and leaves max_entries unchecked. When the map is later freed, fd_array_map_free() iterates the ptrs[] array with a signed int loop variable: for (i = 0; i < array->map.max_entries; i++) BUG_ON(array->ptrs[i] != NULL); On arm64 (and any LP64 arch) int is 32-bit signed, while max_entries is u32. With max_entries having bit 31 set (e.g. 0xFF00000A, observed from a syzkaller run), the loop runs past i = 0x7FFFFFFF: i++ wraps to 0x80000000, which as a signed int is negative. The address computation for &array->ptrs[i] sign-extends the 32-bit index (sxtw on arm64) into a 64-bit negative offset: array + sxtw(0x80000000) * 8 + offsetof(bpf_array, ptrs) = array + 0xFFFFFFFC00000000 + 0x108 -> wraps to an unmapped address, level-1 translation fault, panic This is reachable today because the existing overflow backstop in array_map_alloc() lives inside the `if (!bypass_spec_v1)` block. Since commit 2c78ee898d8f ("bpf: Implement CAP_BPF") renamed the old `if (unpriv)` guard to `if (!bypass_spec_v1)`, the semantics inverted: a root caller with CAP_PERFMON (or mitigations=off) takes the bypass path and skips the -E2BIG check entirely, so the raw attr->max_entries is stored into map->max_entries unchanged and the ~32 GB vmalloc (overcommit) region is handed out. The earlier unprivileged-path fix for max_entries overflow was carried along into the bypass block, so it does not cover the root path described here. Reject max_entries > INT_MAX in array_map_alloc_check(), the common entry point shared by all callers including the bypass path. This mirrors the existing value_size > INT_MAX guard a few lines above. The cut half of the u32 range (0x80000000..0xFFFFFFFF) cannot back a usable map today: - a prog_array at the lower bound already needs ~16 GB of contiguous virtual memory (and ~32 GB for the 0xFF00000A value seen in the field), which either fails allocation or drives the system into OOM/softlockup long before becoming a working map; - legitimate prog_array usage is bounded by MAX_TAIL_CALL_CNT = 33 and typical array maps are orders of magnitude below INT_MAX. No valid BPF use case is affected; the change converts a deferred whole-system BUG_ON panic (or OOM/softlockup) into an accurate -E2BIG at creation time. Fixes: 2c78ee898d8f ("bpf: Implement CAP_BPF") Signed-off-by: meishaoming --- Changes in v2: - Rebase onto the bpf tree (base a13307e97d5c) so Patchwork CI can apply it cleanly; no code change. --- kernel/bpf/arraymap.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/kernel/bpf/arraymap.c b/kernel/bpf/arraymap.c index 248b4818178c..868bc9f66cdb 100644 --- a/kernel/bpf/arraymap.c +++ b/kernel/bpf/arraymap.c @@ -74,6 +74,9 @@ int array_map_alloc_check(union bpf_attr *attr) /* avoid overflow on round_up(map->value_size) */ if (attr->value_size > INT_MAX) return -E2BIG; + /* avoid signed int iterator overflow in fd_array_map_free() */ + if (attr->max_entries > INT_MAX) + return -E2BIG; /* percpu map value size is bound by PCPU_MIN_UNIT_SIZE */ if (percpu && round_up(attr->value_size, 8) > PCPU_MIN_UNIT_SIZE) return -E2BIG; base-commit: a13307e97d5c54b65720bb71fa379960ded1e51a -- 2.50.1 (Apple Git-155) #/******本邮件及其附件含有小米公司的保密信息,仅限于发送给上面地址中列出的个人或群组。禁止任何其他人以任何形式使用(包括但不限于全部或部分地泄露、复制、或散发)本邮件中的信息。如果您错收了本邮件,请您立即电话或邮件通知发件人并删除本邮件! This e-mail and its attachments contain confidential information from XIAOMI, which is intended only for the person or entity whose address is listed above. Any use of the information contained herein in any way (including, but not limited to, total or partial disclosure, reproduction, or dissemination) by persons other than the intended recipient(s) is prohibited. If you receive this e-mail in error, please notify the sender by phone or email immediately and delete it!******/#