All of lore.kernel.org
 help / color / mirror / Atom feed
From: Stephen Hemminger <stephen@networkplumber.org>
To: netdev@vger.kernel.org
Cc: dsahern@kernel.org, Stephen Hemminger <stephen@networkplumber.org>
Subject: [PATCH iproute2 4/5] netlink: handle unpadded last message in receive loops
Date: Sun,  8 Nov 2026 17:44:01 -0800	[thread overview]
Message-ID: <20261109014434.115922-5-stephen@networkplumber.org> (raw)
In-Reply-To: <20261109014434.115922-1-stephen@networkplumber.org>

The kernel may send a datagram whose last message has no trailing
padding, for example Open vSwitch upcalls with OVS_DP_F_UNALIGNED.
Subtracting the aligned length then leaves the byte count at -1..-3.
__rtnl_talk_iov() and rtnl_listen() compare it as unsigned, read one
more header past the datagram and exit with "malformed message";
rtnl_dump_filter_l() exits with "Remnant of size -3".

Walk the datagram with NLMSG_OK()/NLMSG_NEXT() everywhere, and treat
only a positive rest as a remnant.

Reported-by: Anthropic OSS scanner (ANT-2026-S4ZHKVIW)
Assisted-by: Claude:claude-opus-5-5
Signed-off-by: Stephen Hemminger <stephen@networkplumber.org>
---
 lib/libnetlink.c | 76 +++++++++++++++++-------------------------------
 1 file changed, 27 insertions(+), 49 deletions(-)

diff --git a/lib/libnetlink.c b/lib/libnetlink.c
index 6432d537..de0681ac 100644
--- a/lib/libnetlink.c
+++ b/lib/libnetlink.c
@@ -994,7 +994,8 @@ skip_it:
 			fprintf(stderr, "Message truncated\n");
 			continue;
 		}
-		if (msglen) {
+		/* negative if the last message had no padding */
+		if (msglen > 0) {
 			fprintf(stderr, "!!!Remnant of size %d\n", msglen);
 			exit(1);
 		}
@@ -1088,29 +1089,13 @@ next:
 		if (status < 0)
 			return status;
 
-		for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) {
-			int len = h->nlmsg_len;
-			int l = len - sizeof(*h);
-
-			if (l < 0 || len > status) {
-				if (msg.msg_flags & MSG_TRUNC) {
-					fprintf(stderr, "Truncated message\n");
-					free(buf);
-					return -1;
-				}
-				fprintf(stderr,
-					"!!!malformed message: len=%d\n",
-					len);
-				exit(1);
-			}
+		for (h = (struct nlmsghdr *)buf; NLMSG_OK(h, status);
+		     h = NLMSG_NEXT(h, status)) {
+			int l = h->nlmsg_len - sizeof(*h);
 
 			if (h->nlmsg_pid != rtnl->local.nl_pid ||
-			    (unsigned int)(seq - h->nlmsg_seq) >= iovlen) {
-				/* Don't forget to skip that message. */
-				status -= NLMSG_ALIGN(len);
-				h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
+			    (unsigned int)(seq - h->nlmsg_seq) >= iovlen)
 				continue;
-			}
 
 			if (h->nlmsg_type == NLMSG_ERROR) {
 				struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h);
@@ -1156,21 +1141,23 @@ next:
 			}
 
 			fprintf(stderr, "Unexpected reply!!!\n");
-
-			status -= NLMSG_ALIGN(len);
-			h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
 		}
 		free(buf);
 
+		/* negative if the last message had no padding */
+		if (status > 0) {
+			if (msg.msg_flags & MSG_TRUNC) {
+				fprintf(stderr, "Truncated message\n");
+				return -1;
+			}
+			fprintf(stderr, "!!!Remnant of size %d\n", status);
+			exit(1);
+		}
+
 		if (msg.msg_flags & MSG_TRUNC) {
 			fprintf(stderr, "Message truncated\n");
 			continue;
 		}
-
-		if (status) {
-			fprintf(stderr, "!!!Remnant of size %d\n", status);
-			exit(1);
-		}
 	}
 }
 
@@ -1294,38 +1281,29 @@ int rtnl_listen(struct rtnl_handle *rtnl,
 				}
 		}
 
-		for (h = (struct nlmsghdr *)buf; status >= sizeof(*h); ) {
+		for (h = (struct nlmsghdr *)buf; NLMSG_OK(h, status);
+		     h = NLMSG_NEXT(h, status)) {
 			int err;
-			int len = h->nlmsg_len;
-			int l = len - sizeof(*h);
-
-			if (l < 0 || len > status) {
-				if (msg.msg_flags & MSG_TRUNC) {
-					fprintf(stderr, "Truncated message\n");
-					return -1;
-				}
-				fprintf(stderr,
-					"!!!malformed message: len=%d\n",
-					len);
-				exit(1);
-			}
 
 			err = handler(&ctrl, h, jarg);
 			fflush(stdout);
 			if (err < 0)
 				return err;
+		}
 
-			status -= NLMSG_ALIGN(len);
-			h = (struct nlmsghdr *)((char *)h + NLMSG_ALIGN(len));
+		/* negative if the last message had no padding */
+		if (status > 0) {
+			if (msg.msg_flags & MSG_TRUNC) {
+				fprintf(stderr, "Truncated message\n");
+				return -1;
+			}
+			fprintf(stderr, "!!!Remnant of size %d\n", status);
+			exit(1);
 		}
 		if (msg.msg_flags & MSG_TRUNC) {
 			fprintf(stderr, "Message truncated\n");
 			continue;
 		}
-		if (status) {
-			fprintf(stderr, "!!!Remnant of size %d\n", status);
-			exit(1);
-		}
 	}
 }
 
-- 
2.53.0


  parent reply	other threads:[~2026-11-09  1:44 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-11-09  1:43 [PATCH iproute2 0/5] netlink receive path hardening Stephen Hemminger
2026-11-09  1:43 ` [PATCH iproute2 1/5] netlink: use a counter for sequence numbers Stephen Hemminger
2026-11-09  1:43 ` [PATCH iproute2 2/5] netlink: ignore messages not sent by the kernel Stephen Hemminger
2026-11-09  1:44 ` [PATCH iproute2 3/5] netlink: connect sockets to " Stephen Hemminger
2026-11-09  1:44 ` Stephen Hemminger [this message]
2026-11-09  1:44 ` [PATCH iproute2 5/5] libnetlink: do not read past datagram when recording dump Stephen Hemminger
2026-11-11 17:30 ` [PATCH iproute2 0/5] netlink receive path hardening patchwork-bot+netdevbpf

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261109014434.115922-5-stephen@networkplumber.org \
    --to=stephen@networkplumber.org \
    --cc=dsahern@kernel.org \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.