summaryrefslogtreecommitdiffstats
path: root/src/kernel/tests/lib/tst_buffers.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/kernel/tests/lib/tst_buffers.c')
-rw-r--r--src/kernel/tests/lib/tst_buffers.c143
1 files changed, 143 insertions, 0 deletions
diff --git a/src/kernel/tests/lib/tst_buffers.c b/src/kernel/tests/lib/tst_buffers.c
new file mode 100644
index 0000000..b8b597a
--- /dev/null
+++ b/src/kernel/tests/lib/tst_buffers.c
@@ -0,0 +1,143 @@
+// 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;
+ 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 address %p[%zi]",
+ getpid(), (char*)map->addr + map->buf_shift, -i-1);
+ }
+ }
+}
+
+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));
+ static int print_msg = 1;
+
+ if (print_msg) {
+ tst_res(TINFO, "Test is using guarded buffers");
+ print_msg = 0;
+ }
+
+ 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)
+ map->buf_shift = page_size - (size % page_size);
+ else
+ map->buf_shift = 0;
+
+ setup_canary(map);
+
+ return ret + map->buf_shift;
+}
+
+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;
+ check_canary(i);
+ SAFE_MUNMAP(i->addr, i->size);
+ i = i->next;
+ free(j);
+ }
+
+ maps = NULL;
+}