[LTP] [PATCH v6] Add a test case for mmap MAP_GROWSDOWN flag
Li Wang
liwang@redhat.com
Mon Sep 21 06:08:41 CEST 2020
On Sat, Sep 19, 2020 at 1:16 AM Cyril Hrubis <chrubis@suse.cz> wrote:
> ...
> +/*
> + * Test mmap() MAP_GROWSDOWN flag
> + *
> + * # Test1:
> + *
> + * We assign the memory region partially allocated with MAP_GROWSDOWN
> flag to
> + * a thread as a stack and expect the mapping to grow when we touch the
> + * guard page by calling a recusive function in the thread that uses the
> + * growable mapping as a stack.
> + *
> + * The kernel only grows the memory region when the stack pointer is
> within
> + * guard page when the guard page is touched so simply faulting the
> guard
> + * page will not cause the mapping to grow.
> + *
> + * Newer kernels does not allow a MAP_GROWSDOWN mapping to grow closer
> than
> + * 'stack_guard_gap' pages to an existing mapping. So when we map the
> stack we
> + * make sure there is enough of free address space before the lowest
> stack
> + * address.
> + *
> + * Kernel default 'stack_guard_gap' size is '256 * getpagesize()'.
> + *
> + * The stack memory map would look like:
> + *
> + * | - - - reserved size - - - |
> + *
> + * +-- - - - --+------------+-------------+
> + * | 256 pages | unmapped | mapped |
> + * +-- - - - --+------------+-------------+
> + * | mapped size |
> + * ^ | - - stack size - - |
> + * start
> + * ^ ^
> + * stack bottom stack top
> + *
> + * # Test2:
> + *
> + * We allocate stack as we do in the first test but we mmap a page in
> the
> + * space the stack is supposed to grow into and we expect the thread to
> + * segfault when the guard page is faulted.
> + */
> +
> +#include <unistd.h>
> +#include <pthread.h>
> +#include <sys/mman.h>
> +#include <sys/wait.h>
> +#include <sys/types.h>
> +#include <stdlib.h>
> +#include <stdbool.h>
> +
> +#include "tst_test.h"
> +#include "tst_safe_pthread.h"
> +
> +static long page_size;
> +
> +static bool __attribute__((noinline)) check_stackgrow_up(void)
> +{
> + char local_var;
> + static char *addr;
> +
> + if (!addr) {
> + addr = &local_var;
> + return check_stackgrow_up();
> + }
> +
> + return (addr < &local_var);
> +}
> +
> +static void setup(void)
> +{
> + if (check_stackgrow_up())
> + tst_brk(TCONF, "Test can't be performed with stack grows
> up architecture");
> +
> + page_size = getpagesize();
> +}
> +
> +/*
> + * Returns stack lowest address. Note that the address is not mapped and
> will
> + * be mapped on page fault when we grow the stack to the lowest address
> possible.
> + */
> +static void *allocate_stack(size_t stack_size, size_t mapped_size)
> +{
> + void *start, *stack_top, *stack_bottom;
> +
> + long reserved_size = 256 * page_size + stack_size;
> +
> + start = SAFE_MMAP(NULL, reserved_size, PROT_READ | PROT_WRITE,
> + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
> + SAFE_MUNMAP(start, reserved_size);
> +
> + SAFE_MMAP((start + reserved_size - mapped_size), mapped_size,
> PROT_READ | PROT_WRITE,
> + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN,
> + -1, 0);
> +
> + stack_top = start + reserved_size;
> + stack_bottom = start + reserved_size - stack_size;
>
As the stack grows down, shouldn't grow from stack_bottom to stack_top?
which
means stack_bottom = start + reserved_size.
* | - - - reserved size - - - |
*
* +-- - - - --+------------+-------------+
* | 256 pages | unmapped | mapped |
* +-- - - - --+------------+-------------+
* | mapped size |
* ^ | - - stack size - - |
* start
* ^ ^
* stack top stack bottom
> +
> + tst_res(TINFO, "start = %p, stack_top = %p, stack bottom = %p",
>
a typo here: stack_bottom ^
> + start, stack_top, stack_bottom);
> + tst_res(TINFO, "mapped pages %zu, stack pages %zu",
> + mapped_size/page_size, stack_size/page_size);
> +
> + return stack_bottom;
>
return stack_top here?
--
Regards,
Li Wang
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.linux.it/pipermail/ltp/attachments/20200921/5c817a49/attachment.htm>
More information about the ltp
mailing list