Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

netfilter: make it safer during the inet6_dev->addr_list traversal

inet6_dev->addr_list is protected by inet6_dev->lock, so only using
rcu_read_lock is not enough, we should acquire read_lock_bh(&idev->lock)
before the inet6_dev->addr_list traversal.

Signed-off-by: Liping Zhang <zlpnobody@gmail.com>
Signed-off-by: Pablo Neira Ayuso <pablo@netfilter.org>

authored by

Liping Zhang and committed by
Pablo Neira Ayuso
0c7930e5 3173d5b8

+6 -1
+2
net/netfilter/nf_nat_redirect.c
··· 101 101 rcu_read_lock(); 102 102 idev = __in6_dev_get(skb->dev); 103 103 if (idev != NULL) { 104 + read_lock_bh(&idev->lock); 104 105 list_for_each_entry(ifa, &idev->addr_list, if_list) { 105 106 newdst = ifa->addr; 106 107 addr = true; 107 108 break; 108 109 } 110 + read_unlock_bh(&idev->lock); 109 111 } 110 112 rcu_read_unlock(); 111 113
+4 -1
net/netfilter/xt_TPROXY.c
··· 393 393 394 394 rcu_read_lock(); 395 395 indev = __in6_dev_get(skb->dev); 396 - if (indev) 396 + if (indev) { 397 + read_lock_bh(&indev->lock); 397 398 list_for_each_entry(ifa, &indev->addr_list, if_list) { 398 399 if (ifa->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED)) 399 400 continue; ··· 402 401 laddr = &ifa->addr; 403 402 break; 404 403 } 404 + read_unlock_bh(&indev->lock); 405 + } 405 406 rcu_read_unlock(); 406 407 407 408 return laddr ? laddr : daddr;