aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv6/addrlabel.c
diff options
context:
space:
mode:
authorHannes Frederic Sowa <hannes@stressinduktion.org>2013-09-02 20:13:31 -0400
committerDavid S. Miller <davem@davemloft.net>2013-09-04 14:14:53 -0400
commit639739b5e609a5074839bb22fc061b37baa06269 (patch)
treefdfb281e6c5d629ecec0702cf9d89f3a3f818ee6 /net/ipv6/addrlabel.c
parenta8e9fd0f7462f5cada5189513d12fe6c9cce2105 (diff)
ipv6: fix null pointer dereference in __ip6addrlbl_add
Commit b67bfe0d42cac56c512dd5da4b1b347a23f4b70a ("hlist: drop the node parameter from iterators") changed the behavior of hlist_for_each_entry_safe to leave the p argument NULL. Fix this up by tracking the last argument. Reported-by: Michele Baldessari <michele@acksyn.org> Cc: Hideaki YOSHIFUJI <yoshfuji@linux-ipv6.org> Cc: Sasha Levin <sasha.levin@oracle.com> Signed-off-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Tested-by: Michele Baldessari <michele@acksyn.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv6/addrlabel.c')
-rw-r--r--net/ipv6/addrlabel.c48
1 files changed, 23 insertions, 25 deletions
diff --git a/net/ipv6/addrlabel.c b/net/ipv6/addrlabel.c
index f083a583a05c..b30ad3741b46 100644
--- a/net/ipv6/addrlabel.c
+++ b/net/ipv6/addrlabel.c
@@ -251,38 +251,36 @@ static struct ip6addrlbl_entry *ip6addrlbl_alloc(struct net *net,
251/* add a label */ 251/* add a label */
252static int __ip6addrlbl_add(struct ip6addrlbl_entry *newp, int replace) 252static int __ip6addrlbl_add(struct ip6addrlbl_entry *newp, int replace)
253{ 253{
254 struct hlist_node *n;
255 struct ip6addrlbl_entry *last = NULL, *p = NULL;
254 int ret = 0; 256 int ret = 0;
255 257
256 ADDRLABEL(KERN_DEBUG "%s(newp=%p, replace=%d)\n", 258 ADDRLABEL(KERN_DEBUG "%s(newp=%p, replace=%d)\n", __func__, newp,
257 __func__, 259 replace);
258 newp, replace);
259 260
260 if (hlist_empty(&ip6addrlbl_table.head)) { 261 hlist_for_each_entry_safe(p, n, &ip6addrlbl_table.head, list) {
261 hlist_add_head_rcu(&newp->list, &ip6addrlbl_table.head); 262 if (p->prefixlen == newp->prefixlen &&
262 } else { 263 net_eq(ip6addrlbl_net(p), ip6addrlbl_net(newp)) &&
263 struct hlist_node *n; 264 p->ifindex == newp->ifindex &&
264 struct ip6addrlbl_entry *p = NULL; 265 ipv6_addr_equal(&p->prefix, &newp->prefix)) {
265 hlist_for_each_entry_safe(p, n, 266 if (!replace) {
266 &ip6addrlbl_table.head, list) { 267 ret = -EEXIST;
267 if (p->prefixlen == newp->prefixlen &&
268 net_eq(ip6addrlbl_net(p), ip6addrlbl_net(newp)) &&
269 p->ifindex == newp->ifindex &&
270 ipv6_addr_equal(&p->prefix, &newp->prefix)) {
271 if (!replace) {
272 ret = -EEXIST;
273 goto out;
274 }
275 hlist_replace_rcu(&p->list, &newp->list);
276 ip6addrlbl_put(p);
277 goto out;
278 } else if ((p->prefixlen == newp->prefixlen && !p->ifindex) ||
279 (p->prefixlen < newp->prefixlen)) {
280 hlist_add_before_rcu(&newp->list, &p->list);
281 goto out; 268 goto out;
282 } 269 }
270 hlist_replace_rcu(&p->list, &newp->list);
271 ip6addrlbl_put(p);
272 goto out;
273 } else if ((p->prefixlen == newp->prefixlen && !p->ifindex) ||
274 (p->prefixlen < newp->prefixlen)) {
275 hlist_add_before_rcu(&newp->list, &p->list);
276 goto out;
283 } 277 }
284 hlist_add_after_rcu(&p->list, &newp->list); 278 last = p;
285 } 279 }
280 if (last)
281 hlist_add_after_rcu(&last->list, &newp->list);
282 else
283 hlist_add_head_rcu(&newp->list, &ip6addrlbl_table.head);
286out: 284out:
287 if (!ret) 285 if (!ret)
288 ip6addrlbl_table.seq++; 286 ip6addrlbl_table.seq++;