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 | |
| 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>
| -rw-r--r-- | Documentation/networking/packet_mmap.txt | 10 | ||||
| -rw-r--r-- | net/packet/af_packet.c | 65 |
2 files changed, 50 insertions, 25 deletions
diff --git a/Documentation/networking/packet_mmap.txt b/Documentation/networking/packet_mmap.txt index 23dd80e82b8e..0f4376ec8852 100644 --- a/Documentation/networking/packet_mmap.txt +++ b/Documentation/networking/packet_mmap.txt | |||
| @@ -123,6 +123,16 @@ Transmission process is similar to capture as shown below. | |||
| 123 | [shutdown] close() --------> destruction of the transmission socket and | 123 | [shutdown] close() --------> destruction of the transmission socket and |
| 124 | deallocation of all associated resources. | 124 | deallocation of all associated resources. |
| 125 | 125 | ||
| 126 | Socket creation and destruction is also straight forward, and is done | ||
| 127 | the same way as in capturing described in the previous paragraph: | ||
| 128 | |||
| 129 | int fd = socket(PF_PACKET, mode, 0); | ||
| 130 | |||
| 131 | The protocol can optionally be 0 in case we only want to transmit | ||
| 132 | via this socket, which avoids an expensive call to packet_rcv(). | ||
| 133 | In this case, you also need to bind(2) the TX_RING with sll_protocol = 0 | ||
| 134 | set. Otherwise, htons(ETH_P_ALL) or any other protocol, for example. | ||
| 135 | |||
| 126 | Binding the socket to your network interface is mandatory (with zero copy) to | 136 | Binding the socket to your network interface is mandatory (with zero copy) to |
| 127 | know the header size of frames used in the circular buffer. | 137 | know the header size of frames used in the circular buffer. |
| 128 | 138 | ||
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 | } |
