Commit de5720f9 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'net-fix-potential-crash-in-net-sched-cls_u32-c'

Eric Dumazet says:

====================
net: fix potential crash in net/sched/cls_u32.c

GangMin Kim provided a report and a repro fooling u32_classify().

Add skb_header_pointer_careful() variant of skb_header_pointer()
and use it in net/sched/cls_u32.c.

Later we can also use it in net/sched/act_pedit.c
====================

Link: https://patch.msgid.link/20260128141539.3404400-1-edumazet@google.com


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 37d312bf cabd1a97
Loading
Loading
Loading
Loading
+12 −0
Original line number Diff line number Diff line
@@ -4301,6 +4301,18 @@ skb_header_pointer(const struct sk_buff *skb, int offset, int len, void *buffer)
				    skb_headlen(skb), buffer);
}

/* Variant of skb_header_pointer() where @offset is user-controlled
 * and potentially negative.
 */
static inline void * __must_check
skb_header_pointer_careful(const struct sk_buff *skb, int offset,
			   int len, void *buffer)
{
	if (unlikely(offset < 0 && -offset > skb_headroom(skb)))
		return NULL;
	return skb_header_pointer(skb, offset, len, buffer);
}

static inline void * __must_check
skb_pointer_if_linear(const struct sk_buff *skb, int offset, int len)
{
+6 −7
Original line number Diff line number Diff line
@@ -161,10 +161,8 @@ TC_INDIRECT_SCOPE int u32_classify(struct sk_buff *skb,
			int toff = off + key->off + (off2 & key->offmask);
			__be32 *data, hdata;

			if (skb_headroom(skb) + toff > INT_MAX)
				goto out;

			data = skb_header_pointer(skb, toff, 4, &hdata);
			data = skb_header_pointer_careful(skb, toff, 4,
							  &hdata);
			if (!data)
				goto out;
			if ((*data ^ key->val) & key->mask) {
@@ -214,8 +212,9 @@ TC_INDIRECT_SCOPE int u32_classify(struct sk_buff *skb,
		if (ht->divisor) {
			__be32 *data, hdata;

			data = skb_header_pointer(skb, off + n->sel.hoff, 4,
						  &hdata);
			data = skb_header_pointer_careful(skb,
							  off + n->sel.hoff,
							  4, &hdata);
			if (!data)
				goto out;
			sel = ht->divisor & u32_hash_fold(*data, &n->sel,
@@ -229,7 +228,7 @@ TC_INDIRECT_SCOPE int u32_classify(struct sk_buff *skb,
			if (n->sel.flags & TC_U32_VAROFFSET) {
				__be16 *data, hdata;

				data = skb_header_pointer(skb,
				data = skb_header_pointer_careful(skb,
							  off + n->sel.offoff,
							  2, &hdata);
				if (!data)