]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
netlink-socket: ignore ECHRNG/EXFULL errors from recvmsg_safe() if we expect truncation 37165/head
authorLennart Poettering <lennart@poettering.net>
Thu, 17 Apr 2025 06:19:43 +0000 (08:19 +0200)
committerLennart Poettering <lennart@poettering.net>
Thu, 17 Apr 2025 06:26:06 +0000 (08:26 +0200)
When we receive a netlink messages from userspace we need to drop it
from the queue. Hence we need call recvmsg() on the socket for it. We do
this with a zero-size socket read() buffer, so that the message would be
truncated when copied to userspace, and we do not have to allocate any
memory for it, but it's still dropped.

This was broken in ad501930d749e00f9686d29692b3142c36914f31, which
turned datagram truncation into an error (rightfully so I think – for
the common case). That broke this code here, because here we *expect*
truncation, and need to handle it gracefully.

Hence simply check for the two error codes for truncated payload or
cdata, and eat it up.

src/libsystemd/sd-netlink/netlink-socket.c

index 9d2b3984c2b11dd6271a7e3995e6b57d32816c5f..a6ac9789302edd63ddd3fd77ba791d3db0b6c6e2 100644 (file)
@@ -162,11 +162,8 @@ static int socket_recv_message(int fd, void *buf, size_t buf_size, uint32_t *ret
         assert(peek || (buf && buf_size > 0));
 
         n = recvmsg_safe(fd, &msg, peek ? (MSG_PEEK|MSG_TRUNC) : 0);
-        if (ERRNO_IS_NEG_TRANSIENT(n)) {
-                if (ret_mcast_group)
-                        *ret_mcast_group = 0;
-                return 0;
-        }
+        if (ERRNO_IS_NEG_TRANSIENT(n))
+                goto transient;
         if (n == -ENOBUFS)
                 return log_debug_errno(n, "sd-netlink: kernel receive buffer overrun");
         if (n == -ECHRNG)
@@ -181,15 +178,15 @@ static int socket_recv_message(int fd, void *buf, size_t buf_size, uint32_t *ret
                 log_debug("sd-netlink: ignoring message from PID %"PRIu32, sender.nl.nl_pid);
 
                 if (peek) {
-                        /* drop the message */
+                        /* Drop the message. Note that we ignore ECHRNG/EXFULL errors here, which
+                         * recvmsg_safe() returns in case the payload or cdata is truncated. Here it's quite
+                         * likely it is truncated, because we pass a zero-sized buffer. */
                         n = recvmsg_safe(fd, &msg, 0);
-                        if (n < 0)
+                        if (n < 0 && !IN_SET(n, -ECHRNG, -EXFULL))
                                 return (int) n;
                 }
 
-                if (ret_mcast_group)
-                        *ret_mcast_group = 0;
-                return 0;
+                goto transient;
         }
 
         if (ret_mcast_group) {
@@ -203,6 +200,12 @@ static int socket_recv_message(int fd, void *buf, size_t buf_size, uint32_t *ret
         }
 
         return (int) n;
+
+transient:
+        if (ret_mcast_group)
+                *ret_mcast_group = 0;
+
+        return 0;
 }
 
 DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(