From 2337fa244e4b8543f2daa4e527c65e10b30bc18e Mon Sep 17 00:00:00 2001 From: Gennaro Cimmino Date: Tue, 15 Sep 2026 09:19:06 +0200 Subject: [PATCH] realtek: l3: refuse a route id the table cannot hold find_first_zero_bit() returns the size it was given when every bit is set, and neither route allocator tests for that. On a full table the id becomes MAX_ROUTES or MAX_HOST_ROUTES and set_bit() writes one word past the bitmap: the two bitmaps sit next to each other in struct otto_l3_ctrl, followed by the interface array, so overflowing the prefix one marks host route slot 0 as used and overflowing the host one sets a bit in the first interface pointer. A prefix route id is also the row the route is written at, so it goes on to ask for row 512 of a 512-row table; otto_table_index_ok() refuses the access and warns once per boot, while otto_l3_fib_add_v4() reports success and marks the route offloaded. Say the table is full and return NULL, which the caller already handles: it turns a failed allocation into -ENOSPC. No-op on RTL838x and RTL931x, whose notifiers return early because cfg->setup is NULL. Compile-tested only: reaching either branch takes 512 prefix or 1536 host routes offloaded at once, which the bench cannot produce. Assisted-by: Claude:claude-opus-5 Signed-off-by: Gennaro Cimmino Link: https://github.com/openwrt/openwrt/pull/25194 Signed-off-by: Markus Stockhausen --- .../realtek/files-6.18/drivers/net/dsa/rtl83xx/l3.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/l3.c b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/l3.c index 36a5170b036..6fa61800431 100644 --- a/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/l3.c +++ b/target/linux/realtek/files-6.18/drivers/net/dsa/rtl83xx/l3.c @@ -1013,6 +1013,12 @@ static struct otto_l3_route *otto_l3_host_route_alloc(struct otto_l3_ctrl *ctrl, mutex_lock(ctrl->lock); idx = find_first_zero_bit(ctrl->host_route_use_bm, MAX_HOST_ROUTES); + if (idx >= MAX_HOST_ROUTES) { + dev_err(ctrl->dev, "host route table full, %d entries in use\n", + MAX_HOST_ROUTES); + mutex_unlock(ctrl->lock); + return NULL; + } dev_dbg(ctrl->dev, "id: %d, ip %pI4\n", idx, &ip); r = kzalloc(sizeof(*r), GFP_KERNEL); @@ -1057,6 +1063,12 @@ static struct otto_l3_route *otto_l3_route_alloc(struct otto_l3_ctrl *ctrl, u32 mutex_lock(ctrl->lock); idx = find_first_zero_bit(ctrl->route_use_bm, MAX_ROUTES); + if (idx >= MAX_ROUTES) { + dev_err(ctrl->dev, "prefix route table full, %d entries in use\n", + MAX_ROUTES); + mutex_unlock(ctrl->lock); + return NULL; + } dev_dbg(ctrl->dev, "id: %d, ip %pI4\n", idx, &ip); r = kzalloc(sizeof(*r), GFP_KERNEL);