mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
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: f3483c8e1d ("net: rfs: hash function change")
Signed-off-by: Dudu Lu <phx0fer@gmail.com>
Link: https://patch.msgid.link/20261021155522.67521-1-phx0fer@gmail.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>
This commit is contained in:
parent
d3ff07f5ac
commit
24927bdf0f
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user