Skip to content

Commit f7b5279

Browse files
author
Paolo Abeni
committed
Merge branch 'sockmap-vsock-for-connectible-sockets-allow-only-connected'
Michal Luczaj says: ==================== sockmap, vsock: For connectible sockets allow only connected Series deals with one more case of vsock surprising BPF/sockmap by being inconsistency about (having an) assigned transport. KASAN: null-ptr-deref in range [0x0000000000000120-0x0000000000000127] CPU: 7 UID: 0 PID: 56 Comm: kworker/7:0 Not tainted 6.14.0-rc1+ Workqueue: vsock-loopback vsock_loopback_work RIP: 0010:vsock_read_skb+0x4b/0x90 Call Trace: sk_psock_verdict_data_ready+0xa4/0x2e0 virtio_transport_recv_pkt+0x1ca8/0x2acc vsock_loopback_work+0x27d/0x3f0 process_one_work+0x846/0x1420 worker_thread+0x5b3/0xf80 kthread+0x35a/0x700 ret_from_fork+0x2d/0x70 ret_from_fork_asm+0x1a/0x30 This bug, similarly to commit f6abafc ("vsock/bpf: return early if transport is not assigned"), could be fixed with a single NULL check. But instead, let's explore another approach: take a hint from vsock_bpf_update_proto() and teach sockmap to accept only vsocks that are already connected (no risk of transport being dropped or reassigned). At the same time straight reject the listeners (vsock listening sockets do not carry any transport anyway). This way BPF does not have to worry about vsk->transport becoming NULL. Signed-off-by: Michal Luczaj <[email protected]> ==================== Link: https://patch.msgid.link/[email protected] Signed-off-by: Paolo Abeni <[email protected]>
2 parents 0a4f598 + 85928e9 commit f7b5279

File tree

4 files changed

+59
-19
lines changed

4 files changed

+59
-19
lines changed

net/core/sock_map.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -541,6 +541,9 @@ static bool sock_map_sk_state_allowed(const struct sock *sk)
541541
return (1 << sk->sk_state) & (TCPF_ESTABLISHED | TCPF_LISTEN);
542542
if (sk_is_stream_unix(sk))
543543
return (1 << sk->sk_state) & TCPF_ESTABLISHED;
544+
if (sk_is_vsock(sk) &&
545+
(sk->sk_type == SOCK_STREAM || sk->sk_type == SOCK_SEQPACKET))
546+
return (1 << sk->sk_state) & TCPF_ESTABLISHED;
544547
return true;
545548
}
546549

net/vmw_vsock/af_vsock.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,6 +1189,9 @@ static int vsock_read_skb(struct sock *sk, skb_read_actor_t read_actor)
11891189
{
11901190
struct vsock_sock *vsk = vsock_sk(sk);
11911191

1192+
if (WARN_ON_ONCE(!vsk->transport))
1193+
return -ENODEV;
1194+
11921195
return vsk->transport->read_skb(vsk, read_actor);
11931196
}
11941197

net/vmw_vsock/vsock_bpf.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ static int vsock_bpf_recvmsg(struct sock *sk, struct msghdr *msg,
8787
lock_sock(sk);
8888
vsk = vsock_sk(sk);
8989

90-
if (!vsk->transport) {
90+
if (WARN_ON_ONCE(!vsk->transport)) {
9191
copied = -ENODEV;
9292
goto out;
9393
}

tools/testing/selftests/bpf/prog_tests/sockmap_basic.c

Lines changed: 52 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -111,31 +111,35 @@ static void test_sockmap_create_update_free(enum bpf_map_type map_type)
111111

112112
static void test_sockmap_vsock_delete_on_close(void)
113113
{
114-
int err, c, p, map;
115-
const int zero = 0;
116-
117-
err = create_pair(AF_VSOCK, SOCK_STREAM, &c, &p);
118-
if (!ASSERT_OK(err, "create_pair(AF_VSOCK)"))
119-
return;
114+
int map, c, p, err, zero = 0;
120115

121116
map = bpf_map_create(BPF_MAP_TYPE_SOCKMAP, NULL, sizeof(int),
122117
sizeof(int), 1, NULL);
123-
if (!ASSERT_GE(map, 0, "bpf_map_create")) {
124-
close(c);
125-
goto out;
126-
}
118+
if (!ASSERT_OK_FD(map, "bpf_map_create"))
119+
return;
127120

128-
err = bpf_map_update_elem(map, &zero, &c, BPF_NOEXIST);
129-
close(c);
130-
if (!ASSERT_OK(err, "bpf_map_update"))
131-
goto out;
121+
err = create_pair(AF_VSOCK, SOCK_STREAM, &c, &p);
122+
if (!ASSERT_OK(err, "create_pair"))
123+
goto close_map;
132124

133-
err = bpf_map_update_elem(map, &zero, &p, BPF_NOEXIST);
125+
if (xbpf_map_update_elem(map, &zero, &c, BPF_NOEXIST))
126+
goto close_socks;
127+
128+
xclose(c);
129+
xclose(p);
130+
131+
err = create_pair(AF_VSOCK, SOCK_STREAM, &c, &p);
132+
if (!ASSERT_OK(err, "create_pair"))
133+
goto close_map;
134+
135+
err = bpf_map_update_elem(map, &zero, &c, BPF_NOEXIST);
134136
ASSERT_OK(err, "after close(), bpf_map_update");
135137

136-
out:
137-
close(p);
138-
close(map);
138+
close_socks:
139+
xclose(c);
140+
xclose(p);
141+
close_map:
142+
xclose(map);
139143
}
140144

141145
static void test_skmsg_helpers(enum bpf_map_type map_type)
@@ -1061,6 +1065,34 @@ static void test_sockmap_skb_verdict_vsock_poll(void)
10611065
test_sockmap_pass_prog__destroy(skel);
10621066
}
10631067

1068+
static void test_sockmap_vsock_unconnected(void)
1069+
{
1070+
struct sockaddr_storage addr;
1071+
int map, s, zero = 0;
1072+
socklen_t alen;
1073+
1074+
map = bpf_map_create(BPF_MAP_TYPE_SOCKMAP, NULL, sizeof(int),
1075+
sizeof(int), 1, NULL);
1076+
if (!ASSERT_OK_FD(map, "bpf_map_create"))
1077+
return;
1078+
1079+
s = xsocket(AF_VSOCK, SOCK_STREAM, 0);
1080+
if (s < 0)
1081+
goto close_map;
1082+
1083+
/* Fail connect(), but trigger transport assignment. */
1084+
init_addr_loopback(AF_VSOCK, &addr, &alen);
1085+
if (!ASSERT_ERR(connect(s, sockaddr(&addr), alen), "connect"))
1086+
goto close_sock;
1087+
1088+
ASSERT_ERR(bpf_map_update_elem(map, &zero, &s, BPF_ANY), "map_update");
1089+
1090+
close_sock:
1091+
xclose(s);
1092+
close_map:
1093+
xclose(map);
1094+
}
1095+
10641096
void test_sockmap_basic(void)
10651097
{
10661098
if (test__start_subtest("sockmap create_update_free"))
@@ -1127,4 +1159,6 @@ void test_sockmap_basic(void)
11271159
test_skmsg_helpers_with_link(BPF_MAP_TYPE_SOCKHASH);
11281160
if (test__start_subtest("sockmap skb_verdict vsock poll"))
11291161
test_sockmap_skb_verdict_vsock_poll();
1162+
if (test__start_subtest("sockmap vsock unconnected"))
1163+
test_sockmap_vsock_unconnected();
11301164
}

0 commit comments

Comments
 (0)