|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH net-next 11/15] net: skbuff: refuse to segment a nested frag_list
skb_segment() walks head_skb's frag_list, but for each member it only
looks at the linear part and frags[], never at the member's own
frag_list. head_skb->len still counts those bytes, so with a nested
frag_list the walk runs out of members while it still owes data, sets
list_skb to NULL, and dereferences it on the next pass, before any of
the layout checks get a chance to catch it.
Nothing in the tree is known to build such an skb; GRO flushes instead
of chaining an skb that already has a frag_list. Check for it up front
and fail the segmentation with -EINVAL, with a DEBUG_NET_WARN_ON_ONCE()
for debug kernels, like the other frag_list layout checks.
Assisted-by: LLM
Signed-off-by: Josef Bacik <josef@xxxxxxxxxxxxxx>
---
net/core/skbuff.c | 21 +++++++++++++++++++++
1 file changed, 21 insertions(+)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 56cec58bccb7..b6ada54ecc57 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -4962,6 +4962,17 @@ struct sk_buff *skb_segment_list(struct sk_buff *skb,
}
EXPORT_SYMBOL_GPL(skb_segment_list);
+/* skb_segment() only walks one level of frag_list. */
+static bool skb_segment_nested_frag_list(const struct sk_buff *head_skb)
+{
+ const struct sk_buff *iter;
+
+ skb_walk_frags(head_skb, iter)
+ if (skb_has_frag_list(iter))
+ return true;
+ return false;
+}
+
/**
* skb_segment - Perform protocol segmentation on skb.
* @head_skb: buffer to segment
@@ -5023,6 +5034,16 @@ struct sk_buff *skb_segment(struct sk_buff *head_skb,
sg = !!(features & NETIF_F_SG);
csum = !!can_checksum_protocol(features, proto);
+ /* The walk below never looks inside a member's own frag_list, but
+ * head_skb->len counts those bytes, so it would run out of members
+ * and dereference a NULL list_skb.
+ */
+ if (unlikely(list_skb && skb_segment_nested_frag_list(head_skb))) {
+ DEBUG_NET_WARN_ON_ONCE(1);
+ err = -EINVAL;
+ goto err;
+ }
+
if (sg && csum && !gso_by_frags) {
if (!max_segs && !(features & NETIF_F_GSO_PARTIAL)) {
struct sk_buff *iter;
--
2.55.0
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |