From: Yu Watanabe Date: Thu, 24 Nov 2022 18:36:39 +0000 (+0900) Subject: sd-netlink: fix possible use-after-free X-Git-Tag: v253-rc1~431^2~8 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=bc1a8e2b6ea5477fb662f032f0ac553f319b711e;p=thirdparty%2Fsystemd.git sd-netlink: fix possible use-after-free When we receive a multi-part message and fail to parse it, then the prviously received message is freed with the _cleanup_ attribute, but still referenced by sd_netlink.rqueue_partial. That causes use-after-free when we receive another multi-part message. --- diff --git a/src/libsystemd/sd-netlink/netlink-socket.c b/src/libsystemd/sd-netlink/netlink-socket.c index 5128f8fb4be..fcf971b8f67 100644 --- a/src/libsystemd/sd-netlink/netlink-socket.c +++ b/src/libsystemd/sd-netlink/netlink-socket.c @@ -241,6 +241,24 @@ static int socket_recv_message(int fd, void *buf, size_t buf_size, uint32_t *ret return (int) n; } +static sd_netlink_message *netlink_take_partial_message(sd_netlink *nl, uint32_t seqnum) { + assert(nl); + + for (unsigned i = 0; i < nl->rqueue_partial_size; i++) + if (message_get_serial(nl->rqueue_partial[i]) == seqnum) { + sd_netlink_message *found = nl->rqueue_partial[i]; + + /* remove the message form the partial read queue */ + memmove(nl->rqueue_partial + i, nl->rqueue_partial + i + 1, + sizeof(sd_netlink_message*) * (nl->rqueue_partial_size - i - 1)); + nl->rqueue_partial_size--; + + return found; + } + + return NULL; +} + /* On success, the number of bytes received is returned and *ret points to the received message * which has a valid header and the correct size. * If nothing useful was received 0 is returned. @@ -251,7 +269,6 @@ int socket_read_message(sd_netlink *nl) { bool multi_part = false, done = false; size_t len; uint32_t group; - unsigned i = 0; int r; assert(nl); @@ -279,13 +296,7 @@ int socket_read_message(sd_netlink *nl) { if (nl->rbuffer->nlmsg_flags & NLM_F_MULTI) { multi_part = true; - - for (i = 0; i < nl->rqueue_partial_size; i++) - if (message_get_serial(nl->rqueue_partial[i]) == - nl->rbuffer->nlmsg_seq) { - first = nl->rqueue_partial[i]; - break; - } + first = netlink_take_partial_message(nl, nl->rbuffer->nlmsg_seq); } for (struct nlmsghdr *new_msg = nl->rbuffer; NLMSG_OK(new_msg, len) && !done; new_msg = NLMSG_NEXT(new_msg, len)) { @@ -358,28 +369,14 @@ int socket_read_message(sd_netlink *nl) { return r; nl->rqueue[nl->rqueue_size++] = TAKE_PTR(first); - - if (multi_part && (i < nl->rqueue_partial_size)) { - /* remove the message form the partial read queue */ - memmove(nl->rqueue_partial + i, nl->rqueue_partial + i + 1, - sizeof(sd_netlink_message*) * (nl->rqueue_partial_size - i - 1)); - nl->rqueue_partial_size--; - } - return 1; } else { - /* we only got a partial multi-part message, push it on the - partial read queue */ - if (i < nl->rqueue_partial_size) - nl->rqueue_partial[i] = TAKE_PTR(first); - else { - r = netlink_rqueue_partial_make_room(nl); - if (r < 0) - return r; - - nl->rqueue_partial[nl->rqueue_partial_size++] = TAKE_PTR(first); - } + /* we only got a partial multi-part message, push it on the partial read queue. */ + r = netlink_rqueue_partial_make_room(nl); + if (r < 0) + return r; + nl->rqueue_partial[nl->rqueue_partial_size++] = TAKE_PTR(first); return 0; } }