ipv6: fix null pointer dereference in __ip6addrlbl_add
Commit b67bfe0d42
("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>
This commit is contained in:
parent
a8e9fd0f74
commit
639739b5e6
|
@ -251,38 +251,36 @@ static struct ip6addrlbl_entry *ip6addrlbl_alloc(struct net *net,
|
|||
/* add a label */
|
||||
static int __ip6addrlbl_add(struct ip6addrlbl_entry *newp, int replace)
|
||||
{
|
||||
struct hlist_node *n;
|
||||
struct ip6addrlbl_entry *last = NULL, *p = NULL;
|
||||
int ret = 0;
|
||||
|
||||
ADDRLABEL(KERN_DEBUG "%s(newp=%p, replace=%d)\n",
|
||||
__func__,
|
||||
newp, replace);
|
||||
ADDRLABEL(KERN_DEBUG "%s(newp=%p, replace=%d)\n", __func__, newp,
|
||||
replace);
|
||||
|
||||
if (hlist_empty(&ip6addrlbl_table.head)) {
|
||||
hlist_add_head_rcu(&newp->list, &ip6addrlbl_table.head);
|
||||
} else {
|
||||
struct hlist_node *n;
|
||||
struct ip6addrlbl_entry *p = NULL;
|
||||
hlist_for_each_entry_safe(p, n,
|
||||
&ip6addrlbl_table.head, list) {
|
||||
if (p->prefixlen == newp->prefixlen &&
|
||||
net_eq(ip6addrlbl_net(p), ip6addrlbl_net(newp)) &&
|
||||
p->ifindex == newp->ifindex &&
|
||||
ipv6_addr_equal(&p->prefix, &newp->prefix)) {
|
||||
if (!replace) {
|
||||
ret = -EEXIST;
|
||||
goto out;
|
||||
}
|
||||
hlist_replace_rcu(&p->list, &newp->list);
|
||||
ip6addrlbl_put(p);
|
||||
goto out;
|
||||
} else if ((p->prefixlen == newp->prefixlen && !p->ifindex) ||
|
||||
(p->prefixlen < newp->prefixlen)) {
|
||||
hlist_add_before_rcu(&newp->list, &p->list);
|
||||
hlist_for_each_entry_safe(p, n, &ip6addrlbl_table.head, list) {
|
||||
if (p->prefixlen == newp->prefixlen &&
|
||||
net_eq(ip6addrlbl_net(p), ip6addrlbl_net(newp)) &&
|
||||
p->ifindex == newp->ifindex &&
|
||||
ipv6_addr_equal(&p->prefix, &newp->prefix)) {
|
||||
if (!replace) {
|
||||
ret = -EEXIST;
|
||||
goto out;
|
||||
}
|
||||
hlist_replace_rcu(&p->list, &newp->list);
|
||||
ip6addrlbl_put(p);
|
||||
goto out;
|
||||
} else if ((p->prefixlen == newp->prefixlen && !p->ifindex) ||
|
||||
(p->prefixlen < newp->prefixlen)) {
|
||||
hlist_add_before_rcu(&newp->list, &p->list);
|
||||
goto out;
|
||||
}
|
||||
hlist_add_after_rcu(&p->list, &newp->list);
|
||||
last = p;
|
||||
}
|
||||
if (last)
|
||||
hlist_add_after_rcu(&last->list, &newp->list);
|
||||
else
|
||||
hlist_add_head_rcu(&newp->list, &ip6addrlbl_table.head);
|
||||
out:
|
||||
if (!ret)
|
||||
ip6addrlbl_table.seq++;
|
||||
|
|
Loading…
Reference in New Issue
Block a user