Re: [PATCH] net/sched: cls_u32: validate offshift to prevent shift-out-of-bounds
From: Jamal Hadi Salim <jhs@mojatatu.com>
Date: 2026-07-22 13:02:21
Also in:
lkml
On Sun, Jul 19, 2026 at 11:45 PM Cen Zhang (Microsoft) [off-list ref] wrote:
quoted hunk ↗ jump to hunk
u32_change() copies the user-provided tc_u32_sel.offshift (unsigned char, 0-255) into the kernel knode object without bounds validation. When a packet later hits u32_classify() with TC_U32_VAROFFSET set, it evaluates `ntohs(offmask & *data) >> offshift` where the left operand is a 16-bit value promoted to a 32-bit int. Any offshift >= 32 is undefined behavior per C11 §6.5.7, triggerable by an unprivileged user via user/network namespaces. UBSAN: shift-out-of-bounds in net/sched/cls_u32.c:236:43 shift exponent 32 is too large for 32-bit type int Fix this by rejecting offshift >= 16 during filter creation in u32_change(). Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reported-by: AutonomousCodeSecurity@microsoft.com Signed-off-by: Cen Zhang (Microsoft) <redacted> --- net/sched/cls_u32.c | 7 +++++++ 1 file changed, 7 insertions(+)diff --git a/net/sched/cls_u32.c b/net/sched/cls_u32.c index 8f30cc82181d..e7a9a49353f9 100644 --- a/net/sched/cls_u32.c +++ b/net/sched/cls_u32.c@@ -1107,6 +1107,13 @@ static int u32_change(struct net *net, struct sk_buff *in_skb, goto erridr; } + if (s->flags & TC_U32_VAROFFSET && s->offshift >= 16) {
Remove this VAROFFSET flag test. It is possible that someone could make a call from user space without this flag and use skip_sw and it ends up in a driver which doesnt check for this boundary. Otherwise both Victor and myself tested with POC and were able to verify the bug and the fix. Please add Victor's tested by and my acked-by when you resubmit. cheers, jamal
+ NL_SET_ERR_MSG_MOD(extack,
+ "offshift must be less than 16");
+ err = -EINVAL;
+ goto erridr;
+ }
+
n = kzalloc_flex(*n, sel.keys, s->nkeys);
if (n == NULL) {
err = -ENOBUFS;
--
2.53.0