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

openSUSE Build Service is sponsored by