Commit b698b9a8 authored by Jakub Kicinski's avatar Jakub Kicinski
Browse files

Merge branch 'vsock-null-ptr-deref-when-so_linger-enabled'

Michal Luczaj says:

====================
vsock: null-ptr-deref when SO_LINGER enabled

syzbot pointed out that a recent patching of a use-after-free introduced a
null-ptr-deref. This series fixes the problem and adds a test.

v2: https://lore.kernel.org/20250206-vsock-linger-nullderef-v2-0-f8a1f19146f8@rbox.co
v1: https://lore.kernel.org/20250204-vsock-linger-nullderef-v1-0-6eb1760fa93e@rbox.co
====================

Link: https://patch.msgid.link/20250210-vsock-linger-nullderef-v3-0-ef6244d02b54@rbox.co


Signed-off-by: default avatarJakub Kicinski <kuba@kernel.org>
parents 15d6f74f 440c9d48
Loading
Loading
Loading
Loading
+7 −1
Original line number Diff line number Diff line
@@ -824,13 +824,19 @@ static void __vsock_release(struct sock *sk, int level)
	 */
	lock_sock_nested(sk, level);

	sock_orphan(sk);
	/* Indicate to vsock_remove_sock() that the socket is being released and
	 * can be removed from the bound_table. Unlike transport reassignment
	 * case, where the socket must remain bound despite vsock_remove_sock()
	 * being called from the transport release() callback.
	 */
	sock_set_flag(sk, SOCK_DEAD);

	if (vsk->transport)
		vsk->transport->release(vsk);
	else if (sock_type_connectible(sk->sk_type))
		vsock_remove_sock(vsk);

	sock_orphan(sk);
	sk->sk_shutdown = SHUTDOWN_MASK;

	skb_queue_purge(&sk->sk_receive_queue);
+41 −0
Original line number Diff line number Diff line
@@ -1788,6 +1788,42 @@ static void test_stream_connect_retry_server(const struct test_opts *opts)
	close(fd);
}

static void test_stream_linger_client(const struct test_opts *opts)
{
	struct linger optval = {
		.l_onoff = 1,
		.l_linger = 1
	};
	int fd;

	fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
	if (fd < 0) {
		perror("connect");
		exit(EXIT_FAILURE);
	}

	if (setsockopt(fd, SOL_SOCKET, SO_LINGER, &optval, sizeof(optval))) {
		perror("setsockopt(SO_LINGER)");
		exit(EXIT_FAILURE);
	}

	close(fd);
}

static void test_stream_linger_server(const struct test_opts *opts)
{
	int fd;

	fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
	if (fd < 0) {
		perror("accept");
		exit(EXIT_FAILURE);
	}

	vsock_wait_remote_close(fd);
	close(fd);
}

static struct test_case test_cases[] = {
	{
		.name = "SOCK_STREAM connection reset",
@@ -1943,6 +1979,11 @@ static struct test_case test_cases[] = {
		.run_client = test_stream_connect_retry_client,
		.run_server = test_stream_connect_retry_server,
	},
	{
		.name = "SOCK_STREAM SO_LINGER null-ptr-deref",
		.run_client = test_stream_linger_client,
		.run_server = test_stream_linger_server,
	},
	{},
};