Skip to content

Commit c015511

Browse files
n132Ulrich Hecht
authored andcommitted
net/sched: sch_qfq: Fix null-deref in agg_dequeue
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 <xmei5@asu.edu> Reviewed-by: Cong Wang <xiyou.wangcong@gmail.com> Link: https://patch.msgid.link/20250705212143.3982664-1-xmei5@asu.edu Signed-off-by: Paolo Abeni <pabeni@redhat.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> [uli: backport to 4.19] Signed-off-by: Ulrich Hecht <uli@kernel.org> Reviewed-by: Pavel Machek <pavel@nabladev.com>
1 parent 8f0f1d0 commit c015511

4 files changed

Lines changed: 25 additions & 28 deletions

File tree

include/net/pkt_sched.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,6 @@ struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r,
109109
struct netlink_ext_ack *extack);
110110
void qdisc_put_rtab(struct qdisc_rate_table *tab);
111111
void qdisc_put_stab(struct qdisc_size_table *tab);
112-
void qdisc_warn_nonwc(const char *txt, struct Qdisc *qdisc);
113112
bool sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,
114113
struct net_device *dev, struct netdev_queue *txq,
115114
spinlock_t *root_lock, bool validate);
@@ -153,4 +152,28 @@ struct tc_etf_qopt_offload {
153152
s32 queue;
154153
};
155154

155+
static inline void qdisc_warn_nonwc(const char *txt, struct Qdisc *qdisc)
156+
{
157+
if (!(qdisc->flags & TCQ_F_WARN_NONWC)) {
158+
pr_warn("%s: %s qdisc %X: is non-work-conserving?\n",
159+
txt, qdisc->ops->id, qdisc->handle >> 16);
160+
qdisc->flags |= TCQ_F_WARN_NONWC;
161+
}
162+
}
163+
164+
static inline unsigned int qdisc_peek_len(struct Qdisc *sch)
165+
{
166+
struct sk_buff *skb;
167+
unsigned int len;
168+
169+
skb = sch->ops->peek(sch);
170+
if (unlikely(skb == NULL)) {
171+
qdisc_warn_nonwc("qdisc_peek_len", sch);
172+
return 0;
173+
}
174+
len = qdisc_pkt_len(skb);
175+
176+
return len;
177+
}
178+
156179
#endif

net/sched/sch_api.c

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -602,16 +602,6 @@ void __qdisc_calculate_pkt_len(struct sk_buff *skb,
602602
}
603603
EXPORT_SYMBOL(__qdisc_calculate_pkt_len);
604604

605-
void qdisc_warn_nonwc(const char *txt, struct Qdisc *qdisc)
606-
{
607-
if (!(qdisc->flags & TCQ_F_WARN_NONWC)) {
608-
pr_warn("%s: %s qdisc %X: is non-work-conserving?\n",
609-
txt, qdisc->ops->id, qdisc->handle >> 16);
610-
qdisc->flags |= TCQ_F_WARN_NONWC;
611-
}
612-
}
613-
EXPORT_SYMBOL(qdisc_warn_nonwc);
614-
615605
static enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer)
616606
{
617607
struct qdisc_watchdog *wd = container_of(timer, struct qdisc_watchdog,

net/sched/sch_hfsc.c

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -831,22 +831,6 @@ update_vf(struct hfsc_class *cl, unsigned int len, u64 cur_time)
831831
}
832832
}
833833

834-
static unsigned int
835-
qdisc_peek_len(struct Qdisc *sch)
836-
{
837-
struct sk_buff *skb;
838-
unsigned int len;
839-
840-
skb = sch->ops->peek(sch);
841-
if (unlikely(skb == NULL)) {
842-
qdisc_warn_nonwc("qdisc_peek_len", sch);
843-
return 0;
844-
}
845-
len = qdisc_pkt_len(skb);
846-
847-
return len;
848-
}
849-
850834
static void
851835
hfsc_purge_queue(struct Qdisc *sch, struct hfsc_class *cl)
852836
{

net/sched/sch_qfq.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1011,7 +1011,7 @@ static struct sk_buff *agg_dequeue(struct qfq_aggregate *agg,
10111011

10121012
if (cl->qdisc->q.qlen == 0) /* no more packets, remove from list */
10131013
list_del_init(&cl->alist);
1014-
else if (cl->deficit < qdisc_pkt_len(cl->qdisc->ops->peek(cl->qdisc))) {
1014+
else if (cl->deficit < qdisc_peek_len(cl->qdisc)) {
10151015
cl->deficit += agg->lmax;
10161016
list_move_tail(&cl->alist, &agg->active);
10171017
}

0 commit comments

Comments
 (0)