diff options
| author | John Fastabend <john.fastabend@gmail.com> | 2018-07-05 11:50:04 -0400 |
|---|---|---|
| committer | Alexei Starovoitov <ast@kernel.org> | 2018-07-07 18:19:30 -0400 |
| commit | 99ba2b5aba24e022683a7db63204f9e306fe7ab9 (patch) | |
| tree | e174736f65a9dd001a67e2f007f93b5fd6265992 /kernel/bpf/sockmap.c | |
| parent | 0c6bc6e531a6db36f49622f1f115770160f7afb0 (diff) | |
bpf: sockhash, disallow bpf_tcp_close and update in parallel
After latest lock updates there is no longer anything preventing a
close and recvmsg call running in parallel. Additionally, we can
race update with close if we close a socket and simultaneously update
if via the BPF userspace API (note the cgroup ops are already run
with sock_lock held).
To resolve this take sock_lock in close and update paths.
Reported-by: syzbot+b680e42077a0d7c9a0c4@syzkaller.appspotmail.com
Fixes: e9db4ef6bf4c ("bpf: sockhash fix omitted bucket lock in sock_close")
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'kernel/bpf/sockmap.c')
| -rw-r--r-- | kernel/bpf/sockmap.c | 15 |
1 files changed, 15 insertions, 0 deletions
diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c index 00fb2e328d1b..9c67e96fe336 100644 --- a/kernel/bpf/sockmap.c +++ b/kernel/bpf/sockmap.c | |||
| @@ -312,10 +312,12 @@ static void bpf_tcp_close(struct sock *sk, long timeout) | |||
| 312 | struct smap_psock *psock; | 312 | struct smap_psock *psock; |
| 313 | struct sock *osk; | 313 | struct sock *osk; |
| 314 | 314 | ||
| 315 | lock_sock(sk); | ||
| 315 | rcu_read_lock(); | 316 | rcu_read_lock(); |
| 316 | psock = smap_psock_sk(sk); | 317 | psock = smap_psock_sk(sk); |
| 317 | if (unlikely(!psock)) { | 318 | if (unlikely(!psock)) { |
| 318 | rcu_read_unlock(); | 319 | rcu_read_unlock(); |
| 320 | release_sock(sk); | ||
| 319 | return sk->sk_prot->close(sk, timeout); | 321 | return sk->sk_prot->close(sk, timeout); |
| 320 | } | 322 | } |
| 321 | 323 | ||
| @@ -371,6 +373,7 @@ static void bpf_tcp_close(struct sock *sk, long timeout) | |||
| 371 | e = psock_map_pop(sk, psock); | 373 | e = psock_map_pop(sk, psock); |
| 372 | } | 374 | } |
| 373 | rcu_read_unlock(); | 375 | rcu_read_unlock(); |
| 376 | release_sock(sk); | ||
| 374 | close_fun(sk, timeout); | 377 | close_fun(sk, timeout); |
| 375 | } | 378 | } |
| 376 | 379 | ||
| @@ -2069,7 +2072,13 @@ static int sock_map_update_elem(struct bpf_map *map, | |||
| 2069 | return -EOPNOTSUPP; | 2072 | return -EOPNOTSUPP; |
| 2070 | } | 2073 | } |
| 2071 | 2074 | ||
| 2075 | lock_sock(skops.sk); | ||
| 2076 | preempt_disable(); | ||
| 2077 | rcu_read_lock(); | ||
| 2072 | err = sock_map_ctx_update_elem(&skops, map, key, flags); | 2078 | err = sock_map_ctx_update_elem(&skops, map, key, flags); |
| 2079 | rcu_read_unlock(); | ||
| 2080 | preempt_enable(); | ||
| 2081 | release_sock(skops.sk); | ||
| 2073 | fput(socket->file); | 2082 | fput(socket->file); |
| 2074 | return err; | 2083 | return err; |
| 2075 | } | 2084 | } |
| @@ -2410,7 +2419,13 @@ static int sock_hash_update_elem(struct bpf_map *map, | |||
| 2410 | return -EINVAL; | 2419 | return -EINVAL; |
| 2411 | } | 2420 | } |
| 2412 | 2421 | ||
| 2422 | lock_sock(skops.sk); | ||
| 2423 | preempt_disable(); | ||
| 2424 | rcu_read_lock(); | ||
| 2413 | err = sock_hash_ctx_update_elem(&skops, map, key, flags); | 2425 | err = sock_hash_ctx_update_elem(&skops, map, key, flags); |
| 2426 | rcu_read_unlock(); | ||
| 2427 | preempt_enable(); | ||
| 2428 | release_sock(skops.sk); | ||
| 2414 | fput(socket->file); | 2429 | fput(socket->file); |
| 2415 | return err; | 2430 | return err; |
| 2416 | } | 2431 | } |
