aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorRobert Shearman <rshearma@brocade.com>2015-06-05 13:51:54 -0400
committerDavid S. Miller <davem@davemloft.net>2015-06-08 15:12:45 -0400
commit27e41fcfa6b326ad44eee7e0b1930d080b270895 (patch)
tree58b71aa33019e31628c0bcdbf557634e1603cb04 /net
parent1489bdeeae1a47171926e255956c9fc251db13a0 (diff)
ipv6: fix possible use after free of dev stats
The memory pointed to by idev->stats.icmpv6msgdev, idev->stats.icmpv6dev and idev->stats.ipv6 can each be used in an RCU read context without taking a reference on idev. For example, through IP6_*_STATS_* calls in ip6_rcv. These memory blocks are freed without waiting for an RCU grace period to elapse. This could lead to the memory being written to after it has been freed. Fix this by using call_rcu to free the memory used for stats, as well as idev after an RCU grace period has elapsed. Signed-off-by: Robert Shearman <rshearma@brocade.com> Acked-by: Hannes Frederic Sowa <hannes@stressinduktion.org> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/ipv6/addrconf_core.c11
1 files changed, 9 insertions, 2 deletions
diff --git a/net/ipv6/addrconf_core.c b/net/ipv6/addrconf_core.c
index d873ceea86e6..ca09bf49ac68 100644
--- a/net/ipv6/addrconf_core.c
+++ b/net/ipv6/addrconf_core.c
@@ -133,6 +133,14 @@ static void snmp6_free_dev(struct inet6_dev *idev)
133 free_percpu(idev->stats.ipv6); 133 free_percpu(idev->stats.ipv6);
134} 134}
135 135
136static void in6_dev_finish_destroy_rcu(struct rcu_head *head)
137{
138 struct inet6_dev *idev = container_of(head, struct inet6_dev, rcu);
139
140 snmp6_free_dev(idev);
141 kfree(idev);
142}
143
136/* Nobody refers to this device, we may destroy it. */ 144/* Nobody refers to this device, we may destroy it. */
137 145
138void in6_dev_finish_destroy(struct inet6_dev *idev) 146void in6_dev_finish_destroy(struct inet6_dev *idev)
@@ -151,7 +159,6 @@ void in6_dev_finish_destroy(struct inet6_dev *idev)
151 pr_warn("Freeing alive inet6 device %p\n", idev); 159 pr_warn("Freeing alive inet6 device %p\n", idev);
152 return; 160 return;
153 } 161 }
154 snmp6_free_dev(idev); 162 call_rcu(&idev->rcu, in6_dev_finish_destroy_rcu);
155 kfree_rcu(idev, rcu);
156} 163}
157EXPORT_SYMBOL(in6_dev_finish_destroy); 164EXPORT_SYMBOL(in6_dev_finish_destroy);