All of lore.kernel.org
 help / color / mirror / Atom feed
* [LTP] [PATCH v3 1/6] Add SAFE_REALLOC() helper function to LTP library
@ 2021-05-05  8:18 Martin Doucha
  2021-05-05  8:18 ` [LTP] [PATCH v3 2/6] Add SAFE_RECV() " Martin Doucha
                   ` (5 more replies)
  0 siblings, 6 replies; 26+ messages in thread
From: Martin Doucha @ 2021-05-05  8:18 UTC (permalink / raw)
  To: ltp

Signed-off-by: Martin Doucha <mdoucha@suse.cz>
Reviewed-by: Cyril Hrubis <chrubis@suse.cz>
---

Sorry for resubmitting so soon, I forgot to include the gitignore/runfile
paperwork for the new test. Fixed in patch 6.

Changes since v1: None

 include/tst_safe_macros.h |  5 +++++
 lib/tst_safe_macros.c     | 15 +++++++++++++++
 2 files changed, 20 insertions(+)

diff --git a/include/tst_safe_macros.h b/include/tst_safe_macros.h
index b9d9baa1a..d6f32ef4c 100644
--- a/include/tst_safe_macros.h
+++ b/include/tst_safe_macros.h
@@ -67,6 +67,11 @@ int safe_dup2(const char *file, const int lineno, int oldfd, int newfd);
 #define SAFE_MALLOC(size) \
 	safe_malloc(__FILE__, __LINE__, NULL, (size))
 
+void *safe_realloc(const char *file, const int lineno, void *ptr, size_t size);
+
+#define SAFE_REALLOC(ptr, size) \
+	safe_realloc(__FILE__, __LINE__, (ptr), (size))
+
 #define SAFE_MKDIR(pathname, mode) \
 	safe_mkdir(__FILE__, __LINE__, NULL, (pathname), (mode))
 
diff --git a/lib/tst_safe_macros.c b/lib/tst_safe_macros.c
index 182b690bb..fd5f1704b 100644
--- a/lib/tst_safe_macros.c
+++ b/lib/tst_safe_macros.c
@@ -5,6 +5,7 @@
 
 #define _GNU_SOURCE
 #include <unistd.h>
+#include <stdlib.h>
 #include <errno.h>
 #include <sched.h>
 #include <sys/ptrace.h>
@@ -433,6 +434,20 @@ int safe_dup2(const char *file, const int lineno, int oldfd, int newfd)
 	return rval;
 }
 
+void *safe_realloc(const char *file, const int lineno, void *ptr, size_t size)
+{
+	void *ret;
+
+	ret = realloc(ptr, size);
+
+	if (!ret) {
+		tst_brk_(file, lineno, TBROK | TERRNO,
+			"realloc(%p, %zu) failed", ptr, size);
+	}
+
+	return ret;
+}
+
 sighandler_t safe_signal(const char *file, const int lineno,
 	int signum, sighandler_t handler)
 {
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [LTP] [PATCH v3 2/6] Add SAFE_RECV() helper function to LTP library
  2021-05-05  8:18 [LTP] [PATCH v3 1/6] Add SAFE_REALLOC() helper function to LTP library Martin Doucha
@ 2021-05-05  8:18 ` Martin Doucha
  2021-05-10  7:55   ` Petr Vorel
  2021-05-05  8:18 ` [LTP] [PATCH v3 3/6] Add SAFE_IOCTL() variant for library code Martin Doucha
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 26+ messages in thread
From: Martin Doucha @ 2021-05-05  8:18 UTC (permalink / raw)
  To: ltp

Signed-off-by: Martin Doucha <mdoucha@suse.cz>
Reviewed-by: Cyril Hrubis <chrubis@suse.cz>
---

Changes since v1: None

 include/safe_net_fn.h  |  3 +++
 include/tst_safe_net.h |  3 +++
 lib/safe_net.c         | 25 +++++++++++++++++++++++++
 3 files changed, 31 insertions(+)

diff --git a/include/safe_net_fn.h b/include/safe_net_fn.h
index 2fda11fab..ff81b1337 100644
--- a/include/safe_net_fn.h
+++ b/include/safe_net_fn.h
@@ -47,6 +47,9 @@ ssize_t safe_sendto(const char *file, const int lineno, char len_strict,
 ssize_t safe_sendmsg(const char *file, const int lineno, size_t msg_len,
 		  int sockfd, const struct msghdr *msg, int flags);
 
+ssize_t safe_recv(const char *file, const int lineno, size_t len,
+	int sockfd, void *buf, size_t size, int flags);
+
 ssize_t safe_recvmsg(const char *file, const int lineno, size_t msg_len,
 		  int sockfd, struct msghdr *msg, int flags);
 
diff --git a/include/tst_safe_net.h b/include/tst_safe_net.h
index 78a488a18..e85b79a3e 100644
--- a/include/tst_safe_net.h
+++ b/include/tst_safe_net.h
@@ -42,6 +42,9 @@
 #define SAFE_SENDMSG(msg_len, fd, msg, flags) \
 	safe_sendmsg(__FILE__, __LINE__, msg_len, fd, msg, flags)
 
+#define SAFE_RECV(msg_len, fd, buf, size, flags)		\
+	safe_recv(__FILE__, __LINE__, (msg_len), (fd), (buf), (size), (flags))
+
 #define SAFE_RECVMSG(msg_len, fd, msg, flags)		\
 	safe_recvmsg(__FILE__, __LINE__, msg_len, fd, msg, flags)
 
diff --git a/lib/safe_net.c b/lib/safe_net.c
index f9ebea610..211fd9b67 100644
--- a/lib/safe_net.c
+++ b/lib/safe_net.c
@@ -273,6 +273,31 @@ ssize_t safe_sendmsg(const char *file, const int lineno, size_t len,
 	return rval;
 }
 
+ssize_t safe_recv(const char *file, const int lineno, size_t len,
+	int sockfd, void *buf, size_t size, int flags)
+{
+	ssize_t rval;
+
+	rval = recv(sockfd, buf, size, flags);
+
+	if (rval == -1) {
+		tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
+			"recv(%d, %p, %zu, %d) failed", sockfd, buf, size,
+			flags);
+	} else if (rval < 0) {
+		tst_brkm_(file, lineno, TBROK | TERRNO, NULL,
+			"Invalid recv(%d, %p, %zu, %d) return value %zd",
+			sockfd, buf, size, flags, rval);
+	} else if (len && (size_t)rval != len) {
+		tst_brkm_(file, lineno, TBROK, NULL,
+			"recv(%d, %p, %zu, %d) ret(%zd) != len(%zu)",
+			sockfd, buf, size, flags, rval, len);
+	}
+
+	return rval;
+
+}
+
 ssize_t safe_recvmsg(const char *file, const int lineno, size_t len,
 		     int sockfd, struct msghdr *msg, int flags)
 {
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [LTP] [PATCH v3 3/6] Add SAFE_IOCTL() variant for library code
  2021-05-05  8:18 [LTP] [PATCH v3 1/6] Add SAFE_REALLOC() helper function to LTP library Martin Doucha
  2021-05-05  8:18 ` [LTP] [PATCH v3 2/6] Add SAFE_RECV() " Martin Doucha
@ 2021-05-05  8:18 ` Martin Doucha
  2021-05-05  9:12   ` Cyril Hrubis
  2021-05-10  7:57   ` Petr Vorel
  2021-05-05  8:18 ` [LTP] [PATCH v3 4/6] Add rtnetlink helper library Martin Doucha
                   ` (3 subsequent siblings)
  5 siblings, 2 replies; 26+ messages in thread
From: Martin Doucha @ 2021-05-05  8:18 UTC (permalink / raw)
  To: ltp

SAFE_IOCTL() cannot be implemented as a function due to the variadic argument
but the macro still needs a variant which accepts arbitrary file:line position
for error messages as arguments.

Signed-off-by: Martin Doucha <mdoucha@suse.cz>
---

Changes since v1: New patch

 include/tst_safe_macros.h | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/include/tst_safe_macros.h b/include/tst_safe_macros.h
index d6f32ef4c..dcef58bda 100644
--- a/include/tst_safe_macros.h
+++ b/include/tst_safe_macros.h
@@ -211,13 +211,16 @@ pid_t safe_getpgid(const char *file, const int lineno, pid_t pid);
 #define SAFE_READDIR(dirp) \
 	safe_readdir(__FILE__, __LINE__, NULL, (dirp))
 
-#define SAFE_IOCTL(fd, request, ...)                         \
+#define SAFE_IOCTL_(file, lineno, fd, request, ...)          \
 	({int tst_ret_ = ioctl(fd, request, ##__VA_ARGS__);  \
 	  tst_ret_ < 0 ?                                     \
-	   tst_brk(TBROK | TERRNO,                           \
+	   tst_brk_((file), (lineno), TBROK | TERRNO,        \
 	            "ioctl(%i,%s,...) failed", fd, #request), 0 \
 	 : tst_ret_;})
 
+#define SAFE_IOCTL(fd, request, ...) \
+	SAFE_IOCTL_(__FILE__, __LINE__, (fd), (request), ##__VA_ARGS__)
+
 #define SAFE_FCNTL(fd, cmd, ...)                            \
 	({int tst_ret_ = fcntl(fd, cmd, ##__VA_ARGS__);     \
 	  tst_ret_ == -1 ?                                  \
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [LTP] [PATCH v3 4/6] Add rtnetlink helper library
  2021-05-05  8:18 [LTP] [PATCH v3 1/6] Add SAFE_REALLOC() helper function to LTP library Martin Doucha
  2021-05-05  8:18 ` [LTP] [PATCH v3 2/6] Add SAFE_RECV() " Martin Doucha
  2021-05-05  8:18 ` [LTP] [PATCH v3 3/6] Add SAFE_IOCTL() variant for library code Martin Doucha
@ 2021-05-05  8:18 ` Martin Doucha
  2021-05-05 10:17   ` Petr Vorel
                     ` (3 more replies)
  2021-05-05  8:18 ` [LTP] [PATCH v3 5/6] Add helper functions for managing network interfaces Martin Doucha
                   ` (2 subsequent siblings)
  5 siblings, 4 replies; 26+ messages in thread
From: Martin Doucha @ 2021-05-05  8:18 UTC (permalink / raw)
  To: ltp

This library provides simple interface for creating arbitrary rtnetlink
messages with complex attributes, sending requests and receiving results.

Signed-off-by: Martin Doucha <mdoucha@suse.cz>
---

Changes since v1:
- fixed error handling in tst_rtnl_create_context()
- renamed tst_rtnl_free_context() to tst_rtnl_destroy_context()
- switched from select() to poll() in tst_rtnl_wait()
- use tst_rtnl_add_message() for adding NLMSG_DONE
- receive all pending messages in tst_rtnl_recv(), not just one
- use inline struct initialization where possible

 include/tst_rtnetlink.h | 106 +++++++++++
 lib/tst_rtnetlink.c     | 407 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 513 insertions(+)
 create mode 100644 include/tst_rtnetlink.h
 create mode 100644 lib/tst_rtnetlink.c

diff --git a/include/tst_rtnetlink.h b/include/tst_rtnetlink.h
new file mode 100644
index 000000000..12ec258f2
--- /dev/null
+++ b/include/tst_rtnetlink.h
@@ -0,0 +1,106 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2021 Linux Test Project
+ */
+
+#ifndef TST_RTNETLINK_H
+#define TST_RTNETLINK_H
+
+struct tst_rtnl_context;
+
+struct tst_rtnl_attr_list {
+	unsigned short type;
+	const void *data;
+	ssize_t len;
+	const struct tst_rtnl_attr_list *sublist;
+};
+
+struct tst_rtnl_message {
+	struct nlmsghdr *header;
+	struct nlmsgerr *err;
+	void *payload;
+	size_t payload_size;
+};
+
+/* Open a netlink socket */
+struct tst_rtnl_context *tst_rtnl_create_context(const char *file,
+	const int lineno);
+#define RTNL_CREATE_CONTEXT() tst_rtnl_create_context(__FILE__, __LINE__)
+
+/* Free a tst_rtnl_message array returned by tst_rtnl_recv() */
+void tst_rtnl_free_message(struct tst_rtnl_message *msg);
+#define RTNL_FREE_MESSAGE tst_rtnl_free_message
+
+/* Close netlink socket */
+void tst_rtnl_destroy_context(const char *file, const int lineno,
+	struct tst_rtnl_context *ctx);
+#define RTNL_DESTROY_CONTEXT(ctx) \
+	tst_rtnl_destroy_context(__FILE__, __LINE__, (ctx))
+
+/* Send all messages in given buffer */
+int tst_rtnl_send(const char *file, const int lineno,
+	struct tst_rtnl_context *ctx);
+#define RTNL_SEND(ctx) tst_rtnl_send(__FILE__, __LINE__, (ctx))
+
+/* Send all messages in given buffer and validate kernel response */
+int tst_rtnl_send_validate(const char *file, const int lineno,
+	struct tst_rtnl_context *ctx);
+#define RTNL_SEND_VALIDATE(ctx) \
+	tst_rtnl_send_validate(__FILE__, __LINE__, (ctx))
+
+/* Wait until data is available for reading from the netlink socket */
+int tst_rtnl_wait(struct tst_rtnl_context *ctx);
+#define RTNL_WAIT tst_rtnl_wait
+
+/*
+ * Read from netlink socket and return an array of partially parsed messages.
+ * header == NULL indicates end of array.
+ */
+struct tst_rtnl_message *tst_rtnl_recv(const char *file, const int lineno,
+	struct tst_rtnl_context *ctx);
+#define RTNL_RECV(ctx) tst_rtnl_recv(__FILE__, __LINE__, (ctx))
+
+/* Add new message to buffer */
+int tst_rtnl_add_message(const char *file, const int lineno,
+	struct tst_rtnl_context *ctx, const struct nlmsghdr *header,
+	const void *payload, size_t payload_size);
+#define RTNL_ADD_MESSAGE(ctx, header, payload, psize) \
+	tst_rtnl_add_message(__FILE__, __LINE__, (ctx), (header), (payload), \
+		(psize))
+
+/* Add arbitrary attribute to last message */
+int tst_rtnl_add_attr(const char *file, const int lineno,
+	struct tst_rtnl_context *ctx, unsigned short type, const void *data,
+	unsigned short len);
+#define RTNL_ADD_ATTR(ctx, type, data, len) \
+	tst_rtnl_add_attr(__FILE__, __LINE__, (ctx), (type), (data), (len))
+
+/* Add string attribute to last message */
+int tst_rtnl_add_attr_string(const char *file, const int lineno,
+	struct tst_rtnl_context *ctx, unsigned short type, const char *data);
+#define RTNL_ADD_ATTR_STRING(ctx, type, data) \
+	tst_rtnl_add_attr_string(__FILE__, __LINE__, (ctx), (type), (data))
+
+/*
+ * Add list of arbitrary attributes to last message. The list is terminated
+ * by attribute with negative length. Nested sublists are supported.
+ */
+int tst_rtnl_add_attr_list(const char *file, const int lineno,
+	struct tst_rtnl_context *ctx, const struct tst_rtnl_attr_list *list);
+#define RTNL_ADD_ATTR_LIST(ctx, list) \
+	tst_rtnl_add_attr_list(__FILE__, __LINE__, (ctx), (list))
+
+/* Check that all sent messages with NLM_F_ACK flag have been acked without
+ * error. Usage:
+ *
+ * tst_rtnl_send(ctx);
+ * tst_rtnl_wait(ctx);
+ * response = tst_rtnl_recv(ctx);
+ * if (!tst_rtnl_check_acks(ctx, response)) { ... }
+ * tst_rtnl_free_message(response);
+ */
+int tst_rtnl_check_acks(const char *file, const int lineno,
+	struct tst_rtnl_context *ctx, struct tst_rtnl_message *response);
+#define RTNL_CHECK_ACKS(ctx, response) \
+	tst_rtnl_context(__FILE__, __LINE__, (ctx), (response))
+
+#endif /* TST_RTNETLINK_H */
diff --git a/lib/tst_rtnetlink.c b/lib/tst_rtnetlink.c
new file mode 100644
index 000000000..cd5013064
--- /dev/null
+++ b/lib/tst_rtnetlink.c
@@ -0,0 +1,407 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2021 Linux Test Project
+ */
+
+#include <stdlib.h>
+#include <limits.h>
+#include <asm/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/poll.h>
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+#include "tst_rtnetlink.h"
+
+struct tst_rtnl_context {
+	int socket;
+	pid_t pid;
+	uint32_t seq;
+	size_t bufsize, datalen;
+	char *buffer;
+	struct nlmsghdr *curmsg;
+};
+
+static int tst_rtnl_grow_buffer(const char *file, const int lineno,
+	struct tst_rtnl_context *ctx, size_t size)
+{
+	size_t needed, offset, curlen = NLMSG_ALIGN(ctx->datalen);
+	char *buf;
+
+	if (ctx->bufsize - curlen >= size)
+		return 1;
+
+	needed = size - (ctx->bufsize - curlen);
+	size = ctx->bufsize + (ctx->bufsize > needed ? ctx->bufsize : needed);
+	size = NLMSG_ALIGN(size);
+	buf = safe_realloc(file, lineno, ctx->buffer, size);
+
+	if (!buf)
+		return 0;
+
+	memset(buf + ctx->bufsize, 0, size - ctx->bufsize);
+	offset = ((char *)ctx->curmsg) - ctx->buffer;
+	ctx->buffer = buf;
+	ctx->curmsg = (struct nlmsghdr *)(buf + offset);
+	ctx->bufsize = size;
+	return 1;
+}
+
+void tst_rtnl_destroy_context(const char *file, const int lineno,
+	struct tst_rtnl_context *ctx)
+{
+	safe_close(file, lineno, NULL, ctx->socket);
+	free(ctx->buffer);
+	free(ctx);
+}
+
+struct tst_rtnl_context *tst_rtnl_create_context(const char *file,
+	const int lineno)
+{
+	struct tst_rtnl_context *ctx;
+	struct sockaddr_nl addr = { .nl_family = AF_NETLINK };
+
+	ctx = safe_malloc(file, lineno, NULL, sizeof(struct tst_rtnl_context));
+
+	if (!ctx)
+		return NULL;
+
+	ctx->pid = 0;
+	ctx->seq = 0;
+	ctx->buffer = NULL;
+	ctx->bufsize = 1024;
+	ctx->datalen = 0;
+	ctx->curmsg = NULL;
+	ctx->socket = safe_socket(file, lineno, NULL, AF_NETLINK,
+		SOCK_DGRAM | SOCK_CLOEXEC, NETLINK_ROUTE);
+
+	if (ctx->socket < 0) {
+		free(ctx);
+		return NULL;
+	}
+
+	if (safe_bind(file, lineno, NULL, ctx->socket, (struct sockaddr *)&addr,
+		sizeof(addr))) {
+		tst_rtnl_destroy_context(file, lineno, ctx);
+		return NULL;
+	}
+
+	ctx->buffer = safe_malloc(file, lineno, NULL, ctx->bufsize);
+
+	if (!ctx->buffer) {
+		tst_rtnl_destroy_context(file, lineno, ctx);
+		return NULL;
+	}
+
+	memset(ctx->buffer, 0, ctx->bufsize);
+	return ctx;
+}
+
+void tst_rtnl_free_message(struct tst_rtnl_message *msg)
+{
+	if (!msg)
+		return;
+
+	// all ptr->header and ptr->info pointers point to the same buffer
+	// msg->header is the start of the buffer
+	free(msg->header);
+	free(msg);
+}
+
+int tst_rtnl_send(const char *file, const int lineno,
+	struct tst_rtnl_context *ctx)
+{
+	int ret;
+	struct sockaddr_nl addr = { .nl_family = AF_NETLINK };
+	struct iovec iov;
+	struct msghdr msg = {
+		.msg_name = &addr,
+		.msg_namelen = sizeof(addr),
+		.msg_iov = &iov,
+		.msg_iovlen = 1
+	};
+
+	if (!ctx->curmsg) {
+		tst_brk_(file, lineno, TBROK, "%s(): No message to send",
+			__func__);
+		return 0;
+	}
+
+	if (ctx->curmsg->nlmsg_flags & NLM_F_MULTI) {
+		struct nlmsghdr eom = { .nlmsg_type = NLMSG_DONE };
+
+		if (!tst_rtnl_add_message(file, lineno, ctx, &eom, NULL, 0))
+			return 0;
+
+		/* NLMSG_DONE message must not have NLM_F_MULTI flag */
+		ctx->curmsg->nlmsg_flags = 0;
+	}
+
+	iov.iov_base = ctx->buffer;
+	iov.iov_len = ctx->datalen;
+	ret = safe_sendmsg(file, lineno, ctx->datalen, ctx->socket, &msg, 0);
+
+	if (ret > 0)
+		ctx->curmsg = NULL;
+
+	return ret;
+}
+
+int tst_rtnl_wait(struct tst_rtnl_context *ctx)
+{
+	struct pollfd fdinfo = {
+		.fd = ctx->socket,
+		.events = POLLIN
+	};
+
+	return poll(&fdinfo, 1, 1000);
+}
+
+struct tst_rtnl_message *tst_rtnl_recv(const char *file, const int lineno,
+	struct tst_rtnl_context *ctx)
+{
+	char tmp, *tmpbuf, *buffer = NULL;
+	struct tst_rtnl_message *ret;
+	struct nlmsghdr *ptr;
+	size_t retsize, bufsize = 0;
+	ssize_t size;
+	int i, size_left, msgcount;
+
+	/* Each recv() call returns one message, read all pending messages */
+	while (1) {
+		errno = 0;
+		size = recv(ctx->socket, &tmp, 1,
+			MSG_DONTWAIT | MSG_PEEK | MSG_TRUNC);
+
+		if (size < 0) {
+			if (errno != EAGAIN) {
+				tst_brk_(file, lineno, TBROK | TERRNO,
+					"recv() failed");
+			}
+
+			break;
+		}
+
+		tmpbuf = safe_realloc(file, lineno, buffer, bufsize + size);
+
+		if (!tmpbuf)
+			break;
+
+		buffer = tmpbuf;
+		size = safe_recv(file, lineno, size, ctx->socket,
+			buffer + bufsize, size, 0);
+
+		if (size < 0)
+			break;
+
+		bufsize += size;
+	}
+
+	if (!bufsize) {
+		free(buffer);
+		return NULL;
+	}
+
+	ptr = (struct nlmsghdr *)buffer;
+	size_left = bufsize;
+	msgcount = 0;
+
+	for (; size_left > 0 && NLMSG_OK(ptr, size_left); msgcount++)
+		ptr = NLMSG_NEXT(ptr, size_left);
+
+	retsize = (msgcount + 1) * sizeof(struct tst_rtnl_message);
+	ret = safe_malloc(file, lineno, NULL, retsize);
+
+	if (!ret) {
+		free(buffer);
+		return NULL;
+	}
+
+	memset(ret, 0, retsize);
+	ptr = (struct nlmsghdr *)buffer;
+	size_left = bufsize;
+
+	for (i = 0; i < msgcount; i++, ptr = NLMSG_NEXT(ptr, size_left)) {
+		ret[i].header = ptr;
+		ret[i].payload = NLMSG_DATA(ptr);
+		ret[i].payload_size = NLMSG_PAYLOAD(ptr, 0);
+
+		if (ptr->nlmsg_type == NLMSG_ERROR)
+			ret[i].err = NLMSG_DATA(ptr);
+	}
+
+	return ret;
+}
+
+int tst_rtnl_add_message(const char *file, const int lineno,
+	struct tst_rtnl_context *ctx, const struct nlmsghdr *header,
+	const void *payload, size_t payload_size)
+{
+	size_t size;
+	unsigned int extra_flags = 0;
+
+	if (!tst_rtnl_grow_buffer(file, lineno, ctx, NLMSG_SPACE(payload_size)))
+		return 0;
+
+	if (!ctx->curmsg) {
+		/*
+		 * datalen may hold the size of last sent message for ACK
+		 * checking, reset it back to 0 here
+		 */
+		ctx->datalen = 0;
+		ctx->curmsg = (struct nlmsghdr *)ctx->buffer;
+	} else {
+		size = NLMSG_ALIGN(ctx->curmsg->nlmsg_len);
+
+		extra_flags = NLM_F_MULTI;
+		ctx->curmsg->nlmsg_flags |= extra_flags;
+		ctx->curmsg = NLMSG_NEXT(ctx->curmsg, size);
+		ctx->datalen = NLMSG_ALIGN(ctx->datalen);
+	}
+
+	*ctx->curmsg = *header;
+	ctx->curmsg->nlmsg_len = NLMSG_LENGTH(payload_size);
+	ctx->curmsg->nlmsg_flags |= extra_flags;
+	ctx->curmsg->nlmsg_seq = ctx->seq++;
+	ctx->curmsg->nlmsg_pid = ctx->pid;
+
+	if (payload_size)
+		memcpy(NLMSG_DATA(ctx->curmsg), payload, payload_size);
+
+	ctx->datalen += ctx->curmsg->nlmsg_len;
+	return 1;
+}
+
+int tst_rtnl_add_attr(const char *file, const int lineno,
+	struct tst_rtnl_context *ctx, unsigned short type,
+	const void *data, unsigned short len)
+{
+	size_t size;
+	struct rtattr *attr;
+
+	if (!ctx->curmsg) {
+		tst_brk_(file, lineno, TBROK,
+			"%s(): No message to add attributes to", __func__);
+		return 0;
+	}
+
+	if (!tst_rtnl_grow_buffer(file, lineno, ctx, RTA_SPACE(len)))
+		return 0;
+
+	size = NLMSG_ALIGN(ctx->curmsg->nlmsg_len);
+	attr = (struct rtattr *)(((char *)ctx->curmsg) + size);
+	attr->rta_type = type;
+	attr->rta_len = RTA_LENGTH(len);
+	memcpy(RTA_DATA(attr), data, len);
+	ctx->curmsg->nlmsg_len = size + attr->rta_len;
+	ctx->datalen = NLMSG_ALIGN(ctx->datalen) + attr->rta_len;
+	return 1;
+}
+
+int tst_rtnl_add_attr_string(const char *file, const int lineno,
+	struct tst_rtnl_context *ctx, unsigned short type,
+	const char *data)
+{
+	return tst_rtnl_add_attr(file, lineno, ctx, type, data,
+		strlen(data) + 1);
+}
+
+int tst_rtnl_add_attr_list(const char *file, const int lineno,
+	struct tst_rtnl_context *ctx,
+	const struct tst_rtnl_attr_list *list)
+{
+	int i, ret;
+	size_t offset;
+
+	for (i = 0; list[i].len >= 0; i++) {
+		if (list[i].len > USHRT_MAX) {
+			tst_brk_(file, lineno, TBROK,
+				"%s(): Attribute value too long", __func__);
+			return -1;
+		}
+
+		offset = NLMSG_ALIGN(ctx->datalen);
+		ret = tst_rtnl_add_attr(file, lineno, ctx, list[i].type,
+			list[i].data, list[i].len);
+
+		if (!ret)
+			return -1;
+
+		if (list[i].sublist) {
+			struct rtattr *attr;
+
+			ret = tst_rtnl_add_attr_list(file, lineno, ctx,
+				list[i].sublist);
+
+			if (ret < 0)
+				return ret;
+
+			attr = (struct rtattr *)(ctx->buffer + offset);
+
+			if (ctx->datalen - offset > USHRT_MAX) {
+				tst_brk_(file, lineno, TBROK,
+					"%s(): Sublist too long", __func__);
+				return -1;
+			}
+
+			attr->rta_len = ctx->datalen - offset;
+		}
+	}
+
+	return i;
+}
+
+int tst_rtnl_check_acks(const char *file, const int lineno,
+	struct tst_rtnl_context *ctx, struct tst_rtnl_message *res)
+{
+	struct nlmsghdr *msg = (struct nlmsghdr *)ctx->buffer;
+	int size_left = ctx->datalen;
+
+	for (; size_left > 0 && NLMSG_OK(msg, size_left);
+		msg = NLMSG_NEXT(msg, size_left)) {
+
+		if (!(msg->nlmsg_flags & NLM_F_ACK))
+			continue;
+
+		while (res->header && res->header->nlmsg_seq != msg->nlmsg_seq)
+			res++;
+
+		if (!res->err || res->header->nlmsg_seq != msg->nlmsg_seq) {
+			tst_brk_(file, lineno, TBROK,
+				"No ACK found for Netlink message %u",
+				msg->nlmsg_seq);
+			return 0;
+		}
+
+		if (res->err->error) {
+			TST_ERR = -res->err->error;
+			return 0;
+		}
+	}
+
+	return 1;
+}
+
+int tst_rtnl_send_validate(const char *file, const int lineno,
+	struct tst_rtnl_context *ctx)
+{
+	struct tst_rtnl_message *response;
+	int ret;
+
+	TST_ERR = 0;
+
+	if (tst_rtnl_send(file, lineno, ctx) <= 0)
+		return 0;
+
+	tst_rtnl_wait(ctx);
+	response = tst_rtnl_recv(file, lineno, ctx);
+
+	if (!response)
+		return 0;
+
+	ret = tst_rtnl_check_acks(file, lineno, ctx, response);
+	tst_rtnl_free_message(response);
+	return ret;
+}
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [LTP] [PATCH v3 5/6] Add helper functions for managing network interfaces
  2021-05-05  8:18 [LTP] [PATCH v3 1/6] Add SAFE_REALLOC() helper function to LTP library Martin Doucha
                   ` (2 preceding siblings ...)
  2021-05-05  8:18 ` [LTP] [PATCH v3 4/6] Add rtnetlink helper library Martin Doucha
@ 2021-05-05  8:18 ` Martin Doucha
  2021-05-05 12:39   ` Cyril Hrubis
  2021-05-05  8:18 ` [LTP] [PATCH v3 6/6] Add test for CVE 2020-25705 Martin Doucha
  2021-05-10  7:42 ` [LTP] [PATCH v3 1/6] Add SAFE_REALLOC() helper function to LTP library Petr Vorel
  5 siblings, 1 reply; 26+ messages in thread
From: Martin Doucha @ 2021-05-05  8:18 UTC (permalink / raw)
  To: ltp

The library currently supports:
- creating a virtual ethernet device pair
- removing network interfaces
- enabling or disabling a network interface
- managing interface addresses
- managing routing table entries
- moving network interfaces between network namespaces

Signed-off-by: Martin Doucha <mdoucha@suse.cz>
---

Changes since v1:
- renamed tst_netdevice_index() to tst_netdev_index_by_name()
- renamed tst_netdevice_activate() to tst_netdev_set_state()
- shortened tst_netdevice_*() to tst_netdev_*()
- use inline struct initialization where possible
- use SAFE_IOCTL_()
- added modify_route_inet() internal helper function

Changes I've decided not to do:
- moving *_address_inet() and *_route_inet() functions to header file
- breaking long lines like if(foo & tst_rtnl_add_attr(...)) before the function
  call instead of in the argument list, the result would be too long

 include/tst_netdevice.h | 118 ++++++++++
 lib/tst_netdevice.c     | 463 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 581 insertions(+)
 create mode 100644 include/tst_netdevice.h
 create mode 100644 lib/tst_netdevice.c

diff --git a/include/tst_netdevice.h b/include/tst_netdevice.h
new file mode 100644
index 000000000..3a6698731
--- /dev/null
+++ b/include/tst_netdevice.h
@@ -0,0 +1,118 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later
+ * Copyright (c) 2021 Linux Test Project
+ */
+
+#ifndef TST_NETDEVICE_H
+#define TST_NETDEVICE_H
+
+/* Find device index for given network interface name. */
+int tst_netdev_index_by_name(const char *file, const int lineno,
+	const char *ifname);
+#define NETDEV_INDEX_BY_NAME(ifname) \
+	tst_netdev_index_by_name(__FILE__, __LINE__, (ifname))
+
+/* Activate or deactivate network interface */
+int tst_netdev_set_state(const char *file, const int lineno,
+	const char *ifname, int up);
+#define NETDEV_SET_STATE(ifname, up) \
+	tst_netdev_set_state(__FILE__, __LINE__, (ifname), (up))
+
+/* Create a connected pair of virtual network devices */
+int tst_create_veth_pair(const char *file, const int lineno,
+	const char *ifname1, const char *ifname2);
+#define CREATE_VETH_PAIR(ifname1, ifname2) \
+	tst_create_veth_pair(__FILE__, __LINE__, (ifname1), (ifname2))
+
+int tst_remove_netdev(const char *file, const int lineno, const char *ifname);
+#define REMOVE_NETDEV(ifname) tst_remove_netdev(__FILE__, __LINE__, (ifname))
+
+int tst_netdev_add_address(const char *file, const int lineno,
+	const char *ifname, unsigned int family, const void *address,
+	unsigned int prefix, size_t addrlen, unsigned int flags);
+#define NETDEV_ADD_ADDRESS(ifname, family, address, prefix, addrlen, flags) \
+	tst_netdev_add_address(__FILE__, __LINE__, (ifname), (family), \
+		(address), (prefix), (addrlen), (flags))
+
+int tst_netdev_add_address_inet(const char *file, const int lineno,
+	const char *ifname, in_addr_t address, unsigned int prefix,
+	unsigned int flags);
+#define NETDEV_ADD_ADDRESS_INET(ifname, address, prefix, flags) \
+	tst_netdev_add_address_inet(__FILE__, __LINE__, (ifname), (address), \
+		(prefix), (flags))
+
+int tst_netdev_remove_address(const char *file, const int lineno,
+	const char *ifname, unsigned int family, const void *address,
+	size_t addrlen);
+#define NETDEV_REMOVE_ADDRESS(ifname, family, address, addrlen) \
+	tst_netdev_remove_address(__FILE__, __LINE__, (ifname), (family), \
+		(address), (addrlen))
+
+int tst_netdev_remove_address_inet(const char *file, const int lineno,
+	const char *ifname, in_addr_t address);
+#define NETDEV_REMOVE_ADDRESS_INET(ifname, address) \
+	tst_netdev_remove_address_inet(__FILE__, __LINE__, (ifname), (address))
+
+int tst_netdev_change_ns_fd(const char *file, const int lineno,
+	const char *ifname, int nsfd);
+#define NETDEV_CHANGE_NS_FD(ifname, nsfd) \
+	tst_netdev_change_ns_fd(__FILE__, __LINE__, (ifname), (nsfd))
+
+int tst_netdev_change_ns_pid(const char *file, const int lineno,
+	const char *ifname, pid_t nspid);
+#define NETDEV_CHANGE_NS_PID(ifname, nspid) \
+	tst_netdev_change_ns_pid(__FILE__, __LINE__, (ifname), (nspid))
+
+/*
+ * Add new static entry to main routing table. If you specify gateway address,
+ * the interface name is optional.
+ */
+int tst_netdev_add_route(const char *file, const int lineno,
+	const char *ifname, unsigned int family, const void *srcaddr,
+	unsigned int srcprefix, size_t srclen, const void *dstaddr,
+	unsigned int dstprefix, size_t dstlen, const void *gateway,
+	size_t gatewaylen);
+#define NETDEV_ADD_ROUTE(ifname, family, srcaddr, srcprefix, srclen, dstaddr, \
+	dstprefix, dstlen, gateway, gatewaylen) \
+	tst_netdev_add_route(__FILE__, __LINE__, (ifname), (family), \
+		(srcaddr), (srcprefix), (srclen), (dstaddr), (dstprefix), \
+		(dstlen), (gateway), (gatewaylen))
+
+/*
+ * Simplified function for adding IPv4 static route. If you set srcprefix
+ * or dstprefix to 0, the corresponding address will be ignored. Interface
+ * name is optional if gateway address is non-zero.
+ */
+int tst_netdev_add_route_inet(const char *file, const int lineno,
+	const char *ifname, in_addr_t srcaddr, unsigned int srcprefix,
+	in_addr_t dstaddr, unsigned int dstprefix, in_addr_t gateway);
+#define NETDEV_ADD_ROUTE_INET(ifname, srcaddr, srcprefix, dstaddr, dstprefix, \
+	gateway) \
+	tst_netdev_add_route_inet(__FILE__, __LINE__, (ifname), (srcaddr), \
+		(srcprefix), (dstaddr), (dstprefix), (gateway))
+
+/*
+ * Remove static entry from main routing table.
+ */
+int tst_netdev_remove_route(const char *file, const int lineno,
+	const char *ifname, unsigned int family, const void *srcaddr,
+	unsigned int srcprefix, size_t srclen, const void *dstaddr,
+	unsigned int dstprefix, size_t dstlen, const void *gateway,
+	size_t gatewaylen);
+#define NETDEV_REMOVE_ROUTE(ifname, family, srcaddr, srcprefix, srclen, \
+	dstaddr, dstprefix, dstlen, gateway, gatewaylen) \
+	tst_netdev_remove_route(__FILE__, __LINE__, (ifname), (family), \
+		(srcaddr), (srcprefix), (srclen), (dstaddr), (dstprefix), \
+		(dstlen), (gateway), (gatewaylen))
+
+/*
+ * Simplified function for removing IPv4 static route.
+ */
+int tst_netdev_remove_route_inet(const char *file, const int lineno,
+	const char *ifname, in_addr_t srcaddr, unsigned int srcprefix,
+	in_addr_t dstaddr, unsigned int dstprefix, in_addr_t gateway);
+#define NETDEV_REMOVE_ROUTE_INET(ifname, srcaddr, srcprefix, dstaddr, \
+	dstprefix, gateway) \
+	tst_netdev_remove_route_inet(__FILE__, __LINE__, (ifname), (srcaddr), \
+		(srcprefix), (dstaddr), (dstprefix), (gateway))
+
+#endif /* TST_NETDEVICE_H */
diff --git a/lib/tst_netdevice.c b/lib/tst_netdevice.c
new file mode 100644
index 000000000..93019a140
--- /dev/null
+++ b/lib/tst_netdevice.c
@@ -0,0 +1,463 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2021 Linux Test Project
+ */
+
+#include <asm/types.h>
+#include <linux/netlink.h>
+#include <linux/rtnetlink.h>
+#include <linux/veth.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+#include "tst_rtnetlink.h"
+#include "tst_netdevice.h"
+
+static struct tst_rtnl_context *create_request(const char *file,
+	const int lineno, unsigned int type, unsigned int flags,
+	const void *payload, size_t psize)
+{
+	struct tst_rtnl_context *ctx;
+	struct nlmsghdr header = {
+		.nlmsg_type = type,
+		.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK | flags,
+	};
+
+	ctx = tst_rtnl_create_context(file, lineno);
+
+	if (!ctx)
+		return NULL;
+
+	if (!tst_rtnl_add_message(file, lineno, ctx, &header, payload, psize)) {
+		tst_rtnl_destroy_context(file, lineno, ctx);
+		return NULL;
+	}
+
+	return ctx;
+}
+
+int tst_netdev_index_by_name(const char *file, const int lineno,
+	const char *ifname)
+{
+	struct ifreq ifr;
+	int sock, ret;
+
+	if (strlen(ifname) >= IFNAMSIZ) {
+		tst_brk_(file, lineno, TBROK,
+			"Network device name \"%s\" too long", ifname);
+		return -1;
+	}
+
+	sock = safe_socket(file, lineno, NULL, AF_INET, SOCK_DGRAM, 0);
+
+	if (sock < 0)
+		return -1;
+
+	strcpy(ifr.ifr_name, ifname);
+	ret = SAFE_IOCTL_(file, lineno, sock, SIOCGIFINDEX, &ifr);
+	safe_close(file, lineno, NULL, sock);
+	return ret ? -1 : ifr.ifr_ifindex;
+}
+
+int tst_netdev_set_state(const char *file, const int lineno,
+	const char *ifname, int up)
+{
+	struct ifreq ifr;
+	int sock, ret;
+
+	if (strlen(ifname) >= IFNAMSIZ) {
+		tst_brk_(file, lineno, TBROK,
+			"Network device name \"%s\" too long", ifname);
+		return -1;
+	}
+
+	sock = safe_socket(file, lineno, NULL, AF_INET, SOCK_DGRAM, 0);
+
+	if (sock < 0)
+		return -1;
+
+	strcpy(ifr.ifr_name, ifname);
+	ret = SAFE_IOCTL_(file, lineno, sock, SIOCGIFFLAGS, &ifr);
+
+	if (ret) {
+		safe_close(file, lineno, NULL, sock);
+		return ret;
+	}
+
+	if (up)
+		ifr.ifr_flags |= IFF_UP;
+	else
+		ifr.ifr_flags &= ~IFF_UP;
+
+	ret = SAFE_IOCTL_(file, lineno, sock, SIOCSIFFLAGS, &ifr);
+	safe_close(file, lineno, NULL, sock);
+	return ret;
+}
+
+int tst_create_veth_pair(const char *file, const int lineno,
+	const char *ifname1, const char *ifname2)
+{
+	int ret;
+	struct ifinfomsg info = { .ifi_family = AF_UNSPEC };
+	struct tst_rtnl_context *ctx;
+	struct tst_rtnl_attr_list peerinfo[] = {
+		{IFLA_IFNAME, ifname2, strlen(ifname2) + 1, NULL},
+		{0, NULL, -1, NULL}
+	};
+	struct tst_rtnl_attr_list peerdata[] = {
+		{VETH_INFO_PEER, &info, sizeof(info), peerinfo},
+		{0, NULL, -1, NULL}
+	};
+	struct tst_rtnl_attr_list attrs[] = {
+		{IFLA_IFNAME, ifname1, strlen(ifname1) + 1, NULL},
+		{IFLA_LINKINFO, NULL, 0, (const struct tst_rtnl_attr_list[]){
+			{IFLA_INFO_KIND, "veth", 4, NULL},
+			{IFLA_INFO_DATA, NULL, 0, peerdata},
+			{0, NULL, -1, NULL}
+		}},
+		{0, NULL, -1, NULL}
+	};
+
+	if (strlen(ifname1) >= IFNAMSIZ) {
+		tst_brk_(file, lineno, TBROK,
+			"Network device name \"%s\" too long", ifname1);
+		return 0;
+	}
+
+	if (strlen(ifname2) >= IFNAMSIZ) {
+		tst_brk_(file, lineno, TBROK,
+			"Network device name \"%s\" too long", ifname2);
+		return 0;
+	}
+
+	ctx = create_request(file, lineno, RTM_NEWLINK,
+		NLM_F_CREATE | NLM_F_EXCL, &info, sizeof(info));
+
+	if (!ctx)
+		return 0;
+
+	if (tst_rtnl_add_attr_list(file, lineno, ctx, attrs) != 2) {
+		tst_rtnl_destroy_context(file, lineno, ctx);
+		return 0;
+	}
+
+	ret = tst_rtnl_send_validate(file, lineno, ctx);
+	tst_rtnl_destroy_context(file, lineno, ctx);
+
+	if (!ret) {
+		tst_brk_(file, lineno, TBROK | TTERRNO,
+			"Failed to create veth interfaces %s+%s", ifname1,
+			ifname2);
+	}
+
+	return ret;
+}
+
+int tst_remove_netdev(const char *file, const int lineno, const char *ifname)
+{
+	struct ifinfomsg info = { .ifi_family = AF_UNSPEC };
+	struct tst_rtnl_context *ctx;
+	int ret;
+
+	if (strlen(ifname) >= IFNAMSIZ) {
+		tst_brk_(file, lineno, TBROK,
+			"Network device name \"%s\" too long", ifname);
+		return 0;
+	}
+
+	ctx = create_request(file, lineno, RTM_DELLINK, 0, &info, sizeof(info));
+
+	if (!ctx)
+		return 0;
+
+	if (!tst_rtnl_add_attr_string(file, lineno, ctx, IFLA_IFNAME, ifname)) {
+		tst_rtnl_destroy_context(file, lineno, ctx);
+		return 0;
+	}
+
+	ret = tst_rtnl_send_validate(file, lineno, ctx);
+	tst_rtnl_destroy_context(file, lineno, ctx);
+
+	if (!ret) {
+		tst_brk_(file, lineno, TBROK | TTERRNO,
+			"Failed to remove netdevice %s", ifname);
+	}
+
+	return ret;
+}
+
+static int modify_address(const char *file, const int lineno,
+	unsigned int action, unsigned int nl_flags, const char *ifname,
+	unsigned int family, const void *address, unsigned int prefix,
+	size_t addrlen, uint32_t addr_flags)
+{
+	struct tst_rtnl_context *ctx;
+	int index, ret;
+	struct ifaddrmsg info = {
+		.ifa_family = family,
+		.ifa_prefixlen = prefix
+	};
+
+	index = tst_netdev_index_by_name(file, lineno, ifname);
+
+	if (index < 0) {
+		tst_brk_(file, lineno, TBROK, "Interface %s not found", ifname);
+		return 0;
+	}
+
+	info.ifa_index = index;
+	ctx = create_request(file, lineno, action, nl_flags, &info,
+		sizeof(info));
+
+	if (!ctx)
+		return 0;
+
+	if (!tst_rtnl_add_attr(file, lineno, ctx, IFA_FLAGS, &addr_flags,
+		sizeof(uint32_t))) {
+		tst_rtnl_destroy_context(file, lineno, ctx);
+		return 0;
+	}
+
+	if (!tst_rtnl_add_attr(file, lineno, ctx, IFA_LOCAL, address,
+		addrlen)) {
+		tst_rtnl_destroy_context(file, lineno, ctx);
+		return 0;
+	}
+
+	ret = tst_rtnl_send_validate(file, lineno, ctx);
+	tst_rtnl_destroy_context(file, lineno, ctx);
+
+	if (!ret) {
+		tst_brk_(file, lineno, TBROK | TTERRNO,
+			"Failed to modify %s network address", ifname);
+	}
+
+	return ret;
+}
+
+int tst_netdev_add_address(const char *file, const int lineno,
+	const char *ifname, unsigned int family, const void *address,
+	unsigned int prefix, size_t addrlen, unsigned int flags)
+{
+	return modify_address(file, lineno, RTM_NEWADDR,
+		NLM_F_CREATE | NLM_F_EXCL, ifname, family, address, prefix,
+		addrlen, flags);
+}
+
+int tst_netdev_add_address_inet(const char *file, const int lineno,
+	const char *ifname, in_addr_t address, unsigned int prefix,
+	unsigned int flags)
+{
+	return tst_netdev_add_address(file, lineno, ifname, AF_INET,
+		&address, prefix, sizeof(address), flags);
+}
+
+int tst_netdev_remove_address(const char *file, const int lineno,
+	const char *ifname, unsigned int family, const void *address,
+	size_t addrlen)
+{
+	return modify_address(file, lineno, RTM_DELADDR, 0, ifname, family,
+		address, 0, addrlen, 0);
+}
+
+int tst_netdev_remove_address_inet(const char *file, const int lineno,
+	const char *ifname, in_addr_t address)
+{
+	return tst_netdev_remove_address(file, lineno, ifname, AF_INET,
+		&address, sizeof(address));
+}
+
+static int change_ns(const char *file, const int lineno, const char *ifname,
+	unsigned short attr, uint32_t value)
+{
+	struct ifinfomsg info = { .ifi_family = AF_UNSPEC };
+	struct tst_rtnl_context *ctx;
+	int ret;
+
+	if (strlen(ifname) >= IFNAMSIZ) {
+		tst_brk_(file, lineno, TBROK,
+			"Network device name \"%s\" too long", ifname);
+		return 0;
+	}
+
+	ctx = create_request(file, lineno, RTM_NEWLINK, 0, &info, sizeof(info));
+
+	if (!tst_rtnl_add_attr_string(file, lineno, ctx, IFLA_IFNAME, ifname)) {
+		tst_rtnl_destroy_context(file, lineno, ctx);
+		return 0;
+	}
+
+	if (!tst_rtnl_add_attr(file, lineno, ctx, attr, &value,
+		sizeof(uint32_t))) {
+		tst_rtnl_destroy_context(file, lineno, ctx);
+		return 0;
+	}
+
+	ret = tst_rtnl_send_validate(file, lineno, ctx);
+	tst_rtnl_destroy_context(file, lineno, ctx);
+
+	if (!ret) {
+		tst_brk_(file, lineno, TBROK | TTERRNO,
+			"Failed to move %s to another namespace", ifname);
+	}
+
+	return ret;
+}
+
+int tst_netdev_change_ns_fd(const char *file, const int lineno,
+	const char *ifname, int nsfd)
+{
+	return change_ns(file, lineno, ifname, IFLA_NET_NS_FD, nsfd);
+}
+
+int tst_netdev_change_ns_pid(const char *file, const int lineno,
+	const char *ifname, pid_t nspid)
+{
+	return change_ns(file, lineno, ifname, IFLA_NET_NS_PID, nspid);
+}
+
+static int modify_route(const char *file, const int lineno, unsigned int action,
+	unsigned int flags, const char *ifname, unsigned int family,
+	const void *srcaddr, unsigned int srcprefix, size_t srclen,
+	const void *dstaddr, unsigned int dstprefix, size_t dstlen,
+	const void *gateway, size_t gatewaylen)
+{
+	struct tst_rtnl_context *ctx;
+	int ret;
+	int32_t index;
+	struct rtmsg info = {
+		.rtm_family = family,
+		.rtm_dst_len = dstprefix,
+		.rtm_src_len = srcprefix,
+		.rtm_table = RT_TABLE_MAIN,
+		.rtm_protocol = RTPROT_STATIC,
+		.rtm_type = RTN_UNICAST
+	};
+
+	if (!ifname && !gateway) {
+		tst_brk_(file, lineno, TBROK,
+			"Interface name or gateway address required");
+		return 0;
+	}
+
+	if (ifname && strlen(ifname) >= IFNAMSIZ) {
+		tst_brk_(file, lineno, TBROK,
+			"Network device name \"%s\" too long", ifname);
+		return 0;
+	}
+
+	if (ifname) {
+		index = tst_netdev_index_by_name(file, lineno, ifname);
+
+		if (index < 0)
+			return 0;
+	}
+
+	if (action == RTM_DELROUTE)
+		info.rtm_scope = RT_SCOPE_NOWHERE;
+	else
+		info.rtm_scope = RT_SCOPE_UNIVERSE;
+
+	ctx = create_request(file, lineno, action, flags, &info, sizeof(info));
+
+	if (srcaddr && !tst_rtnl_add_attr(file, lineno, ctx, RTA_SRC, srcaddr,
+		srclen)) {
+		tst_rtnl_destroy_context(file, lineno, ctx);
+		return 0;
+	}
+
+	if (dstaddr && !tst_rtnl_add_attr(file, lineno, ctx, RTA_DST, dstaddr,
+		dstlen)) {
+		tst_rtnl_destroy_context(file, lineno, ctx);
+		return 0;
+	}
+
+	if (gateway && !tst_rtnl_add_attr(file, lineno, ctx, RTA_GATEWAY,
+		gateway, gatewaylen)) {
+		tst_rtnl_destroy_context(file, lineno, ctx);
+		return 0;
+	}
+
+	if (ifname && !tst_rtnl_add_attr(file, lineno, ctx, RTA_OIF, &index,
+		sizeof(index))) {
+		tst_rtnl_destroy_context(file, lineno, ctx);
+		return 0;
+	}
+
+	ret = tst_rtnl_send_validate(file, lineno, ctx);
+	tst_rtnl_destroy_context(file, lineno, ctx);
+
+	if (!ret) {
+		tst_brk_(file, lineno, TBROK | TTERRNO,
+			"Failed to modify network route");
+	}
+
+	return ret;
+}
+
+static int modify_route_inet(const char *file, const int lineno,
+	unsigned int action, unsigned int flags, const char *ifname,
+	in_addr_t srcaddr, unsigned int srcprefix, in_addr_t dstaddr,
+	unsigned int dstprefix, in_addr_t gateway)
+{
+	void *src = NULL, *dst = NULL, *gw = NULL;
+	size_t srclen = 0, dstlen = 0, gwlen = 0;
+
+	if (srcprefix) {
+		src = &srcaddr;
+		srclen = sizeof(srcaddr);
+	}
+
+	if (dstprefix) {
+		dst = &dstaddr;
+		dstlen = sizeof(dstaddr);
+	}
+
+	if (gateway) {
+		gw = &gateway;
+		gwlen = sizeof(gateway);
+	}
+
+	return modify_route(file, lineno, action, flags, ifname, AF_INET, src,
+		srcprefix, srclen, dst, dstprefix, dstlen, gw, gwlen);
+}
+
+int tst_netdev_add_route(const char *file, const int lineno,
+	const char *ifname, unsigned int family, const void *srcaddr,
+	unsigned int srcprefix, size_t srclen, const void *dstaddr,
+	unsigned int dstprefix, size_t dstlen, const void *gateway,
+	size_t gatewaylen)
+{
+	return modify_route(file, lineno, RTM_NEWROUTE,
+		NLM_F_CREATE | NLM_F_EXCL, ifname, family, srcaddr, srcprefix,
+		srclen, dstaddr, dstprefix, dstlen, gateway, gatewaylen);
+}
+
+int tst_netdev_add_route_inet(const char *file, const int lineno,
+	const char *ifname, in_addr_t srcaddr, unsigned int srcprefix,
+	in_addr_t dstaddr, unsigned int dstprefix, in_addr_t gateway)
+{
+	return modify_route_inet(file, lineno, RTM_NEWROUTE,
+		NLM_F_CREATE | NLM_F_EXCL, ifname, srcaddr, srcprefix, dstaddr,
+		dstprefix, gateway);
+}
+
+int tst_netdev_remove_route(const char *file, const int lineno,
+	const char *ifname, unsigned int family, const void *srcaddr,
+	unsigned int srcprefix, size_t srclen, const void *dstaddr,
+	unsigned int dstprefix, size_t dstlen, const void *gateway,
+	size_t gatewaylen)
+{
+	return modify_route(file, lineno, RTM_DELROUTE, 0, ifname, family,
+		srcaddr, srcprefix, srclen, dstaddr, dstprefix, dstlen,
+		gateway, gatewaylen);
+}
+
+int tst_netdev_remove_route_inet(const char *file, const int lineno,
+	const char *ifname, in_addr_t srcaddr, unsigned int srcprefix,
+	in_addr_t dstaddr, unsigned int dstprefix, in_addr_t gateway)
+{
+	return modify_route_inet(file, lineno, RTM_DELROUTE, 0, ifname,
+		srcaddr, srcprefix, dstaddr, dstprefix, gateway);
+}
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [LTP] [PATCH v3 6/6] Add test for CVE 2020-25705
  2021-05-05  8:18 [LTP] [PATCH v3 1/6] Add SAFE_REALLOC() helper function to LTP library Martin Doucha
                   ` (3 preceding siblings ...)
  2021-05-05  8:18 ` [LTP] [PATCH v3 5/6] Add helper functions for managing network interfaces Martin Doucha
@ 2021-05-05  8:18 ` Martin Doucha
  2021-05-05 10:04   ` Petr Vorel
  2021-05-05 13:06   ` Cyril Hrubis
  2021-05-10  7:42 ` [LTP] [PATCH v3 1/6] Add SAFE_REALLOC() helper function to LTP library Petr Vorel
  5 siblings, 2 replies; 26+ messages in thread
From: Martin Doucha @ 2021-05-05  8:18 UTC (permalink / raw)
  To: ltp

Fixes #742

Signed-off-by: Martin Doucha <mdoucha@suse.cz>
---

Changes since v1: New patch

Changes since v2: Added missing gitignore and runfile entry for the new test

 runtest/cve                    |   1 +
 testcases/cve/.gitignore       |   1 +
 testcases/cve/cve-2020-25705.c | 262 +++++++++++++++++++++++++++++++++
 3 files changed, 264 insertions(+)
 create mode 100644 testcases/cve/cve-2020-25705.c

diff --git a/runtest/cve b/runtest/cve
index f650854f9..eea951576 100644
--- a/runtest/cve
+++ b/runtest/cve
@@ -60,4 +60,5 @@ cve-2019-8912 af_alg07
 cve-2020-11494 pty04
 cve-2020-14386 sendto03
 cve-2020-14416 pty03
+cve-2020-25705 cve-2020-25705
 cve-2020-29373 io_uring02
diff --git a/testcases/cve/.gitignore b/testcases/cve/.gitignore
index 01a3e4c8f..7078d1ac3 100644
--- a/testcases/cve/.gitignore
+++ b/testcases/cve/.gitignore
@@ -10,3 +10,4 @@ stack_clash
 cve-2017-17052
 cve-2017-16939
 cve-2017-17053
+cve-2020-25705
diff --git a/testcases/cve/cve-2020-25705.c b/testcases/cve/cve-2020-25705.c
new file mode 100644
index 000000000..7d6bbafa8
--- /dev/null
+++ b/testcases/cve/cve-2020-25705.c
@@ -0,0 +1,262 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (C) 2020 SUSE LLC
+ * Author: Nicolai Stange <nstange@suse.de>
+ * LTP port: Martin Doucha <mdoucha@suse.cz>
+ *
+ * CVE-2020-25705
+ *
+ * Test of ICMP rate limiting behavior that may be abused for DNS cache
+ * poisoning attack. Send a few batches of 100 packets to a closed UDP port
+ * and count the ICMP errors. If the number of errors is always the same
+ * for each batch (not randomized), the system is vulnerable. Send packets
+ * from multiple IP addresses to bypass per-address ICMP throttling.
+ *
+ * Fixed in:
+ *
+ *  commit b38e7819cae946e2edf869e604af1e65a5d241c5
+ *  Author: Eric Dumazet <edumazet@google.com>
+ *  Date:   Thu Oct 15 11:42:00 2020 -0700
+ *
+ *  icmp: randomize the global rate limiter
+ */
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <linux/if_addr.h>
+#include <linux/errqueue.h>
+
+#include <sched.h>
+#include <limits.h>
+#include "tst_test.h"
+#include "tst_netdevice.h"
+
+#define DSTADDR 0xfa444e02 /* 250.68.78.2 */
+#define SRCADDR_BASE 0xfa444e41 /* 250.68.78.65 */
+#define SRCADDR_COUNT 50
+#define BATCH_COUNT 8
+#define BUFSIZE 1024
+
+static int parentns = -1, childns = -1;
+static int fds[SRCADDR_COUNT];
+
+static void setup(void)
+{
+	struct sockaddr_in ipaddr = { .sin_family = AF_INET };
+	uint32_t addr;
+	int i;
+	int real_uid = getuid();
+	int real_gid = getgid();
+
+	for (i = 0; i < SRCADDR_COUNT; i++)
+		fds[i] = -1;
+
+	SAFE_UNSHARE(CLONE_NEWUSER);
+	SAFE_UNSHARE(CLONE_NEWNET);
+	SAFE_FILE_PRINTF("/proc/self/setgroups", "deny");
+	SAFE_FILE_PRINTF("/proc/self/uid_map", "0 %d 1\n", real_uid);
+	SAFE_FILE_PRINTF("/proc/self/gid_map", "0 %d 1\n", real_gid);
+
+	/*
+	 * Create network namespace to hide the destination interface from
+	 * the test process.
+	 */
+	parentns = SAFE_OPEN("/proc/self/ns/net", O_RDONLY);
+	SAFE_UNSHARE(CLONE_NEWNET);
+
+	/* Do NOT close this FD, or both interfaces will be destroyed */
+	childns = SAFE_OPEN("/proc/self/ns/net", O_RDONLY);
+
+	/* Configure child namespace */
+	CREATE_VETH_PAIR("ltp_veth1", "ltp_veth2");
+	addr = DSTADDR;
+	NETDEV_ADD_ADDRESS_INET("ltp_veth2", htonl(addr), 26,
+		IFA_F_NOPREFIXROUTE);
+	NETDEV_SET_STATE("ltp_veth2", 1);
+	NETDEV_ADD_ROUTE_INET("ltp_veth2", 0, 0, htonl(0xfa444e40), 26,
+		0);
+
+	/* Configure parent namespace */
+	NETDEV_CHANGE_NS_FD("ltp_veth1", parentns);
+	SAFE_SETNS(parentns, CLONE_NEWNET);
+	addr = SRCADDR_BASE; /* 250.68.78.65 */
+
+	for (i = 0; i < SRCADDR_COUNT; i++, addr++) {
+		NETDEV_ADD_ADDRESS_INET("ltp_veth1", htonl(addr), 26,
+			IFA_F_NOPREFIXROUTE);
+	}
+
+	NETDEV_SET_STATE("ltp_veth1", 1);
+	NETDEV_ADD_ROUTE_INET("ltp_veth1", 0, 0, htonl(0xfa444e00), 26, 0);
+	SAFE_FILE_PRINTF("/proc/sys/net/ipv4/conf/ltp_veth1/forwarding", "1");
+
+	/* Open test sockets */
+	for (i = 0; i < SRCADDR_COUNT; i++) {
+		ipaddr.sin_addr.s_addr = htonl(SRCADDR_BASE + i);
+		fds[i] = SAFE_SOCKET(AF_INET, SOCK_DGRAM, 0);
+		SAFE_SETSOCKOPT_INT(fds[i], IPPROTO_IP, IP_RECVERR, 1);
+		SAFE_BIND(fds[i], (struct sockaddr *)&ipaddr, sizeof(ipaddr));
+	}
+}
+
+static int count_icmp_errors(int fd)
+{
+	int error_count = 0;
+	ssize_t len;
+	char msgbuf[BUFSIZE], errbuf[BUFSIZE];
+	struct sockaddr_in addr;
+	struct cmsghdr *cmsg;
+	struct sock_extended_err exterr;
+	struct iovec iov = {
+		.iov_base = msgbuf,
+		.iov_len = BUFSIZE
+	};
+
+	while (1) {
+		struct msghdr msg = {
+			.msg_name = (struct sockaddr *)&addr,
+			.msg_namelen = sizeof(addr),
+			.msg_iov = &iov,
+			.msg_iovlen = 1,
+			.msg_flags = 0,
+			.msg_control = errbuf,
+			.msg_controllen = BUFSIZE
+		};
+
+		memset(errbuf, 0, BUFSIZE);
+		errno = 0;
+		len = recvmsg(fd, &msg, MSG_ERRQUEUE);
+
+		if (len == -1) {
+			if (errno == EWOULDBLOCK || errno == EAGAIN)
+				break;
+
+			tst_brk(TBROK | TERRNO, "recvmsg() failed");
+		}
+
+		if (len < 0) {
+			tst_brk(TBROK | TERRNO,
+				"Invalid recvmsg() return value %zd", len);
+		}
+
+		for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
+			cmsg = CMSG_NXTHDR(&msg, cmsg)) {
+			if (cmsg->cmsg_level != SOL_IP)
+				continue;
+
+			if (cmsg->cmsg_type != IP_RECVERR)
+				continue;
+
+			memcpy(&exterr, CMSG_DATA(cmsg), sizeof(exterr));
+
+			if (exterr.ee_origin != SO_EE_ORIGIN_ICMP)
+				tst_brk(TBROK, "Unexpected non-ICMP error");
+
+			if (exterr.ee_errno != ECONNREFUSED) {
+				TST_ERR = exterr.ee_errno;
+				tst_brk(TBROK | TTERRNO,
+					"Unexpected ICMP error");
+			}
+
+			error_count++;
+		}
+	}
+
+	return error_count;
+}
+
+static int packet_batch(const struct sockaddr *addr, socklen_t addrsize)
+{
+	int i, j, error_count = 0;
+	char data = 0;
+
+	for (i = 0; i < SRCADDR_COUNT; i++) {
+		for (j = 0; j < 2; j++) {
+			error_count += count_icmp_errors(fds[i]);
+			TEST(sendto(fds[i], &data, sizeof(data), 0, addr,
+				addrsize));
+
+			if (TST_RET == -1) {
+				if (TST_ERR == ECONNREFUSED) {
+					j--; /* flush ICMP errors and retry */
+					continue;
+				}
+
+				tst_brk(TBROK | TTERRNO, "sento() failed");
+			}
+
+			if (TST_RET < 0) {
+				tst_brk(TBROK | TTERRNO,
+					"Invalid sento() return value %ld",
+					TST_RET);
+			}
+		}
+	}
+
+	/* Wait and collect pending ICMP errors */
+	sleep(2);
+
+	for (i = 0; i < SRCADDR_COUNT; i++)
+		error_count += count_icmp_errors(fds[i]);
+
+	return error_count;
+}
+
+static void run(void)
+{
+	int i, errors_baseline, errors;
+	struct sockaddr_in addr = {
+		.sin_family = AF_INET,
+		.sin_port = TST_GET_UNUSED_PORT(AF_INET, SOCK_DGRAM),
+		.sin_addr = { htonl(DSTADDR) }
+	};
+
+	errors_baseline = packet_batch((struct sockaddr *)&addr, sizeof(addr));
+	errors = errors_baseline;
+	tst_res(TINFO, "Batch 0: Got %d ICMP errors", errors);
+
+	for (i = 1; i < BATCH_COUNT && errors == errors_baseline; i++) {
+		errors = packet_batch((struct sockaddr *)&addr, sizeof(addr));
+		tst_res(TINFO, "Batch %d: Got %d ICMP errors", i, errors);
+	}
+
+	if (errors == errors_baseline) {
+		tst_res(TFAIL,
+			"ICMP rate limit not randomized, system is vulnerable");
+		return;
+	}
+
+	tst_res(TPASS, "ICMP rate limit is randomized");
+}
+
+static void cleanup(void)
+{
+	int i;
+
+	for (i = 0; i < SRCADDR_COUNT; i++)
+		if (fds[i] >= 0)
+			SAFE_CLOSE(fds[i]);
+
+	if (childns >= 0)
+		SAFE_CLOSE(childns);
+
+	if (parentns >= 0)
+		SAFE_CLOSE(parentns);
+}
+
+static struct tst_test test = {
+	.test_all = run,
+	.setup = setup,
+	.cleanup = cleanup,
+	.needs_kconfigs = (const char *[]) {
+		"CONFIG_USER_NS=y",
+		"CONFIG_NET_NS=y",
+		NULL
+	},
+	.tags = (const struct tst_tag[]) {
+		{"linux-git", "b38e7819cae9"},
+		{"CVE", "2020-25705"},
+		{}
+	}
+};
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 26+ messages in thread

* [LTP] [PATCH v3 3/6] Add SAFE_IOCTL() variant for library code
  2021-05-05  8:18 ` [LTP] [PATCH v3 3/6] Add SAFE_IOCTL() variant for library code Martin Doucha
@ 2021-05-05  9:12   ` Cyril Hrubis
  2021-05-10  7:57   ` Petr Vorel
  1 sibling, 0 replies; 26+ messages in thread
From: Cyril Hrubis @ 2021-05-05  9:12 UTC (permalink / raw)
  To: ltp

Hi!
Reviewed-by: Cyril Hrubis <chrubis@suse.cz>

-- 
Cyril Hrubis
chrubis@suse.cz

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [LTP] [PATCH v3 6/6] Add test for CVE 2020-25705
  2021-05-05  8:18 ` [LTP] [PATCH v3 6/6] Add test for CVE 2020-25705 Martin Doucha
@ 2021-05-05 10:04   ` Petr Vorel
  2021-05-05 10:33     ` Martin Doucha
  2021-05-05 13:06   ` Cyril Hrubis
  1 sibling, 1 reply; 26+ messages in thread
From: Petr Vorel @ 2021-05-05 10:04 UTC (permalink / raw)
  To: ltp

> Fixes #742

LGTM. Few unimportant comments below.

Reviewed-by: Petr Vorel <pvorel@suse.cz>

...
> diff --git a/testcases/cve/cve-2020-25705.c b/testcases/cve/cve-2020-25705.c
> new file mode 100644
> index 000000000..7d6bbafa8
> --- /dev/null
> +++ b/testcases/cve/cve-2020-25705.c
> @@ -0,0 +1,262 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2020 SUSE LLC
> + * Author: Nicolai Stange <nstange@suse.de>
> + * LTP port: Martin Doucha <mdoucha@suse.cz>
> + *
> + * CVE-2020-25705
> + *
> + * Test of ICMP rate limiting behavior that may be abused for DNS cache
> + * poisoning attack. Send a few batches of 100 packets to a closed UDP port
> + * and count the ICMP errors. If the number of errors is always the same
> + * for each batch (not randomized), the system is vulnerable. Send packets
> + * from multiple IP addresses to bypass per-address ICMP throttling.
We probably turn this into docparse during merge.

> + *
> + * Fixed in:
> + *
> + *  commit b38e7819cae946e2edf869e604af1e65a5d241c5
> + *  Author: Eric Dumazet <edumazet@google.com>
> + *  Date:   Thu Oct 15 11:42:00 2020 -0700
> + *
> + *  icmp: randomize the global rate limiter
> + */
> +
> +#include <sys/socket.h>
> +#include <netinet/in.h>
> +#include <arpa/inet.h>
> +#include <linux/if_addr.h>
> +#include <linux/errqueue.h>

#include <time.h>

to fix build failure on MUSL:

cve-2020-25705.c:262:1: warning: missing initializer for field 'needs_cmds' of 'struct tst_test' [-Wmissing-field-initializers]
https://travis-ci.org/github/pevik/ltp/jobs/769551152

> +#include <sched.h>
> +#include <limits.h>
> +#include "tst_test.h"
> +#include "tst_netdevice.h"
> +
> +#define DSTADDR 0xfa444e02 /* 250.68.78.2 */
> +#define SRCADDR_BASE 0xfa444e41 /* 250.68.78.65 */
> +#define SRCADDR_COUNT 50
> +#define BATCH_COUNT 8
> +#define BUFSIZE 1024
> +
> +static int parentns = -1, childns = -1;
> +static int fds[SRCADDR_COUNT];
> +
> +static void setup(void)
> +{
...
> +	/*
> +	 * Create network namespace to hide the destination interface from
> +	 * the test process.
> +	 */
> +	parentns = SAFE_OPEN("/proc/self/ns/net", O_RDONLY);
> +	SAFE_UNSHARE(CLONE_NEWNET);
> +
> +	/* Do NOT close this FD, or both interfaces will be destroyed */
> +	childns = SAFE_OPEN("/proc/self/ns/net", O_RDONLY);
> +
> +	/* Configure child namespace */
> +	CREATE_VETH_PAIR("ltp_veth1", "ltp_veth2");
> +	addr = DSTADDR;
> +	NETDEV_ADD_ADDRESS_INET("ltp_veth2", htonl(addr), 26,
> +		IFA_F_NOPREFIXROUTE);

I wonder if it'd be useful *later* (not bothering with it now) to allow tests
just declare .needs_netdevice = 1 and have generic network setup done (similarly
it's done in tst_net.sh). Or just define addresses a prefixes and do library to
do the setup.

> +	NETDEV_SET_STATE("ltp_veth2", 1);
> +	NETDEV_ADD_ROUTE_INET("ltp_veth2", 0, 0, htonl(0xfa444e40), 26,
nit: maybe define 0xfa444e40 (and 0xfa444e00) and 26 as constants?
> +		0);
> +
> +	/* Configure parent namespace */
> +	NETDEV_CHANGE_NS_FD("ltp_veth1", parentns);
> +	SAFE_SETNS(parentns, CLONE_NEWNET);
> +	addr = SRCADDR_BASE; /* 250.68.78.65 */
nit: maybe repeating the address in the comment is not needed.
> +
> +	for (i = 0; i < SRCADDR_COUNT; i++, addr++) {
> +		NETDEV_ADD_ADDRESS_INET("ltp_veth1", htonl(addr), 26,
> +			IFA_F_NOPREFIXROUTE);
> +	}
> +
> +	NETDEV_SET_STATE("ltp_veth1", 1);
> +	NETDEV_ADD_ROUTE_INET("ltp_veth1", 0, 0, htonl(0xfa444e00), 26, 0);

> +	SAFE_FILE_PRINTF("/proc/sys/net/ipv4/conf/ltp_veth1/forwarding", "1");
> +
> +	/* Open test sockets */
> +	for (i = 0; i < SRCADDR_COUNT; i++) {
> +		ipaddr.sin_addr.s_addr = htonl(SRCADDR_BASE + i);
> +		fds[i] = SAFE_SOCKET(AF_INET, SOCK_DGRAM, 0);
> +		SAFE_SETSOCKOPT_INT(fds[i], IPPROTO_IP, IP_RECVERR, 1);
> +		SAFE_BIND(fds[i], (struct sockaddr *)&ipaddr, sizeof(ipaddr));
> +	}
> +}
> +
> +static int count_icmp_errors(int fd)
> +{
> +	int error_count = 0;
> +	ssize_t len;
> +	char msgbuf[BUFSIZE], errbuf[BUFSIZE];
> +	struct sockaddr_in addr;
> +	struct cmsghdr *cmsg;
> +	struct sock_extended_err exterr;
> +	struct iovec iov = {
> +		.iov_base = msgbuf,
> +		.iov_len = BUFSIZE
> +	};
> +
> +	while (1) {
> +		struct msghdr msg = {
> +			.msg_name = (struct sockaddr *)&addr,
> +			.msg_namelen = sizeof(addr),
> +			.msg_iov = &iov,
> +			.msg_iovlen = 1,
> +			.msg_flags = 0,
> +			.msg_control = errbuf,
> +			.msg_controllen = BUFSIZE
> +		};
> +
> +		memset(errbuf, 0, BUFSIZE);
> +		errno = 0;
> +		len = recvmsg(fd, &msg, MSG_ERRQUEUE);
> +
> +		if (len == -1) {
> +			if (errno == EWOULDBLOCK || errno == EAGAIN)
> +				break;
> +
> +			tst_brk(TBROK | TERRNO, "recvmsg() failed");
> +		}
> +
> +		if (len < 0) {
> +			tst_brk(TBROK | TERRNO,
> +				"Invalid recvmsg() return value %zd", len);
> +		}
> +
> +		for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
> +			cmsg = CMSG_NXTHDR(&msg, cmsg)) {
> +			if (cmsg->cmsg_level != SOL_IP)
> +				continue;
> +
> +			if (cmsg->cmsg_type != IP_RECVERR)
> +				continue;
> +
> +			memcpy(&exterr, CMSG_DATA(cmsg), sizeof(exterr));
> +
> +			if (exterr.ee_origin != SO_EE_ORIGIN_ICMP)
> +				tst_brk(TBROK, "Unexpected non-ICMP error");
> +
> +			if (exterr.ee_errno != ECONNREFUSED) {
> +				TST_ERR = exterr.ee_errno;
> +				tst_brk(TBROK | TTERRNO,
> +					"Unexpected ICMP error");
> +			}
> +
> +			error_count++;
> +		}
> +	}
> +
> +	return error_count;
> +}

FYI I tested the test on several VM. Very old kernel detects problem only on
more runs. But given it's 3.16 (and b38e7819cae9 is a fix for 4cdf507d5452 from
v3.18-rc1 we can ignore this).

Kind regards,
Petr

# ./cve-2020-25705
tst_kconfig.c:64: TINFO: Parsing kernel config '/boot/config-3.16.0-11-amd64'
tst_test.c:1313: TINFO: Timeout per run is 0h 05m 00s
cve-2020-25705.c:217: TINFO: Batch 0: Got 85 ICMP errors
cve-2020-25705.c:221: TINFO: Batch 1: Got 100 ICMP errors
cve-2020-25705.c:230: TPASS: ICMP rate limit is randomized

-i2
# ./cve-2020-25705 -i2
tst_kconfig.c:64: TINFO: Parsing kernel config '/boot/config-3.16.0-11-amd64'
tst_test.c:1313: TINFO: Timeout per run is 0h 05m 00s
cve-2020-25705.c:217: TINFO: Batch 0: Got 85 ICMP errors
cve-2020-25705.c:221: TINFO: Batch 1: Got 100 ICMP errors
cve-2020-25705.c:230: TPASS: ICMP rate limit is randomized
cve-2020-25705.c:217: TINFO: Batch 0: Got 100 ICMP errors
cve-2020-25705.c:221: TINFO: Batch 1: Got 100 ICMP errors
cve-2020-25705.c:221: TINFO: Batch 2: Got 100 ICMP errors
cve-2020-25705.c:221: TINFO: Batch 3: Got 100 ICMP errors
cve-2020-25705.c:221: TINFO: Batch 4: Got 100 ICMP errors
cve-2020-25705.c:221: TINFO: Batch 5: Got 100 ICMP errors
cve-2020-25705.c:221: TINFO: Batch 6: Got 100 ICMP errors
cve-2020-25705.c:221: TINFO: Batch 7: Got 100 ICMP errors
cve-2020-25705.c:226: TFAIL: ICMP rate limit not randomized, system is vulnerable

HINT: You _MAY_ be missing kernel fixes, see:

https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=b38e7819cae9

HINT: You _MAY_ be vulnerable to CVE(s), see:

https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2020-25705

Summary:
passed   1
failed   1
broken   0
skipped  0
warnings 0

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [LTP] [PATCH v3 4/6] Add rtnetlink helper library
  2021-05-05  8:18 ` [LTP] [PATCH v3 4/6] Add rtnetlink helper library Martin Doucha
@ 2021-05-05 10:17   ` Petr Vorel
  2021-05-05 10:25     ` Martin Doucha
  2021-05-05 11:26   ` Petr Vorel
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 26+ messages in thread
From: Petr Vorel @ 2021-05-05 10:17 UTC (permalink / raw)
  To: ltp

Hi Martin,

it'd be great if you (later) add docs from v1 cover letter [1] into
doc/test-writing-guidelines.txt.

Kind regards,
Petr

[1] https://patchwork.ozlabs.org/project/ltp/cover/20210426111918.4304-1-mdoucha@suse.cz/

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [LTP] [PATCH v3 4/6] Add rtnetlink helper library
  2021-05-05 10:17   ` Petr Vorel
@ 2021-05-05 10:25     ` Martin Doucha
  2021-05-05 11:24       ` Petr Vorel
  0 siblings, 1 reply; 26+ messages in thread
From: Martin Doucha @ 2021-05-05 10:25 UTC (permalink / raw)
  To: ltp

On 05. 05. 21 12:17, Petr Vorel wrote:
> Hi Martin,
> 
> it'd be great if you (later) add docs from v1 cover letter [1] into
> doc/test-writing-guidelines.txt.
> 
> [1] https://patchwork.ozlabs.org/project/ltp/cover/20210426111918.4304-1-mdoucha@suse.cz/

I think we should discuss the documentation structure first.
test-writing-guidelines.txt is already too long and unreadable. We
should probably split it by topic and put the network management docs
into a separate file from the outset since I'm planning to build an
entire packetdrill-like userspace TCP stack on top of it in the future.

-- 
Martin Doucha   mdoucha@suse.cz
QA Engineer for Software Maintenance
SUSE LINUX, s.r.o.
CORSO IIa
Krizikova 148/34
186 00 Prague 8
Czech Republic

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [LTP] [PATCH v3 6/6] Add test for CVE 2020-25705
  2021-05-05 10:04   ` Petr Vorel
@ 2021-05-05 10:33     ` Martin Doucha
  2021-05-05 11:13       ` Petr Vorel
  0 siblings, 1 reply; 26+ messages in thread
From: Martin Doucha @ 2021-05-05 10:33 UTC (permalink / raw)
  To: ltp

On 05. 05. 21 12:04, Petr Vorel wrote:
> I wonder if it'd be useful *later* (not bothering with it now) to allow tests
> just declare .needs_netdevice = 1 and have generic network setup done (similarly
> it's done in tst_net.sh). Or just define addresses a prefixes and do library to
> do the setup.

Sounds like a good idea.

> 
>> +	NETDEV_SET_STATE("ltp_veth2", 1);
>> +	NETDEV_ADD_ROUTE_INET("ltp_veth2", 0, 0, htonl(0xfa444e40), 26,
> nit: maybe define 0xfa444e40 (and 0xfa444e00) and 26 as constants?
>> +		0);
>> +
>> +	/* Configure parent namespace */
>> +	NETDEV_CHANGE_NS_FD("ltp_veth1", parentns);
>> +	SAFE_SETNS(parentns, CLONE_NEWNET);
>> +	addr = SRCADDR_BASE; /* 250.68.78.65 */
> nit: maybe repeating the address in the comment is not needed.

Yes, I should fix this and the <time.h> issue. Please push everything up
to patch 5 and then I'll resubmit v4 just for this patch.

> FYI I tested the test on several VM. Very old kernel detects problem only on
> more runs. But given it's 3.16 (and b38e7819cae9 is a fix for 4cdf507d5452 from
> v3.18-rc1 we can ignore this).

Pass is expected here. Vanilla v3.16 AFAIK does not have the global ICMP
rate limiter which introduced the real vulnerability in the first place.

-- 
Martin Doucha   mdoucha@suse.cz
QA Engineer for Software Maintenance
SUSE LINUX, s.r.o.
CORSO IIa
Krizikova 148/34
186 00 Prague 8
Czech Republic

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [LTP] [PATCH v3 6/6] Add test for CVE 2020-25705
  2021-05-05 10:33     ` Martin Doucha
@ 2021-05-05 11:13       ` Petr Vorel
  0 siblings, 0 replies; 26+ messages in thread
From: Petr Vorel @ 2021-05-05 11:13 UTC (permalink / raw)
  To: ltp

Hi Martin,

> Yes, I should fix this and the <time.h> issue. Please push everything up
> to patch 5 and then I'll resubmit v4 just for this patch.
NOTE: <time.h> must be included *before* <linux/errqueue.h>
(maybe bug in musl headers).
I suppose Cyril will merge these 4 patches soon.

> > FYI I tested the test on several VM. Very old kernel detects problem only on
> > more runs. But given it's 3.16 (and b38e7819cae9 is a fix for 4cdf507d5452 from
> > v3.18-rc1 we can ignore this).

> Pass is expected here. Vanilla v3.16 AFAIK does not have the global ICMP
> rate limiter which introduced the real vulnerability in the first place.
Sure. I was just surprised to get different result on -i1 and on -i >= 2.

Kind regards,
Petr

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [LTP] [PATCH v3 4/6] Add rtnetlink helper library
  2021-05-05 10:25     ` Martin Doucha
@ 2021-05-05 11:24       ` Petr Vorel
  0 siblings, 0 replies; 26+ messages in thread
From: Petr Vorel @ 2021-05-05 11:24 UTC (permalink / raw)
  To: ltp

> On 05. 05. 21 12:17, Petr Vorel wrote:
> > Hi Martin,

> > it'd be great if you (later) add docs from v1 cover letter [1] into
> > doc/test-writing-guidelines.txt.

> > [1] https://patchwork.ozlabs.org/project/ltp/cover/20210426111918.4304-1-mdoucha@suse.cz/

> I think we should discuss the documentation structure first.
> test-writing-guidelines.txt is already too long and unreadable.
Agree. I was thinking this week to at least split C and shell API, that would
help a bit.

> We should probably split it by topic and put the network management docs
> into a separate file from the outset since I'm planning to build an
> entire packetdrill-like userspace TCP stack on top of it in the future.
Thanks a lot!

Kind regards,
Petr

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [LTP] [PATCH v3 4/6] Add rtnetlink helper library
  2021-05-05  8:18 ` [LTP] [PATCH v3 4/6] Add rtnetlink helper library Martin Doucha
  2021-05-05 10:17   ` Petr Vorel
@ 2021-05-05 11:26   ` Petr Vorel
  2021-05-05 12:16     ` Cyril Hrubis
  2021-05-05 13:15     ` Martin Doucha
  2021-05-05 12:14   ` Cyril Hrubis
  2021-05-10  9:07   ` Petr Vorel
  3 siblings, 2 replies; 26+ messages in thread
From: Petr Vorel @ 2021-05-05 11:26 UTC (permalink / raw)
  To: ltp

> This library provides simple interface for creating arbitrary rtnetlink
> messages with complex attributes, sending requests and receiving results.

> Changes since v1:
> - fixed error handling in tst_rtnl_create_context()
> - renamed tst_rtnl_free_context() to tst_rtnl_destroy_context()
> - switched from select() to poll() in tst_rtnl_wait()
> - use tst_rtnl_add_message() for adding NLMSG_DONE
> - receive all pending messages in tst_rtnl_recv(), not just one
> - use inline struct initialization where possible

>  include/tst_rtnetlink.h | 106 +++++++++++
>  lib/tst_rtnetlink.c     | 407 ++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 513 insertions(+)
>  create mode 100644 include/tst_rtnetlink.h
>  create mode 100644 lib/tst_rtnetlink.c

> diff --git a/include/tst_rtnetlink.h b/include/tst_rtnetlink.h
> new file mode 100644
> index 000000000..12ec258f2
> --- /dev/null
> +++ b/include/tst_rtnetlink.h
> @@ -0,0 +1,106 @@
> +/* SPDX-License-Identifier: GPL-2.0-or-later
> + * Copyright (c) 2021 Linux Test Project
> + */
> +
> +#ifndef TST_RTNETLINK_H
> +#define TST_RTNETLINK_H

I guess this header will always be internal, right?  (only tst_netdevice.h is
going to be used in tests) Otherwise it might need to include headers
(<linux/netlink.h>, and also <unistd.h> or <sys/types.h> for ssize_t which are
now only in C library sources).

...
> +int tst_rtnl_add_message(const char *file, const int lineno,
> +	struct tst_rtnl_context *ctx, const struct nlmsghdr *header,
> +	const void *payload, size_t payload_size)
> +{
> +	size_t size;
> +	unsigned int extra_flags = 0;
> +
> +	if (!tst_rtnl_grow_buffer(file, lineno, ctx, NLMSG_SPACE(payload_size)))
Shouldn't there be an error message?
Or maybe at tst_rtnl_grow_buffer() on if (!buf)

Reviewed-by: Petr Vorel <pvorel@suse.cz>
Nice code, thanks!

Kind regards,
Petr

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [LTP] [PATCH v3 4/6] Add rtnetlink helper library
  2021-05-05  8:18 ` [LTP] [PATCH v3 4/6] Add rtnetlink helper library Martin Doucha
  2021-05-05 10:17   ` Petr Vorel
  2021-05-05 11:26   ` Petr Vorel
@ 2021-05-05 12:14   ` Cyril Hrubis
  2021-05-10  9:07   ` Petr Vorel
  3 siblings, 0 replies; 26+ messages in thread
From: Cyril Hrubis @ 2021-05-05 12:14 UTC (permalink / raw)
  To: ltp

Hi!
Reviewed-by: Cyril Hrubis <chrubis@suse.cz>

-- 
Cyril Hrubis
chrubis@suse.cz

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [LTP] [PATCH v3 4/6] Add rtnetlink helper library
  2021-05-05 11:26   ` Petr Vorel
@ 2021-05-05 12:16     ` Cyril Hrubis
  2021-05-05 20:20       ` Petr Vorel
  2021-05-05 13:15     ` Martin Doucha
  1 sibling, 1 reply; 26+ messages in thread
From: Cyril Hrubis @ 2021-05-05 12:16 UTC (permalink / raw)
  To: ltp

Hi!
> > +int tst_rtnl_add_message(const char *file, const int lineno,
> > +	struct tst_rtnl_context *ctx, const struct nlmsghdr *header,
> > +	const void *payload, size_t payload_size)
> > +{
> > +	size_t size;
> > +	unsigned int extra_flags = 0;
> > +
> > +	if (!tst_rtnl_grow_buffer(file, lineno, ctx, NLMSG_SPACE(payload_size)))
> Shouldn't there be an error message?
> Or maybe at tst_rtnl_grow_buffer() on if (!buf)

As far as I can tell we will get error message from the safe_realloc()

> Reviewed-by: Petr Vorel <pvorel@suse.cz>
> Nice code, thanks!
> 
> Kind regards,
> Petr

-- 
Cyril Hrubis
chrubis@suse.cz

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [LTP] [PATCH v3 5/6] Add helper functions for managing network interfaces
  2021-05-05  8:18 ` [LTP] [PATCH v3 5/6] Add helper functions for managing network interfaces Martin Doucha
@ 2021-05-05 12:39   ` Cyril Hrubis
  0 siblings, 0 replies; 26+ messages in thread
From: Cyril Hrubis @ 2021-05-05 12:39 UTC (permalink / raw)
  To: ltp

Hi!
Reviewed-by: Cyril Hrubis <chrubis@suse.cz>

-- 
Cyril Hrubis
chrubis@suse.cz

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [LTP] [PATCH v3 6/6] Add test for CVE 2020-25705
  2021-05-05  8:18 ` [LTP] [PATCH v3 6/6] Add test for CVE 2020-25705 Martin Doucha
  2021-05-05 10:04   ` Petr Vorel
@ 2021-05-05 13:06   ` Cyril Hrubis
  2021-05-05 15:54     ` Martin Doucha
  1 sibling, 1 reply; 26+ messages in thread
From: Cyril Hrubis @ 2021-05-05 13:06 UTC (permalink / raw)
  To: ltp

Hi!
> diff --git a/testcases/cve/cve-2020-25705.c b/testcases/cve/cve-2020-25705.c

Can we please name the file icmp_rate_limit01.c or something more human
readable than the cve-2020-25705?

> new file mode 100644
> index 000000000..7d6bbafa8
> --- /dev/null
> +++ b/testcases/cve/cve-2020-25705.c
> @@ -0,0 +1,262 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (C) 2020 SUSE LLC
> + * Author: Nicolai Stange <nstange@suse.de>
> + * LTP port: Martin Doucha <mdoucha@suse.cz>
> + *
> + * CVE-2020-25705
> + *
> + * Test of ICMP rate limiting behavior that may be abused for DNS cache
> + * poisoning attack. Send a few batches of 100 packets to a closed UDP port
> + * and count the ICMP errors. If the number of errors is always the same
> + * for each batch (not randomized), the system is vulnerable. Send packets
> + * from multiple IP addresses to bypass per-address ICMP throttling.
> + *
> + * Fixed in:
> + *
> + *  commit b38e7819cae946e2edf869e604af1e65a5d241c5
> + *  Author: Eric Dumazet <edumazet@google.com>
> + *  Date:   Thu Oct 15 11:42:00 2020 -0700
> + *
> + *  icmp: randomize the global rate limiter
> + */
> +
> +#include <sys/socket.h>
> +#include <netinet/in.h>
> +#include <arpa/inet.h>
> +#include <linux/if_addr.h>
> +#include <linux/errqueue.h>
> +
> +#include <sched.h>
> +#include <limits.h>
> +#include "tst_test.h"
> +#include "tst_netdevice.h"
> +
> +#define DSTADDR 0xfa444e02 /* 250.68.78.2 */
> +#define SRCADDR_BASE 0xfa444e41 /* 250.68.78.65 */
> +#define SRCADDR_COUNT 50
> +#define BATCH_COUNT 8
> +#define BUFSIZE 1024
> +
> +static int parentns = -1, childns = -1;
> +static int fds[SRCADDR_COUNT];
> +
> +static void setup(void)
> +{
> +	struct sockaddr_in ipaddr = { .sin_family = AF_INET };
> +	uint32_t addr;
> +	int i;
> +	int real_uid = getuid();
> +	int real_gid = getgid();
> +
> +	for (i = 0; i < SRCADDR_COUNT; i++)
> +		fds[i] = -1;
> +
> +	SAFE_UNSHARE(CLONE_NEWUSER);
> +	SAFE_UNSHARE(CLONE_NEWNET);
> +	SAFE_FILE_PRINTF("/proc/self/setgroups", "deny");
> +	SAFE_FILE_PRINTF("/proc/self/uid_map", "0 %d 1\n", real_uid);
> +	SAFE_FILE_PRINTF("/proc/self/gid_map", "0 %d 1\n", real_gid);
> +
> +	/*
> +	 * Create network namespace to hide the destination interface from
> +	 * the test process.
> +	 */
> +	parentns = SAFE_OPEN("/proc/self/ns/net", O_RDONLY);
> +	SAFE_UNSHARE(CLONE_NEWNET);
> +
> +	/* Do NOT close this FD, or both interfaces will be destroyed */
> +	childns = SAFE_OPEN("/proc/self/ns/net", O_RDONLY);
> +
> +	/* Configure child namespace */
> +	CREATE_VETH_PAIR("ltp_veth1", "ltp_veth2");
> +	addr = DSTADDR;
> +	NETDEV_ADD_ADDRESS_INET("ltp_veth2", htonl(addr), 26,
> +		IFA_F_NOPREFIXROUTE);
> +	NETDEV_SET_STATE("ltp_veth2", 1);
> +	NETDEV_ADD_ROUTE_INET("ltp_veth2", 0, 0, htonl(0xfa444e40), 26,
> +		0);
> +
> +	/* Configure parent namespace */
> +	NETDEV_CHANGE_NS_FD("ltp_veth1", parentns);
> +	SAFE_SETNS(parentns, CLONE_NEWNET);
> +	addr = SRCADDR_BASE; /* 250.68.78.65 */
> +
> +	for (i = 0; i < SRCADDR_COUNT; i++, addr++) {
> +		NETDEV_ADD_ADDRESS_INET("ltp_veth1", htonl(addr), 26,
> +			IFA_F_NOPREFIXROUTE);
> +	}
> +
> +	NETDEV_SET_STATE("ltp_veth1", 1);
> +	NETDEV_ADD_ROUTE_INET("ltp_veth1", 0, 0, htonl(0xfa444e00), 26, 0);
> +	SAFE_FILE_PRINTF("/proc/sys/net/ipv4/conf/ltp_veth1/forwarding", "1");
> +
> +	/* Open test sockets */
> +	for (i = 0; i < SRCADDR_COUNT; i++) {
> +		ipaddr.sin_addr.s_addr = htonl(SRCADDR_BASE + i);
> +		fds[i] = SAFE_SOCKET(AF_INET, SOCK_DGRAM, 0);
> +		SAFE_SETSOCKOPT_INT(fds[i], IPPROTO_IP, IP_RECVERR, 1);
> +		SAFE_BIND(fds[i], (struct sockaddr *)&ipaddr, sizeof(ipaddr));
> +	}
> +}
> +
> +static int count_icmp_errors(int fd)
> +{
> +	int error_count = 0;
> +	ssize_t len;
> +	char msgbuf[BUFSIZE], errbuf[BUFSIZE];
> +	struct sockaddr_in addr;
> +	struct cmsghdr *cmsg;
> +	struct sock_extended_err exterr;
> +	struct iovec iov = {
> +		.iov_base = msgbuf,
> +		.iov_len = BUFSIZE
> +	};
> +
> +	while (1) {
> +		struct msghdr msg = {
> +			.msg_name = (struct sockaddr *)&addr,
> +			.msg_namelen = sizeof(addr),
> +			.msg_iov = &iov,
> +			.msg_iovlen = 1,
> +			.msg_flags = 0,
> +			.msg_control = errbuf,
> +			.msg_controllen = BUFSIZE
> +		};
> +
> +		memset(errbuf, 0, BUFSIZE);
> +		errno = 0;
> +		len = recvmsg(fd, &msg, MSG_ERRQUEUE);
> +
> +		if (len == -1) {
> +			if (errno == EWOULDBLOCK || errno == EAGAIN)
> +				break;
> +
> +			tst_brk(TBROK | TERRNO, "recvmsg() failed");
> +		}
> +
> +		if (len < 0) {
> +			tst_brk(TBROK | TERRNO,
> +				"Invalid recvmsg() return value %zd", len);
> +		}
> +
> +		for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
> +			cmsg = CMSG_NXTHDR(&msg, cmsg)) {
> +			if (cmsg->cmsg_level != SOL_IP)
> +				continue;
> +
> +			if (cmsg->cmsg_type != IP_RECVERR)
> +				continue;
> +
> +			memcpy(&exterr, CMSG_DATA(cmsg), sizeof(exterr));
> +
> +			if (exterr.ee_origin != SO_EE_ORIGIN_ICMP)
> +				tst_brk(TBROK, "Unexpected non-ICMP error");
> +
> +			if (exterr.ee_errno != ECONNREFUSED) {
> +				TST_ERR = exterr.ee_errno;
> +				tst_brk(TBROK | TTERRNO,
> +					"Unexpected ICMP error");
> +			}
> +
> +			error_count++;
> +		}
> +	}
> +
> +	return error_count;
> +}
> +
> +static int packet_batch(const struct sockaddr *addr, socklen_t addrsize)
> +{
> +	int i, j, error_count = 0;
> +	char data = 0;
> +
> +	for (i = 0; i < SRCADDR_COUNT; i++) {
> +		for (j = 0; j < 2; j++) {
> +			error_count += count_icmp_errors(fds[i]);
> +			TEST(sendto(fds[i], &data, sizeof(data), 0, addr,
> +				addrsize));
> +
> +			if (TST_RET == -1) {
> +				if (TST_ERR == ECONNREFUSED) {
> +					j--; /* flush ICMP errors and retry */
> +					continue;
> +				}
> +
> +				tst_brk(TBROK | TTERRNO, "sento() failed");
> +			}
> +
> +			if (TST_RET < 0) {
> +				tst_brk(TBROK | TTERRNO,
> +					"Invalid sento() return value %ld",
> +					TST_RET);
> +			}
> +		}
> +	}
> +
> +	/* Wait and collect pending ICMP errors */
> +	sleep(2);

Can we do something better than sleep() here?

Maybe just loop over the loop that reads errors with some short sleep
and exit if we haven't got any new errors for a while?

Something as:

	unsigned int timeout_ms = 2000;
	unsigned int no_changes_ms = 0;

	while (timeout_ms) {
		int last_err_cnt = error_count;

		for (i = 0; i < SRCADDR_COUNT; i++)
			error_count += count_icmp_errors(fds[i]);

		if (last_err_cnt == error_count)
			no_changes_ms++;
		else
			no_changes_ms = 0;


		if (no_changes_ms > 500)
			break;

		usleep(1000);
		timeout_ms--;
	}


> +	for (i = 0; i < SRCADDR_COUNT; i++)
> +		error_count += count_icmp_errors(fds[i]);
> +
> +	return error_count;
> +}
> +
> +static void run(void)
> +{
> +	int i, errors_baseline, errors;
> +	struct sockaddr_in addr = {
> +		.sin_family = AF_INET,
> +		.sin_port = TST_GET_UNUSED_PORT(AF_INET, SOCK_DGRAM),
> +		.sin_addr = { htonl(DSTADDR) }
> +	};
> +
> +	errors_baseline = packet_batch((struct sockaddr *)&addr, sizeof(addr));
> +	errors = errors_baseline;
> +	tst_res(TINFO, "Batch 0: Got %d ICMP errors", errors);
> +
> +	for (i = 1; i < BATCH_COUNT && errors == errors_baseline; i++) {
> +		errors = packet_batch((struct sockaddr *)&addr, sizeof(addr));
> +		tst_res(TINFO, "Batch %d: Got %d ICMP errors", i, errors);
> +	}
> +
> +	if (errors == errors_baseline) {
> +		tst_res(TFAIL,
> +			"ICMP rate limit not randomized, system is vulnerable");
> +		return;
> +	}
> +
> +	tst_res(TPASS, "ICMP rate limit is randomized");
> +}
> +
> +static void cleanup(void)
> +{
> +	int i;
> +
> +	for (i = 0; i < SRCADDR_COUNT; i++)
> +		if (fds[i] >= 0)
> +			SAFE_CLOSE(fds[i]);
> +
> +	if (childns >= 0)
> +		SAFE_CLOSE(childns);
> +
> +	if (parentns >= 0)
> +		SAFE_CLOSE(parentns);
> +}
> +
> +static struct tst_test test = {
> +	.test_all = run,
> +	.setup = setup,
> +	.cleanup = cleanup,
> +	.needs_kconfigs = (const char *[]) {
> +		"CONFIG_USER_NS=y",
> +		"CONFIG_NET_NS=y",
> +		NULL
> +	},
> +	.tags = (const struct tst_tag[]) {
> +		{"linux-git", "b38e7819cae9"},
> +		{"CVE", "2020-25705"},
> +		{}
> +	}
> +};
> -- 
> 2.31.1
> 
> 
> -- 
> Mailing list info: https://lists.linux.it/listinfo/ltp

-- 
Cyril Hrubis
chrubis@suse.cz

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [LTP] [PATCH v3 4/6] Add rtnetlink helper library
  2021-05-05 11:26   ` Petr Vorel
  2021-05-05 12:16     ` Cyril Hrubis
@ 2021-05-05 13:15     ` Martin Doucha
  2021-05-05 20:24       ` Petr Vorel
  1 sibling, 1 reply; 26+ messages in thread
From: Martin Doucha @ 2021-05-05 13:15 UTC (permalink / raw)
  To: ltp

On 05. 05. 21 13:26, Petr Vorel wrote:
>> diff --git a/include/tst_rtnetlink.h b/include/tst_rtnetlink.h
>> new file mode 100644
>> index 000000000..12ec258f2
>> --- /dev/null
>> +++ b/include/tst_rtnetlink.h
>> @@ -0,0 +1,106 @@
>> +/* SPDX-License-Identifier: GPL-2.0-or-later
>> + * Copyright (c) 2021 Linux Test Project
>> + */
>> +
>> +#ifndef TST_RTNETLINK_H
>> +#define TST_RTNETLINK_H
> 
> I guess this header will always be internal, right?  (only tst_netdevice.h is
> going to be used in tests) Otherwise it might need to include headers
> (<linux/netlink.h>, and also <unistd.h> or <sys/types.h> for ssize_t which are
> now only in C library sources).

No, I expect that someone will use it for rtnetlink tests sooner or
later. But I don't think those extra #includes matter all that much. If
they get #included in the test itself in the right order, it'll work
just fine.

> ...
>> +int tst_rtnl_add_message(const char *file, const int lineno,
>> +	struct tst_rtnl_context *ctx, const struct nlmsghdr *header,
>> +	const void *payload, size_t payload_size)
>> +{
>> +	size_t size;
>> +	unsigned int extra_flags = 0;
>> +
>> +	if (!tst_rtnl_grow_buffer(file, lineno, ctx, NLMSG_SPACE(payload_size)))
> Shouldn't there be an error message?
> Or maybe at tst_rtnl_grow_buffer() on if (!buf)

As Cyril already pointed out, the only way this call can fail is when
safe_realloc() fails and prints a TWARN because we're in cleanup().
There's no need to print a second error message.

-- 
Martin Doucha   mdoucha@suse.cz
QA Engineer for Software Maintenance
SUSE LINUX, s.r.o.
CORSO IIa
Krizikova 148/34
186 00 Prague 8
Czech Republic

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [LTP] [PATCH v3 6/6] Add test for CVE 2020-25705
  2021-05-05 13:06   ` Cyril Hrubis
@ 2021-05-05 15:54     ` Martin Doucha
  0 siblings, 0 replies; 26+ messages in thread
From: Martin Doucha @ 2021-05-05 15:54 UTC (permalink / raw)
  To: ltp

Hello, Michal and Nicolai,
please see the question about sleep() near the end of this e-mail. This
is a new LTP test for the global ICMP rate limiter exploit that can
enable the SADDNS attack.

On 05. 05. 21 15:06, Cyril Hrubis wrote:
> Hi!
>> diff --git a/testcases/cve/cve-2020-25705.c b/testcases/cve/cve-2020-25705.c
> 
> Can we please name the file icmp_rate_limit01.c or something more human
> readable than the cve-2020-25705?

I'll rename it in v4.

>> new file mode 100644
>> index 000000000..7d6bbafa8
>> --- /dev/null
>> +++ b/testcases/cve/cve-2020-25705.c
>> @@ -0,0 +1,262 @@
>> +// SPDX-License-Identifier: GPL-2.0-or-later
>> +/*
>> + * Copyright (C) 2020 SUSE LLC
>> + * Author: Nicolai Stange <nstange@suse.de>
>> + * LTP port: Martin Doucha <mdoucha@suse.cz>
>> + *
>> + * CVE-2020-25705
>> + *
>> + * Test of ICMP rate limiting behavior that may be abused for DNS cache
>> + * poisoning attack. Send a few batches of 100 packets to a closed UDP port
>> + * and count the ICMP errors. If the number of errors is always the same
>> + * for each batch (not randomized), the system is vulnerable. Send packets
>> + * from multiple IP addresses to bypass per-address ICMP throttling.
>> + *
>> + * Fixed in:
>> + *
>> + *  commit b38e7819cae946e2edf869e604af1e65a5d241c5
>> + *  Author: Eric Dumazet <edumazet@google.com>
>> + *  Date:   Thu Oct 15 11:42:00 2020 -0700
>> + *
>> + *  icmp: randomize the global rate limiter
>> + */
>> +
>> +#include <sys/socket.h>
>> +#include <netinet/in.h>
>> +#include <arpa/inet.h>
>> +#include <linux/if_addr.h>
>> +#include <linux/errqueue.h>
>> +
>> +#include <sched.h>
>> +#include <limits.h>
>> +#include "tst_test.h"
>> +#include "tst_netdevice.h"
>> +
>> +#define DSTADDR 0xfa444e02 /* 250.68.78.2 */
>> +#define SRCADDR_BASE 0xfa444e41 /* 250.68.78.65 */
>> +#define SRCADDR_COUNT 50
>> +#define BATCH_COUNT 8
>> +#define BUFSIZE 1024
>> +
>> +static int parentns = -1, childns = -1;
>> +static int fds[SRCADDR_COUNT];
>> +
>> +static void setup(void)
>> +{
>> +	struct sockaddr_in ipaddr = { .sin_family = AF_INET };
>> +	uint32_t addr;
>> +	int i;
>> +	int real_uid = getuid();
>> +	int real_gid = getgid();
>> +
>> +	for (i = 0; i < SRCADDR_COUNT; i++)
>> +		fds[i] = -1;
>> +
>> +	SAFE_UNSHARE(CLONE_NEWUSER);
>> +	SAFE_UNSHARE(CLONE_NEWNET);
>> +	SAFE_FILE_PRINTF("/proc/self/setgroups", "deny");
>> +	SAFE_FILE_PRINTF("/proc/self/uid_map", "0 %d 1\n", real_uid);
>> +	SAFE_FILE_PRINTF("/proc/self/gid_map", "0 %d 1\n", real_gid);
>> +
>> +	/*
>> +	 * Create network namespace to hide the destination interface from
>> +	 * the test process.
>> +	 */
>> +	parentns = SAFE_OPEN("/proc/self/ns/net", O_RDONLY);
>> +	SAFE_UNSHARE(CLONE_NEWNET);
>> +
>> +	/* Do NOT close this FD, or both interfaces will be destroyed */
>> +	childns = SAFE_OPEN("/proc/self/ns/net", O_RDONLY);
>> +
>> +	/* Configure child namespace */
>> +	CREATE_VETH_PAIR("ltp_veth1", "ltp_veth2");
>> +	addr = DSTADDR;
>> +	NETDEV_ADD_ADDRESS_INET("ltp_veth2", htonl(addr), 26,
>> +		IFA_F_NOPREFIXROUTE);
>> +	NETDEV_SET_STATE("ltp_veth2", 1);
>> +	NETDEV_ADD_ROUTE_INET("ltp_veth2", 0, 0, htonl(0xfa444e40), 26,
>> +		0);
>> +
>> +	/* Configure parent namespace */
>> +	NETDEV_CHANGE_NS_FD("ltp_veth1", parentns);
>> +	SAFE_SETNS(parentns, CLONE_NEWNET);
>> +	addr = SRCADDR_BASE; /* 250.68.78.65 */
>> +
>> +	for (i = 0; i < SRCADDR_COUNT; i++, addr++) {
>> +		NETDEV_ADD_ADDRESS_INET("ltp_veth1", htonl(addr), 26,
>> +			IFA_F_NOPREFIXROUTE);
>> +	}
>> +
>> +	NETDEV_SET_STATE("ltp_veth1", 1);
>> +	NETDEV_ADD_ROUTE_INET("ltp_veth1", 0, 0, htonl(0xfa444e00), 26, 0);
>> +	SAFE_FILE_PRINTF("/proc/sys/net/ipv4/conf/ltp_veth1/forwarding", "1");
>> +
>> +	/* Open test sockets */
>> +	for (i = 0; i < SRCADDR_COUNT; i++) {
>> +		ipaddr.sin_addr.s_addr = htonl(SRCADDR_BASE + i);
>> +		fds[i] = SAFE_SOCKET(AF_INET, SOCK_DGRAM, 0);
>> +		SAFE_SETSOCKOPT_INT(fds[i], IPPROTO_IP, IP_RECVERR, 1);
>> +		SAFE_BIND(fds[i], (struct sockaddr *)&ipaddr, sizeof(ipaddr));
>> +	}
>> +}
>> +
>> +static int count_icmp_errors(int fd)
>> +{
>> +	int error_count = 0;
>> +	ssize_t len;
>> +	char msgbuf[BUFSIZE], errbuf[BUFSIZE];
>> +	struct sockaddr_in addr;
>> +	struct cmsghdr *cmsg;
>> +	struct sock_extended_err exterr;
>> +	struct iovec iov = {
>> +		.iov_base = msgbuf,
>> +		.iov_len = BUFSIZE
>> +	};
>> +
>> +	while (1) {
>> +		struct msghdr msg = {
>> +			.msg_name = (struct sockaddr *)&addr,
>> +			.msg_namelen = sizeof(addr),
>> +			.msg_iov = &iov,
>> +			.msg_iovlen = 1,
>> +			.msg_flags = 0,
>> +			.msg_control = errbuf,
>> +			.msg_controllen = BUFSIZE
>> +		};
>> +
>> +		memset(errbuf, 0, BUFSIZE);
>> +		errno = 0;
>> +		len = recvmsg(fd, &msg, MSG_ERRQUEUE);
>> +
>> +		if (len == -1) {
>> +			if (errno == EWOULDBLOCK || errno == EAGAIN)
>> +				break;
>> +
>> +			tst_brk(TBROK | TERRNO, "recvmsg() failed");
>> +		}
>> +
>> +		if (len < 0) {
>> +			tst_brk(TBROK | TERRNO,
>> +				"Invalid recvmsg() return value %zd", len);
>> +		}
>> +
>> +		for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;
>> +			cmsg = CMSG_NXTHDR(&msg, cmsg)) {
>> +			if (cmsg->cmsg_level != SOL_IP)
>> +				continue;
>> +
>> +			if (cmsg->cmsg_type != IP_RECVERR)
>> +				continue;
>> +
>> +			memcpy(&exterr, CMSG_DATA(cmsg), sizeof(exterr));
>> +
>> +			if (exterr.ee_origin != SO_EE_ORIGIN_ICMP)
>> +				tst_brk(TBROK, "Unexpected non-ICMP error");
>> +
>> +			if (exterr.ee_errno != ECONNREFUSED) {
>> +				TST_ERR = exterr.ee_errno;
>> +				tst_brk(TBROK | TTERRNO,
>> +					"Unexpected ICMP error");
>> +			}
>> +
>> +			error_count++;
>> +		}
>> +	}
>> +
>> +	return error_count;
>> +}
>> +
>> +static int packet_batch(const struct sockaddr *addr, socklen_t addrsize)
>> +{
>> +	int i, j, error_count = 0;
>> +	char data = 0;
>> +
>> +	for (i = 0; i < SRCADDR_COUNT; i++) {
>> +		for (j = 0; j < 2; j++) {
>> +			error_count += count_icmp_errors(fds[i]);
>> +			TEST(sendto(fds[i], &data, sizeof(data), 0, addr,
>> +				addrsize));
>> +
>> +			if (TST_RET == -1) {
>> +				if (TST_ERR == ECONNREFUSED) {
>> +					j--; /* flush ICMP errors and retry */
>> +					continue;
>> +				}
>> +
>> +				tst_brk(TBROK | TTERRNO, "sento() failed");
>> +			}
>> +
>> +			if (TST_RET < 0) {
>> +				tst_brk(TBROK | TTERRNO,
>> +					"Invalid sento() return value %ld",
>> +					TST_RET);
>> +			}
>> +		}
>> +	}
>> +
>> +	/* Wait and collect pending ICMP errors */
>> +	sleep(2);
> 
> Can we do something better than sleep() here?
> 
> Maybe just loop over the loop that reads errors with some short sleep
> and exit if we haven't got any new errors for a while?
> 
> Something as:
> 
> 	unsigned int timeout_ms = 2000;
> 	unsigned int no_changes_ms = 0;
> 
> 	while (timeout_ms) {
> 		int last_err_cnt = error_count;
> 
> 		for (i = 0; i < SRCADDR_COUNT; i++)
> 			error_count += count_icmp_errors(fds[i]);
> 
> 		if (last_err_cnt == error_count)
> 			no_changes_ms++;
> 		else
> 			no_changes_ms = 0;
> 
> 
> 		if (no_changes_ms > 500)
> 			break;
> 
> 		usleep(1000);
> 		timeout_ms--;
> 	}

Well, that's a really tough question since we have no other way of
synchronizing here and we don't even know how many errors we're supposed
to get... Let's ask Michal and Nicolai for advice.

>> +	for (i = 0; i < SRCADDR_COUNT; i++)
>> +		error_count += count_icmp_errors(fds[i]);
>> +
>> +	return error_count;
>> +}
>> +
>> +static void run(void)
>> +{
>> +	int i, errors_baseline, errors;
>> +	struct sockaddr_in addr = {
>> +		.sin_family = AF_INET,
>> +		.sin_port = TST_GET_UNUSED_PORT(AF_INET, SOCK_DGRAM),
>> +		.sin_addr = { htonl(DSTADDR) }
>> +	};
>> +
>> +	errors_baseline = packet_batch((struct sockaddr *)&addr, sizeof(addr));
>> +	errors = errors_baseline;
>> +	tst_res(TINFO, "Batch 0: Got %d ICMP errors", errors);
>> +
>> +	for (i = 1; i < BATCH_COUNT && errors == errors_baseline; i++) {
>> +		errors = packet_batch((struct sockaddr *)&addr, sizeof(addr));
>> +		tst_res(TINFO, "Batch %d: Got %d ICMP errors", i, errors);
>> +	}
>> +
>> +	if (errors == errors_baseline) {
>> +		tst_res(TFAIL,
>> +			"ICMP rate limit not randomized, system is vulnerable");
>> +		return;
>> +	}
>> +
>> +	tst_res(TPASS, "ICMP rate limit is randomized");
>> +}
>> +
>> +static void cleanup(void)
>> +{
>> +	int i;
>> +
>> +	for (i = 0; i < SRCADDR_COUNT; i++)
>> +		if (fds[i] >= 0)
>> +			SAFE_CLOSE(fds[i]);
>> +
>> +	if (childns >= 0)
>> +		SAFE_CLOSE(childns);
>> +
>> +	if (parentns >= 0)
>> +		SAFE_CLOSE(parentns);
>> +}
>> +
>> +static struct tst_test test = {
>> +	.test_all = run,
>> +	.setup = setup,
>> +	.cleanup = cleanup,
>> +	.needs_kconfigs = (const char *[]) {
>> +		"CONFIG_USER_NS=y",
>> +		"CONFIG_NET_NS=y",
>> +		NULL
>> +	},
>> +	.tags = (const struct tst_tag[]) {
>> +		{"linux-git", "b38e7819cae9"},
>> +		{"CVE", "2020-25705"},
>> +		{}
>> +	}
>> +};
>> -- 
>> 2.31.1
>>
>>
>> -- 
>> Mailing list info: https://lists.linux.it/listinfo/ltp
> 

-- 
Martin Doucha   mdoucha@suse.cz
QA Engineer for Software Maintenance
SUSE LINUX, s.r.o.
CORSO IIa
Krizikova 148/34
186 00 Prague 8
Czech Republic

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [LTP] [PATCH v3 4/6] Add rtnetlink helper library
  2021-05-05 12:16     ` Cyril Hrubis
@ 2021-05-05 20:20       ` Petr Vorel
  0 siblings, 0 replies; 26+ messages in thread
From: Petr Vorel @ 2021-05-05 20:20 UTC (permalink / raw)
  To: ltp

> Hi!
> > > +int tst_rtnl_add_message(const char *file, const int lineno,
> > > +	struct tst_rtnl_context *ctx, const struct nlmsghdr *header,
> > > +	const void *payload, size_t payload_size)
> > > +{
> > > +	size_t size;
> > > +	unsigned int extra_flags = 0;
> > > +
> > > +	if (!tst_rtnl_grow_buffer(file, lineno, ctx, NLMSG_SPACE(payload_size)))
> > Shouldn't there be an error message?
> > Or maybe at tst_rtnl_grow_buffer() on if (!buf)

> As far as I can tell we will get error message from the safe_realloc()
Right, thanks for info!

Kind regards,
Petr

> > Reviewed-by: Petr Vorel <pvorel@suse.cz>
> > Nice code, thanks!

> > Kind regards,
> > Petr

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [LTP] [PATCH v3 4/6] Add rtnetlink helper library
  2021-05-05 13:15     ` Martin Doucha
@ 2021-05-05 20:24       ` Petr Vorel
  0 siblings, 0 replies; 26+ messages in thread
From: Petr Vorel @ 2021-05-05 20:24 UTC (permalink / raw)
  To: ltp

> On 05. 05. 21 13:26, Petr Vorel wrote:
> >> diff --git a/include/tst_rtnetlink.h b/include/tst_rtnetlink.h
> >> new file mode 100644
> >> index 000000000..12ec258f2
> >> --- /dev/null
> >> +++ b/include/tst_rtnetlink.h
> >> @@ -0,0 +1,106 @@
> >> +/* SPDX-License-Identifier: GPL-2.0-or-later
> >> + * Copyright (c) 2021 Linux Test Project
> >> + */
> >> +
> >> +#ifndef TST_RTNETLINK_H
> >> +#define TST_RTNETLINK_H

> > I guess this header will always be internal, right?  (only tst_netdevice.h is
> > going to be used in tests) Otherwise it might need to include headers
> > (<linux/netlink.h>, and also <unistd.h> or <sys/types.h> for ssize_t which are
> > now only in C library sources).

> No, I expect that someone will use it for rtnetlink tests sooner or
> later. But I don't think those extra #includes matter all that much. If
> they get #included in the test itself in the right order, it'll work
> just fine.
Sure.

> > ...
> >> +int tst_rtnl_add_message(const char *file, const int lineno,
> >> +	struct tst_rtnl_context *ctx, const struct nlmsghdr *header,
> >> +	const void *payload, size_t payload_size)
> >> +{
> >> +	size_t size;
> >> +	unsigned int extra_flags = 0;
> >> +
> >> +	if (!tst_rtnl_grow_buffer(file, lineno, ctx, NLMSG_SPACE(payload_size)))
> > Shouldn't there be an error message?
> > Or maybe at tst_rtnl_grow_buffer() on if (!buf)

> As Cyril already pointed out, the only way this call can fail is when
> safe_realloc() fails and prints a TWARN because we're in cleanup().
> There's no need to print a second error message.
You're right, thanks for info.

Kind regards,
Petr

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [LTP] [PATCH v3 1/6] Add SAFE_REALLOC() helper function to LTP library
  2021-05-05  8:18 [LTP] [PATCH v3 1/6] Add SAFE_REALLOC() helper function to LTP library Martin Doucha
                   ` (4 preceding siblings ...)
  2021-05-05  8:18 ` [LTP] [PATCH v3 6/6] Add test for CVE 2020-25705 Martin Doucha
@ 2021-05-10  7:42 ` Petr Vorel
  5 siblings, 0 replies; 26+ messages in thread
From: Petr Vorel @ 2021-05-10  7:42 UTC (permalink / raw)
  To: ltp

Hi,

Reviewed-by: Petr Vorel <pvorel@suse.cz>

Kind regards,
Petr

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [LTP] [PATCH v3 2/6] Add SAFE_RECV() helper function to LTP library
  2021-05-05  8:18 ` [LTP] [PATCH v3 2/6] Add SAFE_RECV() " Martin Doucha
@ 2021-05-10  7:55   ` Petr Vorel
  0 siblings, 0 replies; 26+ messages in thread
From: Petr Vorel @ 2021-05-10  7:55 UTC (permalink / raw)
  To: ltp

Hi,

Reviewed-by: Petr Vorel <pvorel@suse.cz>

Kind regards,
Petr

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [LTP] [PATCH v3 3/6] Add SAFE_IOCTL() variant for library code
  2021-05-05  8:18 ` [LTP] [PATCH v3 3/6] Add SAFE_IOCTL() variant for library code Martin Doucha
  2021-05-05  9:12   ` Cyril Hrubis
@ 2021-05-10  7:57   ` Petr Vorel
  1 sibling, 0 replies; 26+ messages in thread
From: Petr Vorel @ 2021-05-10  7:57 UTC (permalink / raw)
  To: ltp

Hi Martin,

Reviewed-by: Petr Vorel <pvorel@suse.cz>

Kind regards,
Petr

^ permalink raw reply	[flat|nested] 26+ messages in thread

* [LTP] [PATCH v3 4/6] Add rtnetlink helper library
  2021-05-05  8:18 ` [LTP] [PATCH v3 4/6] Add rtnetlink helper library Martin Doucha
                     ` (2 preceding siblings ...)
  2021-05-05 12:14   ` Cyril Hrubis
@ 2021-05-10  9:07   ` Petr Vorel
  3 siblings, 0 replies; 26+ messages in thread
From: Petr Vorel @ 2021-05-10  9:07 UTC (permalink / raw)
  To: ltp

Hi,

Reviewed-by: Petr Vorel <pvorel@suse.cz>

> This library provides simple interface for creating arbitrary rtnetlink
> messages with complex attributes, sending requests and receiving results.

I wonder if it'd be good to rewrite route-change-netlink.c to use
tst_netdevice.c instead of libmnl (it'd be nice to get rid of libmnl dependency,
but on the other hand using it means also testing it).

Kind regards,
Petr

^ permalink raw reply	[flat|nested] 26+ messages in thread

end of thread, other threads:[~2021-05-10  9:07 UTC | newest]

Thread overview: 26+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-05  8:18 [LTP] [PATCH v3 1/6] Add SAFE_REALLOC() helper function to LTP library Martin Doucha
2021-05-05  8:18 ` [LTP] [PATCH v3 2/6] Add SAFE_RECV() " Martin Doucha
2021-05-10  7:55   ` Petr Vorel
2021-05-05  8:18 ` [LTP] [PATCH v3 3/6] Add SAFE_IOCTL() variant for library code Martin Doucha
2021-05-05  9:12   ` Cyril Hrubis
2021-05-10  7:57   ` Petr Vorel
2021-05-05  8:18 ` [LTP] [PATCH v3 4/6] Add rtnetlink helper library Martin Doucha
2021-05-05 10:17   ` Petr Vorel
2021-05-05 10:25     ` Martin Doucha
2021-05-05 11:24       ` Petr Vorel
2021-05-05 11:26   ` Petr Vorel
2021-05-05 12:16     ` Cyril Hrubis
2021-05-05 20:20       ` Petr Vorel
2021-05-05 13:15     ` Martin Doucha
2021-05-05 20:24       ` Petr Vorel
2021-05-05 12:14   ` Cyril Hrubis
2021-05-10  9:07   ` Petr Vorel
2021-05-05  8:18 ` [LTP] [PATCH v3 5/6] Add helper functions for managing network interfaces Martin Doucha
2021-05-05 12:39   ` Cyril Hrubis
2021-05-05  8:18 ` [LTP] [PATCH v3 6/6] Add test for CVE 2020-25705 Martin Doucha
2021-05-05 10:04   ` Petr Vorel
2021-05-05 10:33     ` Martin Doucha
2021-05-05 11:13       ` Petr Vorel
2021-05-05 13:06   ` Cyril Hrubis
2021-05-05 15:54     ` Martin Doucha
2021-05-10  7:42 ` [LTP] [PATCH v3 1/6] Add SAFE_REALLOC() helper function to LTP library Petr Vorel

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.