Commit 12069401d895ff84076a50189ca842c0696b84b2
Committed by
David S. Miller
1 parent
7ed767f731
Exists in
ti-lsk-linux-4.1.y
and in
10 other branches
geneve: Fix races between socket add and release.
Currently, searching for a socket to add a reference to is not synchronized with deletion of sockets. This can result in use after free if there is another operation that is removing a socket at the same time. Solving this requires both holding the appropriate lock and checking the refcount to ensure that it has not already hit zero. Inspired by a related (but not exactly the same) issue in the VXLAN driver. Fixes: 0b5e8b8e ("net: Add Geneve tunneling protocol driver") CC: Andy Zhou <azhou@nicira.com> Signed-off-by: Jesse Gross <jesse@nicira.com> Acked-by: Thomas Graf <tgraf@suug.ch> Signed-off-by: David S. Miller <davem@davemloft.net>
Showing 1 changed file with 7 additions and 6 deletions Side-by-side Diff
net/ipv4/geneve.c
... | ... | @@ -296,6 +296,7 @@ |
296 | 296 | geneve_rcv_t *rcv, void *data, |
297 | 297 | bool no_share, bool ipv6) |
298 | 298 | { |
299 | + struct geneve_net *gn = net_generic(net, geneve_net_id); | |
299 | 300 | struct geneve_sock *gs; |
300 | 301 | |
301 | 302 | gs = geneve_socket_create(net, port, rcv, data, ipv6); |
302 | 303 | |
303 | 304 | |
304 | 305 | |
... | ... | @@ -305,15 +306,15 @@ |
305 | 306 | if (no_share) /* Return error if sharing is not allowed. */ |
306 | 307 | return ERR_PTR(-EINVAL); |
307 | 308 | |
309 | + spin_lock(&gn->sock_lock); | |
308 | 310 | gs = geneve_find_sock(net, port); |
309 | - if (gs) { | |
310 | - if (gs->rcv == rcv) | |
311 | - atomic_inc(&gs->refcnt); | |
312 | - else | |
311 | + if (gs && ((gs->rcv != rcv) || | |
312 | + !atomic_add_unless(&gs->refcnt, 1, 0))) | |
313 | 313 | gs = ERR_PTR(-EBUSY); |
314 | - } else { | |
314 | + spin_unlock(&gn->sock_lock); | |
315 | + | |
316 | + if (!gs) | |
315 | 317 | gs = ERR_PTR(-EINVAL); |
316 | - } | |
317 | 318 | |
318 | 319 | return gs; |
319 | 320 | } |