summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCong Wang <xiyou.wangcong@gmail.com>2019-10-07 16:26:28 -0400
committerJakub Kicinski <jakub.kicinski@netronome.com>2019-10-08 19:21:58 -0400
commit6f96c3c6904c26cea9ca2726d5d8a9b0b8205b3c (patch)
tree9f626d3ab135a6964b4c96699694db5a1891d91d
parent0041412694eca70387aee4076254fbed8222700a (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.c36
-rw-r--r--net/sched/sch_api.c3
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
165static 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
165static bool tcf_proto_is_unlocked(const char *kind) 173static 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
1392const struct nla_policy rtm_tca_policy[TCA_MAX + 1] = { 1392const 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 },