diff options
author | Daniel Borkmann <dborkman@redhat.com> | 2013-12-06 05:36:15 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2014-01-15 18:28:46 -0500 |
commit | c3ac8a134305ed1522d8987e62249a85efb09c98 (patch) | |
tree | 0ba2f10ff56d4b922f3f062d5272d14edee0c556 /net/packet | |
parent | 4ea85d9e4113ba0b2d67d762a29c809df948426a (diff) |
packet: fix send path when running with proto == 0
[ Upstream commit 66e56cd46b93ef407c60adcac62cf33b06119d50 ]
Commit e40526cb20b5 introduced a cached dev pointer, that gets
hooked into register_prot_hook(), __unregister_prot_hook() to
update the device used for the send path.
We need to fix this up, as otherwise this will not work with
sockets created with protocol = 0, plus with sll_protocol = 0
passed via sockaddr_ll when doing the bind.
So instead, assign the pointer directly. The compiler can inline
these helper functions automagically.
While at it, also assume the cached dev fast-path as likely(),
and document this variant of socket creation as it seems it is
not widely used (seems not even the author of TX_RING was aware
of that in his reference example [1]). Tested with reproducer
from e40526cb20b5.
[1] http://wiki.ipxwarzone.com/index.php5?title=Linux_packet_mmap#Example
Fixes: e40526cb20b5 ("packet: fix use after free race in send path when dev is released")
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Tested-by: Salam Noureddine <noureddine@aristanetworks.com>
Tested-by: Jesper Dangaard Brouer <brouer@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'net/packet')
-rw-r--r-- | net/packet/af_packet.c | 65 |
1 files changed, 40 insertions, 25 deletions
diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index c503ad6f610f..e8b5a0dfca21 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c | |||
@@ -237,6 +237,30 @@ struct packet_skb_cb { | |||
237 | static void __fanout_unlink(struct sock *sk, struct packet_sock *po); | 237 | static void __fanout_unlink(struct sock *sk, struct packet_sock *po); |
238 | static void __fanout_link(struct sock *sk, struct packet_sock *po); | 238 | static void __fanout_link(struct sock *sk, struct packet_sock *po); |
239 | 239 | ||
240 | static struct net_device *packet_cached_dev_get(struct packet_sock *po) | ||
241 | { | ||
242 | struct net_device *dev; | ||
243 | |||
244 | rcu_read_lock(); | ||
245 | dev = rcu_dereference(po->cached_dev); | ||
246 | if (likely(dev)) | ||
247 | dev_hold(dev); | ||
248 | rcu_read_unlock(); | ||
249 | |||
250 | return dev; | ||
251 | } | ||
252 | |||
253 | static void packet_cached_dev_assign(struct packet_sock *po, | ||
254 | struct net_device *dev) | ||
255 | { | ||
256 | rcu_assign_pointer(po->cached_dev, dev); | ||
257 | } | ||
258 | |||
259 | static void packet_cached_dev_reset(struct packet_sock *po) | ||
260 | { | ||
261 | RCU_INIT_POINTER(po->cached_dev, NULL); | ||
262 | } | ||
263 | |||
240 | /* register_prot_hook must be invoked with the po->bind_lock held, | 264 | /* register_prot_hook must be invoked with the po->bind_lock held, |
241 | * or from a context in which asynchronous accesses to the packet | 265 | * or from a context in which asynchronous accesses to the packet |
242 | * socket is not possible (packet_create()). | 266 | * socket is not possible (packet_create()). |
@@ -246,12 +270,10 @@ static void register_prot_hook(struct sock *sk) | |||
246 | struct packet_sock *po = pkt_sk(sk); | 270 | struct packet_sock *po = pkt_sk(sk); |
247 | 271 | ||
248 | if (!po->running) { | 272 | if (!po->running) { |
249 | if (po->fanout) { | 273 | if (po->fanout) |
250 | __fanout_link(sk, po); | 274 | __fanout_link(sk, po); |
251 | } else { | 275 | else |
252 | dev_add_pack(&po->prot_hook); | 276 | dev_add_pack(&po->prot_hook); |
253 | rcu_assign_pointer(po->cached_dev, po->prot_hook.dev); | ||
254 | } | ||
255 | 277 | ||
256 | sock_hold(sk); | 278 | sock_hold(sk); |
257 | po->running = 1; | 279 | po->running = 1; |
@@ -270,12 +292,11 @@ static void __unregister_prot_hook(struct sock *sk, bool sync) | |||
270 | struct packet_sock *po = pkt_sk(sk); | 292 | struct packet_sock *po = pkt_sk(sk); |
271 | 293 | ||
272 | po->running = 0; | 294 | po->running = 0; |
273 | if (po->fanout) { | 295 | |
296 | if (po->fanout) | ||
274 | __fanout_unlink(sk, po); | 297 | __fanout_unlink(sk, po); |
275 | } else { | 298 | else |
276 | __dev_remove_pack(&po->prot_hook); | 299 | __dev_remove_pack(&po->prot_hook); |
277 | RCU_INIT_POINTER(po->cached_dev, NULL); | ||
278 | } | ||
279 | 300 | ||
280 | __sock_put(sk); | 301 | __sock_put(sk); |
281 | 302 | ||
@@ -2048,19 +2069,6 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb, | |||
2048 | return tp_len; | 2069 | return tp_len; |
2049 | } | 2070 | } |
2050 | 2071 | ||
2051 | static struct net_device *packet_cached_dev_get(struct packet_sock *po) | ||
2052 | { | ||
2053 | struct net_device *dev; | ||
2054 | |||
2055 | rcu_read_lock(); | ||
2056 | dev = rcu_dereference(po->cached_dev); | ||
2057 | if (dev) | ||
2058 | dev_hold(dev); | ||
2059 | rcu_read_unlock(); | ||
2060 | |||
2061 | return dev; | ||
2062 | } | ||
2063 | |||
2064 | static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) | 2072 | static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) |
2065 | { | 2073 | { |
2066 | struct sk_buff *skb; | 2074 | struct sk_buff *skb; |
@@ -2077,7 +2085,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg) | |||
2077 | 2085 | ||
2078 | mutex_lock(&po->pg_vec_lock); | 2086 | mutex_lock(&po->pg_vec_lock); |
2079 | 2087 | ||
2080 | if (saddr == NULL) { | 2088 | if (likely(saddr == NULL)) { |
2081 | dev = packet_cached_dev_get(po); | 2089 | dev = packet_cached_dev_get(po); |
2082 | proto = po->num; | 2090 | proto = po->num; |
2083 | addr = NULL; | 2091 | addr = NULL; |
@@ -2231,7 +2239,7 @@ static int packet_snd(struct socket *sock, | |||
2231 | * Get and verify the address. | 2239 | * Get and verify the address. |
2232 | */ | 2240 | */ |
2233 | 2241 | ||
2234 | if (saddr == NULL) { | 2242 | if (likely(saddr == NULL)) { |
2235 | dev = packet_cached_dev_get(po); | 2243 | dev = packet_cached_dev_get(po); |
2236 | proto = po->num; | 2244 | proto = po->num; |
2237 | addr = NULL; | 2245 | addr = NULL; |
@@ -2440,6 +2448,8 @@ static int packet_release(struct socket *sock) | |||
2440 | 2448 | ||
2441 | spin_lock(&po->bind_lock); | 2449 | spin_lock(&po->bind_lock); |
2442 | unregister_prot_hook(sk, false); | 2450 | unregister_prot_hook(sk, false); |
2451 | packet_cached_dev_reset(po); | ||
2452 | |||
2443 | if (po->prot_hook.dev) { | 2453 | if (po->prot_hook.dev) { |
2444 | dev_put(po->prot_hook.dev); | 2454 | dev_put(po->prot_hook.dev); |
2445 | po->prot_hook.dev = NULL; | 2455 | po->prot_hook.dev = NULL; |
@@ -2495,14 +2505,17 @@ static int packet_do_bind(struct sock *sk, struct net_device *dev, __be16 protoc | |||
2495 | 2505 | ||
2496 | spin_lock(&po->bind_lock); | 2506 | spin_lock(&po->bind_lock); |
2497 | unregister_prot_hook(sk, true); | 2507 | unregister_prot_hook(sk, true); |
2508 | |||
2498 | po->num = protocol; | 2509 | po->num = protocol; |
2499 | po->prot_hook.type = protocol; | 2510 | po->prot_hook.type = protocol; |
2500 | if (po->prot_hook.dev) | 2511 | if (po->prot_hook.dev) |
2501 | dev_put(po->prot_hook.dev); | 2512 | dev_put(po->prot_hook.dev); |
2502 | po->prot_hook.dev = dev; | ||
2503 | 2513 | ||
2514 | po->prot_hook.dev = dev; | ||
2504 | po->ifindex = dev ? dev->ifindex : 0; | 2515 | po->ifindex = dev ? dev->ifindex : 0; |
2505 | 2516 | ||
2517 | packet_cached_dev_assign(po, dev); | ||
2518 | |||
2506 | if (protocol == 0) | 2519 | if (protocol == 0) |
2507 | goto out_unlock; | 2520 | goto out_unlock; |
2508 | 2521 | ||
@@ -2615,7 +2628,8 @@ static int packet_create(struct net *net, struct socket *sock, int protocol, | |||
2615 | po = pkt_sk(sk); | 2628 | po = pkt_sk(sk); |
2616 | sk->sk_family = PF_PACKET; | 2629 | sk->sk_family = PF_PACKET; |
2617 | po->num = proto; | 2630 | po->num = proto; |
2618 | RCU_INIT_POINTER(po->cached_dev, NULL); | 2631 | |
2632 | packet_cached_dev_reset(po); | ||
2619 | 2633 | ||
2620 | sk->sk_destruct = packet_sock_destruct; | 2634 | sk->sk_destruct = packet_sock_destruct; |
2621 | sk_refcnt_debug_inc(sk); | 2635 | sk_refcnt_debug_inc(sk); |
@@ -3369,6 +3383,7 @@ static int packet_notifier(struct notifier_block *this, unsigned long msg, void | |||
3369 | sk->sk_error_report(sk); | 3383 | sk->sk_error_report(sk); |
3370 | } | 3384 | } |
3371 | if (msg == NETDEV_UNREGISTER) { | 3385 | if (msg == NETDEV_UNREGISTER) { |
3386 | packet_cached_dev_reset(po); | ||
3372 | po->ifindex = -1; | 3387 | po->ifindex = -1; |
3373 | if (po->prot_hook.dev) | 3388 | if (po->prot_hook.dev) |
3374 | dev_put(po->prot_hook.dev); | 3389 | dev_put(po->prot_hook.dev); |