Re: [PATCH] net/sched: cls_u32: validate offshift to prevent shift-out-of-bounds
From: Jamal Hadi Salim
Date: Wed Jul 22 2026 - 09:07:56 EST
On Sun, Jul 19, 2026 at 11:45 PM Cen Zhang (Microsoft)
<blbllhy@xxxxxxxxx> wrote:
>
> 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@xxxxxxxxxxxxx
> Signed-off-by: Cen Zhang (Microsoft) <blbllhy@xxxxxxxxx>
> ---
> 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
>