| // 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; |
| } |