Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

sch_cake: Return __NET_XMIT_STOLEN when consuming enqueued skb

When the GSO splitting feature of sch_cake is enabled, GSO superpackets
will be broken up and the resulting segments enqueued in place of the
original skb. In this case, CAKE calls consume_skb() on the original skb,
but still returns NET_XMIT_SUCCESS. This can confuse parent qdiscs into
assuming the original skb still exists, when it really has been freed. Fix
this by adding the __NET_XMIT_STOLEN flag to the return value in this case.

Fixes: 0c850344d388 ("sch_cake: Conditionally split GSO segments")
Signed-off-by: Toke Høiland-Jørgensen <toke@toke.dk>
Reported-by: zdi-disclosures@trendmicro.com # ZDI-CAN-18231
Link: https://lore.kernel.org/r/20220831092103.442868-1-toke@toke.dk
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

authored by

Toke Høiland-Jørgensen and committed by
Jakub Kicinski
90fabae8 5a3a5998

+3 -1
+3 -1
net/sched/sch_cake.c
··· 1713 1713 } 1714 1714 idx--; 1715 1715 flow = &b->flows[idx]; 1716 + ret = NET_XMIT_SUCCESS; 1716 1717 1717 1718 /* ensure shaper state isn't stale */ 1718 1719 if (!b->tin_backlog) { ··· 1772 1771 1773 1772 qdisc_tree_reduce_backlog(sch, 1-numsegs, len-slen); 1774 1773 consume_skb(skb); 1774 + ret |= __NET_XMIT_STOLEN; 1775 1775 } else { 1776 1776 /* not splitting */ 1777 1777 cobalt_set_enqueue_time(skb, now); ··· 1906 1904 } 1907 1905 b->drop_overlimit += dropped; 1908 1906 } 1909 - return NET_XMIT_SUCCESS; 1907 + return ret; 1910 1908 } 1911 1909 1912 1910 static struct sk_buff *cake_dequeue_one(struct Qdisc *sch)