]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
sd-netlink: do not link non-multipart messages
authorYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 26 Nov 2022 00:35:53 +0000 (09:35 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Sat, 26 Nov 2022 02:28:27 +0000 (11:28 +0900)
Previously, if a single packet contains multiple non-multipart messages,
then the messages were linked and saved as a single entry, especially
even if the messages has different serial numbers. Though, not sure if
the kernel sends such packet. But at least for safety, let's link only
multipart messages.

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

index 1aaa4b712c7730e0c5a52434e1ef1c58321b81bc..2a9f64141903c1052d9f7d6e072fad59ee94f847 100644 (file)
@@ -376,10 +376,9 @@ finalize:
  * On failure, a negative error code is returned.
  */
 int socket_read_message(sd_netlink *nl) {
-        _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *first = NULL;
-        bool multi_part = false, done = false;
-        size_t len;
+        bool done = false;
         uint32_t group;
+        size_t len;
         int r;
 
         assert(nl);
@@ -405,12 +404,7 @@ int socket_read_message(sd_netlink *nl) {
                 return 0;
         }
 
-        if (nl->rbuffer->nlmsg_flags & NLM_F_MULTI) {
-                multi_part = true;
-                first = hashmap_remove(nl->rqueue_partial_by_serial, UINT32_TO_PTR(nl->rbuffer->nlmsg_seq));
-        }
-
-        for (struct nlmsghdr *hdr = nl->rbuffer; NLMSG_OK(hdr, len) && !done; hdr = NLMSG_NEXT(hdr, len)) {
+        for (struct nlmsghdr *hdr = nl->rbuffer; NLMSG_OK(hdr, len); hdr = NLMSG_NEXT(hdr, len)) {
                 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
 
                 r = parse_message_one(nl, group, hdr, &m);
@@ -419,36 +413,44 @@ int socket_read_message(sd_netlink *nl) {
                 if (r == 0)
                         continue;
 
-                if (hdr->nlmsg_type == NLMSG_DONE) {
-                        /* finished reading multi-part message */
-                        done = true;
+                if (hdr->nlmsg_flags & NLM_F_MULTI) {
+                        if (hdr->nlmsg_type == NLMSG_DONE) {
+                                _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *existing = NULL;
 
-                        /* if first is not defined, put NLMSG_DONE into the receive queue. */
-                        if (first)
-                                continue;
-                }
+                                /* finished reading multi-part message */
+                                existing = hashmap_remove(nl->rqueue_partial_by_serial, UINT32_TO_PTR(hdr->nlmsg_seq));
 
-                /* push the message onto the multi-part message stack */
-                if (first)
-                        m->next = first;
-                first = TAKE_PTR(m);
+                                /* if we receive only NLMSG_DONE, put it into the receive queue. */
+                                r = netlink_queue_received_message(nl, existing ?: m);
+                                if (r < 0)
+                                        return r;
+
+                                done = true;
+                        } else {
+                                sd_netlink_message *existing;
+
+                                existing = hashmap_remove(nl->rqueue_partial_by_serial, UINT32_TO_PTR(hdr->nlmsg_seq));
+                                if (existing)
+                                        /* push the message onto the multi-part message stack */
+                                        m->next = existing;
+
+                                /* put it into the queue for partially received messages. */
+                                r = netlink_queue_partially_received_message(nl, m);
+                                if (r < 0)
+                                        return r;
+                        }
+
+                } else {
+                        r = netlink_queue_received_message(nl, m);
+                        if (r < 0)
+                                return r;
+
+                        done = true;
+                }
         }
 
         if (len > 0)
                 log_debug("sd-netlink: discarding trailing %zu bytes of incoming message", len);
 
-        if (!first)
-                return 0;
-
-        done = done || !multi_part;
-        if (done)
-                /* we got a complete message, push it on the read queue */
-                r = netlink_queue_received_message(nl, first);
-        else
-                /* we only got a partial multi-part message, push it on the partial read queue. */
-                r = netlink_queue_partially_received_message(nl, first);
-        if (r < 0)
-                return r;
-
         return done;
 }