diff options
author | Cong Wang <xiyou.wangcong@gmail.com> | 2019-10-07 16:26:28 -0400 |
---|---|---|
committer | Jakub Kicinski <jakub.kicinski@netronome.com> | 2019-10-08 19:21:58 -0400 |
commit | 6f96c3c6904c26cea9ca2726d5d8a9b0b8205b3c (patch) | |
tree | 9f626d3ab135a6964b4c96699694db5a1891d91d | |
parent | 0041412694eca70387aee4076254fbed8222700a (diff) |
net_sched: fix backward compatibility for TCA_KIND
Marcelo noticed a backward compatibility issue of TCA_KIND
after we move from NLA_STRING to NLA_NUL_STRING, so it is probably
too late to change it.
Instead, to make everyone happy, we can just insert a NUL to
terminate the string with nla_strlcpy() like we do for TC actions.
Fixes: 62794fc4fbf5 ("net_sched: add max len check for TCA_KIND")
Reported-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Cc: Jamal Hadi Salim <jhs@mojatatu.com>
Cc: Jiri Pirko <jiri@resnulli.us>
Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
Reviewed-by: Marcelo Ricardo Leitner <marcelo.leitner@gmail.com>
Signed-off-by: Jakub Kicinski <jakub.kicinski@netronome.com>
-rw-r--r-- | net/sched/cls_api.c | 36 | ||||
-rw-r--r-- | net/sched/sch_api.c | 3 |
2 files changed, 34 insertions, 5 deletions
diff --git a/net/sched/cls_api.c b/net/sched/cls_api.c index 64584a1df425..8717c0b26c90 100644 --- a/net/sched/cls_api.c +++ b/net/sched/cls_api.c | |||
@@ -162,11 +162,22 @@ static inline u32 tcf_auto_prio(struct tcf_proto *tp) | |||
162 | return TC_H_MAJ(first); | 162 | return TC_H_MAJ(first); |
163 | } | 163 | } |
164 | 164 | ||
165 | static bool tcf_proto_check_kind(struct nlattr *kind, char *name) | ||
166 | { | ||
167 | if (kind) | ||
168 | return nla_strlcpy(name, kind, IFNAMSIZ) >= IFNAMSIZ; | ||
169 | memset(name, 0, IFNAMSIZ); | ||
170 | return false; | ||
171 | } | ||
172 | |||
165 | static bool tcf_proto_is_unlocked(const char *kind) | 173 | static bool tcf_proto_is_unlocked(const char *kind) |
166 | { | 174 | { |
167 | const struct tcf_proto_ops *ops; | 175 | const struct tcf_proto_ops *ops; |
168 | bool ret; | 176 | bool ret; |
169 | 177 | ||
178 | if (strlen(kind) == 0) | ||
179 | return false; | ||
180 | |||
170 | ops = tcf_proto_lookup_ops(kind, false, NULL); | 181 | ops = tcf_proto_lookup_ops(kind, false, NULL); |
171 | /* On error return false to take rtnl lock. Proto lookup/create | 182 | /* On error return false to take rtnl lock. Proto lookup/create |
172 | * functions will perform lookup again and properly handle errors. | 183 | * functions will perform lookup again and properly handle errors. |
@@ -1843,6 +1854,7 @@ static int tc_new_tfilter(struct sk_buff *skb, struct nlmsghdr *n, | |||
1843 | { | 1854 | { |
1844 | struct net *net = sock_net(skb->sk); | 1855 | struct net *net = sock_net(skb->sk); |
1845 | struct nlattr *tca[TCA_MAX + 1]; | 1856 | struct nlattr *tca[TCA_MAX + 1]; |
1857 | char name[IFNAMSIZ]; | ||
1846 | struct tcmsg *t; | 1858 | struct tcmsg *t; |
1847 | u32 protocol; | 1859 | u32 protocol; |
1848 | u32 prio; | 1860 | u32 prio; |
@@ -1899,13 +1911,19 @@ replay: | |||
1899 | if (err) | 1911 | if (err) |
1900 | return err; | 1912 | return err; |
1901 | 1913 | ||
1914 | if (tcf_proto_check_kind(tca[TCA_KIND], name)) { | ||
1915 | NL_SET_ERR_MSG(extack, "Specified TC filter name too long"); | ||
1916 | err = -EINVAL; | ||
1917 | goto errout; | ||
1918 | } | ||
1919 | |||
1902 | /* Take rtnl mutex if rtnl_held was set to true on previous iteration, | 1920 | /* Take rtnl mutex if rtnl_held was set to true on previous iteration, |
1903 | * block is shared (no qdisc found), qdisc is not unlocked, classifier | 1921 | * block is shared (no qdisc found), qdisc is not unlocked, classifier |
1904 | * type is not specified, classifier is not unlocked. | 1922 | * type is not specified, classifier is not unlocked. |
1905 | */ | 1923 | */ |
1906 | if (rtnl_held || | 1924 | if (rtnl_held || |
1907 | (q && !(q->ops->cl_ops->flags & QDISC_CLASS_OPS_DOIT_UNLOCKED)) || | 1925 | (q && !(q->ops->cl_ops->flags & QDISC_CLASS_OPS_DOIT_UNLOCKED)) || |
1908 | !tca[TCA_KIND] || !tcf_proto_is_unlocked(nla_data(tca[TCA_KIND]))) { | 1926 | !tcf_proto_is_unlocked(name)) { |
1909 | rtnl_held = true; | 1927 | rtnl_held = true; |
1910 | rtnl_lock(); | 1928 | rtnl_lock(); |
1911 | } | 1929 | } |
@@ -2063,6 +2081,7 @@ static int tc_del_tfilter(struct sk_buff *skb, struct nlmsghdr *n, | |||
2063 | { | 2081 | { |
2064 | struct net *net = sock_net(skb->sk); | 2082 | struct net *net = sock_net(skb->sk); |
2065 | struct nlattr *tca[TCA_MAX + 1]; | 2083 | struct nlattr *tca[TCA_MAX + 1]; |
2084 | char name[IFNAMSIZ]; | ||
2066 | struct tcmsg *t; | 2085 | struct tcmsg *t; |
2067 | u32 protocol; | 2086 | u32 protocol; |
2068 | u32 prio; | 2087 | u32 prio; |
@@ -2102,13 +2121,18 @@ static int tc_del_tfilter(struct sk_buff *skb, struct nlmsghdr *n, | |||
2102 | if (err) | 2121 | if (err) |
2103 | return err; | 2122 | return err; |
2104 | 2123 | ||
2124 | if (tcf_proto_check_kind(tca[TCA_KIND], name)) { | ||
2125 | NL_SET_ERR_MSG(extack, "Specified TC filter name too long"); | ||
2126 | err = -EINVAL; | ||
2127 | goto errout; | ||
2128 | } | ||
2105 | /* Take rtnl mutex if flushing whole chain, block is shared (no qdisc | 2129 | /* Take rtnl mutex if flushing whole chain, block is shared (no qdisc |
2106 | * found), qdisc is not unlocked, classifier type is not specified, | 2130 | * found), qdisc is not unlocked, classifier type is not specified, |
2107 | * classifier is not unlocked. | 2131 | * classifier is not unlocked. |
2108 | */ | 2132 | */ |
2109 | if (!prio || | 2133 | if (!prio || |
2110 | (q && !(q->ops->cl_ops->flags & QDISC_CLASS_OPS_DOIT_UNLOCKED)) || | 2134 | (q && !(q->ops->cl_ops->flags & QDISC_CLASS_OPS_DOIT_UNLOCKED)) || |
2111 | !tca[TCA_KIND] || !tcf_proto_is_unlocked(nla_data(tca[TCA_KIND]))) { | 2135 | !tcf_proto_is_unlocked(name)) { |
2112 | rtnl_held = true; | 2136 | rtnl_held = true; |
2113 | rtnl_lock(); | 2137 | rtnl_lock(); |
2114 | } | 2138 | } |
@@ -2216,6 +2240,7 @@ static int tc_get_tfilter(struct sk_buff *skb, struct nlmsghdr *n, | |||
2216 | { | 2240 | { |
2217 | struct net *net = sock_net(skb->sk); | 2241 | struct net *net = sock_net(skb->sk); |
2218 | struct nlattr *tca[TCA_MAX + 1]; | 2242 | struct nlattr *tca[TCA_MAX + 1]; |
2243 | char name[IFNAMSIZ]; | ||
2219 | struct tcmsg *t; | 2244 | struct tcmsg *t; |
2220 | u32 protocol; | 2245 | u32 protocol; |
2221 | u32 prio; | 2246 | u32 prio; |
@@ -2252,12 +2277,17 @@ static int tc_get_tfilter(struct sk_buff *skb, struct nlmsghdr *n, | |||
2252 | if (err) | 2277 | if (err) |
2253 | return err; | 2278 | return err; |
2254 | 2279 | ||
2280 | if (tcf_proto_check_kind(tca[TCA_KIND], name)) { | ||
2281 | NL_SET_ERR_MSG(extack, "Specified TC filter name too long"); | ||
2282 | err = -EINVAL; | ||
2283 | goto errout; | ||
2284 | } | ||
2255 | /* Take rtnl mutex if block is shared (no qdisc found), qdisc is not | 2285 | /* Take rtnl mutex if block is shared (no qdisc found), qdisc is not |
2256 | * unlocked, classifier type is not specified, classifier is not | 2286 | * unlocked, classifier type is not specified, classifier is not |
2257 | * unlocked. | 2287 | * unlocked. |
2258 | */ | 2288 | */ |
2259 | if ((q && !(q->ops->cl_ops->flags & QDISC_CLASS_OPS_DOIT_UNLOCKED)) || | 2289 | if ((q && !(q->ops->cl_ops->flags & QDISC_CLASS_OPS_DOIT_UNLOCKED)) || |
2260 | !tca[TCA_KIND] || !tcf_proto_is_unlocked(nla_data(tca[TCA_KIND]))) { | 2290 | !tcf_proto_is_unlocked(name)) { |
2261 | rtnl_held = true; | 2291 | rtnl_held = true; |
2262 | rtnl_lock(); | 2292 | rtnl_lock(); |
2263 | } | 2293 | } |
diff --git a/net/sched/sch_api.c b/net/sched/sch_api.c index 81d58b280612..1047825d9f48 100644 --- a/net/sched/sch_api.c +++ b/net/sched/sch_api.c | |||
@@ -1390,8 +1390,7 @@ check_loop_fn(struct Qdisc *q, unsigned long cl, struct qdisc_walker *w) | |||
1390 | } | 1390 | } |
1391 | 1391 | ||
1392 | const struct nla_policy rtm_tca_policy[TCA_MAX + 1] = { | 1392 | const struct nla_policy rtm_tca_policy[TCA_MAX + 1] = { |
1393 | [TCA_KIND] = { .type = NLA_NUL_STRING, | 1393 | [TCA_KIND] = { .type = NLA_STRING }, |
1394 | .len = IFNAMSIZ - 1 }, | ||
1395 | [TCA_RATE] = { .type = NLA_BINARY, | 1394 | [TCA_RATE] = { .type = NLA_BINARY, |
1396 | .len = sizeof(struct tc_estimator) }, | 1395 | .len = sizeof(struct tc_estimator) }, |
1397 | [TCA_STAB] = { .type = NLA_NESTED }, | 1396 | [TCA_STAB] = { .type = NLA_NESTED }, |