aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorThomas Graf <tgraf@suug.ch>2007-03-24 15:46:02 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-03-25 21:48:00 -0400
commite1701c68c1d1aeb3213d7016593ea9a1d4309417 (patch)
tree96dc2e47b36589636b15602dcdcfd2ea426260b7 /net
parent5f85813c33ddbf6d11ccfdbcc01f176e24a76bd2 (diff)
[NET]: Fix fib_rules compatibility breakage
Based upon a patch from Patrick McHardy. The fib_rules netlink attribute policy introduced in 2.6.19 broke userspace compatibilty. When specifying a rule with "from all" or "to all", iproute adds a zero byte long netlink attribute, but the policy requires all addresses to have a size equal to sizeof(struct in_addr)/sizeof(struct in6_addr), resulting in a validation error. Check attribute length of FRA_SRC/FRA_DST in the generic framework by letting the family specific rules implementation provide the length of an address. Report an error if address length is non zero but no address attribute is provided. Fix actual bug by checking address length for non-zero instead of relying on availability of attribute. Signed-off-by: Thomas Graf <tgraf@suug.ch> Signed-off-by: Patrick McHardy <kaber@trash.net> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/core/fib_rules.c30
-rw-r--r--net/decnet/dn_rules.c13
-rw-r--r--net/ipv4/fib_rules.c14
-rw-r--r--net/ipv6/fib6_rules.c14
4 files changed, 47 insertions, 24 deletions
diff --git a/net/core/fib_rules.c b/net/core/fib_rules.c
index 3aea4e87d3d..d011819a805 100644
--- a/net/core/fib_rules.c
+++ b/net/core/fib_rules.c
@@ -152,6 +152,28 @@ out:
152 152
153EXPORT_SYMBOL_GPL(fib_rules_lookup); 153EXPORT_SYMBOL_GPL(fib_rules_lookup);
154 154
155static int validate_rulemsg(struct fib_rule_hdr *frh, struct nlattr **tb,
156 struct fib_rules_ops *ops)
157{
158 int err = -EINVAL;
159
160 if (frh->src_len)
161 if (tb[FRA_SRC] == NULL ||
162 frh->src_len > (ops->addr_size * 8) ||
163 nla_len(tb[FRA_SRC]) != ops->addr_size)
164 goto errout;
165
166 if (frh->dst_len)
167 if (tb[FRA_DST] == NULL ||
168 frh->dst_len > (ops->addr_size * 8) ||
169 nla_len(tb[FRA_DST]) != ops->addr_size)
170 goto errout;
171
172 err = 0;
173errout:
174 return err;
175}
176
155int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg) 177int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
156{ 178{
157 struct fib_rule_hdr *frh = nlmsg_data(nlh); 179 struct fib_rule_hdr *frh = nlmsg_data(nlh);
@@ -173,6 +195,10 @@ int fib_nl_newrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
173 if (err < 0) 195 if (err < 0)
174 goto errout; 196 goto errout;
175 197
198 err = validate_rulemsg(frh, tb, ops);
199 if (err < 0)
200 goto errout;
201
176 rule = kzalloc(ops->rule_size, GFP_KERNEL); 202 rule = kzalloc(ops->rule_size, GFP_KERNEL);
177 if (rule == NULL) { 203 if (rule == NULL) {
178 err = -ENOMEM; 204 err = -ENOMEM;
@@ -260,6 +286,10 @@ int fib_nl_delrule(struct sk_buff *skb, struct nlmsghdr* nlh, void *arg)
260 if (err < 0) 286 if (err < 0)
261 goto errout; 287 goto errout;
262 288
289 err = validate_rulemsg(frh, tb, ops);
290 if (err < 0)
291 goto errout;
292
263 list_for_each_entry(rule, ops->rules_list, list) { 293 list_for_each_entry(rule, ops->rules_list, list) {
264 if (frh->action && (frh->action != rule->action)) 294 if (frh->action && (frh->action != rule->action))
265 continue; 295 continue;
diff --git a/net/decnet/dn_rules.c b/net/decnet/dn_rules.c
index b6c98ac93dc..5e86dd54230 100644
--- a/net/decnet/dn_rules.c
+++ b/net/decnet/dn_rules.c
@@ -109,8 +109,6 @@ errout:
109 109
110static struct nla_policy dn_fib_rule_policy[FRA_MAX+1] __read_mostly = { 110static struct nla_policy dn_fib_rule_policy[FRA_MAX+1] __read_mostly = {
111 FRA_GENERIC_POLICY, 111 FRA_GENERIC_POLICY,
112 [FRA_SRC] = { .type = NLA_U16 },
113 [FRA_DST] = { .type = NLA_U16 },
114}; 112};
115 113
116static int dn_fib_rule_match(struct fib_rule *rule, struct flowi *fl, int flags) 114static int dn_fib_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
@@ -133,7 +131,7 @@ static int dn_fib_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
133 int err = -EINVAL; 131 int err = -EINVAL;
134 struct dn_fib_rule *r = (struct dn_fib_rule *)rule; 132 struct dn_fib_rule *r = (struct dn_fib_rule *)rule;
135 133
136 if (frh->src_len > 16 || frh->dst_len > 16 || frh->tos) 134 if (frh->tos)
137 goto errout; 135 goto errout;
138 136
139 if (rule->table == RT_TABLE_UNSPEC) { 137 if (rule->table == RT_TABLE_UNSPEC) {
@@ -150,10 +148,10 @@ static int dn_fib_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
150 } 148 }
151 } 149 }
152 150
153 if (tb[FRA_SRC]) 151 if (frh->src_len)
154 r->src = nla_get_le16(tb[FRA_SRC]); 152 r->src = nla_get_le16(tb[FRA_SRC]);
155 153
156 if (tb[FRA_DST]) 154 if (frh->dst_len)
157 r->dst = nla_get_le16(tb[FRA_DST]); 155 r->dst = nla_get_le16(tb[FRA_DST]);
158 156
159 r->src_len = frh->src_len; 157 r->src_len = frh->src_len;
@@ -176,10 +174,10 @@ static int dn_fib_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
176 if (frh->dst_len && (r->dst_len != frh->dst_len)) 174 if (frh->dst_len && (r->dst_len != frh->dst_len))
177 return 0; 175 return 0;
178 176
179 if (tb[FRA_SRC] && (r->src != nla_get_le16(tb[FRA_SRC]))) 177 if (frh->src_len && (r->src != nla_get_le16(tb[FRA_SRC])))
180 return 0; 178 return 0;
181 179
182 if (tb[FRA_DST] && (r->dst != nla_get_le16(tb[FRA_DST]))) 180 if (frh->dst_len && (r->dst != nla_get_le16(tb[FRA_DST])))
183 return 0; 181 return 0;
184 182
185 return 1; 183 return 1;
@@ -249,6 +247,7 @@ int dn_fib_dump_rules(struct sk_buff *skb, struct netlink_callback *cb)
249static struct fib_rules_ops dn_fib_rules_ops = { 247static struct fib_rules_ops dn_fib_rules_ops = {
250 .family = AF_DECnet, 248 .family = AF_DECnet,
251 .rule_size = sizeof(struct dn_fib_rule), 249 .rule_size = sizeof(struct dn_fib_rule),
250 .addr_size = sizeof(u16),
252 .action = dn_fib_rule_action, 251 .action = dn_fib_rule_action,
253 .match = dn_fib_rule_match, 252 .match = dn_fib_rule_match,
254 .configure = dn_fib_rule_configure, 253 .configure = dn_fib_rule_configure,
diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c
index b837c33e040..c660c074c76 100644
--- a/net/ipv4/fib_rules.c
+++ b/net/ipv4/fib_rules.c
@@ -171,8 +171,6 @@ static struct fib_table *fib_empty_table(void)
171 171
172static struct nla_policy fib4_rule_policy[FRA_MAX+1] __read_mostly = { 172static struct nla_policy fib4_rule_policy[FRA_MAX+1] __read_mostly = {
173 FRA_GENERIC_POLICY, 173 FRA_GENERIC_POLICY,
174 [FRA_SRC] = { .type = NLA_U32 },
175 [FRA_DST] = { .type = NLA_U32 },
176 [FRA_FLOW] = { .type = NLA_U32 }, 174 [FRA_FLOW] = { .type = NLA_U32 },
177}; 175};
178 176
@@ -183,8 +181,7 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
183 int err = -EINVAL; 181 int err = -EINVAL;
184 struct fib4_rule *rule4 = (struct fib4_rule *) rule; 182 struct fib4_rule *rule4 = (struct fib4_rule *) rule;
185 183
186 if (frh->src_len > 32 || frh->dst_len > 32 || 184 if (frh->tos & ~IPTOS_TOS_MASK)
187 (frh->tos & ~IPTOS_TOS_MASK))
188 goto errout; 185 goto errout;
189 186
190 if (rule->table == RT_TABLE_UNSPEC) { 187 if (rule->table == RT_TABLE_UNSPEC) {
@@ -201,10 +198,10 @@ static int fib4_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
201 } 198 }
202 } 199 }
203 200
204 if (tb[FRA_SRC]) 201 if (frh->src_len)
205 rule4->src = nla_get_be32(tb[FRA_SRC]); 202 rule4->src = nla_get_be32(tb[FRA_SRC]);
206 203
207 if (tb[FRA_DST]) 204 if (frh->dst_len)
208 rule4->dst = nla_get_be32(tb[FRA_DST]); 205 rule4->dst = nla_get_be32(tb[FRA_DST]);
209 206
210#ifdef CONFIG_NET_CLS_ROUTE 207#ifdef CONFIG_NET_CLS_ROUTE
@@ -242,10 +239,10 @@ static int fib4_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
242 return 0; 239 return 0;
243#endif 240#endif
244 241
245 if (tb[FRA_SRC] && (rule4->src != nla_get_be32(tb[FRA_SRC]))) 242 if (frh->src_len && (rule4->src != nla_get_be32(tb[FRA_SRC])))
246 return 0; 243 return 0;
247 244
248 if (tb[FRA_DST] && (rule4->dst != nla_get_be32(tb[FRA_DST]))) 245 if (frh->dst_len && (rule4->dst != nla_get_be32(tb[FRA_DST])))
249 return 0; 246 return 0;
250 247
251 return 1; 248 return 1;
@@ -309,6 +306,7 @@ static size_t fib4_rule_nlmsg_payload(struct fib_rule *rule)
309static struct fib_rules_ops fib4_rules_ops = { 306static struct fib_rules_ops fib4_rules_ops = {
310 .family = AF_INET, 307 .family = AF_INET,
311 .rule_size = sizeof(struct fib4_rule), 308 .rule_size = sizeof(struct fib4_rule),
309 .addr_size = sizeof(u32),
312 .action = fib4_rule_action, 310 .action = fib4_rule_action,
313 .match = fib4_rule_match, 311 .match = fib4_rule_match,
314 .configure = fib4_rule_configure, 312 .configure = fib4_rule_configure,
diff --git a/net/ipv6/fib6_rules.c b/net/ipv6/fib6_rules.c
index 0862809ffcf..ea3035b4e3e 100644
--- a/net/ipv6/fib6_rules.c
+++ b/net/ipv6/fib6_rules.c
@@ -131,8 +131,6 @@ static int fib6_rule_match(struct fib_rule *rule, struct flowi *fl, int flags)
131 131
132static struct nla_policy fib6_rule_policy[FRA_MAX+1] __read_mostly = { 132static struct nla_policy fib6_rule_policy[FRA_MAX+1] __read_mostly = {
133 FRA_GENERIC_POLICY, 133 FRA_GENERIC_POLICY,
134 [FRA_SRC] = { .len = sizeof(struct in6_addr) },
135 [FRA_DST] = { .len = sizeof(struct in6_addr) },
136}; 134};
137 135
138static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb, 136static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
@@ -142,9 +140,6 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
142 int err = -EINVAL; 140 int err = -EINVAL;
143 struct fib6_rule *rule6 = (struct fib6_rule *) rule; 141 struct fib6_rule *rule6 = (struct fib6_rule *) rule;
144 142
145 if (frh->src_len > 128 || frh->dst_len > 128)
146 goto errout;
147
148 if (rule->action == FR_ACT_TO_TBL) { 143 if (rule->action == FR_ACT_TO_TBL) {
149 if (rule->table == RT6_TABLE_UNSPEC) 144 if (rule->table == RT6_TABLE_UNSPEC)
150 goto errout; 145 goto errout;
@@ -155,11 +150,11 @@ static int fib6_rule_configure(struct fib_rule *rule, struct sk_buff *skb,
155 } 150 }
156 } 151 }
157 152
158 if (tb[FRA_SRC]) 153 if (frh->src_len)
159 nla_memcpy(&rule6->src.addr, tb[FRA_SRC], 154 nla_memcpy(&rule6->src.addr, tb[FRA_SRC],
160 sizeof(struct in6_addr)); 155 sizeof(struct in6_addr));
161 156
162 if (tb[FRA_DST]) 157 if (frh->dst_len)
163 nla_memcpy(&rule6->dst.addr, tb[FRA_DST], 158 nla_memcpy(&rule6->dst.addr, tb[FRA_DST],
164 sizeof(struct in6_addr)); 159 sizeof(struct in6_addr));
165 160
@@ -186,11 +181,11 @@ static int fib6_rule_compare(struct fib_rule *rule, struct fib_rule_hdr *frh,
186 if (frh->tos && (rule6->tclass != frh->tos)) 181 if (frh->tos && (rule6->tclass != frh->tos))
187 return 0; 182 return 0;
188 183
189 if (tb[FRA_SRC] && 184 if (frh->src_len &&
190 nla_memcmp(tb[FRA_SRC], &rule6->src.addr, sizeof(struct in6_addr))) 185 nla_memcmp(tb[FRA_SRC], &rule6->src.addr, sizeof(struct in6_addr)))
191 return 0; 186 return 0;
192 187
193 if (tb[FRA_DST] && 188 if (frh->dst_len &&
194 nla_memcmp(tb[FRA_DST], &rule6->dst.addr, sizeof(struct in6_addr))) 189 nla_memcmp(tb[FRA_DST], &rule6->dst.addr, sizeof(struct in6_addr)))
195 return 0; 190 return 0;
196 191
@@ -240,6 +235,7 @@ static size_t fib6_rule_nlmsg_payload(struct fib_rule *rule)
240static struct fib_rules_ops fib6_rules_ops = { 235static struct fib_rules_ops fib6_rules_ops = {
241 .family = AF_INET6, 236 .family = AF_INET6,
242 .rule_size = sizeof(struct fib6_rule), 237 .rule_size = sizeof(struct fib6_rule),
238 .addr_size = sizeof(struct in6_addr),
243 .action = fib6_rule_action, 239 .action = fib6_rule_action,
244 .match = fib6_rule_match, 240 .match = fib6_rule_match,
245 .configure = fib6_rule_configure, 241 .configure = fib6_rule_configure,