Commit 639739b5e609a5074839bb22fc061b37baa06269

Authored by Hannes Frederic Sowa
Committed by David S. Miller
1 parent a8e9fd0f74

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>

Showing 1 changed file with 23 additions and 25 deletions Side-by-side Diff

net/ipv6/addrlabel.c
... ... @@ -251,38 +251,36 @@
251 251 /* add a label */
252 252 static 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 256 int ret = 0;
255 257  
256   - ADDRLABEL(KERN_DEBUG "%s(newp=%p, replace=%d)\n",
257   - __func__,
258   - newp, replace);
  258 + ADDRLABEL(KERN_DEBUG "%s(newp=%p, replace=%d)\n", __func__, newp,
  259 + replace);
259 260  
260   - if (hlist_empty(&ip6addrlbl_table.head)) {
261   - hlist_add_head_rcu(&newp->list, &ip6addrlbl_table.head);
262   - } else {
263   - struct hlist_node *n;
264   - struct ip6addrlbl_entry *p = NULL;
265   - hlist_for_each_entry_safe(p, n,
266   - &ip6addrlbl_table.head, list) {
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);
  261 + hlist_for_each_entry_safe(p, n, &ip6addrlbl_table.head, list) {
  262 + if (p->prefixlen == newp->prefixlen &&
  263 + net_eq(ip6addrlbl_net(p), ip6addrlbl_net(newp)) &&
  264 + p->ifindex == newp->ifindex &&
  265 + ipv6_addr_equal(&p->prefix, &newp->prefix)) {
  266 + if (!replace) {
  267 + ret = -EEXIST;
277 268 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;
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);
286 284 out:
287 285 if (!ret)
288 286 ip6addrlbl_table.seq++;