Skip to content

Commit dd831ac

Browse files
n132Paolo Abeni
authored andcommitted
net/sched: sch_qfq: Fix null-deref in agg_dequeue
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 <[email protected]> Reviewed-by: Cong Wang <[email protected]> Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
1 parent 0fda5cc commit dd831ac

File tree

4 files changed

+25
-28
lines changed

4 files changed

+25
-28
lines changed

include/net/pkt_sched.h

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,6 @@ struct qdisc_rate_table *qdisc_get_rtab(struct tc_ratespec *r,
114114
struct netlink_ext_ack *extack);
115115
void qdisc_put_rtab(struct qdisc_rate_table *tab);
116116
void qdisc_put_stab(struct qdisc_size_table *tab);
117-
void qdisc_warn_nonwc(const char *txt, struct Qdisc *qdisc);
118117
bool sch_direct_xmit(struct sk_buff *skb, struct Qdisc *q,
119118
struct net_device *dev, struct netdev_queue *txq,
120119
spinlock_t *root_lock, bool validate);
@@ -290,4 +289,28 @@ static inline bool tc_qdisc_stats_dump(struct Qdisc *sch,
290289
return true;
291290
}
292291

292+
static inline void qdisc_warn_nonwc(const char *txt, struct Qdisc *qdisc)
293+
{
294+
if (!(qdisc->flags & TCQ_F_WARN_NONWC)) {
295+
pr_warn("%s: %s qdisc %X: is non-work-conserving?\n",
296+
txt, qdisc->ops->id, qdisc->handle >> 16);
297+
qdisc->flags |= TCQ_F_WARN_NONWC;
298+
}
299+
}
300+
301+
static inline unsigned int qdisc_peek_len(struct Qdisc *sch)
302+
{
303+
struct sk_buff *skb;
304+
unsigned int len;
305+
306+
skb = sch->ops->peek(sch);
307+
if (unlikely(skb == NULL)) {
308+
qdisc_warn_nonwc("qdisc_peek_len", sch);
309+
return 0;
310+
}
311+
len = qdisc_pkt_len(skb);
312+
313+
return len;
314+
}
315+
293316
#endif

net/sched/sch_api.c

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -601,16 +601,6 @@ void __qdisc_calculate_pkt_len(struct sk_buff *skb,
601601
qdisc_skb_cb(skb)->pkt_len = pkt_len;
602602
}
603603

604-
void qdisc_warn_nonwc(const char *txt, struct Qdisc *qdisc)
605-
{
606-
if (!(qdisc->flags & TCQ_F_WARN_NONWC)) {
607-
pr_warn("%s: %s qdisc %X: is non-work-conserving?\n",
608-
txt, qdisc->ops->id, qdisc->handle >> 16);
609-
qdisc->flags |= TCQ_F_WARN_NONWC;
610-
}
611-
}
612-
EXPORT_SYMBOL(qdisc_warn_nonwc);
613-
614604
static enum hrtimer_restart qdisc_watchdog(struct hrtimer *timer)
615605
{
616606
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
@@ -835,22 +835,6 @@ update_vf(struct hfsc_class *cl, unsigned int len, u64 cur_time)
835835
}
836836
}
837837

838-
static unsigned int
839-
qdisc_peek_len(struct Qdisc *sch)
840-
{
841-
struct sk_buff *skb;
842-
unsigned int len;
843-
844-
skb = sch->ops->peek(sch);
845-
if (unlikely(skb == NULL)) {
846-
qdisc_warn_nonwc("qdisc_peek_len", sch);
847-
return 0;
848-
}
849-
len = qdisc_pkt_len(skb);
850-
851-
return len;
852-
}
853-
854838
static void
855839
hfsc_adjust_levels(struct hfsc_class *cl)
856840
{

net/sched/sch_qfq.c

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

990990
if (cl->qdisc->q.qlen == 0) /* no more packets, remove from list */
991991
list_del_init(&cl->alist);
992-
else if (cl->deficit < qdisc_pkt_len(cl->qdisc->ops->peek(cl->qdisc))) {
992+
else if (cl->deficit < qdisc_peek_len(cl->qdisc)) {
993993
cl->deficit += agg->lmax;
994994
list_move_tail(&cl->alist, &agg->active);
995995
}

0 commit comments

Comments
 (0)