diff options
author | Liping Zhang <zlpnobody@gmail.com> | 2017-04-02 05:27:53 -0400 |
---|---|---|
committer | Pablo Neira Ayuso <pablo@netfilter.org> | 2017-04-08 17:52:16 -0400 |
commit | 0c7930e5763bdd189bd50035c025a9cbe5e82f23 (patch) | |
tree | e050756cd08b43500bc7e2b8a6f803a9f0b376bb /net | |
parent | 3173d5b8c89e67fa3176292ff9af06f09f365348 (diff) |
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>
Diffstat (limited to 'net')
-rw-r--r-- | net/netfilter/nf_nat_redirect.c | 2 | ||||
-rw-r--r-- | net/netfilter/xt_TPROXY.c | 5 |
2 files changed, 6 insertions, 1 deletions
diff --git a/net/netfilter/nf_nat_redirect.c b/net/netfilter/nf_nat_redirect.c index d43869879fcf..86067560a318 100644 --- a/net/netfilter/nf_nat_redirect.c +++ b/net/netfilter/nf_nat_redirect.c | |||
@@ -101,11 +101,13 @@ nf_nat_redirect_ipv6(struct sk_buff *skb, const struct nf_nat_range *range, | |||
101 | rcu_read_lock(); | 101 | rcu_read_lock(); |
102 | idev = __in6_dev_get(skb->dev); | 102 | idev = __in6_dev_get(skb->dev); |
103 | if (idev != NULL) { | 103 | if (idev != NULL) { |
104 | read_lock_bh(&idev->lock); | ||
104 | list_for_each_entry(ifa, &idev->addr_list, if_list) { | 105 | list_for_each_entry(ifa, &idev->addr_list, if_list) { |
105 | newdst = ifa->addr; | 106 | newdst = ifa->addr; |
106 | addr = true; | 107 | addr = true; |
107 | break; | 108 | break; |
108 | } | 109 | } |
110 | read_unlock_bh(&idev->lock); | ||
109 | } | 111 | } |
110 | rcu_read_unlock(); | 112 | rcu_read_unlock(); |
111 | 113 | ||
diff --git a/net/netfilter/xt_TPROXY.c b/net/netfilter/xt_TPROXY.c index 80cb7babeb64..df7f1df00330 100644 --- a/net/netfilter/xt_TPROXY.c +++ b/net/netfilter/xt_TPROXY.c | |||
@@ -393,7 +393,8 @@ tproxy_laddr6(struct sk_buff *skb, const struct in6_addr *user_laddr, | |||
393 | 393 | ||
394 | rcu_read_lock(); | 394 | rcu_read_lock(); |
395 | indev = __in6_dev_get(skb->dev); | 395 | indev = __in6_dev_get(skb->dev); |
396 | if (indev) | 396 | if (indev) { |
397 | read_lock_bh(&indev->lock); | ||
397 | list_for_each_entry(ifa, &indev->addr_list, if_list) { | 398 | list_for_each_entry(ifa, &indev->addr_list, if_list) { |
398 | if (ifa->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED)) | 399 | if (ifa->flags & (IFA_F_TENTATIVE | IFA_F_DEPRECATED)) |
399 | continue; | 400 | continue; |
@@ -401,6 +402,8 @@ tproxy_laddr6(struct sk_buff *skb, const struct in6_addr *user_laddr, | |||
401 | laddr = &ifa->addr; | 402 | laddr = &ifa->addr; |
402 | break; | 403 | break; |
403 | } | 404 | } |
405 | read_unlock_bh(&indev->lock); | ||
406 | } | ||
404 | rcu_read_unlock(); | 407 | rcu_read_unlock(); |
405 | 408 | ||
406 | return laddr ? laddr : daddr; | 409 | return laddr ? laddr : daddr; |