Skip to content

Commit 54fedb4

Browse files
jrfastabborkmann
authored andcommitted
bpf: sockmap, fix smap_list_map_remove when psock is in many maps
If a hashmap is free'd with open socks it removes the reference to the hash entry from the psock. If that is the last reference to the psock then it will also be free'd by the reference counting logic. However the current logic that removes the hash reference from the list of references is broken. In smap_list_remove() we first check if the sockmap entry matches and then check if the hashmap entry matches. But, the sockmap entry sill always match because its NULL in this case which causes the first entry to be removed from the list. If this is always the "right" entry (because the user adds/removes entries in order) then everything is OK but otherwise a subsequent bpf_tcp_close() may reference a free'd object. To fix this create two list handlers one for sockmap and one for sockhash. Reported-by: syzbot+0ce137753c78f7b6acc1@syzkaller.appspotmail.com Fixes: 8111038 ("bpf: sockmap, add hash map support") Acked-by: Martin KaFai Lau <kafai@fb.com> Signed-off-by: John Fastabend <john.fastabend@gmail.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
1 parent 9901c5d commit 54fedb4

File tree

1 file changed

+22
-12
lines changed

1 file changed

+22
-12
lines changed

kernel/bpf/sockmap.c

Lines changed: 22 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1602,17 +1602,27 @@ static struct bpf_map *sock_map_alloc(union bpf_attr *attr)
16021602
return ERR_PTR(err);
16031603
}
16041604

1605-
static void smap_list_remove(struct smap_psock *psock,
1606-
struct sock **entry,
1607-
struct htab_elem *hash_link)
1605+
static void smap_list_map_remove(struct smap_psock *psock,
1606+
struct sock **entry)
16081607
{
16091608
struct smap_psock_map_entry *e, *tmp;
16101609

16111610
list_for_each_entry_safe(e, tmp, &psock->maps, list) {
1612-
if (e->entry == entry || e->hash_link == hash_link) {
1611+
if (e->entry == entry)
1612+
list_del(&e->list);
1613+
}
1614+
}
1615+
1616+
static void smap_list_hash_remove(struct smap_psock *psock,
1617+
struct htab_elem *hash_link)
1618+
{
1619+
struct smap_psock_map_entry *e, *tmp;
1620+
1621+
list_for_each_entry_safe(e, tmp, &psock->maps, list) {
1622+
struct htab_elem *c = e->hash_link;
1623+
1624+
if (c == hash_link)
16131625
list_del(&e->list);
1614-
break;
1615-
}
16161626
}
16171627
}
16181628

@@ -1647,7 +1657,7 @@ static void sock_map_free(struct bpf_map *map)
16471657
* to be null and queued for garbage collection.
16481658
*/
16491659
if (likely(psock)) {
1650-
smap_list_remove(psock, &stab->sock_map[i], NULL);
1660+
smap_list_map_remove(psock, &stab->sock_map[i]);
16511661
smap_release_sock(psock, sock);
16521662
}
16531663
write_unlock_bh(&sock->sk_callback_lock);
@@ -1706,7 +1716,7 @@ static int sock_map_delete_elem(struct bpf_map *map, void *key)
17061716

17071717
if (psock->bpf_parse)
17081718
smap_stop_sock(psock, sock);
1709-
smap_list_remove(psock, &stab->sock_map[k], NULL);
1719+
smap_list_map_remove(psock, &stab->sock_map[k]);
17101720
smap_release_sock(psock, sock);
17111721
out:
17121722
write_unlock_bh(&sock->sk_callback_lock);
@@ -1908,7 +1918,7 @@ static int sock_map_ctx_update_elem(struct bpf_sock_ops_kern *skops,
19081918
struct smap_psock *opsock = smap_psock_sk(osock);
19091919

19101920
write_lock_bh(&osock->sk_callback_lock);
1911-
smap_list_remove(opsock, &stab->sock_map[i], NULL);
1921+
smap_list_map_remove(opsock, &stab->sock_map[i]);
19121922
smap_release_sock(opsock, osock);
19131923
write_unlock_bh(&osock->sk_callback_lock);
19141924
}
@@ -2142,7 +2152,7 @@ static void sock_hash_free(struct bpf_map *map)
21422152
* (psock) to be null and queued for garbage collection.
21432153
*/
21442154
if (likely(psock)) {
2145-
smap_list_remove(psock, NULL, l);
2155+
smap_list_hash_remove(psock, l);
21462156
smap_release_sock(psock, sock);
21472157
}
21482158
write_unlock_bh(&sock->sk_callback_lock);
@@ -2322,7 +2332,7 @@ static int sock_hash_ctx_update_elem(struct bpf_sock_ops_kern *skops,
23222332
psock = smap_psock_sk(l_old->sk);
23232333

23242334
hlist_del_rcu(&l_old->hash_node);
2325-
smap_list_remove(psock, NULL, l_old);
2335+
smap_list_hash_remove(psock, l_old);
23262336
smap_release_sock(psock, l_old->sk);
23272337
free_htab_elem(htab, l_old);
23282338
}
@@ -2390,7 +2400,7 @@ static int sock_hash_delete_elem(struct bpf_map *map, void *key)
23902400
* to be null and queued for garbage collection.
23912401
*/
23922402
if (likely(psock)) {
2393-
smap_list_remove(psock, NULL, l);
2403+
smap_list_hash_remove(psock, l);
23942404
smap_release_sock(psock, sock);
23952405
}
23962406
write_unlock_bh(&sock->sk_callback_lock);

0 commit comments

Comments
 (0)