Skip to content

Commit 2a689f7

Browse files
melbinkmPaolo Abeni
authored andcommitted
vsock/test: add stream TX credit bounds test
Add a regression test for the TX credit bounds fix. The test verifies that a sender with a small local buffer size cannot queue excessive data even when the peer advertises a large receive buffer. The client: - Sets a small buffer size (64 KiB) - Connects to server (which advertises 2 MiB buffer) - Sends in non-blocking mode until EAGAIN - Verifies total queued data is bounded This guards against the original vulnerability where a remote peer could cause unbounded kernel memory allocation by advertising a large buffer and reading slowly. Suggested-by: Stefano Garzarella <sgarzare@redhat.com> Signed-off-by: Melbin K Mathew <mlbnkm1@gmail.com> [Stefano: use sock_buf_size to check the bytes sent + small fixes] Signed-off-by: Stefano Garzarella <sgarzare@redhat.com> Link: https://patch.msgid.link/20260121093628.9941-5-sgarzare@redhat.com Acked-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
1 parent 8ee784f commit 2a689f7

1 file changed

Lines changed: 101 additions & 0 deletions

File tree

tools/testing/vsock/vsock_test.c

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,7 @@ static void test_stream_msg_peek_server(const struct test_opts *opts)
347347
}
348348

349349
#define SOCK_BUF_SIZE (2 * 1024 * 1024)
350+
#define SOCK_BUF_SIZE_SMALL (64 * 1024)
350351
#define MAX_MSG_PAGES 4
351352

352353
static void test_seqpacket_msg_bounds_client(const struct test_opts *opts)
@@ -2230,6 +2231,101 @@ static void test_stream_accepted_setsockopt_server(const struct test_opts *opts)
22302231
close(fd);
22312232
}
22322233

2234+
static void test_stream_tx_credit_bounds_client(const struct test_opts *opts)
2235+
{
2236+
unsigned long long sock_buf_size;
2237+
size_t total = 0;
2238+
char buf[4096];
2239+
int fd;
2240+
2241+
memset(buf, 'A', sizeof(buf));
2242+
2243+
fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
2244+
if (fd < 0) {
2245+
perror("connect");
2246+
exit(EXIT_FAILURE);
2247+
}
2248+
2249+
sock_buf_size = SOCK_BUF_SIZE_SMALL;
2250+
2251+
setsockopt_ull_check(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE,
2252+
sock_buf_size,
2253+
"setsockopt(SO_VM_SOCKETS_BUFFER_MAX_SIZE)");
2254+
2255+
setsockopt_ull_check(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE,
2256+
sock_buf_size,
2257+
"setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)");
2258+
2259+
if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) < 0) {
2260+
perror("fcntl(F_SETFL)");
2261+
exit(EXIT_FAILURE);
2262+
}
2263+
2264+
control_expectln("SRVREADY");
2265+
2266+
for (;;) {
2267+
ssize_t sent = send(fd, buf, sizeof(buf), 0);
2268+
2269+
if (sent == 0) {
2270+
fprintf(stderr, "unexpected EOF while sending bytes\n");
2271+
exit(EXIT_FAILURE);
2272+
}
2273+
2274+
if (sent < 0) {
2275+
if (errno == EINTR)
2276+
continue;
2277+
2278+
if (errno == EAGAIN || errno == EWOULDBLOCK)
2279+
break;
2280+
2281+
perror("send");
2282+
exit(EXIT_FAILURE);
2283+
}
2284+
2285+
total += sent;
2286+
}
2287+
2288+
control_writeln("CLIDONE");
2289+
close(fd);
2290+
2291+
/* We should not be able to send more bytes than the value set as
2292+
* local buffer size.
2293+
*/
2294+
if (total > sock_buf_size) {
2295+
fprintf(stderr,
2296+
"TX credit too large: queued %zu bytes (expected <= %llu)\n",
2297+
total, sock_buf_size);
2298+
exit(EXIT_FAILURE);
2299+
}
2300+
}
2301+
2302+
static void test_stream_tx_credit_bounds_server(const struct test_opts *opts)
2303+
{
2304+
unsigned long long sock_buf_size;
2305+
int fd;
2306+
2307+
fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
2308+
if (fd < 0) {
2309+
perror("accept");
2310+
exit(EXIT_FAILURE);
2311+
}
2312+
2313+
sock_buf_size = SOCK_BUF_SIZE;
2314+
2315+
setsockopt_ull_check(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE,
2316+
sock_buf_size,
2317+
"setsockopt(SO_VM_SOCKETS_BUFFER_MAX_SIZE)");
2318+
2319+
setsockopt_ull_check(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE,
2320+
sock_buf_size,
2321+
"setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)");
2322+
2323+
control_writeln("SRVREADY");
2324+
control_expectln("CLIDONE");
2325+
2326+
close(fd);
2327+
}
2328+
22332329
static struct test_case test_cases[] = {
22342330
{
22352331
.name = "SOCK_STREAM connection reset",
@@ -2419,6 +2515,11 @@ static struct test_case test_cases[] = {
24192515
.run_client = test_stream_msgzcopy_mangle_client,
24202516
.run_server = test_stream_msgzcopy_mangle_server,
24212517
},
2518+
{
2519+
.name = "SOCK_STREAM TX credit bounds",
2520+
.run_client = test_stream_tx_credit_bounds_client,
2521+
.run_server = test_stream_tx_credit_bounds_server,
2522+
},
24222523
{},
24232524
};
24242525

0 commit comments

Comments
 (0)