Skip to content

Commit da71714

Browse files
jhsmtdavem330
authored andcommitted
net/sched: fix a qdisc modification with ambiguous command request
When replacing an existing root qdisc, with one that is of the same kind, the request boils down to essentially a parameterization change i.e not one that requires allocation and grafting of a new qdisc. syzbot was able to create a scenario which resulted in a taprio qdisc replacing an existing taprio qdisc with a combination of NLM_F_CREATE, NLM_F_REPLACE and NLM_F_EXCL leading to create and graft scenario. The fix ensures that only when the qdisc kinds are different that we should allow a create and graft, otherwise it goes into the "change" codepath. While at it, fix the code and comments to improve readability. While syzbot was able to create the issue, it did not zone on the root cause. Analysis from Vladimir Oltean <[email protected]> helped narrow it down. v1->V2 changes: - remove "inline" function definition (Vladmir) - remove extrenous braces in branches (Vladmir) - change inline function names (Pedro) - Run tdc tests (Victor) v2->v3 changes: - dont break else/if (Simon) Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Reported-by: [email protected] Closes: https://lore.kernel.org/netdev/20230816225759.g25x76kmgzya2gei@skbuf/T/ Tested-by: Vladimir Oltean <[email protected]> Tested-by: Victor Nogueira <[email protected]> Reviewed-by: Pedro Tammela <[email protected]> Reviewed-by: Victor Nogueira <[email protected]> Signed-off-by: Jamal Hadi Salim <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent de43975 commit da71714

File tree

1 file changed

+40
-13
lines changed

1 file changed

+40
-13
lines changed

net/sched/sch_api.c

Lines changed: 40 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1547,10 +1547,28 @@ static int tc_get_qdisc(struct sk_buff *skb, struct nlmsghdr *n,
15471547
return 0;
15481548
}
15491549

1550+
static bool req_create_or_replace(struct nlmsghdr *n)
1551+
{
1552+
return (n->nlmsg_flags & NLM_F_CREATE &&
1553+
n->nlmsg_flags & NLM_F_REPLACE);
1554+
}
1555+
1556+
static bool req_create_exclusive(struct nlmsghdr *n)
1557+
{
1558+
return (n->nlmsg_flags & NLM_F_CREATE &&
1559+
n->nlmsg_flags & NLM_F_EXCL);
1560+
}
1561+
1562+
static bool req_change(struct nlmsghdr *n)
1563+
{
1564+
return (!(n->nlmsg_flags & NLM_F_CREATE) &&
1565+
!(n->nlmsg_flags & NLM_F_REPLACE) &&
1566+
!(n->nlmsg_flags & NLM_F_EXCL));
1567+
}
1568+
15501569
/*
15511570
* Create/change qdisc.
15521571
*/
1553-
15541572
static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n,
15551573
struct netlink_ext_ack *extack)
15561574
{
@@ -1644,27 +1662,35 @@ static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n,
16441662
*
16451663
* We know, that some child q is already
16461664
* attached to this parent and have choice:
1647-
* either to change it or to create/graft new one.
1665+
* 1) change it or 2) create/graft new one.
1666+
* If the requested qdisc kind is different
1667+
* than the existing one, then we choose graft.
1668+
* If they are the same then this is "change"
1669+
* operation - just let it fallthrough..
16481670
*
16491671
* 1. We are allowed to create/graft only
1650-
* if CREATE and REPLACE flags are set.
1672+
* if the request is explicitly stating
1673+
* "please create if it doesn't exist".
16511674
*
1652-
* 2. If EXCL is set, requestor wanted to say,
1653-
* that qdisc tcm_handle is not expected
1675+
* 2. If the request is to exclusive create
1676+
* then the qdisc tcm_handle is not expected
16541677
* to exist, so that we choose create/graft too.
16551678
*
16561679
* 3. The last case is when no flags are set.
1680+
* This will happen when for example tc
1681+
* utility issues a "change" command.
16571682
* Alas, it is sort of hole in API, we
16581683
* cannot decide what to do unambiguously.
1659-
* For now we select create/graft, if
1660-
* user gave KIND, which does not match existing.
1684+
* For now we select create/graft.
16611685
*/
1662-
if ((n->nlmsg_flags & NLM_F_CREATE) &&
1663-
(n->nlmsg_flags & NLM_F_REPLACE) &&
1664-
((n->nlmsg_flags & NLM_F_EXCL) ||
1665-
(tca[TCA_KIND] &&
1666-
nla_strcmp(tca[TCA_KIND], q->ops->id))))
1667-
goto create_n_graft;
1686+
if (tca[TCA_KIND] &&
1687+
nla_strcmp(tca[TCA_KIND], q->ops->id)) {
1688+
if (req_create_or_replace(n) ||
1689+
req_create_exclusive(n))
1690+
goto create_n_graft;
1691+
else if (req_change(n))
1692+
goto create_n_graft2;
1693+
}
16681694
}
16691695
}
16701696
} else {
@@ -1698,6 +1724,7 @@ static int tc_modify_qdisc(struct sk_buff *skb, struct nlmsghdr *n,
16981724
NL_SET_ERR_MSG(extack, "Qdisc not found. To create specify NLM_F_CREATE flag");
16991725
return -ENOENT;
17001726
}
1727+
create_n_graft2:
17011728
if (clid == TC_H_INGRESS) {
17021729
if (dev_ingress_queue(dev)) {
17031730
q = qdisc_create(dev, dev_ingress_queue(dev),

0 commit comments

Comments
 (0)