[PATCH v9 3/4] Netlink: handle multi netlink messages

Fabien Siron fabien.siron at epita.fr
Wed Jul 6 15:49:24 UTC 2016


Handle the case where there are several messages in the buffer.
This is very useful to some protocols like SOCK_DIAG.

* netlink.c (fetch_nlmsg, next_nlmsg): New functions.
(decode_netlink_msg): New function.
(decode_netlink): Call decode_netlink_msg().
* tests/netlink_parsing.c (send_query): Adapt test.
---
 netlink.c                | 101 +++++++++++++++++++++++++++++++++++++++++------
 tests/netlink_protocol.c |  81 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 168 insertions(+), 14 deletions(-)

diff --git a/netlink.c b/netlink.c
index c43f6e7..fc746ed 100644
--- a/netlink.c
+++ b/netlink.c
@@ -31,34 +31,109 @@
 #include "xlat/netlink_flags.h"
 #include "xlat/netlink_types.h"
 
-void
-decode_netlink(struct tcb *tcp, unsigned long addr, unsigned long size)
-{
-	struct nlmsghdr nlmsghdr;
+/* since our target is not in the same process, here are some utils for nlmsg */
+static int
+fetch_nlmsg(struct tcb *tcp, struct nlmsghdr *nlmsghdr, unsigned long addr,
+	    unsigned long len) {
+	if (addr == 0)
+		return 0;
+	if (len < sizeof(struct nlmsghdr)) {
+		if (len != 0)
+			printstr(tcp, addr, len);
+		return 0;
+	}
+
+	if (umove_or_printaddr(tcp, addr, nlmsghdr) == -1)
+		return 0;
+
+	return 1;
+}
 
+static unsigned long
+next_nlmsg(struct nlmsghdr *nlmsghdr, unsigned long addr, unsigned long *len) {
+	unsigned long nlmsg_len = NLMSG_ALIGN(nlmsghdr->nlmsg_len);
+
+	if (nlmsg_len < sizeof(struct nlmsghdr)) {
+		addr = 0;
+		nlmsg_len = sizeof(struct nlmsghdr);
+	}
+
+	if (*len >= nlmsg_len)
+		*len -= nlmsg_len;
+	else
+		*len = 0;
+
+	if (addr && addr + nlmsg_len > addr)
+		return addr + nlmsg_len;
+	else
+		return 0;
+}
+
+static void
+decode_netlink_msg(struct tcb *tcp, struct nlmsghdr *nlmsghdr,
+		   unsigned long addr, unsigned long size)
+{
 	if (size < sizeof(struct nlmsghdr)) {
 		printstr(tcp, addr, size);
 		return;
 	}
-	if (umove_or_printaddr(tcp, addr, &nlmsghdr))
-		return;
 
-	tprintf("{{len=%u, type=", nlmsghdr.nlmsg_len);
+	tprintf("{{len=%u, type=", nlmsghdr->nlmsg_len);
 
-	printxval(netlink_types, nlmsghdr.nlmsg_type, "NLMSG_???");
+	printxval(netlink_types, nlmsghdr->nlmsg_type, "NLMSG_???");
 
 	tprints(", flags=");
-	printflags(netlink_flags, nlmsghdr.nlmsg_flags, "NLM_F_???");
+	printflags(netlink_flags, nlmsghdr->nlmsg_flags, "NLM_F_???");
 	/* manage get/new requests */
 
-	tprintf(", seq=%u, pid=%u}", nlmsghdr.nlmsg_seq,
-		nlmsghdr.nlmsg_pid);
+	tprintf(", seq=%u, pid=%u}", nlmsghdr->nlmsg_seq,
+		nlmsghdr->nlmsg_pid);
 
-	if (size - sizeof(struct nlmsghdr) > 0) {
+	if (nlmsghdr->nlmsg_len - sizeof(struct nlmsghdr) > 0) {
 		tprints(", ");
+
 		printstr(tcp, addr + sizeof(struct nlmsghdr),
-			 size - sizeof(struct nlmsghdr));
+			 nlmsghdr->nlmsg_len - sizeof(struct nlmsghdr));
 	}
 
 	tprints("}");
 }
+
+void
+decode_netlink(struct tcb *tcp, unsigned long addr, unsigned long total_size) {
+	struct nlmsghdr nlmsghdr;
+	unsigned long elt, size = total_size;
+	int print_array = 0;
+
+	if (total_size == 0)
+		printaddr(addr);
+
+	for (elt = 0; fetch_nlmsg(tcp, &nlmsghdr, addr, size);
+	     addr = next_nlmsg(&nlmsghdr, addr, &size), elt++) {
+		if (elt == max_strlen && abbrev(tcp)) {
+			tprints("...");
+			break;
+		}
+		if (addr == 0)
+			printaddr(addr);
+
+		if (nlmsghdr.nlmsg_len < sizeof(struct nlmsghdr)) {
+			printstr(tcp, addr, nlmsghdr.nlmsg_len);
+			break;
+		}
+
+		if (size == total_size &&
+		    NLMSG_ALIGN(nlmsghdr.nlmsg_len) < total_size) {
+			print_array = 1;
+			tprints("[");
+		}
+
+		decode_netlink_msg(tcp, &nlmsghdr, addr, size);
+
+		if (size > nlmsghdr.nlmsg_len)
+			tprints(", ");
+	}
+	if (print_array) {
+		tprints("]");
+	}
+}
diff --git a/tests/netlink_protocol.c b/tests/netlink_protocol.c
index eb6a843..04ac6b0 100644
--- a/tests/netlink_protocol.c
+++ b/tests/netlink_protocol.c
@@ -44,7 +44,7 @@
 static void
 send_query(const int fd)
 {
-	struct {
+	struct req {
 		struct nlmsghdr nlh;
 		char magic[4];
 	} req = {
@@ -55,8 +55,17 @@ send_query(const int fd)
 		},
 		.magic = "abcd"
 	};
+	struct {
+		struct req req1;
+		char padding[NLMSG_ALIGN(sizeof(req)) - sizeof(req)];
+		struct req req2;
+	} reqs = {
+		.req1 = req,
+		.req2 = req
+	};
 
 	const void *const efault = tail_alloc(sizeof(struct nlmsghdr) - 1);
+	void *efault2 = tail_alloc(sizeof(req));
 
 	if (sendto(fd, &req, sizeof(req), MSG_DONTWAIT, NULL, 0) !=
 	    (unsigned) sizeof(req))
@@ -91,6 +100,76 @@ send_query(const int fd)
 
 	printf("sendto(%d, %p, %u, MSG_DONTWAIT, NULL, 0) = -1 "
 	       "EFAULT (%m)\n", fd, efault, (unsigned) sizeof(struct nlmsghdr));
+
+	memcpy(efault2, &reqs, sizeof(req));
+
+	sendto(fd, efault2, sizeof(reqs), MSG_DONTWAIT, NULL, 0);
+
+	printf("sendto(%d, [{{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x"
+	       ", seq=0, pid=0}, \"abcd\"}, %p], %u, MSG_DONTWAIT, NULL, 0) = -1 "
+	       "EFAULT (%m)\n", fd, (unsigned) sizeof(req), NLM_F_DUMP,
+	       ((unsigned char *)efault2 + sizeof(req)),
+	       (unsigned) sizeof(reqs));
+
+	sendto(fd, &reqs, sizeof(reqs), MSG_DONTWAIT, NULL, 0);
+
+	printf("sendto(%d, [{{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x"
+	       ", seq=0, pid=0}, \"abcd\"}, {{len=%u, type=NLMSG_NOOP"
+	       ", flags=NLM_F_REQUEST|0x%x, seq=0, pid=0}, \"abcd\"}], %u"
+	       ", MSG_DONTWAIT, NULL, 0) = %u\n", fd, (unsigned) sizeof(req),
+	       NLM_F_DUMP, (unsigned) sizeof(req), NLM_F_DUMP,
+	       (unsigned) sizeof(reqs), (unsigned) sizeof(reqs));
+
+	if (sendto(fd, &req, 0, MSG_DONTWAIT, NULL, 0) != 0)
+		perror_msg_and_skip("sendto");
+
+	printf("sendto(%d, %p, 0, MSG_DONTWAIT, NULL, 0) = 0\n", fd, &req);
+
+	if (sendto(fd, NULL, 0, MSG_DONTWAIT, NULL, 0) != 0)
+		perror_msg_and_skip("sendto");
+
+	printf("sendto(%d, NULL, 0, MSG_DONTWAIT, NULL, 0) = 0\n", fd);
+
+	if (sendto(fd, &req, sizeof(req) - 16, MSG_DONTWAIT, NULL, 0) != sizeof(req) - 16)
+		perror_msg_and_skip("sendto");
+
+	printf("sendto(%d, \"", fd);
+	print_quoted_memory((char *)&req.nlh, sizeof(req) - 16);
+	printf("\", %u, MSG_DONTWAIT, NULL, 0) = %u\n",
+	       (unsigned) sizeof(req) - 16, (unsigned) sizeof(req) - 16);
+
+	if (sendto(fd, &reqs, sizeof(reqs) - 16, MSG_DONTWAIT, NULL, 0) != sizeof(reqs) - 16)
+		perror_msg_and_skip("sendto");
+
+	printf("sendto(%d, [{{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x"
+	       ", seq=0, pid=0}, \"abcd\"}, \"", fd, (unsigned) sizeof(req),
+	       NLM_F_DUMP);
+	print_quoted_memory((char *)&reqs.req2.nlh, sizeof(req) - 16);
+	printf("\"], %u, MSG_DONTWAIT, NULL, 0) = %u\n", (unsigned) sizeof(reqs) - 16,
+		(unsigned) sizeof(reqs) - 16);
+
+	req.nlh.nlmsg_len -= 12;
+
+	if (sendto(fd, &req, sizeof(req), MSG_DONTWAIT, NULL, 0) != sizeof(req))
+		perror_msg_and_skip("sendto");
+
+	printf("sendto(%d, \"", fd);
+	print_quoted_memory((char *)&req.nlh, sizeof(req.nlh.nlmsg_len));
+	printf("\", %u, MSG_DONTWAIT, NULL, 0) = %u\n", (unsigned) sizeof(req),
+	       (unsigned) sizeof(req));
+
+	reqs.req2.nlh.nlmsg_len -= 16;
+
+	if (sendto(fd, &reqs, sizeof(reqs), MSG_DONTWAIT, NULL, 0) != sizeof(reqs))
+		perror_msg_and_skip("sendto");
+
+	printf("sendto(%d, [{{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x"
+	       ", seq=0, pid=0}, \"abcd\"}, \"", fd, (unsigned) sizeof(req),
+	       NLM_F_DUMP);
+	print_quoted_memory((char *)&reqs.req2.nlh, sizeof(reqs.req2.nlh.nlmsg_len));
+	printf("\"], %u, MSG_DONTWAIT, NULL, 0) = %u\n", (unsigned) sizeof(reqs),
+	       (unsigned) sizeof(reqs));
+
 }
 
 int main(void)
-- 
2.9.0





More information about the Strace-devel mailing list