From 73362a23fdd89f7a84809625be25e815d547373e Mon Sep 17 00:00:00 2001
From: "Dmitry V. Levin" <ldv@altlinux.org>
Date: Thu, 7 Jul 2016 09:49:26 +0000
Subject: [PATCH] tests: extend netlink protocol check

* tests/netlink_protocol.c (send_query): Check that no part
of netlink message is fetched beyond the end of message.
Check decoding of zero address and zero length messages.
Check decoding of messages with nlmsg_len exceeding message length.
---
 tests/netlink_protocol.c | 82 ++++++++++++++++++++++++++++------------
 1 file changed, 57 insertions(+), 25 deletions(-)

diff --git a/tests/netlink_protocol.c b/tests/netlink_protocol.c
index eb6a843d..8afea597 100644
--- a/tests/netlink_protocol.c
+++ b/tests/netlink_protocol.c
@@ -29,10 +29,10 @@
  */
 
 #include "tests.h"
+#include <stdio.h>
 #include <string.h>
 #include <unistd.h>
 #include <netinet/in.h>
-#include <stdio.h>
 #include <linux/netlink.h>
 #include <linux/sock_diag.h>
 #include <linux/netlink_diag.h>
@@ -44,53 +44,85 @@
 static void
 send_query(const int fd)
 {
-	struct {
+	static const struct req {
 		struct nlmsghdr nlh;
-		char magic[4];
-	} req = {
+		const char magic[4];
+	} c_req = {
 		.nlh = {
-			.nlmsg_len = sizeof(req),
+			.nlmsg_len = sizeof(struct req),
 			.nlmsg_type = NLMSG_NOOP,
 			.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST
 		},
 		.magic = "abcd"
 	};
+	struct req *const req = tail_memdup(&c_req, sizeof(c_req));
+
+	/* zero address */
+	if (sendto(fd, NULL, sizeof(*req), MSG_DONTWAIT, NULL, 0) != -1)
+		perror_msg_and_skip("sendto");
+
+	printf("sendto(%d, NULL, %u, MSG_DONTWAIT, NULL, 0) = -1 %s (%m)\n",
+	       fd, (unsigned) sizeof(*req), errno2name());
+
+	/* zero length */
+	if (sendto(fd, req, 0, MSG_DONTWAIT, NULL, 0) != 0)
+		perror_msg_and_skip("sendto");
+
+	printf("sendto(%d, \"\", 0, MSG_DONTWAIT, NULL, 0) = 0\n", fd);
+
+	/* zero address and length */
+	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);
 
+	/* unfetchable struct nlmsghdr */
 	const void *const efault = tail_alloc(sizeof(struct nlmsghdr) - 1);
+	sendto(fd, efault, sizeof(struct nlmsghdr), MSG_DONTWAIT, NULL, 0);
 
-	if (sendto(fd, &req, sizeof(req), MSG_DONTWAIT, NULL, 0) !=
-	    (unsigned) sizeof(req))
+	printf("sendto(%d, %p, %u, MSG_DONTWAIT, NULL, 0) = -1 EFAULT (%m)\n",
+	       fd, efault, (unsigned) sizeof(struct nlmsghdr));
+
+	/* whole message length < sizeof(struct nlmsghdr) */
+	if (sendto(fd, req->magic, sizeof(req->magic), MSG_DONTWAIT, NULL, 0)
+	    != (unsigned) sizeof(req->magic))
+		perror_msg_and_skip("sendto");
+
+	printf("sendto(%d, \"abcd\", %u, MSG_DONTWAIT, NULL, 0) = %u\n",
+	       fd, (unsigned) sizeof(req->magic), (unsigned) sizeof(req->magic));
+
+	/* a single message with some data */
+	if (sendto(fd, req, sizeof(*req), MSG_DONTWAIT, NULL, 0) !=
+	    (unsigned) sizeof(*req))
 		perror_msg_and_skip("sendto");
 
 	printf("sendto(%d, {{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), (unsigned) sizeof(req));
+	       fd, req->nlh.nlmsg_len, NLM_F_DUMP,
+	       (unsigned) sizeof(*req), (unsigned) sizeof(*req));
 
-	/* data length is equal to sizeof(struct nlmsghdr) */
-	req.nlh.nlmsg_len = sizeof(req.nlh);
+	/* a single message without data */
+	req->nlh.nlmsg_len = sizeof(req->nlh);
 
-	if (sendto(fd, &req.nlh, sizeof(req.nlh), MSG_DONTWAIT, NULL, 0) !=
-	    (unsigned) sizeof(req.nlh))
+	if (sendto(fd, &req->nlh, sizeof(req->nlh), MSG_DONTWAIT, NULL, 0)
+	    != (unsigned) sizeof(req->nlh))
 		perror_msg_and_skip("sendto");
 
 	printf("sendto(%d, {{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x"
 	       ", seq=0, pid=0}}, %u, MSG_DONTWAIT, NULL, 0) = %u\n",
-	       fd, (unsigned) sizeof(req.nlh), NLM_F_DUMP,
-	       (unsigned) sizeof(req.nlh), (unsigned) sizeof(req.nlh));
+	       fd, req->nlh.nlmsg_len, NLM_F_DUMP,
+	       (unsigned) sizeof(req->nlh), (unsigned) sizeof(req->nlh));
 
-	/* data length is less than sizeof(struct nlmsghdr) */
-	if (sendto(fd, &req.magic, sizeof(req.magic), MSG_DONTWAIT, NULL, 0) !=
-	    (unsigned) sizeof(req.magic))
+	/* nlmsg_len > whole message length */
+	req->nlh.nlmsg_len = sizeof(*req) + 8;
+	if (sendto(fd, req, sizeof(*req), MSG_DONTWAIT, NULL, 0) !=
+	    (unsigned) sizeof(*req))
 		perror_msg_and_skip("sendto");
 
-	printf("sendto(%d, \"abcd\", %u, MSG_DONTWAIT, NULL, 0) = %u\n",
-	       fd, (unsigned) sizeof(req.magic), (unsigned) sizeof(req.magic));
-
-	sendto(fd, efault, sizeof(struct nlmsghdr), MSG_DONTWAIT, NULL, 0);
-
-	printf("sendto(%d, %p, %u, MSG_DONTWAIT, NULL, 0) = -1 "
-	       "EFAULT (%m)\n", fd, efault, (unsigned) sizeof(struct nlmsghdr));
+	printf("sendto(%d, {{len=%u, type=NLMSG_NOOP, flags=NLM_F_REQUEST|0x%x"
+	       ", seq=0, pid=0}, \"abcd\"}, %u, MSG_DONTWAIT, NULL, 0) = %u\n",
+	       fd, req->nlh.nlmsg_len, NLM_F_DUMP,
+	       (unsigned) sizeof(*req), (unsigned) sizeof(*req));
 }
 
 int main(void)
-- 
2.40.0