File 6001-udev_monitor_receive_device-dynamically-allocate-rec.patch of Package systemd.39177
From 5b95fe1b820f7fabf72e658bd0edcb92937d6aee Mon Sep 17 00:00:00 2001
From: Yu Watanabe <watanabe.yu+github@gmail.com>
Date: Fri, 14 Oct 2022 01:18:47 +0900
Subject: [PATCH 6001/6001] udev_monitor_receive_device: dynamically allocate
receive buffer
If udevd broadcasts a processed device with huge amount of properties,
then clients cannot receive the device.
Fixes #24987.
(cherry picked from commit efbd4b3ca84c0426b6ff98d6352f82f3b7c090b2)
[fbui: adjust context]
[fbui: bsc#1226095]
---
src/libudev/libudev-monitor.c | 85 ++++++++++++++++++++++++-----------
1 file changed, 59 insertions(+), 26 deletions(-)
diff --git a/src/libudev/libudev-monitor.c b/src/libudev/libudev-monitor.c
index 8214bbacf5..bdded2d385 100644
--- a/src/libudev/libudev-monitor.c
+++ b/src/libudev/libudev-monitor.c
@@ -577,26 +577,27 @@ tag:
**/
_public_ struct udev_device *udev_monitor_receive_device(struct udev_monitor *udev_monitor)
{
+ _cleanup_free_ uint8_t *buf_alloc = NULL;
struct udev_device *udev_device;
struct msghdr smsg;
- struct iovec iov;
char cred_msg[CMSG_SPACE(sizeof(struct ucred))];
struct cmsghdr *cmsg;
union sockaddr_union snl;
struct ucred *cred;
union {
- struct udev_monitor_netlink_header nlh;
- char raw[8192];
- } buf;
- ssize_t buflen;
- ssize_t bufpos;
+ struct udev_monitor_netlink_header *nlh;
+ char *nulstr;
+ uint8_t *buf;
+ } message;
+ struct iovec iov;
+ size_t offset;
+ ssize_t n = 0;
bool is_initialized = false;
retry:
if (udev_monitor == NULL)
return NULL;
- iov.iov_base = &buf;
- iov.iov_len = sizeof(buf);
+
memzero(&smsg, sizeof(struct msghdr));
smsg.msg_iov = &iov;
smsg.msg_iovlen = 1;
@@ -605,15 +606,43 @@ retry:
smsg.msg_name = &snl;
smsg.msg_namelen = sizeof(snl);
- buflen = recvmsg(udev_monitor->sock, &smsg, 0);
- if (buflen < 0) {
+ n = recv(udev_monitor->sock, NULL, 0, MSG_PEEK|MSG_TRUNC);
+ if (n < 0) {
+ log_error_errno(n, "Failed to get the received message size: %m");
+ return NULL;
+ }
+
+ if ((size_t) n < 4U*1024U*1024U / sizeof(uint8_t) / 2)
+ message.buf = newa(uint8_t, n);
+ else {
+ mfree(buf_alloc);
+
+ buf_alloc = new(uint8_t, n);
+ if (!buf_alloc)
+ return NULL;
+
+ message.buf = buf_alloc;
+ }
+
+ iov = (struct iovec) {
+ .iov_base = message.buf,
+ .iov_len = n,
+ };
+
+ n = recvmsg(udev_monitor->sock, &smsg, 0);
+ if (n < 0) {
if (errno != EINTR)
log_debug("unable to receive message");
return NULL;
}
- if (buflen < 32 || (smsg.msg_flags & MSG_TRUNC)) {
- log_debug("invalid message length");
+ if (smsg.msg_flags & MSG_TRUNC) {
+ log_debug("Received truncated message");
+ return NULL;
+ }
+
+ if (n < 32) {
+ log_debug("Invalid message length (%zi)", n);
return NULL;
}
@@ -644,39 +673,43 @@ retry:
return NULL;
}
- if (memcmp(buf.raw, "libudev", 8) == 0) {
+ if (!memchr(message.buf, 0, n)) {
+ log_debug("Received message without NUL");
+ return NULL;
+ }
+
+ if (streq(message.nulstr, "libudev")) {
/* udev message needs proper version magic */
- if (buf.nlh.magic != htonl(UDEV_MONITOR_MAGIC)) {
+ if (message.nlh->magic != htonl(UDEV_MONITOR_MAGIC)) {
log_debug("unrecognized message signature (%x != %x)",
- buf.nlh.magic, htonl(UDEV_MONITOR_MAGIC));
+ message.nlh->magic, htonl(UDEV_MONITOR_MAGIC));
return NULL;
}
- if (buf.nlh.properties_off+32 > (size_t)buflen) {
+ if (message.nlh->properties_off + 32 > (size_t)n) {
log_debug("message smaller than expected (%u > %zd)",
- buf.nlh.properties_off+32, buflen);
+ message.nlh->properties_off + 32, n);
return NULL;
}
- bufpos = buf.nlh.properties_off;
+ offset = message.nlh->properties_off;
/* devices received from udev are always initialized */
is_initialized = true;
} else {
- /* kernel message with header */
- bufpos = strlen(buf.raw) + 1;
- if ((size_t)bufpos < sizeof("a@/d") || bufpos >= buflen) {
- log_debug("invalid message length");
+ /* check kernel message header */
+ if (!strstr(message.nulstr, "@/")) {
+ log_debug("Invalid message header");
return NULL;
}
- /* check message header */
- if (strstr(buf.raw, "@/") == NULL) {
- log_debug("unrecognized message header");
+ offset = strlen(message.nulstr) + 1;
+ if (offset >= (size_t) n) {
+ log_debug("Invalid message length");
return NULL;
}
}
- udev_device = udev_device_new_from_nulstr(udev_monitor->udev, &buf.raw[bufpos], buflen - bufpos);
+ udev_device = udev_device_new_from_nulstr(udev_monitor->udev, message.nulstr + offset, n - offset);
if (!udev_device) {
log_debug("could not create device: %m");
return NULL;
--
2.35.3