From b3563bffd6cbe336207e321b6b58839aa09bab42 Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Wed, 29 Oct 2025 14:34:52 +0100 Subject: [PATCH] 5.10-stable patches added patches: net-sched-sch_qfq-fix-null-deref-in-agg_dequeue.patch series --- ...ch_qfq-fix-null-deref-in-agg_dequeue.patch | 129 ++++++++++++++++++ queue-5.10/series | 1 + 2 files changed, 130 insertions(+) create mode 100644 queue-5.10/net-sched-sch_qfq-fix-null-deref-in-agg_dequeue.patch create mode 100644 queue-5.10/series diff --git a/queue-5.10/net-sched-sch_qfq-fix-null-deref-in-agg_dequeue.patch b/queue-5.10/net-sched-sch_qfq-fix-null-deref-in-agg_dequeue.patch new file mode 100644 index 0000000000..d9f0d14def --- /dev/null +++ b/queue-5.10/net-sched-sch_qfq-fix-null-deref-in-agg_dequeue.patch @@ -0,0 +1,129 @@ +From dd831ac8221e691e9e918585b1003c7071df0379 Mon Sep 17 00:00:00 2001 +From: Xiang Mei +Date: Sat, 5 Jul 2025 14:21:43 -0700 +Subject: net/sched: sch_qfq: Fix null-deref in agg_dequeue + +From: Xiang Mei + +commit dd831ac8221e691e9e918585b1003c7071df0379 upstream. + +To prevent a potential crash in agg_dequeue (net/sched/sch_qfq.c) +when cl->qdisc->ops->peek(cl->qdisc) returns NULL, we check the return +value before using it, similar to the existing approach in sch_hfsc.c. + +To avoid code duplication, the following changes are made: + +1. Changed qdisc_warn_nonwc(include/net/pkt_sched.h) into a static +inline function. + +2. Moved qdisc_peek_len from net/sched/sch_hfsc.c to +include/net/pkt_sched.h so that sch_qfq can reuse it. + +3. Applied qdisc_peek_len in agg_dequeue to avoid crashing. + +Signed-off-by: Xiang Mei +Reviewed-by: Cong Wang +Link: https://patch.msgid.link/20250705212143.3982664-1-xmei5@asu.edu +Signed-off-by: Paolo Abeni +Signed-off-by: Greg Kroah-Hartman +--- + include/net/pkt_sched.h | 25 ++++++++++++++++++++++++- + net/sched/sch_api.c | 10 ---------- + net/sched/sch_hfsc.c | 16 ---------------- + net/sched/sch_qfq.c | 2 +- + 4 files changed, 25 insertions(+), 28 deletions(-) + +--- a/include/net/pkt_sched.h ++++ b/include/net/pkt_sched.h +@@ -114,7 +114,6 @@ struct qdisc_rate_table *qdisc_get_rtab( + struct netlink_ext_ack *extack); + void qdisc_put_rtab(struct qdisc_rate_table *tab); + void qdisc_put_stab(struct qdisc_size_table *tab); +-void qdisc_warn_nonwc(const char *txt, struct Qdisc *qdisc); + bool sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q, + struct net_device *dev, struct netdev_queue *txq, + spinlock_t *root_lock, bool validate); +@@ -190,4 +189,28 @@ static inline void skb_txtime_consumed(s + skb->tstamp = ktime_set(0, 0); + } + ++static inline void qdisc_warn_nonwc(const char *txt, struct Qdisc *qdisc) ++{ ++ if (!(qdisc->flags & TCQ_F_WARN_NONWC)) { ++ pr_warn("%s: %s qdisc %X: is non-work-conserving?\n", ++ txt, qdisc->ops->id, qdisc->handle >> 16); ++ qdisc->flags |= TCQ_F_WARN_NONWC; ++ } ++} ++ ++static inline unsigned int qdisc_peek_len(struct Qdisc *sch) ++{ ++ struct sk_buff *skb; ++ unsigned int len; ++ ++ skb = sch->ops->peek(sch); ++ if (unlikely(skb == NULL)) { ++ qdisc_warn_nonwc("qdisc_peek_len", sch); ++ return 0; ++ } ++ len = qdisc_pkt_len(skb); ++ ++ return len; ++} ++ + #endif +--- a/net/sched/sch_api.c ++++ b/net/sched/sch_api.c +@@ -595,16 +595,6 @@ out: + qdisc_skb_cb(skb)->pkt_len = pkt_len; + } + +-void qdisc_warn_nonwc(const char *txt, struct Qdisc *qdisc) +-{ +- if (!(qdisc->flags & TCQ_F_WARN_NONWC)) { +- pr_warn("%s: %s qdisc %X: is non-work-conserving?\n", +- txt, qdisc->ops->id, qdisc->handle >> 16); +- qdisc->flags |= TCQ_F_WARN_NONWC; +- } +-} +-EXPORT_SYMBOL(qdisc_warn_nonwc); +- + static enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer) + { + struct qdisc_watchdog *wd = container_of(timer, struct qdisc_watchdog, +--- a/net/sched/sch_hfsc.c ++++ b/net/sched/sch_hfsc.c +@@ -836,22 +836,6 @@ update_vf(struct hfsc_class *cl, unsigne + } + } + +-static unsigned int +-qdisc_peek_len(struct Qdisc *sch) +-{ +- struct sk_buff *skb; +- unsigned int len; +- +- skb = sch->ops->peek(sch); +- if (unlikely(skb == NULL)) { +- qdisc_warn_nonwc("qdisc_peek_len", sch); +- return 0; +- } +- len = qdisc_pkt_len(skb); +- +- return len; +-} +- + static void + hfsc_adjust_levels(struct hfsc_class *cl) + { +--- a/net/sched/sch_qfq.c ++++ b/net/sched/sch_qfq.c +@@ -1007,7 +1007,7 @@ static struct sk_buff *agg_dequeue(struc + + if (cl->qdisc->q.qlen == 0) /* no more packets, remove from list */ + list_del_init(&cl->alist); +- else if (cl->deficit < qdisc_pkt_len(cl->qdisc->ops->peek(cl->qdisc))) { ++ else if (cl->deficit < qdisc_peek_len(cl->qdisc)) { + cl->deficit += agg->lmax; + list_move_tail(&cl->alist, &agg->active); + } diff --git a/queue-5.10/series b/queue-5.10/series new file mode 100644 index 0000000000..64bc2c1eea --- /dev/null +++ b/queue-5.10/series @@ -0,0 +1 @@ +net-sched-sch_qfq-fix-null-deref-in-agg_dequeue.patch -- 2.47.3