unix: enforce recvmmsg buffer size requirements (#5095)
The documentation already stated that the receive buffer should be a multiple of 64 KiB when the UV_UDP_RECVMMSG is used, but make that more prominent in the documentation and enforce it in the code. Refs: https://github.com/libuv/libuv/security/advisories/GHSA-r846-fxvr-f3rx
This commit is contained in:
parent
9f0101dcb8
commit
8877568581
@ -76,7 +76,8 @@ Data types
|
||||
*/
|
||||
UV_UDP_REUSEPORT = 64,
|
||||
/*
|
||||
* Indicates that recvmmsg should be used, if available.
|
||||
* Indicates that recvmmsg should be used, if available. The uv_alloc_cb
|
||||
* for this handle should create buffers that are multiples of 64 KiB.
|
||||
*/
|
||||
UV_UDP_RECVMMSG = 256
|
||||
};
|
||||
@ -168,7 +169,8 @@ API
|
||||
The remaining bits can be used to set one of these flags:
|
||||
|
||||
* `UV_UDP_RECVMMSG`: if set, and the platform supports it, :man:`recvmmsg(2)` will
|
||||
be used.
|
||||
be used. The :c:type:`uv_alloc_cb` for this handle should create
|
||||
buffers that are multiples of 64 KiB.
|
||||
|
||||
.. versionadded:: 1.7.0
|
||||
.. versionchanged:: 1.37.0 added the `UV_UDP_RECVMMSG` flag.
|
||||
@ -481,8 +483,8 @@ API
|
||||
`suggested_size` in `alloc_cb` for udp_recv is always set to the size of 1 max size dgram.
|
||||
|
||||
.. versionchanged:: 1.35.0 added support for :man:`recvmmsg(2)` on supported platforms).
|
||||
The use of this feature requires a buffer larger than
|
||||
2 * 64KB to be passed to `alloc_cb`.
|
||||
The :c:type:`uv_alloc_cb` for this handle should create
|
||||
buffers that are multiples of 64 KiB.
|
||||
.. versionchanged:: 1.37.0 :man:`recvmmsg(2)` support is no longer enabled implicitly,
|
||||
it must be explicitly requested by passing the `UV_UDP_RECVMMSG` flag to
|
||||
:c:func:`uv_udp_init_ex`.
|
||||
|
||||
@ -705,7 +705,8 @@ enum uv_udp_flags {
|
||||
*/
|
||||
UV_UDP_REUSEPORT = 64,
|
||||
/*
|
||||
* Indicates that recvmmsg should be used, if available.
|
||||
* Indicates that recvmmsg should be used, if available. The uv_alloc_cb
|
||||
* for this handle should create buffers that are multiples of 64 KiB.
|
||||
*/
|
||||
UV_UDP_RECVMMSG = 256
|
||||
};
|
||||
|
||||
@ -217,6 +217,8 @@ static int uv__udp_recvmmsg(uv_udp_t* handle, uv_buf_t* buf, int flag) {
|
||||
|
||||
/* prepare structures for recvmmsg */
|
||||
chunks = buf->len / UV__UDP_DGRAM_MAXSIZE;
|
||||
if (chunks == 0)
|
||||
return UV_EINVAL;
|
||||
if (chunks > ARRAY_SIZE(iov))
|
||||
chunks = ARRAY_SIZE(iov);
|
||||
for (k = 0; k < chunks; ++k) {
|
||||
@ -316,8 +318,11 @@ static void uv__udp_recvmsg(uv_udp_t* handle, int flag) {
|
||||
|
||||
if (uv_udp_using_recvmmsg(handle)) {
|
||||
nread = uv__udp_recvmmsg(handle, &buf, flag);
|
||||
if (nread > 0)
|
||||
count -= nread;
|
||||
if (nread <= 0) {
|
||||
handle->recv_cb(handle, nread, &buf, NULL, 0);
|
||||
return;
|
||||
}
|
||||
count -= nread;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
@ -181,6 +181,7 @@ TEST_DECLARE (udp_recvmsg_unreachable_error)
|
||||
TEST_DECLARE (udp_recvmsg_unreachable_error6)
|
||||
TEST_DECLARE (udp_send_pollerr_no_recv)
|
||||
TEST_DECLARE (udp_mmsg)
|
||||
TEST_DECLARE (udp_mmsg_small_buf)
|
||||
TEST_DECLARE (udp_multicast_join)
|
||||
TEST_DECLARE (udp_multicast_join6)
|
||||
TEST_DECLARE (udp_multicast_ttl)
|
||||
@ -826,6 +827,7 @@ TASK_LIST_START
|
||||
TEST_ENTRY (udp_options6)
|
||||
TEST_ENTRY (udp_no_autobind)
|
||||
TEST_ENTRY (udp_mmsg)
|
||||
TEST_ENTRY (udp_mmsg_small_buf)
|
||||
TEST_ENTRY (udp_multicast_interface)
|
||||
TEST_ENTRY (udp_multicast_interface6)
|
||||
TEST_ENTRY (udp_multicast_join)
|
||||
|
||||
@ -106,6 +106,31 @@ static void recv_cb(uv_udp_t* handle,
|
||||
}
|
||||
|
||||
|
||||
static void small_alloc_cb(uv_handle_t* handle,
|
||||
size_t suggested_size,
|
||||
uv_buf_t* buf) {
|
||||
CHECK_HANDLE(handle);
|
||||
buf->len = 64;
|
||||
buf->base = malloc(buf->len);
|
||||
ASSERT_NOT_NULL(buf->base);
|
||||
alloc_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
static void small_recv_cb(uv_udp_t* handle,
|
||||
ssize_t nread,
|
||||
const uv_buf_t* rcvbuf,
|
||||
const struct sockaddr* addr,
|
||||
unsigned flags) {
|
||||
CHECK_HANDLE(handle);
|
||||
ASSERT_EQ(UV_EINVAL, nread);
|
||||
uv_close((uv_handle_t*) &recver, close_cb);
|
||||
uv_close((uv_handle_t*) &sender, close_cb);
|
||||
free(rcvbuf->base);
|
||||
recv_cb_called++;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(udp_mmsg) {
|
||||
struct sockaddr_in addr;
|
||||
uv_buf_t buf;
|
||||
@ -148,3 +173,31 @@ TEST_IMPL(udp_mmsg) {
|
||||
MAKE_VALGRIND_HAPPY(uv_default_loop());
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
TEST_IMPL(udp_mmsg_small_buf) {
|
||||
struct sockaddr_in addr;
|
||||
uv_loop_t* loop;
|
||||
uv_buf_t buf;
|
||||
|
||||
loop = uv_default_loop();
|
||||
ASSERT_OK(uv_udp_init_ex(loop, &recver, AF_UNSPEC | UV_UDP_RECVMMSG));
|
||||
if (uv_udp_using_recvmmsg(&recver)) {
|
||||
ASSERT_OK(uv_ip4_addr("0.0.0.0", TEST_PORT, &addr));
|
||||
ASSERT_OK(uv_udp_bind(&recver, (const struct sockaddr*) &addr, 0));
|
||||
ASSERT_OK(uv_udp_recv_start(&recver, small_alloc_cb, small_recv_cb));
|
||||
ASSERT_OK(uv_ip4_addr("127.0.0.1", TEST_PORT, &addr));
|
||||
ASSERT_OK(uv_udp_init(loop, &sender));
|
||||
buf = uv_buf_init("PING", 4);
|
||||
ASSERT_EQ(4, uv_udp_try_send(&sender, &buf, 1, (const struct sockaddr*) &addr));
|
||||
ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT));
|
||||
ASSERT_EQ(1, recv_cb_called);
|
||||
ASSERT_EQ(2, close_cb_called);
|
||||
} else {
|
||||
uv_close((uv_handle_t*) &recver, close_cb);
|
||||
ASSERT_OK(uv_run(loop, UV_RUN_DEFAULT));
|
||||
ASSERT_EQ(1, close_cb_called);
|
||||
}
|
||||
MAKE_VALGRIND_HAPPY(loop);
|
||||
return 0;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user