aboutsummaryrefslogtreecommitdiffstats
path: root/kernel
diff options
context:
space:
mode:
authorJohn Fastabend <john.fastabend@gmail.com>2018-07-05 11:05:56 -0400
committerAlexei Starovoitov <ast@kernel.org>2018-07-07 18:16:58 -0400
commit547b3aa451ae2739585547db9fbdee11a43ff999 (patch)
treee691f1e7a7ce545c4796040583e2a813fb70fa46 /kernel
parentc48424d993fafd1e04b228fbd46176f828233d82 (diff)
bpf: sockmap, error path can not release psock in multi-map case
The current code, in the error path of sock_hash_ctx_update_elem, checks if the sock has a psock in the user data and if so decrements the reference count of the psock. However, if the error happens early in the error path we may have never incremented the psock reference count and if the psock exists because the sock is in another map then we may inadvertently decrement the reference count. Fix this by making the error path only call smap_release_sock if the error happens after the increment. Reported-by: syzbot+d464d2c20c717ef5a6a8@syzkaller.appspotmail.com Fixes: 81110384441a ("bpf: sockmap, add hash map support") Signed-off-by: John Fastabend <john.fastabend@gmail.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
Diffstat (limited to 'kernel')
-rw-r--r--kernel/bpf/sockmap.c17
1 files changed, 6 insertions, 11 deletions
diff --git a/kernel/bpf/sockmap.c b/kernel/bpf/sockmap.c
index cf7b6a6dbd1f..3847a7ce7dae 100644
--- a/kernel/bpf/sockmap.c
+++ b/kernel/bpf/sockmap.c
@@ -1896,7 +1896,7 @@ static int __sock_map_ctx_update_elem(struct bpf_map *map,
1896 e = kzalloc(sizeof(*e), GFP_ATOMIC | __GFP_NOWARN); 1896 e = kzalloc(sizeof(*e), GFP_ATOMIC | __GFP_NOWARN);
1897 if (!e) { 1897 if (!e) {
1898 err = -ENOMEM; 1898 err = -ENOMEM;
1899 goto out_progs; 1899 goto out_free;
1900 } 1900 }
1901 } 1901 }
1902 1902
@@ -2342,7 +2342,10 @@ static int sock_hash_ctx_update_elem(struct bpf_sock_ops_kern *skops,
2342 if (err) 2342 if (err)
2343 goto err; 2343 goto err;
2344 2344
2345 /* bpf_map_update_elem() can be called in_irq() */ 2345 /* psock is valid here because otherwise above *ctx_update_elem would
2346 * have thrown an error. It is safe to skip error check.
2347 */
2348 psock = smap_psock_sk(sock);
2346 raw_spin_lock_bh(&b->lock); 2349 raw_spin_lock_bh(&b->lock);
2347 l_old = lookup_elem_raw(head, hash, key, key_size); 2350 l_old = lookup_elem_raw(head, hash, key, key_size);
2348 if (l_old && map_flags == BPF_NOEXIST) { 2351 if (l_old && map_flags == BPF_NOEXIST) {
@@ -2360,12 +2363,6 @@ static int sock_hash_ctx_update_elem(struct bpf_sock_ops_kern *skops,
2360 goto bucket_err; 2363 goto bucket_err;
2361 } 2364 }
2362 2365
2363 psock = smap_psock_sk(sock);
2364 if (unlikely(!psock)) {
2365 err = -EINVAL;
2366 goto bucket_err;
2367 }
2368
2369 rcu_assign_pointer(e->hash_link, l_new); 2366 rcu_assign_pointer(e->hash_link, l_new);
2370 rcu_assign_pointer(e->htab, 2367 rcu_assign_pointer(e->htab,
2371 container_of(map, struct bpf_htab, map)); 2368 container_of(map, struct bpf_htab, map));
@@ -2388,12 +2385,10 @@ static int sock_hash_ctx_update_elem(struct bpf_sock_ops_kern *skops,
2388 raw_spin_unlock_bh(&b->lock); 2385 raw_spin_unlock_bh(&b->lock);
2389 return 0; 2386 return 0;
2390bucket_err: 2387bucket_err:
2388 smap_release_sock(psock, sock);
2391 raw_spin_unlock_bh(&b->lock); 2389 raw_spin_unlock_bh(&b->lock);
2392err: 2390err:
2393 kfree(e); 2391 kfree(e);
2394 psock = smap_psock_sk(sock);
2395 if (psock)
2396 smap_release_sock(psock, sock);
2397 return err; 2392 return err;
2398} 2393}
2399 2394