diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2022-11-26 09:35:53 +0900 |
---|---|---|
committer | Yu Watanabe <watanabe.yu+github@gmail.com> | 2022-11-26 11:28:27 +0900 |
commit | a8ac052624495d5f974674187e29c6fb9671f94f (patch) | |
tree | ee232209b9c6757dc308dc7755ef374221445bfc /src/libsystemd | |
parent | 9482429af9696ce16b90b2de97b15336235bcd30 (diff) | |
download | systemd-a8ac052624495d5f974674187e29c6fb9671f94f.tar.gz |
sd-netlink: do not link non-multipart messages
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.
Diffstat (limited to 'src/libsystemd')
-rw-r--r-- | src/libsystemd/sd-netlink/netlink-socket.c | 68 |
1 files changed, 35 insertions, 33 deletions
diff --git a/src/libsystemd/sd-netlink/netlink-socket.c b/src/libsystemd/sd-netlink/netlink-socket.c index 1aaa4b712c..2a9f641419 100644 --- a/src/libsystemd/sd-netlink/netlink-socket.c +++ b/src/libsystemd/sd-netlink/netlink-socket.c @@ -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; } |