mirror of
https://github.com/torvalds/linux.git
synced 2026-03-08 03:24:45 +01:00
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>
This commit is contained in:
parent
8ee784fdf0
commit
2a689f76ed
1 changed files with 101 additions and 0 deletions
|
|
@ -347,6 +347,7 @@ static void test_stream_msg_peek_server(const struct test_opts *opts)
|
|||
}
|
||||
|
||||
#define SOCK_BUF_SIZE (2 * 1024 * 1024)
|
||||
#define SOCK_BUF_SIZE_SMALL (64 * 1024)
|
||||
#define MAX_MSG_PAGES 4
|
||||
|
||||
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)
|
|||
close(fd);
|
||||
}
|
||||
|
||||
static void test_stream_tx_credit_bounds_client(const struct test_opts *opts)
|
||||
{
|
||||
unsigned long long sock_buf_size;
|
||||
size_t total = 0;
|
||||
char buf[4096];
|
||||
int fd;
|
||||
|
||||
memset(buf, 'A', sizeof(buf));
|
||||
|
||||
fd = vsock_stream_connect(opts->peer_cid, opts->peer_port);
|
||||
if (fd < 0) {
|
||||
perror("connect");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
sock_buf_size = SOCK_BUF_SIZE_SMALL;
|
||||
|
||||
setsockopt_ull_check(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE,
|
||||
sock_buf_size,
|
||||
"setsockopt(SO_VM_SOCKETS_BUFFER_MAX_SIZE)");
|
||||
|
||||
setsockopt_ull_check(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE,
|
||||
sock_buf_size,
|
||||
"setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)");
|
||||
|
||||
if (fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK) < 0) {
|
||||
perror("fcntl(F_SETFL)");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
control_expectln("SRVREADY");
|
||||
|
||||
for (;;) {
|
||||
ssize_t sent = send(fd, buf, sizeof(buf), 0);
|
||||
|
||||
if (sent == 0) {
|
||||
fprintf(stderr, "unexpected EOF while sending bytes\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
if (sent < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
|
||||
if (errno == EAGAIN || errno == EWOULDBLOCK)
|
||||
break;
|
||||
|
||||
perror("send");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
total += sent;
|
||||
}
|
||||
|
||||
control_writeln("CLIDONE");
|
||||
close(fd);
|
||||
|
||||
/* We should not be able to send more bytes than the value set as
|
||||
* local buffer size.
|
||||
*/
|
||||
if (total > sock_buf_size) {
|
||||
fprintf(stderr,
|
||||
"TX credit too large: queued %zu bytes (expected <= %llu)\n",
|
||||
total, sock_buf_size);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
static void test_stream_tx_credit_bounds_server(const struct test_opts *opts)
|
||||
{
|
||||
unsigned long long sock_buf_size;
|
||||
int fd;
|
||||
|
||||
fd = vsock_stream_accept(VMADDR_CID_ANY, opts->peer_port, NULL);
|
||||
if (fd < 0) {
|
||||
perror("accept");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
sock_buf_size = SOCK_BUF_SIZE;
|
||||
|
||||
setsockopt_ull_check(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_MAX_SIZE,
|
||||
sock_buf_size,
|
||||
"setsockopt(SO_VM_SOCKETS_BUFFER_MAX_SIZE)");
|
||||
|
||||
setsockopt_ull_check(fd, AF_VSOCK, SO_VM_SOCKETS_BUFFER_SIZE,
|
||||
sock_buf_size,
|
||||
"setsockopt(SO_VM_SOCKETS_BUFFER_SIZE)");
|
||||
|
||||
control_writeln("SRVREADY");
|
||||
control_expectln("CLIDONE");
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
static struct test_case test_cases[] = {
|
||||
{
|
||||
.name = "SOCK_STREAM connection reset",
|
||||
|
|
@ -2419,6 +2515,11 @@ static struct test_case test_cases[] = {
|
|||
.run_client = test_stream_msgzcopy_mangle_client,
|
||||
.run_server = test_stream_msgzcopy_mangle_server,
|
||||
},
|
||||
{
|
||||
.name = "SOCK_STREAM TX credit bounds",
|
||||
.run_client = test_stream_tx_credit_bounds_client,
|
||||
.run_server = test_stream_tx_credit_bounds_server,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue