All of lore.kernel.org
 help / color / mirror / Atom feed
* [LTP] [RFC PATCH 0/9] Introduce guarded buffers
@ 2019-08-01  9:26 Cyril Hrubis
  2019-08-01  9:26 ` [LTP] [RFC PATCH 1/9] lib: Add support for " Cyril Hrubis
                   ` (9 more replies)
  0 siblings, 10 replies; 37+ messages in thread
From: Cyril Hrubis @ 2019-08-01  9:26 UTC (permalink / raw)
  To: ltp

This is initial attempt to implement:

https://github.com/linux-test-project/ltp/issues/531

The idea of guarded buffers is that with these buffers undefined
behavior and possibly silent memory corruptions are turned into
segfaults which is much easier to spot and debug.

The first two commits introduce API for allocating guarded buffers with
poisoned PROT_NONE page right after the buffer and canary before the
buffer. Tests using these buffers will catch any access after the buffer
and writes before the buffer.

The next few patches make use of the buffers in a few tests mostly to
show the intended usage in real testcases. Applying these buffers to the
rest of the testcases would need much more effort though.

Cyril Hrubis (9):
  lib: Add support for guarded buffers
  lib: Add a canary for guarded buffers
  syscalls/preadv01: Make use of guarded buffers.
  syscalls/accept4_01: Make use of guarded buffers.
  syscalls/add_key04: Make use of guarded buffers.
  syscalls/adjtimex: Make use of guarded buffers.
  syscalls/clock_getres01: Make use of guarded buffers.
  syscalls/clock_settime01: Make use of guarded buffers.
  syscalls/sendmmsg01: Make use of guarded buffers.

 include/tst_buffers.h                         |  63 ++++++++
 include/tst_test.h                            |   6 +
 lib/newlib_tests/.gitignore                   |   1 +
 lib/newlib_tests/test_guarded_buf.c           |  86 +++++++++++
 lib/tst_buffers.c                             | 138 ++++++++++++++++++
 lib/tst_test.c                                |   5 +
 testcases/kernel/syscalls/accept/accept02.c   |  41 +++---
 .../kernel/syscalls/accept4/accept4_01.c      |  24 +--
 testcases/kernel/syscalls/add_key/add_key04.c |  13 +-
 .../kernel/syscalls/adjtimex/adjtimex01.c     |  23 +--
 .../kernel/syscalls/adjtimex/adjtimex02.c     |  39 ++---
 .../syscalls/clock_getres/clock_getres01.c    |  12 +-
 .../syscalls/clock_settime/clock_settime01.c  |  29 ++--
 testcases/kernel/syscalls/preadv/preadv01.c   |  10 +-
 .../kernel/syscalls/sendmmsg/sendmmsg01.c     |  68 +++++----
 15 files changed, 446 insertions(+), 112 deletions(-)
 create mode 100644 include/tst_buffers.h
 create mode 100644 lib/newlib_tests/test_guarded_buf.c
 create mode 100644 lib/tst_buffers.c

-- 
2.21.0


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

* [LTP] [RFC PATCH 1/9] lib: Add support for guarded buffers
  2019-08-01  9:26 [LTP] [RFC PATCH 0/9] Introduce guarded buffers Cyril Hrubis
@ 2019-08-01  9:26 ` Cyril Hrubis
  2019-08-01 10:39   ` Jan Stancek
                     ` (3 more replies)
  2019-08-01  9:26 ` [LTP] [RFC PATCH 2/9] lib: Add a canary " Cyril Hrubis
                   ` (8 subsequent siblings)
  9 siblings, 4 replies; 37+ messages in thread
From: Cyril Hrubis @ 2019-08-01  9:26 UTC (permalink / raw)
  To: ltp

This commit adds a support for guarder buffers. Guarded buffer is a
buffer allocated so that there is PROT_NONE page immediatelly after the
end of the buffer i.e. any access after the buffer generates
SEGFAULT/EFAULT etc.

The library is hooked into the tst_test structure so that all you need
is to fill up an NULL terminated array of buffer pointers and sizes to
get the respective buffers allocated. The library supports allocating
memory in test runtime as well as well as allocating more complex
buffers, which currently are iovec vectors.

All buffers are freeed automatically at the end of the test.

Example usage looks like:

static struct foo *foo_ptr;
static struct iovec *iov;
static void *buf_ptr;
static char *id;
...

static void run(void)
{
	...

	foo_ptr->bar = 1;
	foo_ptr->buf = buf_ptr;

	...
}

static void setup(void)
{
	...

	id = strdup(string);

	...
}

static struct tst_test test = {
	...
	.bufs = (struct tst_buffers []) {
		{&foo_ptr, .size = sizeof(*foo_ptr)},
		{&buf_ptr, .size = BUF_SIZE},
		{&iov, .iov_sizes = (int[]){128, 32, -1},
		{}
	}
};

Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
---
 include/tst_buffers.h                       |  63 ++++++++++++
 include/tst_test.h                          |   6 ++
 lib/newlib_tests/.gitignore                 |   1 +
 lib/newlib_tests/test_guarded_buf.c         |  78 ++++++++++++++
 lib/tst_buffers.c                           | 106 ++++++++++++++++++++
 lib/tst_test.c                              |   5 +
 testcases/kernel/syscalls/accept/accept02.c |  41 ++++----
 7 files changed, 281 insertions(+), 19 deletions(-)
 create mode 100644 include/tst_buffers.h
 create mode 100644 lib/newlib_tests/test_guarded_buf.c
 create mode 100644 lib/tst_buffers.c

diff --git a/include/tst_buffers.h b/include/tst_buffers.h
new file mode 100644
index 000000000..d19ac8cf0
--- /dev/null
+++ b/include/tst_buffers.h
@@ -0,0 +1,63 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#ifndef TST_BUFFERS_H__
+#define TST_BUFFERS_H__
+
+/*
+ * Buffer description consist of a pointer to a pointer and buffer type/size
+ * encoded as a different structure members.
+ *
+ * Only one of the size and iov_sizes can be set at a time.
+ */
+struct tst_buffers {
+	/*
+	 * This pointer points to a buffer pointer.
+	 */
+	void *ptr;
+	/*
+	 * Buffer size.
+	 */
+	size_t size;
+	/*
+	 * Array of iov buffer sizes terminated by -1.
+	 */
+	int *iov_sizes;
+};
+
+/*
+ * Allocates buffers based on the tst_buffers structure.
+ *
+ * @bufs NULL terminated array of test buffer descriptions.
+ *
+ * This is called from the test library if the tst_test->bufs pointer is set.
+ */
+void tst_buffers_alloc(struct tst_buffers bufs[]);
+
+/*
+ * strdup() that callls tst_alloc().
+ */
+char *tst_strdup(const char *str);
+
+/*
+ * Allocates size bytes, returns pointer to the allocated buffer.
+ */
+void *tst_alloc(size_t size);
+
+/*
+ * Allocates iovec structure including the buffers.
+ *
+ * @sizes -1 terminated array of buffer sizes.
+ */
+struct iovec *tst_iovec_alloc(int sizes[]);
+
+/*
+ * Frees all allocated buffers.
+ *
+ * This is called at the end of the test automatically.
+ */
+void tst_free_all(void);
+
+#endif	/* TST_BUFFERS_H__ */
diff --git a/include/tst_test.h b/include/tst_test.h
index 2e07ff16b..cdeaf6ad0 100644
--- a/include/tst_test.h
+++ b/include/tst_test.h
@@ -35,6 +35,7 @@
 #include "tst_path_has_mnt_flags.h"
 #include "tst_sys_conf.h"
 #include "tst_coredump.h"
+#include "tst_buffers.h"
 
 /*
  * Reports testcase result.
@@ -200,6 +201,11 @@ struct tst_test {
 	 * test.
 	 */
 	const char *const *needs_kconfigs;
+
+	/*
+	 * NULL-terminated array to be allocated buffers.
+	 */
+	struct tst_buffers *bufs;
 };
 
 /*
diff --git a/lib/newlib_tests/.gitignore b/lib/newlib_tests/.gitignore
index d92b89872..6788ddf90 100644
--- a/lib/newlib_tests/.gitignore
+++ b/lib/newlib_tests/.gitignore
@@ -26,3 +26,4 @@ test_exec
 test_exec_child
 test_kconfig
 variant
+test_guarded_buf
diff --git a/lib/newlib_tests/test_guarded_buf.c b/lib/newlib_tests/test_guarded_buf.c
new file mode 100644
index 000000000..2951dce23
--- /dev/null
+++ b/lib/newlib_tests/test_guarded_buf.c
@@ -0,0 +1,78 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+/*
+ * Test that acces after guarded buffer causes segfault.
+ */
+
+#include <stdlib.h>
+#include <sys/wait.h>
+#include "tst_test.h"
+
+#define BUF1_LEN 10
+#define BUF2_LEN 4096
+#define BUF3_LEN 12004
+
+static char *buf1;
+static char *buf2;
+static char *buf3;
+
+static void do_test(unsigned int n)
+{
+	int pid = SAFE_FORK();
+	int status;
+
+	if (!pid) {
+		switch (n) {
+		case 0:
+			buf1[BUF1_LEN - 1] = 0;
+		break;
+		case 1:
+			buf2[BUF2_LEN - 1] = 0;
+		break;
+		case 2:
+			buf3[BUF3_LEN - 1] = 0;
+		break;
+		case 3:
+			buf1[BUF1_LEN] = 0;
+		break;
+		case 4:
+			buf2[BUF2_LEN] = 0;
+		break;
+		case 5:
+			buf3[BUF3_LEN] = 0;
+		break;
+		}
+
+		exit(0);
+	}
+
+	SAFE_WAITPID(pid, &status, 0);
+
+	if (n < 3) {
+		if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
+			tst_res(TPASS, "Exitted normally");
+			return;
+		}
+	} else {
+		if (WIFSIGNALED(status) && WTERMSIG(status) == SIGSEGV) {
+			tst_res(TPASS, "Killed by SIGSEGV");
+			return;
+		}
+	}
+
+	tst_res(TFAIL, "Child %s", tst_strstatus(status));
+}
+
+static struct tst_test test = {
+	.forks_child = 1,
+	.test = do_test,
+	.tcnt = 6,
+	.bufs = (struct tst_buffers []) {
+		{&buf1, .size = BUF1_LEN},
+		{&buf2, .size = BUF2_LEN},
+		{&buf3, .size = BUF3_LEN},
+	}
+};
diff --git a/lib/tst_buffers.c b/lib/tst_buffers.c
new file mode 100644
index 000000000..c4b2859d1
--- /dev/null
+++ b/lib/tst_buffers.c
@@ -0,0 +1,106 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Cyril Hrubis <chrubis@suse.cz>
+ */
+
+#include <sys/mman.h>
+#include <stdlib.h>
+#define TST_NO_DEFAULT_MAIN
+#include "tst_test.h"
+
+struct map {
+	void *addr;
+	size_t size;
+	struct map *next;
+};
+
+static struct map *maps;
+
+void *tst_alloc(size_t size)
+{
+	size_t page_size = getpagesize();
+	unsigned int pages = (size / page_size) + !!(size % page_size) + 1;
+	void *ret;
+	struct map *map = SAFE_MALLOC(sizeof(struct map));
+
+	ret = SAFE_MMAP(NULL, page_size * pages, PROT_READ | PROT_WRITE,
+	                MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
+
+	mprotect(ret + (pages-1) * page_size, page_size, PROT_NONE);
+
+	map->addr = ret;
+	map->size = pages * page_size;
+	map->next = maps;
+	maps = map;
+
+	if (size % page_size)
+		ret += page_size - (size % page_size);
+
+	return ret;
+}
+
+static int count_iovec(int *sizes)
+{
+	int ret = 0;
+
+	while (sizes[ret++] != -1);
+
+	return ret - 1;
+}
+
+struct iovec *tst_iovec_alloc(int sizes[])
+{
+	int i, cnt = count_iovec(sizes);
+	struct iovec *iovec;
+
+	if (cnt <= 0)
+		return NULL;
+
+	iovec = tst_alloc(sizeof(struct iovec) * cnt);
+
+	for (i = 0; i < cnt; i++) {
+		if (sizes[i]) {
+			iovec[i].iov_base = tst_alloc(sizes[i]);
+			iovec[i].iov_len = sizes[i];
+		} else {
+			iovec[i].iov_base = NULL;
+			iovec[i].iov_base = 0;
+		}
+	}
+
+	return iovec;
+}
+
+void tst_buffers_alloc(struct tst_buffers bufs[])
+{
+	unsigned int i;
+
+	for (i = 0; bufs[i].ptr; i++) {
+		if (bufs[i].size)
+			*((void**)bufs[i].ptr) = tst_alloc(bufs[i].size);
+		else
+			*((void**)bufs[i].ptr) = tst_iovec_alloc(bufs[i].iov_sizes);
+	}
+}
+
+char *tst_strdup(const char *str)
+{
+	size_t len = strlen(str);
+	char *ret = tst_alloc(len + 1);
+	return strcpy(ret, str);
+}
+
+void tst_free_all(void)
+{
+	struct map *i = maps;
+
+	while (i) {
+		struct map *j = i;
+		tst_res(TINFO, "Freeing %p %zu", i->addr, i->size);
+		SAFE_MUNMAP(i->addr, i->size);
+		i = i->next;
+		free(j);
+	}
+
+	maps = NULL;
+}
diff --git a/lib/tst_test.c b/lib/tst_test.c
index 245e287fa..8dc71dbb3 100644
--- a/lib/tst_test.c
+++ b/lib/tst_test.c
@@ -283,6 +283,8 @@ static void do_test_cleanup(void)
 	if (tst_test->cleanup)
 		tst_test->cleanup();
 
+	tst_free_all();
+
 	tst_brk_handler = tst_vbrk_;
 }
 
@@ -802,6 +804,9 @@ static void do_setup(int argc, char *argv[])
 
 	setup_ipc();
 
+	if (tst_test->bufs)
+		tst_buffers_alloc(tst_test->bufs);
+
 	if (needs_tmpdir() && !tst_tmpdir_created())
 		tst_tmpdir();
 
diff --git a/testcases/kernel/syscalls/accept/accept02.c b/testcases/kernel/syscalls/accept/accept02.c
index df048ede4..1a0f625c9 100644
--- a/testcases/kernel/syscalls/accept/accept02.c
+++ b/testcases/kernel/syscalls/accept/accept02.c
@@ -33,10 +33,9 @@ static int client_sockfd;
 static int server_port;
 static socklen_t addr_len;
 
-static struct sockaddr_in server_addr;
-static struct sockaddr_in client_addr;
-static struct group_req mc_group;
-
+static struct sockaddr_in *server_addr;
+static struct sockaddr_in *client_addr;
+static struct group_req *mc_group;
 
 static void *server_thread(void *arg)
 {
@@ -44,27 +43,27 @@ static void *server_thread(void *arg)
 
 	op = 1;
 	op_len = sizeof(op);
-	mc_group_len = sizeof(mc_group);
+	mc_group_len = sizeof(*mc_group);
 
 	server_sockfd = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0);
 
 	SAFE_SETSOCKOPT(server_sockfd, SOL_SOCKET, SO_REUSEADDR, &op, op_len);
 	SAFE_SETSOCKOPT(server_sockfd, SOL_IP, MCAST_JOIN_GROUP,
-			&mc_group, mc_group_len);
+			mc_group, mc_group_len);
 
-	SAFE_BIND(server_sockfd, (struct sockaddr *)&server_addr, addr_len);
+	SAFE_BIND(server_sockfd, (struct sockaddr *)server_addr, addr_len);
 	SAFE_LISTEN(server_sockfd, 1);
 
 	TST_CHECKPOINT_WAKE(0);
 
-	TEST(accept(server_sockfd, (struct sockaddr *)&client_addr, &addr_len));
+	TEST(accept(server_sockfd, (struct sockaddr *)client_addr, &addr_len));
 	if (TST_RET == -1)
 		tst_brk(TBROK | TTERRNO, "Could not accept connection");
 
 	clone_server_sockfd = TST_RET;
 
 	TEST(setsockopt(clone_server_sockfd, SOL_IP, MCAST_LEAVE_GROUP,
-			&mc_group, mc_group_len));
+			mc_group, mc_group_len));
 
 	if (TST_RET != -1)
 		tst_res(TFAIL, "Multicast group was copied!");
@@ -80,9 +79,9 @@ static void *server_thread(void *arg)
 static void *client_thread(void *arg)
 {
 	client_sockfd = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0);
-	SAFE_BIND(client_sockfd, (struct sockaddr *)&client_addr, addr_len);
+	SAFE_BIND(client_sockfd, (struct sockaddr *)client_addr, addr_len);
 
-	SAFE_CONNECT(client_sockfd, (struct sockaddr *)&server_addr, addr_len);
+	SAFE_CONNECT(client_sockfd, (struct sockaddr *)server_addr, addr_len);
 
 	SAFE_CLOSE(client_sockfd);
 	return arg;
@@ -92,8 +91,8 @@ static void run(void)
 {
 	pthread_t server_thr, client_thr;
 
-	server_addr.sin_port = server_port;
-	client_addr.sin_port = htons(0);
+	server_addr->sin_port = server_port;
+	client_addr->sin_port = htons(0);
 
 	SAFE_PTHREAD_CREATE(&server_thr, NULL, server_thread, NULL);
 	TST_CHECKPOINT_WAIT(0);
@@ -107,16 +106,20 @@ static void setup(void)
 {
 	struct sockaddr_in *mc_group_addr;
 
-	mc_group.gr_interface = 0;
-	mc_group_addr = (struct sockaddr_in *) &mc_group.gr_group;
+	server_addr = tst_alloc(sizeof(*server_addr));
+	client_addr = tst_alloc(sizeof(*client_addr));
+	mc_group = tst_alloc(sizeof(*mc_group));
+
+	mc_group->gr_interface = 0;
+	mc_group_addr = (struct sockaddr_in *) &mc_group->gr_group;
 	mc_group_addr->sin_family = AF_INET;
 	inet_aton(MULTICASTIP, &mc_group_addr->sin_addr);
 
-	server_addr.sin_family = AF_INET;
-	inet_aton(LOCALHOSTIP, &server_addr.sin_addr);
+	server_addr->sin_family = AF_INET;
+	inet_aton(LOCALHOSTIP, &server_addr->sin_addr);
 
-	client_addr.sin_family = AF_INET;
-	client_addr.sin_addr.s_addr = htons(INADDR_ANY);
+	client_addr->sin_family = AF_INET;
+	client_addr->sin_addr.s_addr = htons(INADDR_ANY);
 
 	addr_len = sizeof(struct sockaddr_in);
 
-- 
2.21.0


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

* [LTP] [RFC PATCH 2/9] lib: Add a canary for guarded buffers
  2019-08-01  9:26 [LTP] [RFC PATCH 0/9] Introduce guarded buffers Cyril Hrubis
  2019-08-01  9:26 ` [LTP] [RFC PATCH 1/9] lib: Add support for " Cyril Hrubis
@ 2019-08-01  9:26 ` Cyril Hrubis
  2019-08-01 10:43   ` Jan Stancek
  2019-08-03 13:02   ` Li Wang
  2019-08-01  9:26 ` [LTP] [RFC PATCH 3/9] syscalls/preadv01: Make use of " Cyril Hrubis
                   ` (7 subsequent siblings)
  9 siblings, 2 replies; 37+ messages in thread
From: Cyril Hrubis @ 2019-08-01  9:26 UTC (permalink / raw)
  To: ltp

In a case that the buffer size is not a multiple of a page size there is
unused space before the start of the buffer. Let's fill that with
center mirrored random bytes and check that the buffer wasn't modified
before we unmap it.

Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
---
 lib/newlib_tests/test_guarded_buf.c | 12 ++++++++--
 lib/tst_buffers.c                   | 36 +++++++++++++++++++++++++++--
 2 files changed, 44 insertions(+), 4 deletions(-)

diff --git a/lib/newlib_tests/test_guarded_buf.c b/lib/newlib_tests/test_guarded_buf.c
index 2951dce23..e41d3fa99 100644
--- a/lib/newlib_tests/test_guarded_buf.c
+++ b/lib/newlib_tests/test_guarded_buf.c
@@ -21,9 +21,17 @@ static char *buf3;
 
 static void do_test(unsigned int n)
 {
-	int pid = SAFE_FORK();
+	int pid;
 	int status;
 
+	if (n == 6) {
+		buf1[-1] = 0;
+		buf3[-1] = 0;
+		tst_res(TPASS, "Buffers dirtied!");
+		return;
+	}
+
+	pid = SAFE_FORK();
 	if (!pid) {
 		switch (n) {
 		case 0:
@@ -69,7 +77,7 @@ static void do_test(unsigned int n)
 static struct tst_test test = {
 	.forks_child = 1,
 	.test = do_test,
-	.tcnt = 6,
+	.tcnt = 7,
 	.bufs = (struct tst_buffers []) {
 		{&buf1, .size = BUF1_LEN},
 		{&buf2, .size = BUF2_LEN},
diff --git a/lib/tst_buffers.c b/lib/tst_buffers.c
index c4b2859d1..bc0cb50d8 100644
--- a/lib/tst_buffers.c
+++ b/lib/tst_buffers.c
@@ -11,11 +11,38 @@
 struct map {
 	void *addr;
 	size_t size;
+	size_t buf_shift;
 	struct map *next;
 };
 
 static struct map *maps;
 
+static void setup_canary(struct map *map)
+{
+	size_t i;
+	char *buf = map->addr;
+
+	for (i = 0; i < map->buf_shift/2; i++) {
+		char c = random();
+		buf[map->buf_shift - i - 1] = c;
+		buf[i] = c;
+	}
+}
+
+static void check_canary(struct map *map)
+{
+	size_t i;
+	char *buf = map->addr;
+
+	for (i = 0; i < map->buf_shift/2; i++) {
+		if (buf[map->buf_shift - i - 1] != buf[i]) {
+			tst_res(TWARN,
+				"pid %i: buffer modified before address %p %zu",
+				(char*)map->addr + map->buf_shift, i);
+		}
+	}
+}
+
 void *tst_alloc(size_t size)
 {
 	size_t page_size = getpagesize();
@@ -34,9 +61,13 @@ void *tst_alloc(size_t size)
 	maps = map;
 
 	if (size % page_size)
-		ret += page_size - (size % page_size);
+		map->buf_shift = page_size - (size % page_size);
+	else
+		map->buf_shift = 0;
+
+	setup_canary(map);
 
-	return ret;
+	return ret + map->buf_shift;
 }
 
 static int count_iovec(int *sizes)
@@ -97,6 +128,7 @@ void tst_free_all(void)
 	while (i) {
 		struct map *j = i;
 		tst_res(TINFO, "Freeing %p %zu", i->addr, i->size);
+		check_canary(i);
 		SAFE_MUNMAP(i->addr, i->size);
 		i = i->next;
 		free(j);
-- 
2.21.0


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

* [LTP] [RFC PATCH 3/9] syscalls/preadv01: Make use of guarded buffers.
  2019-08-01  9:26 [LTP] [RFC PATCH 0/9] Introduce guarded buffers Cyril Hrubis
  2019-08-01  9:26 ` [LTP] [RFC PATCH 1/9] lib: Add support for " Cyril Hrubis
  2019-08-01  9:26 ` [LTP] [RFC PATCH 2/9] lib: Add a canary " Cyril Hrubis
@ 2019-08-01  9:26 ` Cyril Hrubis
  2019-08-01  9:26 ` [LTP] [RFC PATCH 4/9] syscalls/accept4_01: " Cyril Hrubis
                   ` (6 subsequent siblings)
  9 siblings, 0 replies; 37+ messages in thread
From: Cyril Hrubis @ 2019-08-01  9:26 UTC (permalink / raw)
  To: ltp

Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
---
 testcases/kernel/syscalls/preadv/preadv01.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/testcases/kernel/syscalls/preadv/preadv01.c b/testcases/kernel/syscalls/preadv/preadv01.c
index 2452f216a..95431bc60 100644
--- a/testcases/kernel/syscalls/preadv/preadv01.c
+++ b/testcases/kernel/syscalls/preadv/preadv01.c
@@ -24,12 +24,8 @@
 #define CHUNK           64
 
 static int fd;
-static char buf[CHUNK];
 
-static struct iovec rd_iovec[] = {
-	{buf, CHUNK},
-	{NULL, 0},
-};
+static struct iovec *rd_iovec;
 
 static struct tcase {
 	int count;
@@ -111,4 +107,8 @@ static struct tst_test test = {
 	.test = verify_preadv,
 	.min_kver = "2.6.30",
 	.needs_tmpdir = 1,
+	.bufs = (struct tst_buffers []) {
+		{&rd_iovec, .iov_sizes = (int[]){CHUNK, 0, -1}},
+		{},
+	}
 };
-- 
2.21.0


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

* [LTP] [RFC PATCH 4/9] syscalls/accept4_01: Make use of guarded buffers.
  2019-08-01  9:26 [LTP] [RFC PATCH 0/9] Introduce guarded buffers Cyril Hrubis
                   ` (2 preceding siblings ...)
  2019-08-01  9:26 ` [LTP] [RFC PATCH 3/9] syscalls/preadv01: Make use of " Cyril Hrubis
@ 2019-08-01  9:26 ` Cyril Hrubis
  2019-08-01  9:26 ` [LTP] [RFC PATCH 5/9] syscalls/add_key04: " Cyril Hrubis
                   ` (5 subsequent siblings)
  9 siblings, 0 replies; 37+ messages in thread
From: Cyril Hrubis @ 2019-08-01  9:26 UTC (permalink / raw)
  To: ltp

Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
---
 .../kernel/syscalls/accept4/accept4_01.c      | 24 +++++++++++--------
 1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/testcases/kernel/syscalls/accept4/accept4_01.c b/testcases/kernel/syscalls/accept4/accept4_01.c
index dd289cf6d..29e18f27d 100644
--- a/testcases/kernel/syscalls/accept4/accept4_01.c
+++ b/testcases/kernel/syscalls/accept4/accept4_01.c
@@ -35,7 +35,7 @@
 #define USE_SOCKETCALL 1
 #endif
 
-static struct sockaddr_in conn_addr;
+static struct sockaddr_in *conn_addr, *accept_addr;
 static int listening_fd;
 
 #if !(__GLIBC_PREREQ(2, 10))
@@ -80,10 +80,10 @@ static int create_listening_socket(void)
 
 static void setup(void)
 {
-	memset(&conn_addr, 0, sizeof(struct sockaddr_in));
-	conn_addr.sin_family = AF_INET;
-	conn_addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
-	conn_addr.sin_port = htons(PORT_NUM);
+	memset(conn_addr, 0, sizeof(*conn_addr));
+	conn_addr->sin_family = AF_INET;
+	conn_addr->sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+	conn_addr->sin_port = htons(PORT_NUM);
 
 	listening_fd = create_listening_socket();
 }
@@ -108,18 +108,17 @@ static void verify_accept4(unsigned int nr)
 	struct test_case *tcase = &tcases[nr];
 	int connfd, acceptfd;
 	int fdf, flf, fdf_pass, flf_pass, fd_cloexec, fd_nonblock;
-	struct sockaddr_in claddr;
 	socklen_t addrlen;
 
 	connfd = SAFE_SOCKET(AF_INET, SOCK_STREAM, 0);
-	SAFE_CONNECT(connfd, (struct sockaddr *)&conn_addr, sizeof(conn_addr));
-	addrlen = sizeof(claddr);
+	SAFE_CONNECT(connfd, (struct sockaddr *)conn_addr, sizeof(*conn_addr));
+	addrlen = sizeof(*accept_addr);
 
 #if !(__GLIBC_PREREQ(2, 10))
-	TEST(accept4_01(listening_fd, (struct sockaddr *)&claddr, &addrlen,
+	TEST(accept4_01(listening_fd, (struct sockaddr *)accept_addr, &addrlen,
 				tcase->cloexec | tcase->nonblock));
 #else
-	TEST(accept4(listening_fd, (struct sockaddr *)&claddr, &addrlen,
+	TEST(accept4(listening_fd, (struct sockaddr *)accept_addr, &addrlen,
 				tcase->cloexec | tcase->nonblock));
 #endif
 	if (TST_RET == -1) {
@@ -163,4 +162,9 @@ static struct tst_test test = {
 	.setup = setup,
 	.cleanup = cleanup,
 	.test = verify_accept4,
+	.bufs = (struct tst_buffers []) {
+		{&conn_addr, .size = sizeof(*conn_addr)},
+		{&accept_addr, .size = sizeof(*accept_addr)},
+		{},
+	}
 };
-- 
2.21.0


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

* [LTP] [RFC PATCH 5/9] syscalls/add_key04: Make use of guarded buffers.
  2019-08-01  9:26 [LTP] [RFC PATCH 0/9] Introduce guarded buffers Cyril Hrubis
                   ` (3 preceding siblings ...)
  2019-08-01  9:26 ` [LTP] [RFC PATCH 4/9] syscalls/accept4_01: " Cyril Hrubis
@ 2019-08-01  9:26 ` Cyril Hrubis
  2019-08-01  9:26 ` [LTP] [RFC PATCH 6/9] syscalls/adjtimex: " Cyril Hrubis
                   ` (4 subsequent siblings)
  9 siblings, 0 replies; 37+ messages in thread
From: Cyril Hrubis @ 2019-08-01  9:26 UTC (permalink / raw)
  To: ltp

Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
---
 testcases/kernel/syscalls/add_key/add_key04.c | 13 +++++++++++--
 1 file changed, 11 insertions(+), 2 deletions(-)

diff --git a/testcases/kernel/syscalls/add_key/add_key04.c b/testcases/kernel/syscalls/add_key/add_key04.c
index 28cc91f72..12a169eda 100644
--- a/testcases/kernel/syscalls/add_key/add_key04.c
+++ b/testcases/kernel/syscalls/add_key/add_key04.c
@@ -32,6 +32,10 @@
 
 #define ASSOC_ARRAY_FAN_OUT 16
 
+#define PAYLOAD "payload"
+
+static char *payload;
+
 static void do_test(void)
 {
 	int status;
@@ -42,7 +46,6 @@ static void do_test(void)
 
 	if (SAFE_FORK() == 0) {
 		char description[32];
-		const char payload[] = "payload";
 		int i;
 
 		for (i = 0; i < ASSOC_ARRAY_FAN_OUT; i++) {
@@ -55,7 +58,7 @@ static void do_test(void)
 			}
 		}
 
-		TEST(add_key("user", "userkey", payload, sizeof(payload),
+		TEST(add_key("user", "userkey", payload, sizeof(PAYLOAD),
 			     KEY_SPEC_SESSION_KEYRING));
 		if (TST_RET < 0)
 			tst_brk(TBROK | TTERRNO, "unable to create user key");
@@ -72,7 +75,13 @@ static void do_test(void)
 		tst_brk(TBROK, "Child %s", tst_strstatus(status));
 }
 
+static void setup(void)
+{
+	payload = tst_strdup(PAYLOAD);
+}
+
 static struct tst_test test = {
+	.setup = setup,
 	.test_all = do_test,
 	.forks_child = 1,
 };
-- 
2.21.0


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

* [LTP] [RFC PATCH 6/9] syscalls/adjtimex: Make use of guarded buffers.
  2019-08-01  9:26 [LTP] [RFC PATCH 0/9] Introduce guarded buffers Cyril Hrubis
                   ` (4 preceding siblings ...)
  2019-08-01  9:26 ` [LTP] [RFC PATCH 5/9] syscalls/add_key04: " Cyril Hrubis
@ 2019-08-01  9:26 ` Cyril Hrubis
  2019-08-01  9:26 ` [LTP] [RFC PATCH 7/9] syscalls/clock_getres01: " Cyril Hrubis
                   ` (3 subsequent siblings)
  9 siblings, 0 replies; 37+ messages in thread
From: Cyril Hrubis @ 2019-08-01  9:26 UTC (permalink / raw)
  To: ltp

Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
---
 .../kernel/syscalls/adjtimex/adjtimex01.c     | 23 ++++++-----
 .../kernel/syscalls/adjtimex/adjtimex02.c     | 39 +++++++++++--------
 2 files changed, 36 insertions(+), 26 deletions(-)

diff --git a/testcases/kernel/syscalls/adjtimex/adjtimex01.c b/testcases/kernel/syscalls/adjtimex/adjtimex01.c
index 51d75f3e0..60b3544a8 100644
--- a/testcases/kernel/syscalls/adjtimex/adjtimex01.c
+++ b/testcases/kernel/syscalls/adjtimex/adjtimex01.c
@@ -12,14 +12,14 @@
 #define SET_MODE (ADJ_OFFSET | ADJ_FREQUENCY | ADJ_MAXERROR | ADJ_ESTERROR | \
 	ADJ_STATUS | ADJ_TIMECONST | ADJ_TICK)
 
-static struct timex tim_save;
-static struct timex buff;
+static struct timex *tim_save;
+static struct timex *buf;
 
 void verify_adjtimex(void)
 {
-	buff = tim_save;
-	buff.modes = SET_MODE;
-	TEST(adjtimex(&buff));
+	*buf = *tim_save;
+	buf->modes = SET_MODE;
+	TEST(adjtimex(buf));
 	if ((TST_RET >= TIME_OK) && (TST_RET <= TIME_ERROR)) {
 		tst_res(TPASS, "adjtimex() with mode 0x%x ", SET_MODE);
 	} else {
@@ -27,8 +27,8 @@ void verify_adjtimex(void)
 				SET_MODE);
 	}
 
-	buff.modes = ADJ_OFFSET_SINGLESHOT;
-	TEST(adjtimex(&buff));
+	buf->modes = ADJ_OFFSET_SINGLESHOT;
+	TEST(adjtimex(buf));
 	if ((TST_RET >= TIME_OK) && (TST_RET <= TIME_ERROR)) {
 		tst_res(TPASS, "adjtimex() with mode 0x%x ",
 				ADJ_OFFSET_SINGLESHOT);
@@ -41,10 +41,10 @@ void verify_adjtimex(void)
 
 static void setup(void)
 {
-	tim_save.modes = 0;
+	tim_save->modes = 0;
 
 	/* Save current parameters */
-	if ((adjtimex(&tim_save)) == -1) {
+	if ((adjtimex(tim_save)) == -1) {
 		tst_brk(TBROK | TERRNO,
 			"adjtimex(): failed to save current params");
 	}
@@ -54,4 +54,9 @@ static struct tst_test test = {
 	.needs_root = 1,
 	.setup = setup,
 	.test_all = verify_adjtimex,
+	.bufs = (struct tst_buffers []) {
+		{&buf, .size = sizeof(*buf)},
+		{&tim_save, .size = sizeof(*tim_save)},
+		{},
+	}
 };
diff --git a/testcases/kernel/syscalls/adjtimex/adjtimex02.c b/testcases/kernel/syscalls/adjtimex/adjtimex02.c
index 2c0031992..19ee97158 100644
--- a/testcases/kernel/syscalls/adjtimex/adjtimex02.c
+++ b/testcases/kernel/syscalls/adjtimex/adjtimex02.c
@@ -16,14 +16,14 @@
 
 static int hz;			/* HZ from sysconf */
 
-static struct timex tim_save;
-static struct timex buff;
+static struct timex *tim_save;
+static struct timex *buf;
 
 static struct passwd *ltpuser;
 
 static void verify_adjtimex(unsigned int nr)
 {
-	struct timex *buffp;
+	struct timex *bufp;
 	int expected_errno = 0;
 
 	/*
@@ -39,20 +39,20 @@ static void verify_adjtimex(unsigned int nr)
 		return;
 	}
 
-	buff = tim_save;
-	buff.modes = SET_MODE;
-	buffp = &buff;
+	*buf = *tim_save;
+	buf->modes = SET_MODE;
+	bufp = buf;
 	switch (nr) {
 	case 0:
-		buffp = (struct timex *)-1;
+		bufp = (struct timex *)-1;
 		expected_errno = EFAULT;
 		break;
 	case 1:
-		buff.tick = 900000 / hz - 1;
+		buf->tick = 900000 / hz - 1;
 		expected_errno = EINVAL;
 		break;
 	case 2:
-		buff.tick = 1100000 / hz + 1;
+		buf->tick = 1100000 / hz + 1;
 		expected_errno = EINVAL;
 		break;
 	case 3:
@@ -62,18 +62,18 @@ static void verify_adjtimex(unsigned int nr)
 		expected_errno = EPERM;
 		break;
 	case 4:
-		buff.offset = 512000L + 1;
+		buf->offset = 512000L + 1;
 		expected_errno = EINVAL;
 		break;
 	case 5:
-		buff.offset = (-1) * (512000L) - 1;
+		buf->offset = (-1) * (512000L) - 1;
 		expected_errno = EINVAL;
 		break;
 	default:
 		tst_brk(TFAIL, "Invalid test case %u ", nr);
 	}
 
-	TEST(adjtimex(buffp));
+	TEST(adjtimex(bufp));
 	if ((TST_RET == -1) && (TST_ERR == expected_errno)) {
 		tst_res(TPASS | TTERRNO,
 				"adjtimex() error %u ", expected_errno);
@@ -90,23 +90,23 @@ static void verify_adjtimex(unsigned int nr)
 
 static void setup(void)
 {
-	tim_save.modes = 0;
+	tim_save->modes = 0;
 
 	/* set the HZ from sysconf */
 	hz = SAFE_SYSCONF(_SC_CLK_TCK);
 
 	/* Save current parameters */
-	if ((adjtimex(&tim_save)) == -1)
+	if ((adjtimex(tim_save)) == -1)
 		tst_brk(TBROK | TERRNO,
-				"adjtimex(): failed to save current params");
+			"adjtimex(): failed to save current params");
 }
 
 static void cleanup(void)
 {
-	tim_save.modes = SET_MODE;
+	tim_save->modes = SET_MODE;
 
 	/* Restore saved parameters */
-	if ((adjtimex(&tim_save)) == -1)
+	if ((adjtimex(tim_save)) == -1)
 		tst_res(TWARN, "Failed to restore saved parameters");
 }
 
@@ -116,4 +116,9 @@ static struct tst_test test = {
 	.setup = setup,
 	.cleanup = cleanup,
 	.test = verify_adjtimex,
+	.bufs = (struct tst_buffers []) {
+		{&buf, .size = sizeof(*buf)},
+		{&tim_save, .size = sizeof(*tim_save)},
+		{},
+	}
 };
-- 
2.21.0


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

* [LTP] [RFC PATCH 7/9] syscalls/clock_getres01: Make use of guarded buffers.
  2019-08-01  9:26 [LTP] [RFC PATCH 0/9] Introduce guarded buffers Cyril Hrubis
                   ` (5 preceding siblings ...)
  2019-08-01  9:26 ` [LTP] [RFC PATCH 6/9] syscalls/adjtimex: " Cyril Hrubis
@ 2019-08-01  9:26 ` Cyril Hrubis
  2019-08-01  9:26 ` [LTP] [RFC PATCH 8/9] syscalls/clock_settime01: " Cyril Hrubis
                   ` (2 subsequent siblings)
  9 siblings, 0 replies; 37+ messages in thread
From: Cyril Hrubis @ 2019-08-01  9:26 UTC (permalink / raw)
  To: ltp

Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
---
 .../kernel/syscalls/clock_getres/clock_getres01.c    | 12 ++++++++----
 1 file changed, 8 insertions(+), 4 deletions(-)

diff --git a/testcases/kernel/syscalls/clock_getres/clock_getres01.c b/testcases/kernel/syscalls/clock_getres/clock_getres01.c
index 15f323108..e39f2909b 100644
--- a/testcases/kernel/syscalls/clock_getres/clock_getres01.c
+++ b/testcases/kernel/syscalls/clock_getres/clock_getres01.c
@@ -15,12 +15,12 @@
 #include "tst_test.h"
 #include "lapi/posix_clocks.h"
 
-static struct timespec res;
+static struct timespec *res, *null;
 
 static struct test_case {
 	char *name;
 	clockid_t clk_id;
-	struct timespec *res;
+	struct timespec **res;
 	int ret;
 	int err;
 } tcase[] = {
@@ -28,7 +28,7 @@ static struct test_case {
 	{"MONOTONIC", CLOCK_MONOTONIC, &res, 0, 0},
 	{"PROCESS_CPUTIME_ID", CLOCK_PROCESS_CPUTIME_ID, &res, 0, 0},
 	{"THREAD_CPUTIME_ID", CLOCK_THREAD_CPUTIME_ID, &res, 0, 0},
-	{"REALTIME", CLOCK_REALTIME, NULL, 0, 0},
+	{"REALTIME", CLOCK_REALTIME, &null, 0, 0},
 	{"CLOCK_MONOTONIC_RAW", CLOCK_MONOTONIC_RAW, &res, 0, 0,},
 	{"CLOCK_REALTIME_COARSE", CLOCK_REALTIME_COARSE, &res, 0, 0,},
 	{"CLOCK_MONOTONIC_COARSE", CLOCK_MONOTONIC_COARSE, &res, 0, 0,},
@@ -40,7 +40,7 @@ static struct test_case {
 
 static void do_test(unsigned int i)
 {
-	TEST(clock_getres(tcase[i].clk_id, tcase[i].res));
+	TEST(clock_getres(tcase[i].clk_id, *tcase[i].res));
 
 	if (TST_RET != tcase[i].ret) {
 		if (TST_ERR == EINVAL) {
@@ -65,4 +65,8 @@ static void do_test(unsigned int i)
 static struct tst_test test = {
 	.test = do_test,
 	.tcnt = ARRAY_SIZE(tcase),
+	.bufs = (struct tst_buffers []) {
+		{&res, .size = sizeof(*res)},
+		{},
+	}
 };
-- 
2.21.0


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

* [LTP] [RFC PATCH 8/9] syscalls/clock_settime01: Make use of guarded buffers.
  2019-08-01  9:26 [LTP] [RFC PATCH 0/9] Introduce guarded buffers Cyril Hrubis
                   ` (6 preceding siblings ...)
  2019-08-01  9:26 ` [LTP] [RFC PATCH 7/9] syscalls/clock_getres01: " Cyril Hrubis
@ 2019-08-01  9:26 ` Cyril Hrubis
  2019-08-01  9:26 ` [LTP] [RFC PATCH 9/9] syscalls/sendmmsg01: " Cyril Hrubis
  2019-08-06  9:47 ` [LTP] [PATCH v3 0/4] eBPF tests using guarded buffers API Richard Palethorpe
  9 siblings, 0 replies; 37+ messages in thread
From: Cyril Hrubis @ 2019-08-01  9:26 UTC (permalink / raw)
  To: ltp

Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
---
 .../syscalls/clock_settime/clock_settime01.c  | 29 ++++++++++++-------
 1 file changed, 18 insertions(+), 11 deletions(-)

diff --git a/testcases/kernel/syscalls/clock_settime/clock_settime01.c b/testcases/kernel/syscalls/clock_settime/clock_settime01.c
index c68fe59a1..62d349154 100644
--- a/testcases/kernel/syscalls/clock_settime/clock_settime01.c
+++ b/testcases/kernel/syscalls/clock_settime/clock_settime01.c
@@ -23,23 +23,24 @@
 #define DELTA_US (long long) (DELTA_SEC * 1000000)
 #define DELTA_EPS (long long) (DELTA_US * 0.1)
 
+static struct timespec *begin, *change, *end;
+
 static void verify_clock_settime(void)
 {
 	long long elapsed;
-	struct timespec begin, change, end;
 
 	/* test 01: move forward */
 
-	SAFE_CLOCK_GETTIME(CLOCK_REALTIME, &begin);
+	SAFE_CLOCK_GETTIME(CLOCK_REALTIME, begin);
 
-	change = tst_timespec_add_us(begin, DELTA_US);
+	*change = tst_timespec_add_us(*begin, DELTA_US);
 
-	if (clock_settime(CLOCK_REALTIME, &change) != 0)
+	if (clock_settime(CLOCK_REALTIME, change) != 0)
 		tst_brk(TBROK | TTERRNO, "could not set realtime change");
 
-	SAFE_CLOCK_GETTIME(CLOCK_REALTIME, &end);
+	SAFE_CLOCK_GETTIME(CLOCK_REALTIME, end);
 
-	elapsed = tst_timespec_diff_us(end, begin);
+	elapsed = tst_timespec_diff_us(*end, *begin);
 
 	if (elapsed >= DELTA_US && elapsed < (DELTA_US + DELTA_EPS))
 		tst_res(TPASS, "clock_settime(2): was able to advance time");
@@ -48,16 +49,16 @@ static void verify_clock_settime(void)
 
 	/* test 02: move backward */
 
-	SAFE_CLOCK_GETTIME(CLOCK_REALTIME, &begin);
+	SAFE_CLOCK_GETTIME(CLOCK_REALTIME, begin);
 
-	change = tst_timespec_sub_us(begin, DELTA_US);
+	*change = tst_timespec_sub_us(*begin, DELTA_US);
 
-	if (clock_settime(CLOCK_REALTIME, &change) != 0)
+	if (clock_settime(CLOCK_REALTIME, change) != 0)
 		tst_brk(TBROK | TTERRNO, "could not set realtime change");
 
-	SAFE_CLOCK_GETTIME(CLOCK_REALTIME, &end);
+	SAFE_CLOCK_GETTIME(CLOCK_REALTIME, end);
 
-	elapsed = tst_timespec_diff_us(end, begin);
+	elapsed = tst_timespec_diff_us(*end, *begin);
 
 	if (~(elapsed) <= DELTA_US && ~(elapsed) > (DELTA_US - DELTA_EPS))
 		tst_res(TPASS, "clock_settime(2): was able to recede time");
@@ -69,4 +70,10 @@ static struct tst_test test = {
 	.test_all = verify_clock_settime,
 	.needs_root = 1,
 	.restore_wallclock = 1,
+	.bufs = (struct tst_buffers []) {
+		{&begin, .size = sizeof(*begin)},
+		{&change, .size = sizeof(*change)},
+		{&end, .size = sizeof(*end)},
+		{},
+	}
 };
-- 
2.21.0


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

* [LTP] [RFC PATCH 9/9] syscalls/sendmmsg01: Make use of guarded buffers.
  2019-08-01  9:26 [LTP] [RFC PATCH 0/9] Introduce guarded buffers Cyril Hrubis
                   ` (7 preceding siblings ...)
  2019-08-01  9:26 ` [LTP] [RFC PATCH 8/9] syscalls/clock_settime01: " Cyril Hrubis
@ 2019-08-01  9:26 ` Cyril Hrubis
  2019-08-06  9:47 ` [LTP] [PATCH v3 0/4] eBPF tests using guarded buffers API Richard Palethorpe
  9 siblings, 0 replies; 37+ messages in thread
From: Cyril Hrubis @ 2019-08-01  9:26 UTC (permalink / raw)
  To: ltp

We also send one more byte in the second buffer in an attempt to trick
the kernel to write after the second iovec used for receive. Note that
because this is UDP connection this byte is then discarded in kernel and
we don't have to anything even when the test is running in a loop with
the -i parameter.

Signed-off-by: Cyril Hrubis <chrubis@suse.cz>
---
 .../kernel/syscalls/sendmmsg/sendmmsg01.c     | 68 +++++++++----------
 1 file changed, 33 insertions(+), 35 deletions(-)

diff --git a/testcases/kernel/syscalls/sendmmsg/sendmmsg01.c b/testcases/kernel/syscalls/sendmmsg/sendmmsg01.c
index 7411467ee..37084102e 100644
--- a/testcases/kernel/syscalls/sendmmsg/sendmmsg01.c
+++ b/testcases/kernel/syscalls/sendmmsg/sendmmsg01.c
@@ -22,35 +22,27 @@
 
 static int send_sockfd;
 static int receive_sockfd;
-static struct mmsghdr msg[VLEN];
-static struct iovec msg1[2], msg2;
+static struct mmsghdr *snd_msg, *rcv_msg;
+static struct iovec *snd1, *snd2, *rcv1, *rcv2;
 
 static void run(void)
 {
-	struct mmsghdr msgs_in[VLEN];
-	struct iovec iovecs[VLEN];
-	char bufs[VLEN][BUFSIZE+1];
 	struct timespec timeout;
-	int i, retval;
+	int retval;
 
-	retval = do_sendmmsg(send_sockfd, msg, VLEN, 0);
-	if (retval < 0 || msg[0].msg_len != 6 || msg[1].msg_len != 5) {
+	retval = do_sendmmsg(send_sockfd, snd_msg, VLEN, 0);
+	if (retval < 0 || snd_msg[0].msg_len != 6 || snd_msg[1].msg_len != 6) {
 		tst_res(TFAIL|TTERRNO, "sendmmsg failed");
 		return;
 	}
 
-	memset(msgs_in, 0, sizeof(msgs_in));
-	for (i = 0; i < VLEN; i++) {
-		iovecs[i].iov_base = bufs[i];
-		iovecs[i].iov_len = BUFSIZE;
-		msgs_in[i].msg_hdr.msg_iov = &iovecs[i];
-		msgs_in[i].msg_hdr.msg_iovlen = 1;
-	}
+	memset(rcv1->iov_base, 0, rcv1->iov_len);
+	memset(rcv2->iov_base, 0, rcv2->iov_len);
 
 	timeout.tv_sec = 1;
 	timeout.tv_nsec = 0;
 
-	retval = do_recvmmsg(receive_sockfd, msgs_in, VLEN, 0, &timeout);
+	retval = do_recvmmsg(receive_sockfd, rcv_msg, VLEN, 0, &timeout);
 
 	if (retval == -1) {
 		tst_res(TFAIL | TTERRNO, "recvmmsg failed");
@@ -62,14 +54,12 @@ static void run(void)
 		return;
 	}
 
-	bufs[0][msgs_in[0].msg_len] = 0;
-	if (strcmp(bufs[0], "onetwo"))
+	if (memcmp(rcv1->iov_base, "onetwo", 6))
 		tst_res(TFAIL, "Error in first received message");
 	else
 		tst_res(TPASS, "First message received successfully");
 
-	bufs[1][msgs_in[1].msg_len] = 0;
-	if (strcmp(bufs[1], "three"))
+	if (memcmp(rcv2->iov_base, "three", 5))
 		tst_res(TFAIL, "Error in second received message");
 	else
 		tst_res(TPASS, "Second message received successfully");
@@ -88,24 +78,23 @@ static void setup(void)
 	addr.sin_port = port;
 
 	SAFE_BIND(receive_sockfd, (struct sockaddr *)&addr, sizeof(addr));
-	SAFE_CONNECT(send_sockfd, (struct sockaddr *) &addr, sizeof(addr));
-
-	memset(msg1, 0, sizeof(msg1));
-	msg1[0].iov_base = "one";
-	msg1[0].iov_len = 3;
-	msg1[1].iov_base = "two";
-	msg1[1].iov_len = 3;
+	SAFE_CONNECT(send_sockfd, (struct sockaddr *)&addr, sizeof(addr));
 
-	memset(&msg2, 0, sizeof(msg2));
-	msg2.iov_base = "three";
-	msg2.iov_len = 5;
+	memcpy(snd1[0].iov_base, "one", snd1[0].iov_len);
+	memcpy(snd1[1].iov_base, "two", snd1[1].iov_len);
+	memcpy(snd2->iov_base, "three3", snd2->iov_len);
 
-	memset(msg, 0, sizeof(msg));
-	msg[0].msg_hdr.msg_iov = msg1;
-	msg[0].msg_hdr.msg_iovlen = 2;
+	memset(snd_msg, 0, VLEN * sizeof(*snd_msg));
+	snd_msg[0].msg_hdr.msg_iov = snd1;
+	snd_msg[0].msg_hdr.msg_iovlen = 2;
+	snd_msg[1].msg_hdr.msg_iov = snd2;
+	snd_msg[1].msg_hdr.msg_iovlen = 1;
 
-	msg[1].msg_hdr.msg_iov = &msg2;
-	msg[1].msg_hdr.msg_iovlen = 1;
+	memset(rcv_msg, 0, VLEN * sizeof(*rcv_msg));
+	rcv_msg[0].msg_hdr.msg_iov = rcv1;
+	rcv_msg[0].msg_hdr.msg_iovlen = 1;
+	rcv_msg[1].msg_hdr.msg_iov = rcv2;
+	rcv_msg[1].msg_hdr.msg_iovlen = 1;
 
 	test_info();
 }
@@ -123,4 +112,13 @@ static struct tst_test test = {
 	.setup = setup,
 	.cleanup = cleanup,
 	.test_variants = TEST_VARIANTS,
+	.bufs = (struct tst_buffers []) {
+		{&snd1, .iov_sizes = (int[]){3, 3, -1}},
+		{&snd2, .iov_sizes = (int[]){6, -1}},
+		{&rcv1, .iov_sizes = (int[]){6, -1}},
+		{&rcv2, .iov_sizes = (int[]){5, -1}},
+		{&snd_msg, .size = VLEN * sizeof(*snd_msg)},
+		{&rcv_msg, .size = VLEN * sizeof(*rcv_msg)},
+		{},
+	}
 };
-- 
2.21.0


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

* [LTP] [RFC PATCH 1/9] lib: Add support for guarded buffers
  2019-08-01  9:26 ` [LTP] [RFC PATCH 1/9] lib: Add support for " Cyril Hrubis
@ 2019-08-01 10:39   ` Jan Stancek
  2019-08-01 11:45     ` Cyril Hrubis
  2019-08-02 13:57     ` Richard Palethorpe
  2019-08-02 14:20   ` Cyril Hrubis
                     ` (2 subsequent siblings)
  3 siblings, 2 replies; 37+ messages in thread
From: Jan Stancek @ 2019-08-01 10:39 UTC (permalink / raw)
  To: ltp


----- Original Message -----
> This commit adds a support for guarder buffers. Guarded buffer is a
> buffer allocated so that there is PROT_NONE page immediatelly after the
> end of the buffer i.e. any access after the buffer generates
> SEGFAULT/EFAULT etc.
> 
> The library is hooked into the tst_test structure so that all you need
> is to fill up an NULL terminated array of buffer pointers and sizes to
> get the respective buffers allocated. The library supports allocating
> memory in test runtime as well as well as allocating more complex
> buffers, which currently are iovec vectors.

Runtime alloc in loop could be an issue, do we need also runtime free?

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

* [LTP] [RFC PATCH 2/9] lib: Add a canary for guarded buffers
  2019-08-01  9:26 ` [LTP] [RFC PATCH 2/9] lib: Add a canary " Cyril Hrubis
@ 2019-08-01 10:43   ` Jan Stancek
  2019-08-01 11:54     ` Cyril Hrubis
  2019-08-03 13:02   ` Li Wang
  1 sibling, 1 reply; 37+ messages in thread
From: Jan Stancek @ 2019-08-01 10:43 UTC (permalink / raw)
  To: ltp



----- Original Message -----
> In a case that the buffer size is not a multiple of a page size there is
> unused space before the start of the buffer. Let's fill that with
> center mirrored random bytes and check that the buffer wasn't modified
> before we unmap it.
> 
>  void *tst_alloc(size_t size)
>  {
>  	size_t page_size = getpagesize();
> @@ -34,9 +61,13 @@ void *tst_alloc(size_t size)
>  	maps = map;
>  
>  	if (size % page_size)
> -		ret += page_size - (size % page_size);
> +		map->buf_shift = page_size - (size % page_size);
> +	else
> +		map->buf_shift = 0;
> +
> +	setup_canary(map);
>  
> -	return ret;
> +	return ret + map->buf_shift;

My concern here is alignment.

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

* [LTP] [RFC PATCH 1/9] lib: Add support for guarded buffers
  2019-08-01 10:39   ` Jan Stancek
@ 2019-08-01 11:45     ` Cyril Hrubis
  2019-08-02 14:03       ` Richard Palethorpe
  2019-08-02 13:57     ` Richard Palethorpe
  1 sibling, 1 reply; 37+ messages in thread
From: Cyril Hrubis @ 2019-08-01 11:45 UTC (permalink / raw)
  To: ltp

Hi!
> > This commit adds a support for guarder buffers. Guarded buffer is a
> > buffer allocated so that there is PROT_NONE page immediatelly after the
> > end of the buffer i.e. any access after the buffer generates
> > SEGFAULT/EFAULT etc.
> > 
> > The library is hooked into the tst_test structure so that all you need
> > is to fill up an NULL terminated array of buffer pointers and sizes to
> > get the respective buffers allocated. The library supports allocating
> > memory in test runtime as well as well as allocating more complex
> > buffers, which currently are iovec vectors.
> 
> Runtime alloc in loop could be an issue, do we need also runtime free?

We can easily add it if we find it useful, so far all the usecases
were either already allocating buffers in setup or converted to do so.

-- 
Cyril Hrubis
chrubis@suse.cz

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

* [LTP] [RFC PATCH 2/9] lib: Add a canary for guarded buffers
  2019-08-01 10:43   ` Jan Stancek
@ 2019-08-01 11:54     ` Cyril Hrubis
  2019-08-01 16:32       ` Jan Stancek
  0 siblings, 1 reply; 37+ messages in thread
From: Cyril Hrubis @ 2019-08-01 11:54 UTC (permalink / raw)
  To: ltp

Hi!
> > In a case that the buffer size is not a multiple of a page size there is
> > unused space before the start of the buffer. Let's fill that with
> > center mirrored random bytes and check that the buffer wasn't modified
> > before we unmap it.
> > 
> >  void *tst_alloc(size_t size)
> >  {
> >  	size_t page_size = getpagesize();
> > @@ -34,9 +61,13 @@ void *tst_alloc(size_t size)
> >  	maps = map;
> >  
> >  	if (size % page_size)
> > -		ret += page_size - (size % page_size);
> > +		map->buf_shift = page_size - (size % page_size);
> > +	else
> > +		map->buf_shift = 0;
> > +
> > +	setup_canary(map);
> >  
> > -	return ret;
> > +	return ret + map->buf_shift;
> 
> My concern here is alignment.

I'm aware of that. My reasoning here is that:

* The end of the page is aligned by definition to 2^page_order

* Any primitive types such as integer, etc. are hence aligned

* Structures are padded so that the total size is multiple of
  the largest alignment required (because otherwise arrays of
  structures would end up causing unaligned access as well).

That leaves out things such as buffers for direct I/O, the only way to
allocate aligned buffers there is to make the size to be multiple of
the block size.

-- 
Cyril Hrubis
chrubis@suse.cz

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

* [LTP] [RFC PATCH 2/9] lib: Add a canary for guarded buffers
  2019-08-01 11:54     ` Cyril Hrubis
@ 2019-08-01 16:32       ` Jan Stancek
  2019-08-02  9:47         ` Cyril Hrubis
  0 siblings, 1 reply; 37+ messages in thread
From: Jan Stancek @ 2019-08-01 16:32 UTC (permalink / raw)
  To: ltp



----- Original Message -----
> Hi!
> > > In a case that the buffer size is not a multiple of a page size there is
> > > unused space before the start of the buffer. Let's fill that with
> > > center mirrored random bytes and check that the buffer wasn't modified
> > > before we unmap it.
> > > 
> > >  void *tst_alloc(size_t size)
> > >  {
> > >  	size_t page_size = getpagesize();
> > > @@ -34,9 +61,13 @@ void *tst_alloc(size_t size)
> > >  	maps = map;
> > >  
> > >  	if (size % page_size)
> > > -		ret += page_size - (size % page_size);
> > > +		map->buf_shift = page_size - (size % page_size);
> > > +	else
> > > +		map->buf_shift = 0;
> > > +
> > > +	setup_canary(map);
> > >  
> > > -	return ret;
> > > +	return ret + map->buf_shift;
> > 
> > My concern here is alignment.
> 
> I'm aware of that. My reasoning here is that:
> 
> * The end of the page is aligned by definition to 2^page_order
> 
> * Any primitive types such as integer, etc. are hence aligned
> 
> * Structures are padded so that the total size is multiple of
>   the largest alignment required (because otherwise arrays of
>   structures would end up causing unaligned access as well).
> 
> That leaves out things such as buffers for direct I/O, the only way to
> allocate aligned buffers there is to make the size to be multiple of
> the block size.

I don't have concrete example at hand, but I foggily recall
s390 issue from couple years back, where it didn't like odd addresses.
Can't recall if it was data or code pointer.

Could we apply/enforce some minimum alignment, similar to what glibc
does for malloc?

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

* [LTP] [RFC PATCH 2/9] lib: Add a canary for guarded buffers
  2019-08-01 16:32       ` Jan Stancek
@ 2019-08-02  9:47         ` Cyril Hrubis
  2019-08-02 10:54           ` Jan Stancek
  0 siblings, 1 reply; 37+ messages in thread
From: Cyril Hrubis @ 2019-08-02  9:47 UTC (permalink / raw)
  To: ltp

Hi!
> > I'm aware of that. My reasoning here is that:
> > 
> > * The end of the page is aligned by definition to 2^page_order
> > 
> > * Any primitive types such as integer, etc. are hence aligned
> > 
> > * Structures are padded so that the total size is multiple of
> >   the largest alignment required (because otherwise arrays of
> >   structures would end up causing unaligned access as well).
> > 
> > That leaves out things such as buffers for direct I/O, the only way to
> > allocate aligned buffers there is to make the size to be multiple of
> > the block size.
> 
> I don't have concrete example at hand, but I foggily recall
> s390 issue from couple years back, where it didn't like odd addresses.
> Can't recall if it was data or code pointer.

Data should be fine as far as they are aligned accordingly to the type sizes.

I.e. one byte acces is fine on odd addresses, otherwise most of the
functions in string.h wouldn't work.

For shorts i.e. two byte integers odd addresses are slower on x86 and
x86_64 however does not work at all on many architectures. I remember
that 32bit arm used to have in-kernel emulation that mostly did the
right job but sometimes you got wrong results, so unaligned accesses are
better to be avoided.

The question is if kernel expects some alignment for buffers for things
such as read()/write() etc. I doubt so, since that would still break
things like write(fd, "aabbcc" + 1, 3) which I would expect is still
valid code.

Or do you have anything else in mind that may break?

> Could we apply/enforce some minimum alignment, similar to what glibc
> does for malloc?

That would be against the purpose of this patchset, i.e. catching
off-by-one bugs, since the page boundary would be a few bytes after the
end of the buffer in some cases. Well I guess that most of the
allocations would be as a matter of fact aligned and even these that are
not could be easily fixed by choosing buffers that are multiples of
four.

I would be fine with aligning the buffers for architectures that turn
out to be problematic if we find some. However I would like to avoid to
"just in case" modifications.

-- 
Cyril Hrubis
chrubis@suse.cz

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

* [LTP] [RFC PATCH 2/9] lib: Add a canary for guarded buffers
  2019-08-02  9:47         ` Cyril Hrubis
@ 2019-08-02 10:54           ` Jan Stancek
  0 siblings, 0 replies; 37+ messages in thread
From: Jan Stancek @ 2019-08-02 10:54 UTC (permalink / raw)
  To: ltp



----- Original Message -----
> Hi!
> > > I'm aware of that. My reasoning here is that:
> > > 
> > > * The end of the page is aligned by definition to 2^page_order
> > > 
> > > * Any primitive types such as integer, etc. are hence aligned
> > > 
> > > * Structures are padded so that the total size is multiple of
> > >   the largest alignment required (because otherwise arrays of
> > >   structures would end up causing unaligned access as well).
> > > 
> > > That leaves out things such as buffers for direct I/O, the only way to
> > > allocate aligned buffers there is to make the size to be multiple of
> > > the block size.
> > 
> > I don't have concrete example at hand, but I foggily recall
> > s390 issue from couple years back, where it didn't like odd addresses.
> > Can't recall if it was data or code pointer.
> 
> Data should be fine as far as they are aligned accordingly to the type sizes.
> 
> I.e. one byte acces is fine on odd addresses, otherwise most of the
> functions in string.h wouldn't work.
> 
> For shorts i.e. two byte integers odd addresses are slower on x86 and
> x86_64 however does not work at all on many architectures. I remember
> that 32bit arm used to have in-kernel emulation that mostly did the
> right job but sometimes you got wrong results, so unaligned accesses are
> better to be avoided.
> 
> The question is if kernel expects some alignment for buffers for things
> such as read()/write() etc. I doubt so, since that would still break
> things like write(fd, "aabbcc" + 1, 3) which I would expect is still
> valid code.
> 
> Or do you have anything else in mind that may break?

I was thinking of buffers, but as it turns out the example I had in mind
was about alignment of symbols:

[    1.888972] Loading compiled-in X.509 certificates
[    1.888974] Problem parsing in-kernel X.509 certificate list

Dump of assembler code for function load_system_certificate_list:
   0x00000000009ad2c0 <+0>:     stmg    %r6,%r15,72(%r15)
   0x00000000009ad2c6 <+6>:     larl    %r13,0x64bdb8
   0x00000000009ad2cc <+12>:    larl    %r2,0x799032
   0x00000000009ad2d2 <+18>:    tmll    %r15,16256
   0x00000000009ad2d6 <+22>:    lgr     %r14,%r15
   0x00000000009ad2da <+26>:    lay     %r15,-104(%r15)
   0x00000000009ad2e0 <+32>:    je      0x9ad2e2 <load_system_certificate_list+34>
   0x00000000009ad2e4 <+36>:    stg     %r14,152(%r15)
   0x00000000009ad2ea <+42>:    larl    %r8,0x9ee28c <__setup_str_nosmp+5>
                                           ^^^^^^^^
From z/Architecture Principles of Operation SA22-7832-07:
"Only even addresses (halfword addresses) can
be generated. If an odd address is desired,
LOAD ADDRESS can be used to add one to an
address formed by LOAD ADDRESS RELATIVE
LONG."

> 
> > Could we apply/enforce some minimum alignment, similar to what glibc
> > does for malloc?
> 
> That would be against the purpose of this patchset, i.e. catching
> off-by-one bugs, since the page boundary would be a few bytes after the
> end of the buffer in some cases. Well I guess that most of the
> allocations would be as a matter of fact aligned and even these that are
> not could be easily fixed by choosing buffers that are multiples of
> four.

OK, that's a fair point.

> 
> I would be fine with aligning the buffers for architectures that turn
> out to be problematic if we find some. However I would like to avoid to
> "just in case" modifications.
> 
> --
> Cyril Hrubis
> chrubis@suse.cz
> 

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

* [LTP] [RFC PATCH 1/9] lib: Add support for guarded buffers
  2019-08-01 10:39   ` Jan Stancek
  2019-08-01 11:45     ` Cyril Hrubis
@ 2019-08-02 13:57     ` Richard Palethorpe
  2019-08-02 13:59       ` Cyril Hrubis
  1 sibling, 1 reply; 37+ messages in thread
From: Richard Palethorpe @ 2019-08-02 13:57 UTC (permalink / raw)
  To: ltp

Hello,

Jan Stancek <jstancek@redhat.com> writes:

> ----- Original Message -----
>> This commit adds a support for guarder buffers. Guarded buffer is a
>> buffer allocated so that there is PROT_NONE page immediatelly after the
>> end of the buffer i.e. any access after the buffer generates
>> SEGFAULT/EFAULT etc.
>> 
>> The library is hooked into the tst_test structure so that all you need
>> is to fill up an NULL terminated array of buffer pointers and sizes to
>> get the respective buffers allocated. The library supports allocating
>> memory in test runtime as well as well as allocating more complex
>> buffers, which currently are iovec vectors.
>
> Runtime alloc in loop could be an issue, do we need also runtime free?

I think tst_alloc needs a bit more documentation at the least. If we
have runtime free then we need to figure out which map the address
belongs to or what its offset is (if any).

-- 
Thank you,
Richard.

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

* [LTP] [RFC PATCH 1/9] lib: Add support for guarded buffers
  2019-08-02 13:57     ` Richard Palethorpe
@ 2019-08-02 13:59       ` Cyril Hrubis
  2019-08-02 14:23         ` Cyril Hrubis
  2019-08-02 14:36         ` Richard Palethorpe
  0 siblings, 2 replies; 37+ messages in thread
From: Cyril Hrubis @ 2019-08-02 13:59 UTC (permalink / raw)
  To: ltp

Hi!
> >> This commit adds a support for guarder buffers. Guarded buffer is a
> >> buffer allocated so that there is PROT_NONE page immediatelly after the
> >> end of the buffer i.e. any access after the buffer generates
> >> SEGFAULT/EFAULT etc.
> >> 
> >> The library is hooked into the tst_test structure so that all you need
> >> is to fill up an NULL terminated array of buffer pointers and sizes to
> >> get the respective buffers allocated. The library supports allocating
> >> memory in test runtime as well as well as allocating more complex
> >> buffers, which currently are iovec vectors.
> >
> > Runtime alloc in loop could be an issue, do we need also runtime free?
> 
> I think tst_alloc needs a bit more documentation at the least.

I will write an paragraph to test-writing-guidelines.txt about this
functionality.

> If we have runtime free then we need to figure out which map the
> address belongs to or what its offset is (if any).

That's easy, we will store the returned pointer to the map structure
and use it for comparsion...

-- 
Cyril Hrubis
chrubis@suse.cz

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

* [LTP] [RFC PATCH 1/9] lib: Add support for guarded buffers
  2019-08-01 11:45     ` Cyril Hrubis
@ 2019-08-02 14:03       ` Richard Palethorpe
  0 siblings, 0 replies; 37+ messages in thread
From: Richard Palethorpe @ 2019-08-02 14:03 UTC (permalink / raw)
  To: ltp

Hello,

Cyril Hrubis <chrubis@suse.cz> writes:

> Hi!
>> > This commit adds a support for guarder buffers. Guarded buffer is a
>> > buffer allocated so that there is PROT_NONE page immediatelly after the
>> > end of the buffer i.e. any access after the buffer generates
>> > SEGFAULT/EFAULT etc.
>> > 
>> > The library is hooked into the tst_test structure so that all you need
>> > is to fill up an NULL terminated array of buffer pointers and sizes to
>> > get the respective buffers allocated. The library supports allocating
>> > memory in test runtime as well as well as allocating more complex
>> > buffers, which currently are iovec vectors.
>> 
>> Runtime alloc in loop could be an issue, do we need also runtime free?
>
> We can easily add it if we find it useful, so far all the usecases
> were either already allocating buffers in setup or converted to do so.

I am just starting to convert one of the bpf tests and I am considering
just wrapping the systemcall or creating some helper func which takes
whatever buffer is supplied and copy it to a new gaurded buffer. It is
maybe not efficient with large buffer sizes, but in most cases I don't
think it would matter too much.

-- 
Thank you,
Richard.

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

* [LTP] [RFC PATCH 1/9] lib: Add support for guarded buffers
  2019-08-01  9:26 ` [LTP] [RFC PATCH 1/9] lib: Add support for " Cyril Hrubis
  2019-08-01 10:39   ` Jan Stancek
@ 2019-08-02 14:20   ` Cyril Hrubis
  2019-08-03 12:55   ` Li Wang
  2019-08-06  9:03   ` Richard Palethorpe
  3 siblings, 0 replies; 37+ messages in thread
From: Cyril Hrubis @ 2019-08-02 14:20 UTC (permalink / raw)
  To: ltp

Hi!
> diff --git a/testcases/kernel/syscalls/accept/accept02.c b/testcases/kernel/syscalls/accept/accept02.c
> index df048ede4..1a0f625c9 100644
> --- a/testcases/kernel/syscalls/accept/accept02.c
> +++ b/testcases/kernel/syscalls/accept/accept02.c

Sigh looks like I've added this test conversion to this patch as a
mistake, I will move it to a separate patch in v2.

-- 
Cyril Hrubis
chrubis@suse.cz

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

* [LTP] [RFC PATCH 1/9] lib: Add support for guarded buffers
  2019-08-02 13:59       ` Cyril Hrubis
@ 2019-08-02 14:23         ` Cyril Hrubis
  2019-08-02 14:36         ` Richard Palethorpe
  1 sibling, 0 replies; 37+ messages in thread
From: Cyril Hrubis @ 2019-08-02 14:23 UTC (permalink / raw)
  To: ltp

Hi!
> > If we have runtime free then we need to figure out which map the
> > address belongs to or what its offset is (if any).
> 
> That's easy, we will store the returned pointer to the map structure
> and use it for comparsion...

Or we even don't have to do that, we do have a buffer start address and
length so we just need to make sure that the pointer fits the range...

-- 
Cyril Hrubis
chrubis@suse.cz

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

* [LTP] [RFC PATCH 1/9] lib: Add support for guarded buffers
  2019-08-02 13:59       ` Cyril Hrubis
  2019-08-02 14:23         ` Cyril Hrubis
@ 2019-08-02 14:36         ` Richard Palethorpe
  2019-08-02 14:50           ` Cyril Hrubis
  1 sibling, 1 reply; 37+ messages in thread
From: Richard Palethorpe @ 2019-08-02 14:36 UTC (permalink / raw)
  To: ltp

Hello,

Cyril Hrubis <chrubis@suse.cz> writes:

> Hi!
>> >> This commit adds a support for guarder buffers. Guarded buffer is a
>> >> buffer allocated so that there is PROT_NONE page immediatelly after the
>> >> end of the buffer i.e. any access after the buffer generates
>> >> SEGFAULT/EFAULT etc.
>> >> 
>> >> The library is hooked into the tst_test structure so that all you need
>> >> is to fill up an NULL terminated array of buffer pointers and sizes to
>> >> get the respective buffers allocated. The library supports allocating
>> >> memory in test runtime as well as well as allocating more complex
>> >> buffers, which currently are iovec vectors.
>> >
>> > Runtime alloc in loop could be an issue, do we need also runtime free?
>> 
>> I think tst_alloc needs a bit more documentation at the least.
>
> I will write an paragraph to test-writing-guidelines.txt about this
> functionality.
>
>> If we have runtime free then we need to figure out which map the
>> address belongs to or what its offset is (if any).
>
> That's easy, we will store the returned pointer to the map structure
> and use it for comparsion...

So that free() is an O(n) operation where n is the number of maps or you
will use a hash map to make it O(1)?

-- 
Thank you,
Richard.

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

* [LTP] [RFC PATCH 1/9] lib: Add support for guarded buffers
  2019-08-02 14:36         ` Richard Palethorpe
@ 2019-08-02 14:50           ` Cyril Hrubis
  0 siblings, 0 replies; 37+ messages in thread
From: Cyril Hrubis @ 2019-08-02 14:50 UTC (permalink / raw)
  To: ltp

Hi!
> >> If we have runtime free then we need to figure out which map the
> >> address belongs to or what its offset is (if any).
> >
> > That's easy, we will store the returned pointer to the map structure
> > and use it for comparsion...
> 
> So that free() is an O(n) operation where n is the number of maps or you
> will use a hash map to make it O(1)?

I doubt that we will ever allocate more than a few buffers, so it's
perfectly fine that way. Also if you keep allocating and freeing buffer
in a loop it would be at the start of the list, so it would be O(1) as
well.

The only patological case would be allocating thousands of buffers and
then freeing them in a reversed order, which would be O(n^2).

Other options would be storing the pointer to the map before the buffer,
just as malloc does, but I doubt that we will ever need that.

-- 
Cyril Hrubis
chrubis@suse.cz

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

* [LTP] [RFC PATCH 1/9] lib: Add support for guarded buffers
  2019-08-01  9:26 ` [LTP] [RFC PATCH 1/9] lib: Add support for " Cyril Hrubis
  2019-08-01 10:39   ` Jan Stancek
  2019-08-02 14:20   ` Cyril Hrubis
@ 2019-08-03 12:55   ` Li Wang
  2019-08-06  7:36     ` Richard Palethorpe
  2019-08-06  9:03   ` Richard Palethorpe
  3 siblings, 1 reply; 37+ messages in thread
From: Li Wang @ 2019-08-03 12:55 UTC (permalink / raw)
  To: ltp

Hi Cyril,

This is a quite good idea to involve guard buffer in LTP testing. And
you patch set looks very clean & tidy, just have some few comments in
below.

On Thu, Aug 1, 2019 at 5:27 PM Cyril Hrubis <chrubis@suse.cz> wrote:
>
> This commit adds a support for guarder buffers. Guarded buffer is a
> buffer allocated so that there is PROT_NONE page immediatelly after the
> end of the buffer i.e. any access after the buffer generates
> SEGFAULT/EFAULT etc.
>
> The library is hooked into the tst_test structure so that all you need
> is to fill up an NULL terminated array of buffer pointers and sizes to
> get the respective buffers allocated. The library supports allocating
> memory in test runtime as well as well as allocating more complex
> buffers, which currently are iovec vectors.
>
> All buffers are freeed automatically at the end of the test.
...

> + * Allocates size bytes, returns pointer to the allocated buffer.
> + */
> +void *tst_alloc(size_t size);

What about drawing a simple picture in the code comments? That can
help people to understand what kind of buffer structure the
tst_alloc() returned.

/*
 * Allocates size bytes, returns pointer to the allocated buffer.
 *
 * This is the structure of the allocated buferr:
 *
 * |<--  1 page  -->|                 |<--  1 page  -->|
 *
 * -----------------------------------------------------
 * | buf_shift | <-- bufs[i].size --> |  1 guard page  |
 * -----------------------------------------------------
 */
void *tst_alloc(size_t size);

> +++ b/include/tst_test.h
> @@ -35,6 +35,7 @@
>  #include "tst_path_has_mnt_flags.h"
>  #include "tst_sys_conf.h"
>  #include "tst_coredump.h"
> +#include "tst_buffers.h"
>
>  /*
>   * Reports testcase result.
> @@ -200,6 +201,11 @@ struct tst_test {
>          * test.
>          */
>         const char *const *needs_kconfigs;
> +
> +       /*
> +        * NULL-terminated array to be allocated buffers.
> +        */
> +       struct tst_buffers *bufs;

I tend to agree with Richard for this. Looks like adding such a new
field in tst_test struct is a little bit complicated. Maybe we can
define a series macro for doing that, which something likes:

TST_INIT_GUARD_BUFFER(ptr, size)
TST_INIT_IOVEC_GUARD_BUFFER(ptr, iov_sizes)

then, testcase just calling it in setup() if needed.

--
Regards,
Li Wang

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

* [LTP] [RFC PATCH 2/9] lib: Add a canary for guarded buffers
  2019-08-01  9:26 ` [LTP] [RFC PATCH 2/9] lib: Add a canary " Cyril Hrubis
  2019-08-01 10:43   ` Jan Stancek
@ 2019-08-03 13:02   ` Li Wang
  2019-08-08  9:27     ` Cyril Hrubis
  1 sibling, 1 reply; 37+ messages in thread
From: Li Wang @ 2019-08-03 13:02 UTC (permalink / raw)
  To: ltp

On Thu, Aug 1, 2019 at 5:26 PM Cyril Hrubis <chrubis@suse.cz> wrote:
>
> In a case that the buffer size is not a multiple of a page size there is
> unused space before the start of the buffer. Let's fill that with
> center mirrored random bytes and check that the buffer wasn't modified
> before we unmap it.

I like this check canary part. Amazing to me.

> +
> +static void check_canary(struct map *map)
> +{
> +       size_t i;
> +       char *buf = map->addr;
> +
> +       for (i = 0; i < map->buf_shift/2; i++) {
> +               if (buf[map->buf_shift - i - 1] != buf[i]) {
> +                       tst_res(TWARN,
> +                               "pid %i: buffer modified before address %p %zu",
> +                               (char*)map->addr + map->buf_shift, i);

Here you probably missed the getpid() for printing %i match :).

-- 
Regards,
Li Wang

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

* [LTP] [RFC PATCH 1/9] lib: Add support for guarded buffers
  2019-08-03 12:55   ` Li Wang
@ 2019-08-06  7:36     ` Richard Palethorpe
  0 siblings, 0 replies; 37+ messages in thread
From: Richard Palethorpe @ 2019-08-06  7:36 UTC (permalink / raw)
  To: ltp

Hello,

Li Wang <liwang@redhat.com> writes:
>
> I tend to agree with Richard for this. Looks like adding such a new
> field in tst_test struct is a little bit complicated. Maybe we can
> define a series macro for doing that, which something likes:
>
> TST_INIT_GUARD_BUFFER(ptr, size)

I think tst_alloc() is OK (although maybe it should be
tst_guarded_alloc()), but the API is missing its inverse; tst_free().

> TST_INIT_IOVEC_GUARD_BUFFER(ptr, iov_sizes)

Or I guess, tst_alloc() could take tst_buffer(s) as its argument and
return the right type of buffer based on that.

>
> then, testcase just calling it in setup() if needed.

I don't think allocating the buffers in tst_test is a bad idea in
some/most cases. I think the problem is that some primitive, low level
functions are missing, which will make edge cases difficult to deal
with.

--
Thank you,
Richard.

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

* [LTP] [RFC PATCH 1/9] lib: Add support for guarded buffers
  2019-08-01  9:26 ` [LTP] [RFC PATCH 1/9] lib: Add support for " Cyril Hrubis
                     ` (2 preceding siblings ...)
  2019-08-03 12:55   ` Li Wang
@ 2019-08-06  9:03   ` Richard Palethorpe
  2019-08-08  9:06     ` Cyril Hrubis
  3 siblings, 1 reply; 37+ messages in thread
From: Richard Palethorpe @ 2019-08-06  9:03 UTC (permalink / raw)
  To: ltp

Hi,

Cyril Hrubis <chrubis@suse.cz> writes:
> +void tst_free_all(void)
> +{
> +	struct map *i = maps;
> +
> +	while (i) {
> +		struct map *j = i;
> +		tst_res(TINFO, "Freeing %p %zu", i->addr, i->size);

This seems like debug info to me. Not really useful most of the time.

> +		SAFE_MUNMAP(i->addr, i->size);
> +		i = i->next;
> +		free(j);
> +	}
> +
> +	maps = NULL;
> +}

-- 
Thank you,
Richard.

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

* [LTP] [PATCH v3 0/4] eBPF tests using guarded buffers API
  2019-08-01  9:26 [LTP] [RFC PATCH 0/9] Introduce guarded buffers Cyril Hrubis
                   ` (8 preceding siblings ...)
  2019-08-01  9:26 ` [LTP] [RFC PATCH 9/9] syscalls/sendmmsg01: " Cyril Hrubis
@ 2019-08-06  9:47 ` Richard Palethorpe
  2019-08-06  9:47   ` [LTP] [PATCH v3 1/4] BPF: Essential headers for map creation Richard Palethorpe
                     ` (3 more replies)
  9 siblings, 4 replies; 37+ messages in thread
From: Richard Palethorpe @ 2019-08-06  9:47 UTC (permalink / raw)
  To: ltp

Hello,

This is another version of my basic eBPF tests using Metan's guarded buffers
patch set. I have tried to use the new API for any pointer passed to a system
call.

Richard Palethorpe (4):
  BPF: Essential headers for map creation
  BPF: Sanity check creating and updating maps
  BPF: Essential headers for a basic program
  BPF: Sanity check creating a program

 include/lapi/bpf.h                         | 526 +++++++++++++++++++++
 include/lapi/socket.h                      |   4 +
 include/lapi/syscalls/aarch64.in           |   1 +
 include/lapi/syscalls/i386.in              |   1 +
 include/lapi/syscalls/s390.in              |   1 +
 include/lapi/syscalls/sparc.in             |   1 +
 include/lapi/syscalls/x86_64.in            |   1 +
 runtest/syscalls                           |   3 +
 testcases/kernel/syscalls/bpf/.gitignore   |   2 +
 testcases/kernel/syscalls/bpf/Makefile     |  10 +
 testcases/kernel/syscalls/bpf/bpf_map01.c  | 140 ++++++
 testcases/kernel/syscalls/bpf/bpf_prog01.c | 161 +++++++
 12 files changed, 851 insertions(+)
 create mode 100644 include/lapi/bpf.h
 create mode 100644 testcases/kernel/syscalls/bpf/.gitignore
 create mode 100644 testcases/kernel/syscalls/bpf/Makefile
 create mode 100644 testcases/kernel/syscalls/bpf/bpf_map01.c
 create mode 100644 testcases/kernel/syscalls/bpf/bpf_prog01.c

-- 
2.22.0


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

* [LTP] [PATCH v3 1/4] BPF: Essential headers for map creation
  2019-08-06  9:47 ` [LTP] [PATCH v3 0/4] eBPF tests using guarded buffers API Richard Palethorpe
@ 2019-08-06  9:47   ` Richard Palethorpe
  2019-08-06  9:47   ` [LTP] [PATCH v3 2/4] BPF: Sanity check creating and updating maps Richard Palethorpe
                     ` (2 subsequent siblings)
  3 siblings, 0 replies; 37+ messages in thread
From: Richard Palethorpe @ 2019-08-06  9:47 UTC (permalink / raw)
  To: ltp

Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
---
 include/lapi/bpf.h               | 242 +++++++++++++++++++++++++++++++
 include/lapi/syscalls/aarch64.in |   1 +
 include/lapi/syscalls/i386.in    |   1 +
 include/lapi/syscalls/s390.in    |   1 +
 include/lapi/syscalls/sparc.in   |   1 +
 include/lapi/syscalls/x86_64.in  |   1 +
 6 files changed, 247 insertions(+)
 create mode 100644 include/lapi/bpf.h

diff --git a/include/lapi/bpf.h b/include/lapi/bpf.h
new file mode 100644
index 000000000..369de0175
--- /dev/null
+++ b/include/lapi/bpf.h
@@ -0,0 +1,242 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Richard Palethorpe <rpalethorpe@suse.com>
+ *
+ * Essential Extended Berkeley Packet Filter (eBPF) headers
+ *
+ * Mostly copied/adapted from linux/bpf.h and libbpf so that we can perform
+ * some eBPF testing without any external dependencies.
+ */
+
+#ifndef BPF_H
+# define BPF_H
+
+#include <stdint.h>
+
+#include "lapi/syscalls.h"
+
+/* Start copy from linux/bpf.h */
+enum bpf_cmd {
+	BPF_MAP_CREATE,
+	BPF_MAP_LOOKUP_ELEM,
+	BPF_MAP_UPDATE_ELEM,
+	BPF_MAP_DELETE_ELEM,
+	BPF_MAP_GET_NEXT_KEY,
+	BPF_PROG_LOAD,
+	BPF_OBJ_PIN,
+	BPF_OBJ_GET,
+	BPF_PROG_ATTACH,
+	BPF_PROG_DETACH,
+	BPF_PROG_TEST_RUN,
+	BPF_PROG_GET_NEXT_ID,
+	BPF_MAP_GET_NEXT_ID,
+	BPF_PROG_GET_FD_BY_ID,
+	BPF_MAP_GET_FD_BY_ID,
+	BPF_OBJ_GET_INFO_BY_FD,
+	BPF_PROG_QUERY,
+	BPF_RAW_TRACEPOINT_OPEN,
+	BPF_BTF_LOAD,
+	BPF_BTF_GET_FD_BY_ID,
+	BPF_TASK_FD_QUERY,
+	BPF_MAP_LOOKUP_AND_DELETE_ELEM,
+	BPF_MAP_FREEZE,
+};
+
+enum bpf_map_type {
+	BPF_MAP_TYPE_UNSPEC,
+	BPF_MAP_TYPE_HASH,
+	BPF_MAP_TYPE_ARRAY,
+	BPF_MAP_TYPE_PROG_ARRAY,
+	BPF_MAP_TYPE_PERF_EVENT_ARRAY,
+	BPF_MAP_TYPE_PERCPU_HASH,
+	BPF_MAP_TYPE_PERCPU_ARRAY,
+	BPF_MAP_TYPE_STACK_TRACE,
+	BPF_MAP_TYPE_CGROUP_ARRAY,
+	BPF_MAP_TYPE_LRU_HASH,
+	BPF_MAP_TYPE_LRU_PERCPU_HASH,
+	BPF_MAP_TYPE_LPM_TRIE,
+	BPF_MAP_TYPE_ARRAY_OF_MAPS,
+	BPF_MAP_TYPE_HASH_OF_MAPS,
+	BPF_MAP_TYPE_DEVMAP,
+	BPF_MAP_TYPE_SOCKMAP,
+	BPF_MAP_TYPE_CPUMAP,
+	BPF_MAP_TYPE_XSKMAP,
+	BPF_MAP_TYPE_SOCKHASH,
+	BPF_MAP_TYPE_CGROUP_STORAGE,
+	BPF_MAP_TYPE_REUSEPORT_SOCKARRAY,
+	BPF_MAP_TYPE_PERCPU_CGROUP_STORAGE,
+	BPF_MAP_TYPE_QUEUE,
+	BPF_MAP_TYPE_STACK,
+	BPF_MAP_TYPE_SK_STORAGE,
+};
+
+#define BPF_OBJ_NAME_LEN 16U
+
+#define BPF_ANY		0 /* create new element or update existing */
+#define BPF_NOEXIST	1 /* create new element if it didn't exist */
+#define BPF_EXIST	2 /* update existing element */
+#define BPF_F_LOCK	4 /* spin_lock-ed map_lookup/map_update */
+
+#define aligned_uint64_t uint64_t __attribute__((aligned(8)))
+
+union bpf_attr {
+	struct { /* anonymous struct used by BPF_MAP_CREATE command */
+		uint32_t	map_type;	/* one of enum bpf_map_type */
+		uint32_t	key_size;	/* size of key in bytes */
+		uint32_t	value_size;	/* size of value in bytes */
+		uint32_t	max_entries;	/* max number of entries in a map */
+		uint32_t	map_flags;	/* BPF_MAP_CREATE related
+					 * flags defined above.
+					 */
+		uint32_t	inner_map_fd;	/* fd pointing to the inner map */
+		uint32_t	numa_node;	/* numa node (effective only if
+					 * BPF_F_NUMA_NODE is set).
+					 */
+		char	map_name[BPF_OBJ_NAME_LEN];
+		uint32_t	map_ifindex;	/* ifindex of netdev to create on */
+		uint32_t	btf_fd;		/* fd pointing to a BTF type data */
+		uint32_t	btf_key_type_id;	/* BTF type_id of the key */
+		uint32_t	btf_value_type_id;	/* BTF type_id of the value */
+	};
+
+	struct { /* anonymous struct used by BPF_MAP_*_ELEM commands */
+		uint32_t		map_fd;
+		aligned_uint64_t	key;
+		union {
+			aligned_uint64_t value;
+			aligned_uint64_t next_key;
+		};
+		uint64_t		flags;
+	};
+
+	struct { /* anonymous struct used by BPF_PROG_LOAD command */
+		uint32_t		prog_type;	/* one of enum bpf_prog_type */
+		uint32_t		insn_cnt;
+		aligned_uint64_t	insns;
+		aligned_uint64_t	license;
+		uint32_t		log_level;	/* verbosity level of verifier */
+		uint32_t		log_size;	/* size of user buffer */
+		aligned_uint64_t	log_buf;	/* user supplied buffer */
+		uint32_t		kern_version;	/* not used */
+		uint32_t		prog_flags;
+		char		prog_name[BPF_OBJ_NAME_LEN];
+		uint32_t		prog_ifindex;	/* ifindex of netdev to prep for */
+		/* For some prog types expected attach type must be known at
+		 * load time to verify attach type specific parts of prog
+		 * (context accesses, allowed helpers, etc).
+		 */
+		uint32_t		expected_attach_type;
+		uint32_t		prog_btf_fd;	/* fd pointing to BTF type data */
+		uint32_t		func_info_rec_size;	/* userspace bpf_func_info size */
+		aligned_uint64_t	func_info;	/* func info */
+		uint32_t		func_info_cnt;	/* number of bpf_func_info records */
+		uint32_t		line_info_rec_size;	/* userspace bpf_line_info size */
+		aligned_uint64_t	line_info;	/* line info */
+		uint32_t		line_info_cnt;	/* number of bpf_line_info records */
+	};
+
+	struct { /* anonymous struct used by BPF_OBJ_* commands */
+		aligned_uint64_t	pathname;
+		uint32_t		bpf_fd;
+		uint32_t		file_flags;
+	};
+
+	struct { /* anonymous struct used by BPF_PROG_ATTACH/DETACH commands */
+		uint32_t		target_fd;	/* container object to attach to */
+		uint32_t		attach_bpf_fd;	/* eBPF program to attach */
+		uint32_t		attach_type;
+		uint32_t		attach_flags;
+	};
+
+	struct { /* anonymous struct used by BPF_PROG_TEST_RUN command */
+		uint32_t		prog_fd;
+		uint32_t		retval;
+		uint32_t		data_size_in;	/* input: len of data_in */
+		uint32_t		data_size_out;	/* input/output: len of data_out
+						 *   returns ENOSPC if data_out
+						 *   is too small.
+						 */
+		aligned_uint64_t	data_in;
+		aligned_uint64_t	data_out;
+		uint32_t		repeat;
+		uint32_t		duration;
+		uint32_t		ctx_size_in;	/* input: len of ctx_in */
+		uint32_t		ctx_size_out;	/* input/output: len of ctx_out
+						 *   returns ENOSPC if ctx_out
+						 *   is too small.
+						 */
+		aligned_uint64_t	ctx_in;
+		aligned_uint64_t	ctx_out;
+	} test;
+
+	struct { /* anonymous struct used by BPF_*_GET_*_ID */
+		union {
+			uint32_t		start_id;
+			uint32_t		prog_id;
+			uint32_t		map_id;
+			uint32_t		btf_id;
+		};
+		uint32_t		next_id;
+		uint32_t		open_flags;
+	};
+
+	struct { /* anonymous struct used by BPF_OBJ_GET_INFO_BY_FD */
+		uint32_t		bpf_fd;
+		uint32_t		info_len;
+		aligned_uint64_t	info;
+	} info;
+
+	struct { /* anonymous struct used by BPF_PROG_QUERY command */
+		uint32_t		target_fd;	/* container object to query */
+		uint32_t		attach_type;
+		uint32_t		query_flags;
+		uint32_t		attach_flags;
+		aligned_uint64_t	prog_ids;
+		uint32_t		prog_cnt;
+	} query;
+
+	struct {
+		uint64_t name;
+		uint32_t prog_fd;
+	} raw_tracepoint;
+
+	struct { /* anonymous struct for BPF_BTF_LOAD */
+		aligned_uint64_t	btf;
+		aligned_uint64_t	btf_log_buf;
+		uint32_t		btf_size;
+		uint32_t		btf_log_size;
+		uint32_t		btf_log_level;
+	};
+
+	struct {
+		uint32_t		pid;		/* input: pid */
+		uint32_t		fd;		/* input: fd */
+		uint32_t		flags;		/* input: flags */
+		uint32_t		buf_len;	/* input/output: buf len */
+		aligned_uint64_t	buf;		/* input/output:
+						 *   tp_name for tracepoint
+						 *   symbol for kprobe
+						 *   filename for uprobe
+						 */
+		uint32_t		prog_id;	/* output: prod_id */
+		uint32_t		fd_type;	/* output: BPF_FD_TYPE_* */
+		uint64_t		probe_offset;	/* output: probe_offset */
+		uint64_t		probe_addr;	/* output: probe_addr */
+	} task_fd_query;
+} __attribute__((aligned(8)));
+
+/* End copy from linux/bpf.h */
+
+/* Start copy from tools/lib/bpf  */
+inline uint64_t ptr_to_u64(const void *ptr)
+{
+	return (uint64_t) (unsigned long) ptr;
+}
+
+inline int bpf(enum bpf_cmd cmd, union bpf_attr *attr, unsigned int size)
+{
+	return tst_syscall(__NR_bpf, cmd, attr, size);
+}
+/* End copy from tools/lib/bpf */
+
+#endif	/* BPF_H */
diff --git a/include/lapi/syscalls/aarch64.in b/include/lapi/syscalls/aarch64.in
index 7db6e281c..0e00641bc 100644
--- a/include/lapi/syscalls/aarch64.in
+++ b/include/lapi/syscalls/aarch64.in
@@ -258,6 +258,7 @@ process_vm_writev 271
 kcmp 272
 getrandom 278
 memfd_create 279
+bpf 280
 userfaultfd 282
 membarrier 283
 execveat 281
diff --git a/include/lapi/syscalls/i386.in b/include/lapi/syscalls/i386.in
index 02f3955ba..87ab46933 100644
--- a/include/lapi/syscalls/i386.in
+++ b/include/lapi/syscalls/i386.in
@@ -340,6 +340,7 @@ sched_getattr 352
 renameat2 354
 getrandom 355
 memfd_create 356
+bpf 357
 execveat 358
 userfaultfd 374
 membarrier 375
diff --git a/include/lapi/syscalls/s390.in b/include/lapi/syscalls/s390.in
index c304ef4b7..d3f7eb1f6 100644
--- a/include/lapi/syscalls/s390.in
+++ b/include/lapi/syscalls/s390.in
@@ -331,6 +331,7 @@ sched_getattr 346
 renameat2 347
 getrandom 349
 memfd_create 350
+bpf 351
 userfaultfd 355
 membarrier 356
 execveat 354
diff --git a/include/lapi/syscalls/sparc.in b/include/lapi/syscalls/sparc.in
index ab7204663..94a672428 100644
--- a/include/lapi/syscalls/sparc.in
+++ b/include/lapi/syscalls/sparc.in
@@ -336,6 +336,7 @@ kcmp 341
 renameat2 345
 getrandom 347
 memfd_create 348
+bpf 349
 membarrier 351
 userfaultfd 352
 execveat 350
diff --git a/include/lapi/syscalls/x86_64.in b/include/lapi/syscalls/x86_64.in
index fdb414c10..b1cbd4f2f 100644
--- a/include/lapi/syscalls/x86_64.in
+++ b/include/lapi/syscalls/x86_64.in
@@ -307,6 +307,7 @@ sched_getattr 315
 renameat2 316
 getrandom 318
 memfd_create 319
+bpf 321
 execveat 322
 userfaultfd 323
 membarrier 324
-- 
2.22.0


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

* [LTP] [PATCH v3 2/4] BPF: Sanity check creating and updating maps
  2019-08-06  9:47 ` [LTP] [PATCH v3 0/4] eBPF tests using guarded buffers API Richard Palethorpe
  2019-08-06  9:47   ` [LTP] [PATCH v3 1/4] BPF: Essential headers for map creation Richard Palethorpe
@ 2019-08-06  9:47   ` Richard Palethorpe
  2019-08-06  9:47   ` [LTP] [PATCH v3 3/4] BPF: Essential headers for a basic program Richard Palethorpe
  2019-08-06  9:47   ` [LTP] [PATCH v3 4/4] BPF: Sanity check creating a program Richard Palethorpe
  3 siblings, 0 replies; 37+ messages in thread
From: Richard Palethorpe @ 2019-08-06  9:47 UTC (permalink / raw)
  To: ltp

Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
---
 runtest/syscalls                          |   2 +
 testcases/kernel/syscalls/bpf/.gitignore  |   1 +
 testcases/kernel/syscalls/bpf/Makefile    |  10 ++
 testcases/kernel/syscalls/bpf/bpf_map01.c | 140 ++++++++++++++++++++++
 4 files changed, 153 insertions(+)
 create mode 100644 testcases/kernel/syscalls/bpf/.gitignore
 create mode 100644 testcases/kernel/syscalls/bpf/Makefile
 create mode 100644 testcases/kernel/syscalls/bpf/bpf_map01.c

diff --git a/runtest/syscalls b/runtest/syscalls
index a68a4c9d0..9d48285b8 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -32,6 +32,8 @@ bind01 bind01
 bind02 bind02
 bind03 bind03
 
+bpf_map01 bpf_map01
+
 brk01 brk01
 
 capget01 capget01
diff --git a/testcases/kernel/syscalls/bpf/.gitignore b/testcases/kernel/syscalls/bpf/.gitignore
new file mode 100644
index 000000000..f33532484
--- /dev/null
+++ b/testcases/kernel/syscalls/bpf/.gitignore
@@ -0,0 +1 @@
+bpf_map01
diff --git a/testcases/kernel/syscalls/bpf/Makefile b/testcases/kernel/syscalls/bpf/Makefile
new file mode 100644
index 000000000..990c8c83c
--- /dev/null
+++ b/testcases/kernel/syscalls/bpf/Makefile
@@ -0,0 +1,10 @@
+# SPDX-License-Identifier: GPL-2.0-or-later
+# Copyright (c) 2019 Linux Test Project
+
+top_srcdir		?= ../../../..
+
+include $(top_srcdir)/include/mk/testcases.mk
+
+CFLAGS			+= -D_GNU_SOURCE
+
+include $(top_srcdir)/include/mk/generic_leaf_target.mk
diff --git a/testcases/kernel/syscalls/bpf/bpf_map01.c b/testcases/kernel/syscalls/bpf/bpf_map01.c
new file mode 100644
index 000000000..c5ddd8aad
--- /dev/null
+++ b/testcases/kernel/syscalls/bpf/bpf_map01.c
@@ -0,0 +1,140 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Richard Palethorpe <rpalethorpe@suse.com>
+ *
+ * Trivial Extended Berkeley Packet Filter (eBPF) test.
+ *
+ * Sanity check creating and updating maps.
+ */
+
+#include <limits.h>
+#include <string.h>
+
+#include "config.h"
+#include "tst_test.h"
+#include "lapi/bpf.h"
+
+#define KEY_SZ 8
+#define VAL_SZ 1024
+
+struct map_type {
+	uint32_t id;
+	char *name;
+};
+
+static const struct map_type map_types[] = {
+	{BPF_MAP_TYPE_HASH, "hash"},
+	{BPF_MAP_TYPE_ARRAY, "array"}
+};
+
+static void *key;
+static void *val0;
+static void *val1;
+static union bpf_attr *attr;
+
+void run(unsigned int n)
+{
+	int fd, i;
+
+	memset(attr, 0, sizeof(*attr));
+	attr->map_type = map_types[n].id;
+	attr->key_size = n == 0 ? KEY_SZ : 4;
+	attr->value_size = VAL_SZ;
+	attr->max_entries = 1;
+
+	TEST(bpf(BPF_MAP_CREATE, attr, sizeof(*attr)));
+	if (TST_RET == -1) {
+		if (TST_ERR == EPERM) {
+			tst_brk(TCONF | TTERRNO,
+				"bpf() requires CAP_SYS_ADMIN on this system");
+		} else {
+			tst_brk(TFAIL | TTERRNO, "Failed to create %s map",
+				map_types[n].name);
+		}
+	}
+	tst_res(TPASS, "Created %s map", map_types[n].name);
+	fd = TST_RET;
+
+	if (n == 0)
+		memcpy(key, "12345678", KEY_SZ);
+	else
+		memset(key, 0, 4);
+
+	memset(attr, 0, sizeof(*attr));
+	attr->map_fd = fd;
+	attr->key = ptr_to_u64(key);
+	attr->value = ptr_to_u64(val1);
+
+	TEST(bpf(BPF_MAP_LOOKUP_ELEM, attr, sizeof(*attr)));
+	if (n == 0) {
+		if (TST_RET != -1 || TST_ERR != ENOENT) {
+			tst_res(TFAIL | TTERRNO,
+				"Empty hash map lookup should fail with ENOENT");
+		} else {
+			tst_res(TPASS | TTERRNO, "Empty hash map lookup");
+		}
+	} else if (TST_RET != -1) {
+		for (i = 0;;) {
+			if (*(char *) val1 != 0) {
+				tst_res(TFAIL,
+					"Preallocated array map val not zero");
+			} else if (++i >= VAL_SZ) {
+				tst_res(TPASS,
+					"Preallocated array map lookup");
+				break;
+			}
+		}
+	} else {
+		tst_res(TFAIL | TERRNO, "Prellocated array map lookup");
+	}
+
+	memset(attr, 0, sizeof(*attr));
+	attr->map_fd = fd;
+	attr->key = ptr_to_u64(key);
+	attr->value = ptr_to_u64(val0);
+	attr->flags = BPF_ANY;
+
+	TEST(bpf(BPF_MAP_UPDATE_ELEM, attr, sizeof(*attr)));
+	if (TST_RET == -1) {
+		tst_brk(TFAIL | TTERRNO,
+			"Update %s map element",
+			map_types[n].name);
+	} else {
+		tst_res(TPASS,
+			"Update %s map element",
+			map_types[n].name);
+	}
+
+	memset(attr, 0, sizeof(*attr));
+	attr->map_fd = fd;
+	attr->key = ptr_to_u64(key);
+	attr->value = ptr_to_u64(val1);
+
+	TEST(bpf(BPF_MAP_LOOKUP_ELEM, attr, sizeof(*attr)));
+	if (TST_RET == -1) {
+		tst_res(TFAIL | TTERRNO,
+			"%s map lookup missing",
+			map_types[n].name);
+	} else if (memcmp(val0, val1, (size_t) VAL_SZ)) {
+		tst_res(TFAIL,
+			"%s map lookup returned different value",
+			map_types[n].name);
+	} else {
+		tst_res(TPASS, "%s map lookup", map_types[n].name);
+	}
+
+	SAFE_CLOSE(fd);
+}
+
+static struct tst_test test = {
+	.tcnt = 2,
+	.test = run,
+	.min_kver = "3.18",
+	.bufs = (struct tst_buffers []) {
+		{&key, .size = KEY_SZ},
+		{&val0, .size = VAL_SZ},
+		{&val1, .size = VAL_SZ},
+		{&attr, .size = sizeof(*attr)},
+		{NULL},
+	},
+};
-- 
2.22.0


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

* [LTP] [PATCH v3 3/4] BPF: Essential headers for a basic program
  2019-08-06  9:47 ` [LTP] [PATCH v3 0/4] eBPF tests using guarded buffers API Richard Palethorpe
  2019-08-06  9:47   ` [LTP] [PATCH v3 1/4] BPF: Essential headers for map creation Richard Palethorpe
  2019-08-06  9:47   ` [LTP] [PATCH v3 2/4] BPF: Sanity check creating and updating maps Richard Palethorpe
@ 2019-08-06  9:47   ` Richard Palethorpe
  2019-08-06  9:47   ` [LTP] [PATCH v3 4/4] BPF: Sanity check creating a program Richard Palethorpe
  3 siblings, 0 replies; 37+ messages in thread
From: Richard Palethorpe @ 2019-08-06  9:47 UTC (permalink / raw)
  To: ltp

Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
---
 include/lapi/bpf.h    | 286 +++++++++++++++++++++++++++++++++++++++++-
 include/lapi/socket.h |   4 +
 2 files changed, 289 insertions(+), 1 deletion(-)

diff --git a/include/lapi/bpf.h b/include/lapi/bpf.h
index 369de0175..122eb5469 100644
--- a/include/lapi/bpf.h
+++ b/include/lapi/bpf.h
@@ -15,7 +15,57 @@
 
 #include "lapi/syscalls.h"
 
-/* Start copy from linux/bpf.h */
+/* Start copy from linux/bpf_(common).h */
+#define BPF_CLASS(code) ((code) & 0x07)
+#define		BPF_LD		0x00
+#define		BPF_ST		0x02
+#define		BPF_JMP		0x05
+
+#define BPF_SIZE(code)  ((code) & 0x18)
+#define         BPF_DW		0x18	/* double word (64-bit) */
+
+#define BPF_MODE(code)  ((code) & 0xe0)
+#define		BPF_IMM		0x00
+#define		BPF_MEM		0x60
+
+#define BPF_OP(code)    ((code) & 0xf0)
+#define		BPF_ADD		0x00
+
+#define		BPF_JEQ		0x10
+
+#define BPF_SRC(code)   ((code) & 0x08)
+#define		BPF_K		0x00
+#define		BPF_X		0x08
+
+#define BPF_ALU64	0x07	/* alu mode in double word width */
+#define BPF_MOV		0xb0	/* mov reg to reg */
+#define BPF_CALL	0x80	/* function call */
+#define BPF_EXIT	0x90	/* function return */
+
+/* Register numbers */
+enum {
+	BPF_REG_0 = 0,
+	BPF_REG_1,
+	BPF_REG_2,
+	BPF_REG_3,
+	BPF_REG_4,
+	BPF_REG_5,
+	BPF_REG_6,
+	BPF_REG_7,
+	BPF_REG_8,
+	BPF_REG_9,
+	BPF_REG_10,
+	MAX_BPF_REG,
+};
+
+struct bpf_insn {
+	uint8_t	code;		/* opcode */
+	uint8_t	dst_reg:4;	/* dest register */
+	uint8_t	src_reg:4;	/* source register */
+	int16_t	off;		/* signed offset */
+	int32_t	imm;		/* signed immediate constant */
+};
+
 enum bpf_cmd {
 	BPF_MAP_CREATE,
 	BPF_MAP_LOOKUP_ELEM,
@@ -70,6 +120,37 @@ enum bpf_map_type {
 	BPF_MAP_TYPE_SK_STORAGE,
 };
 
+enum bpf_prog_type {
+	BPF_PROG_TYPE_UNSPEC,
+	BPF_PROG_TYPE_SOCKET_FILTER,
+	BPF_PROG_TYPE_KPROBE,
+	BPF_PROG_TYPE_SCHED_CLS,
+	BPF_PROG_TYPE_SCHED_ACT,
+	BPF_PROG_TYPE_TRACEPOINT,
+	BPF_PROG_TYPE_XDP,
+	BPF_PROG_TYPE_PERF_EVENT,
+	BPF_PROG_TYPE_CGROUP_SKB,
+	BPF_PROG_TYPE_CGROUP_SOCK,
+	BPF_PROG_TYPE_LWT_IN,
+	BPF_PROG_TYPE_LWT_OUT,
+	BPF_PROG_TYPE_LWT_XMIT,
+	BPF_PROG_TYPE_SOCK_OPS,
+	BPF_PROG_TYPE_SK_SKB,
+	BPF_PROG_TYPE_CGROUP_DEVICE,
+	BPF_PROG_TYPE_SK_MSG,
+	BPF_PROG_TYPE_RAW_TRACEPOINT,
+	BPF_PROG_TYPE_CGROUP_SOCK_ADDR,
+	BPF_PROG_TYPE_LWT_SEG6LOCAL,
+	BPF_PROG_TYPE_LIRC_MODE2,
+	BPF_PROG_TYPE_SK_REUSEPORT,
+	BPF_PROG_TYPE_FLOW_DISSECTOR,
+	BPF_PROG_TYPE_CGROUP_SYSCTL,
+	BPF_PROG_TYPE_RAW_TRACEPOINT_WRITABLE,
+	BPF_PROG_TYPE_CGROUP_SOCKOPT,
+};
+
+#define BPF_PSEUDO_MAP_FD	1
+
 #define BPF_OBJ_NAME_LEN 16U
 
 #define BPF_ANY		0 /* create new element or update existing */
@@ -225,8 +306,211 @@ union bpf_attr {
 	} task_fd_query;
 } __attribute__((aligned(8)));
 
+#define __BPF_FUNC_MAPPER(FN)		\
+	FN(unspec),			\
+	FN(map_lookup_elem),		\
+	FN(map_update_elem),		\
+	FN(map_delete_elem),		\
+	FN(probe_read),			\
+	FN(ktime_get_ns),		\
+	FN(trace_printk),		\
+	FN(get_prandom_u32),		\
+	FN(get_smp_processor_id),	\
+	FN(skb_store_bytes),		\
+	FN(l3_csum_replace),		\
+	FN(l4_csum_replace),		\
+	FN(tail_call),			\
+	FN(clone_redirect),		\
+	FN(get_current_pid_tgid),	\
+	FN(get_current_uid_gid),	\
+	FN(get_current_comm),		\
+	FN(get_cgroup_classid),		\
+	FN(skb_vlan_push),		\
+	FN(skb_vlan_pop),		\
+	FN(skb_get_tunnel_key),		\
+	FN(skb_set_tunnel_key),		\
+	FN(perf_event_read),		\
+	FN(redirect),			\
+	FN(get_route_realm),		\
+	FN(perf_event_output),		\
+	FN(skb_load_bytes),		\
+	FN(get_stackid),		\
+	FN(csum_diff),			\
+	FN(skb_get_tunnel_opt),		\
+	FN(skb_set_tunnel_opt),		\
+	FN(skb_change_proto),		\
+	FN(skb_change_type),		\
+	FN(skb_under_cgroup),		\
+	FN(get_hash_recalc),		\
+	FN(get_current_task),		\
+	FN(probe_write_user),		\
+	FN(current_task_under_cgroup),	\
+	FN(skb_change_tail),		\
+	FN(skb_pull_data),		\
+	FN(csum_update),		\
+	FN(set_hash_invalid),		\
+	FN(get_numa_node_id),		\
+	FN(skb_change_head),		\
+	FN(xdp_adjust_head),		\
+	FN(probe_read_str),		\
+	FN(get_socket_cookie),		\
+	FN(get_socket_uid),		\
+	FN(set_hash),			\
+	FN(setsockopt),			\
+	FN(skb_adjust_room),		\
+	FN(redirect_map),		\
+	FN(sk_redirect_map),		\
+	FN(sock_map_update),		\
+	FN(xdp_adjust_meta),		\
+	FN(perf_event_read_value),	\
+	FN(perf_prog_read_value),	\
+	FN(getsockopt),			\
+	FN(override_return),		\
+	FN(sock_ops_cb_flags_set),	\
+	FN(msg_redirect_map),		\
+	FN(msg_apply_bytes),		\
+	FN(msg_cork_bytes),		\
+	FN(msg_pull_data),		\
+	FN(bind),			\
+	FN(xdp_adjust_tail),		\
+	FN(skb_get_xfrm_state),		\
+	FN(get_stack),			\
+	FN(skb_load_bytes_relative),	\
+	FN(fib_lookup),			\
+	FN(sock_hash_update),		\
+	FN(msg_redirect_hash),		\
+	FN(sk_redirect_hash),		\
+	FN(lwt_push_encap),		\
+	FN(lwt_seg6_store_bytes),	\
+	FN(lwt_seg6_adjust_srh),	\
+	FN(lwt_seg6_action),		\
+	FN(rc_repeat),			\
+	FN(rc_keydown),			\
+	FN(skb_cgroup_id),		\
+	FN(get_current_cgroup_id),	\
+	FN(get_local_storage),		\
+	FN(sk_select_reuseport),	\
+	FN(skb_ancestor_cgroup_id),	\
+	FN(sk_lookup_tcp),		\
+	FN(sk_lookup_udp),		\
+	FN(sk_release),			\
+	FN(map_push_elem),		\
+	FN(map_pop_elem),		\
+	FN(map_peek_elem),		\
+	FN(msg_push_data),		\
+	FN(msg_pop_data),		\
+	FN(rc_pointer_rel),		\
+	FN(spin_lock),			\
+	FN(spin_unlock),		\
+	FN(sk_fullsock),		\
+	FN(tcp_sock),			\
+	FN(skb_ecn_set_ce),		\
+	FN(get_listener_sock),		\
+	FN(skc_lookup_tcp),		\
+	FN(tcp_check_syncookie),	\
+	FN(sysctl_get_name),		\
+	FN(sysctl_get_current_value),	\
+	FN(sysctl_get_new_value),	\
+	FN(sysctl_set_new_value),	\
+	FN(strtol),			\
+	FN(strtoul),			\
+	FN(sk_storage_get),		\
+	FN(sk_storage_delete),		\
+	FN(send_signal),
+
+/* integer value in 'imm' field of BPF_CALL instruction selects which helper
+ * function eBPF program intends to call
+ */
+#define __BPF_ENUM_FN(x) BPF_FUNC_ ## x
+enum bpf_func_id {
+	__BPF_FUNC_MAPPER(__BPF_ENUM_FN)
+	__BPF_FUNC_MAX_ID,
+};
+#undef __BPF_ENUM_FN
+
 /* End copy from linux/bpf.h */
 
+/* Start copy from tools/include/filter.h */
+
+#define BPF_ALU64_IMM(OP, DST, IMM)				\
+	((struct bpf_insn) {					\
+		.code  = BPF_ALU64 | BPF_OP(OP) | BPF_K,	\
+		.dst_reg = DST,					\
+		.src_reg = 0,					\
+		.off   = 0,					\
+		.imm   = IMM })
+
+#define BPF_MOV64_REG(DST, SRC)					\
+	((struct bpf_insn) {					\
+		.code  = BPF_ALU64 | BPF_MOV | BPF_X,		\
+		.dst_reg = DST,					\
+		.src_reg = SRC,					\
+		.off   = 0,					\
+		.imm   = 0 })
+
+#define BPF_LD_IMM64(DST, IMM)					\
+	BPF_LD_IMM64_RAW(DST, 0, IMM)
+
+#define BPF_LD_IMM64_RAW(DST, SRC, IMM)				\
+	((struct bpf_insn) {					\
+		.code  = BPF_LD | BPF_DW | BPF_IMM,		\
+		.dst_reg = DST,					\
+		.src_reg = SRC,					\
+		.off   = 0,					\
+		.imm   = (uint32_t) (IMM) }),			\
+	((struct bpf_insn) {					\
+		.code  = 0, /* zero is reserved opcode */	\
+		.dst_reg = 0,					\
+		.src_reg = 0,					\
+		.off   = 0,					\
+		.imm   = ((uint64_t) (IMM)) >> 32 })
+
+/* pseudo BPF_LD_IMM64 insn used to refer to process-local map_fd */
+#define BPF_LD_MAP_FD(DST, MAP_FD)				\
+	BPF_LD_IMM64_RAW(DST, BPF_PSEUDO_MAP_FD, MAP_FD)
+
+#define BPF_ST_MEM(SIZE, DST, OFF, IMM)				\
+	((struct bpf_insn) {					\
+		.code  = BPF_ST | BPF_SIZE(SIZE) | BPF_MEM,	\
+		.dst_reg = DST,					\
+		.src_reg = 0,					\
+		.off   = OFF,					\
+		.imm   = IMM })
+
+#define BPF_JMP_IMM(OP, DST, IMM, OFF)				\
+	((struct bpf_insn) {					\
+		.code  = BPF_JMP | BPF_OP(OP) | BPF_K,		\
+		.dst_reg = DST,					\
+		.src_reg = 0,					\
+		.off   = OFF,					\
+		.imm   = IMM })
+
+#define BPF_MOV64_IMM(DST, IMM)					\
+	((struct bpf_insn) {					\
+		.code  = BPF_ALU64 | BPF_MOV | BPF_K,		\
+		.dst_reg = DST,					\
+		.src_reg = 0,					\
+		.off   = 0,					\
+		.imm   = IMM })
+
+#define BPF_EMIT_CALL(FUNC)					\
+	((struct bpf_insn) {					\
+		.code  = BPF_JMP | BPF_CALL,			\
+		.dst_reg = 0,					\
+		.src_reg = 0,					\
+		.off   = 0,					\
+		.imm   = ((FUNC) - BPF_FUNC_unspec) })
+
+#define BPF_EXIT_INSN()						\
+	((struct bpf_insn) {					\
+		.code  = BPF_JMP | BPF_EXIT,			\
+		.dst_reg = 0,					\
+		.src_reg = 0,					\
+		.off   = 0,					\
+		.imm   = 0 })
+
+/* End copy from tools/include/filter.h */
+
 /* Start copy from tools/lib/bpf  */
 inline uint64_t ptr_to_u64(const void *ptr)
 {
diff --git a/include/lapi/socket.h b/include/lapi/socket.h
index 6d9e9fe30..f32782fed 100644
--- a/include/lapi/socket.h
+++ b/include/lapi/socket.h
@@ -38,6 +38,10 @@
 # define SO_BUSY_POLL	46
 #endif
 
+#ifndef SO_ATTACH_BPF
+# define SO_ATTACH_BPF  50
+#endif
+
 #ifndef SO_ZEROCOPY
 # define SO_ZEROCOPY	60
 #endif
-- 
2.22.0


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

* [LTP] [PATCH v3 4/4] BPF: Sanity check creating a program
  2019-08-06  9:47 ` [LTP] [PATCH v3 0/4] eBPF tests using guarded buffers API Richard Palethorpe
                     ` (2 preceding siblings ...)
  2019-08-06  9:47   ` [LTP] [PATCH v3 3/4] BPF: Essential headers for a basic program Richard Palethorpe
@ 2019-08-06  9:47   ` Richard Palethorpe
  3 siblings, 0 replies; 37+ messages in thread
From: Richard Palethorpe @ 2019-08-06  9:47 UTC (permalink / raw)
  To: ltp

Signed-off-by: Richard Palethorpe <rpalethorpe@suse.com>
---
 runtest/syscalls                           |   1 +
 testcases/kernel/syscalls/bpf/.gitignore   |   1 +
 testcases/kernel/syscalls/bpf/bpf_prog01.c | 161 +++++++++++++++++++++
 3 files changed, 163 insertions(+)
 create mode 100644 testcases/kernel/syscalls/bpf/bpf_prog01.c

diff --git a/runtest/syscalls b/runtest/syscalls
index 9d48285b8..c0c325c92 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -33,6 +33,7 @@ bind02 bind02
 bind03 bind03
 
 bpf_map01 bpf_map01
+bpf_prog01 bpf_prog01
 
 brk01 brk01
 
diff --git a/testcases/kernel/syscalls/bpf/.gitignore b/testcases/kernel/syscalls/bpf/.gitignore
index f33532484..7eb5f7c92 100644
--- a/testcases/kernel/syscalls/bpf/.gitignore
+++ b/testcases/kernel/syscalls/bpf/.gitignore
@@ -1 +1,2 @@
 bpf_map01
+bpf_prog01
diff --git a/testcases/kernel/syscalls/bpf/bpf_prog01.c b/testcases/kernel/syscalls/bpf/bpf_prog01.c
new file mode 100644
index 000000000..9cb2a0c86
--- /dev/null
+++ b/testcases/kernel/syscalls/bpf/bpf_prog01.c
@@ -0,0 +1,161 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) 2019 Richard Palethorpe <rpalethorpe@suse.com>
+ *
+ * Trivial Extended Berkeley Packet Filter (eBPF) test.
+ *
+ * Sanity check loading and running bytecode.
+ *
+ * Test flow:
+ * 1. Create array map
+ * 2. Load eBPF program
+ * 3. Attach program to socket
+ * 4. Send packet on socket
+ * 5. This should trigger eBPF program which writes to array map
+ * 6. Verify array map was written to
+ */
+
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "config.h"
+#include "tst_test.h"
+#include "lapi/socket.h"
+#include "lapi/bpf.h"
+
+const char MSG[] = "Ahoj!";
+static char *msg;
+
+/*
+ * The following is a byte code template. We copy it to a guarded buffer and
+ * substitute the runtime value of our map file descriptor.
+ *
+ * r0 - r10 = registers 0 to 10
+ * r0 = return code
+ * r1 - r5 = scratch registers, used for function arguments
+ * r6 - r9 = registers preserved across function calls
+ * fp/r10 = stack frame pointer
+ */
+const struct bpf_insn PROG[] = {
+	/* Load the map FD into r1 (place holder) */
+	BPF_LD_MAP_FD(BPF_REG_1, 0),
+	/* Put (key = 0) on stack and key ptr into r2 */
+	BPF_MOV64_REG(BPF_REG_2, BPF_REG_10),   /* r2 = fp */
+	BPF_ALU64_IMM(BPF_ADD, BPF_REG_2, -8),  /* r2 = r2 - 8 */
+	BPF_ST_MEM(BPF_DW, BPF_REG_2, 0, 0),    /* *r2 = 0 */
+	/* r0 = bpf_map_lookup_elem(r1, r2) */
+	BPF_EMIT_CALL(BPF_FUNC_map_lookup_elem),
+	/* if r0 == 0 goto exit */
+	BPF_JMP_IMM(BPF_JEQ, BPF_REG_0, 0, 3),
+	/* Set map[0] = 1 */
+	BPF_MOV64_REG(BPF_REG_1, BPF_REG_0),     /* r1 = r0 */
+	BPF_ST_MEM(BPF_DW, BPF_REG_1, 0, 1),     /* *r1 = 1 */
+	BPF_MOV64_IMM(BPF_REG_0, 0),             /* r0 = 0 */
+	BPF_EXIT_INSN(),		         /* return r0 */
+};
+static struct bpf_insn *prog;
+static char *log;
+static union bpf_attr *attr;
+
+int load_prog(int fd)
+{
+	prog[0] = BPF_LD_MAP_FD(BPF_REG_1, fd);
+
+	memset(attr, 0, sizeof(*attr));
+	attr->prog_type = BPF_PROG_TYPE_SOCKET_FILTER;
+	attr->insns = ptr_to_u64(prog);
+	attr->insn_cnt = ARRAY_SIZE(PROG);
+	attr->license = ptr_to_u64("GPL");
+	attr->log_buf = ptr_to_u64(log);
+	attr->log_size = BUFSIZ;
+	attr->log_level = 1;
+
+	TEST(bpf(BPF_PROG_LOAD, attr, sizeof(*attr)));
+	if (TST_RET == -1) {
+		if (log[0] != 0) {
+			tst_brk(TFAIL | TTERRNO,
+				"Failed verification: %s",
+				log);
+		} else {
+			tst_brk(TFAIL | TTERRNO, "Failed to load program");
+		}
+	} else {
+		tst_res(TPASS, "Loaded program");
+	}
+
+	return TST_RET;
+}
+
+void setup(void)
+{
+	memcpy(prog, PROG, sizeof(PROG));
+	memcpy(msg, MSG, sizeof(MSG));
+}
+
+void run(void)
+{
+	int map_fd, prog_fd;
+	int sk[2];
+	uint32_t key = 0;
+	uint64_t val;
+
+	memset(attr, 0, sizeof(*attr));
+	attr->map_type = BPF_MAP_TYPE_ARRAY;
+	attr->key_size = 4;
+	attr->value_size = 8;
+	attr->max_entries = 1;
+
+	TEST(bpf(BPF_MAP_CREATE, attr, sizeof(*attr)));
+	if (TST_RET == -1) {
+		if (TST_ERR == EPERM) {
+			tst_brk(TCONF | TTERRNO,
+				"bpf() requires CAP_SYS_ADMIN on this system");
+		} else {
+			tst_brk(TBROK | TTERRNO, "Failed to create array map");
+		}
+	}
+	map_fd = TST_RET;
+
+	prog_fd = load_prog(map_fd);
+
+	SAFE_SOCKETPAIR(AF_UNIX, SOCK_DGRAM, 0, sk);
+	SAFE_SETSOCKOPT(sk[1], SOL_SOCKET, SO_ATTACH_BPF,
+			&prog_fd, sizeof(prog_fd));
+
+	SAFE_WRITE(1, sk[0], msg, sizeof(MSG));
+
+	memset(attr, 0, sizeof(*attr));
+	attr->map_fd = map_fd;
+	attr->key = ptr_to_u64(&key);
+	attr->value = ptr_to_u64(&val);
+
+	TEST(bpf(BPF_MAP_LOOKUP_ELEM, attr, sizeof(*attr)));
+	if (TST_RET == -1) {
+		tst_res(TFAIL | TTERRNO, "array map lookup");
+	} else if (val != 1) {
+		tst_res(TFAIL,
+			"val = %lu, but should be val = 1",
+			val);
+        } else {
+	        tst_res(TPASS, "val = 1");
+	}
+
+	SAFE_CLOSE(prog_fd);
+	SAFE_CLOSE(map_fd);
+	SAFE_CLOSE(sk[0]);
+	SAFE_CLOSE(sk[1]);
+}
+
+static struct tst_test test = {
+	.setup = setup,
+	.test_all = run,
+	.min_kver = "3.18",
+	.bufs = (struct tst_buffers []) {
+		{&log, .size = BUFSIZ},
+		{&prog, .size = sizeof(PROG)},
+		{&attr, .size = sizeof(*attr)},
+		{&msg, .size = sizeof(MSG)},
+		{NULL},
+	}
+};
-- 
2.22.0


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

* [LTP] [RFC PATCH 1/9] lib: Add support for guarded buffers
  2019-08-06  9:03   ` Richard Palethorpe
@ 2019-08-08  9:06     ` Cyril Hrubis
  2019-08-08  9:13       ` Li Wang
  2019-08-08 15:41       ` Richard Palethorpe
  0 siblings, 2 replies; 37+ messages in thread
From: Cyril Hrubis @ 2019-08-08  9:06 UTC (permalink / raw)
  To: ltp

Hi!
> > +void tst_free_all(void)
> > +{
> > +	struct map *i = maps;
> > +
> > +	while (i) {
> > +		struct map *j = i;
> > +		tst_res(TINFO, "Freeing %p %zu", i->addr, i->size);
> 
> This seems like debug info to me. Not really useful most of the time.

Yes, this is a leftover.

I do wonder if we should print a message first time the tst_alloc() is
called so that it's clear that the test is using guarded buffers.

> > +		SAFE_MUNMAP(i->addr, i->size);
> > +		i = i->next;
> > +		free(j);
> > +	}
> > +
> > +	maps = NULL;
> > +}
> 
> -- 
> Thank you,
> Richard.
> 
> -- 
> Mailing list info: https://lists.linux.it/listinfo/ltp

-- 
Cyril Hrubis
chrubis@suse.cz

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

* [LTP] [RFC PATCH 1/9] lib: Add support for guarded buffers
  2019-08-08  9:06     ` Cyril Hrubis
@ 2019-08-08  9:13       ` Li Wang
  2019-08-08 15:41       ` Richard Palethorpe
  1 sibling, 0 replies; 37+ messages in thread
From: Li Wang @ 2019-08-08  9:13 UTC (permalink / raw)
  To: ltp

> > This seems like debug info to me. Not really useful most of the time.
>
> Yes, this is a leftover.
>
> I do wonder if we should print a message first time the tst_alloc() is
> called so that it's clear that the test is using guarded buffers.

Sounds necessary. Or should we need a way for silent using?

-- 
Regards,
Li Wang

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

* [LTP] [RFC PATCH 2/9] lib: Add a canary for guarded buffers
  2019-08-03 13:02   ` Li Wang
@ 2019-08-08  9:27     ` Cyril Hrubis
  0 siblings, 0 replies; 37+ messages in thread
From: Cyril Hrubis @ 2019-08-08  9:27 UTC (permalink / raw)
  To: ltp

Hi!
> > +static void check_canary(struct map *map)
> > +{
> > +       size_t i;
> > +       char *buf = map->addr;
> > +
> > +       for (i = 0; i < map->buf_shift/2; i++) {
> > +               if (buf[map->buf_shift - i - 1] != buf[i]) {
> > +                       tst_res(TWARN,
> > +                               "pid %i: buffer modified before address %p %zu",
> > +                               (char*)map->addr + map->buf_shift, i);
> 
> Here you probably missed the getpid() for printing %i match :).

Ah, right, I guess that this is unfinished last minute modification.

Actually as it is the canaries are checked only for the main library pid
becuase the tst_free_all() is hooked up in the do_test_cleanup().

I guess that we should call it in the run_tests() function before we
call exit(0) for the child processes as well as in the tst_vbrk_() and
after that changes printing pid in the warning makes sense.

-- 
Cyril Hrubis
chrubis@suse.cz

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

* [LTP] [RFC PATCH 1/9] lib: Add support for guarded buffers
  2019-08-08  9:06     ` Cyril Hrubis
  2019-08-08  9:13       ` Li Wang
@ 2019-08-08 15:41       ` Richard Palethorpe
  1 sibling, 0 replies; 37+ messages in thread
From: Richard Palethorpe @ 2019-08-08 15:41 UTC (permalink / raw)
  To: ltp

Hello,

Cyril Hrubis <chrubis@suse.cz> writes:

> Hi!
>> > +void tst_free_all(void)
>> > +{
>> > +	struct map *i = maps;
>> > +
>> > +	while (i) {
>> > +		struct map *j = i;
>> > +		tst_res(TINFO, "Freeing %p %zu", i->addr, i->size);
>> 
>> This seems like debug info to me. Not really useful most of the time.
>
> Yes, this is a leftover.
>
> I do wonder if we should print a message first time the tst_alloc() is
> called so that it's clear that the test is using guarded buffers.

Maybe some summary info.

>
>> > +		SAFE_MUNMAP(i->addr, i->size);
>> > +		i = i->next;
>> > +		free(j);
>> > +	}
>> > +
>> > +	maps = NULL;
>> > +}
>> 
>> -- 
>> Thank you,
>> Richard.
>> 
>> -- 
>> Mailing list info: https://lists.linux.it/listinfo/ltp


-- 
Thank you,
Richard.

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

end of thread, other threads:[~2019-08-08 15:41 UTC | newest]

Thread overview: 37+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-08-01  9:26 [LTP] [RFC PATCH 0/9] Introduce guarded buffers Cyril Hrubis
2019-08-01  9:26 ` [LTP] [RFC PATCH 1/9] lib: Add support for " Cyril Hrubis
2019-08-01 10:39   ` Jan Stancek
2019-08-01 11:45     ` Cyril Hrubis
2019-08-02 14:03       ` Richard Palethorpe
2019-08-02 13:57     ` Richard Palethorpe
2019-08-02 13:59       ` Cyril Hrubis
2019-08-02 14:23         ` Cyril Hrubis
2019-08-02 14:36         ` Richard Palethorpe
2019-08-02 14:50           ` Cyril Hrubis
2019-08-02 14:20   ` Cyril Hrubis
2019-08-03 12:55   ` Li Wang
2019-08-06  7:36     ` Richard Palethorpe
2019-08-06  9:03   ` Richard Palethorpe
2019-08-08  9:06     ` Cyril Hrubis
2019-08-08  9:13       ` Li Wang
2019-08-08 15:41       ` Richard Palethorpe
2019-08-01  9:26 ` [LTP] [RFC PATCH 2/9] lib: Add a canary " Cyril Hrubis
2019-08-01 10:43   ` Jan Stancek
2019-08-01 11:54     ` Cyril Hrubis
2019-08-01 16:32       ` Jan Stancek
2019-08-02  9:47         ` Cyril Hrubis
2019-08-02 10:54           ` Jan Stancek
2019-08-03 13:02   ` Li Wang
2019-08-08  9:27     ` Cyril Hrubis
2019-08-01  9:26 ` [LTP] [RFC PATCH 3/9] syscalls/preadv01: Make use of " Cyril Hrubis
2019-08-01  9:26 ` [LTP] [RFC PATCH 4/9] syscalls/accept4_01: " Cyril Hrubis
2019-08-01  9:26 ` [LTP] [RFC PATCH 5/9] syscalls/add_key04: " Cyril Hrubis
2019-08-01  9:26 ` [LTP] [RFC PATCH 6/9] syscalls/adjtimex: " Cyril Hrubis
2019-08-01  9:26 ` [LTP] [RFC PATCH 7/9] syscalls/clock_getres01: " Cyril Hrubis
2019-08-01  9:26 ` [LTP] [RFC PATCH 8/9] syscalls/clock_settime01: " Cyril Hrubis
2019-08-01  9:26 ` [LTP] [RFC PATCH 9/9] syscalls/sendmmsg01: " Cyril Hrubis
2019-08-06  9:47 ` [LTP] [PATCH v3 0/4] eBPF tests using guarded buffers API Richard Palethorpe
2019-08-06  9:47   ` [LTP] [PATCH v3 1/4] BPF: Essential headers for map creation Richard Palethorpe
2019-08-06  9:47   ` [LTP] [PATCH v3 2/4] BPF: Sanity check creating and updating maps Richard Palethorpe
2019-08-06  9:47   ` [LTP] [PATCH v3 3/4] BPF: Essential headers for a basic program Richard Palethorpe
2019-08-06  9:47   ` [LTP] [PATCH v3 4/4] BPF: Sanity check creating a program Richard Palethorpe

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.