From 24927bdf0f62f63470a065c21d80fff7e4e9f207 Mon Sep 17 00:00:00 2001 From: Dudu Lu Date: Wed, 21 Oct 2026 23:55:22 +0800 Subject: [PATCH] net-sysfs: reject a one-entry RPS flow table store_rps_dev_flow_table_cnt() accepts rps_flow_cnt == 1. For count == 1 the round-up loop leaves mask == 0, which is stored as log == 0 in the tag (tag_ptr |= ilog2(mask) + 1). get_rps_cpu() then calls rfs_slot() -> hash_32(hash, rps_tag_to_log(tag_ptr)) with log == 0: include/linux/hash.h:68 return __hash_32(val) >> (32 - bits); /* bits == 0 -> shift by 32 */ The shift by 32 is undefined and yields the full 32-bit hash, which is used to index the one-entry rps_dev_flow[] table unchecked: UBSAN: shift-out-of-bounds in ./include/linux/hash.h:68:24 shift exponent 32 is too large for 32-bit type 'unsigned int' __ubsan_handle_shift_out_of_bounds+0x11c/0x208 get_rps_cpu+0x12fc/0x1344 netif_rx_internal+0x1e0/0x4d4 rps_dev_flow[] is then read (rflow->cpu) and written (last_qtail) out of bounds on the packet path. Require at least two entries. Fixes: f3483c8e1da6 ("net: rfs: hash function change") Signed-off-by: Dudu Lu Link: https://patch.msgid.link/20261021155522.67521-1-phx0fer@gmail.com Signed-off-by: Jakub Kicinski --- net/core/net-sysfs.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c index b9eeb9972f2b..5c0402389c6d 100644 --- a/net/core/net-sysfs.c +++ b/net/core/net-sysfs.c @@ -1110,6 +1110,13 @@ static ssize_t store_rps_dev_flow_table_cnt(struct netdev_rx_queue *queue, while ((mask | (mask >> 1)) != mask) mask |= (mask >> 1); + /* Require at least two entries. A one-entry table rounds up + * to mask == 0, which encodes log == 0 in the tag. + * get_rps_cpu() then computes hash_32(hash, 0), a shift by 32. + */ + if (!mask) + return -EINVAL; + /* Do not accept too large tables. */ if (mask > (INT_MAX / sizeof(*table) - 1)) return -EINVAL;