<div dir="ltr"><div dir="ltr"><div class="gmail_default" style="font-size:small"><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Sat, Sep 19, 2020 at 1:16 AM Cyril Hrubis <<a href="mailto:chrubis@suse.cz" target="_blank">chrubis@suse.cz</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex"><span class="gmail_default" style="font-size:small">...</span><br>
+/*<br>
+ * Test mmap() MAP_GROWSDOWN flag<br>
+ *<br>
+ * # Test1:<br>
+ *<br>
+ *   We assign the memory region partially allocated with MAP_GROWSDOWN flag to<br>
+ *   a thread as a stack and expect the mapping to grow when we touch the<br>
+ *   guard page by calling a recusive function in the thread that uses the<br>
+ *   growable mapping as a stack.<br>
+ *<br>
+ *   The kernel only grows the memory region when the stack pointer is within<br>
+ *   guard page when the guard page is touched so simply faulting the guard<br>
+ *   page will not cause the mapping to grow.<br>
+ *<br>
+ *   Newer kernels does not allow a MAP_GROWSDOWN mapping to grow closer than<br>
+ *   'stack_guard_gap' pages to an existing mapping. So when we map the stack we<br>
+ *   make sure there is enough of free address space before the lowest stack<br>
+ *   address.<br>
+ *<br>
+ *   Kernel default 'stack_guard_gap' size is '256 * getpagesize()'.<br>
+ *<br>
+ *   The stack memory map would look like:<br>
+ *<br>
+ *   |  -  -  -   reserved  size   -  -  -  |<br>
+ *<br>
+ *   +-- - - - --+------------+-------------+<br>
+ *   | 256 pages |  unmapped  |   mapped    |<br>
+ *   +-- - - - --+------------+-------------+<br>
+ *                            | mapped size |<br>
+ *   ^           |  -  -  stack size  -  -  |<br>
+ *   start<br>
+ *               ^                          ^<br>
+ *               stack bottom       stack top<br>
+ *<br>
+ * # Test2:<br>
+ *<br>
+ *   We allocate stack as we do in the first test but we mmap a page in the<br>
+ *   space the stack is supposed to grow into and we expect the thread to<br>
+ *   segfault when the guard page is faulted.<br>
+ */<br>
+<br>
+#include <unistd.h><br>
+#include <pthread.h><br>
+#include <sys/mman.h><br>
+#include <sys/wait.h><br>
+#include <sys/types.h><br>
+#include <stdlib.h><br>
+#include <stdbool.h><br>
+<br>
+#include "tst_test.h"<br>
+#include "tst_safe_pthread.h"<br>
+<br>
+static long page_size;<br>
+<br>
+static bool __attribute__((noinline)) check_stackgrow_up(void)<br>
+{<br>
+       char local_var;<br>
+       static char *addr;<br>
+<br>
+       if (!addr) {<br>
+               addr = &local_var;<br>
+               return check_stackgrow_up();<br>
+       }<br>
+<br>
+       return (addr < &local_var);<br>
+}<br>
+<br>
+static void setup(void)<br>
+{<br>
+       if (check_stackgrow_up())<br>
+               tst_brk(TCONF, "Test can't be performed with stack grows up architecture");<br>
+<br>
+       page_size = getpagesize();<br>
+}<br>
+<br>
+/*<br>
+ * Returns stack lowest address. Note that the address is not mapped and will<br>
+ * be mapped on page fault when we grow the stack to the lowest address possible.<br>
+ */<br>
+static void *allocate_stack(size_t stack_size, size_t mapped_size)<br>
+{<br>
+       void *start, *stack_top, *stack_bottom;<br>
+<br>
+       long reserved_size = 256 * page_size + stack_size;<br>
+<br>
+       start = SAFE_MMAP(NULL, reserved_size, PROT_READ | PROT_WRITE,<br>
+                         MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);<br>
+       SAFE_MUNMAP(start, reserved_size);<br>
+<br>
+       SAFE_MMAP((start + reserved_size - mapped_size), mapped_size, PROT_READ | PROT_WRITE,<br>
+                 MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN,<br>
+                 -1, 0);<br>
+<br>
+       stack_top = start + reserved_size;<br>
+       stack_bottom = start + reserved_size - stack_size;<br></blockquote><div><br></div><div><div class="gmail_default" style="font-size:small">As the stack grows down, shouldn't grow from stack_bottom to stack_top? which</div><div class="gmail_default" style="font-size:small">means stack_bottom = start + reserved_size.</div><div class="gmail_default" style="font-size:small"><br></div><div class="gmail_default" style="font-size:small"> *   |  -  -  -   reserved  size   -  -  -  |<br> *<br> *   +-- - - - --+------------+-------------+<br> *   | 256 pages |  unmapped  |   mapped    |<br> *   +-- - - - --+------------+-------------+<br> *                            | mapped size |<br> *   ^           |  -  -  stack size  -  -  |<br> *   start<br> *               ^                          ^<br> *               stack top       stack bottom<br></div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+<br>
+       tst_res(TINFO, "start = %p, stack_top = %p, stack bottom = %p",<br></blockquote><div><br></div><div><div class="gmail_default" style="font-size:small">a typo here: stack_bottom ^ </div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">
+               start, stack_top, stack_bottom);<br>
+       tst_res(TINFO, "mapped pages %zu, stack pages %zu",<br>
+               mapped_size/page_size, stack_size/page_size);<br>
+<br>
+       return stack_bottom;<br></blockquote><div><br></div><div><div class="gmail_default" style="font-size:small">return stack_top here?</div></div></div><div><br></div>-- <br><div dir="ltr"><div dir="ltr"><div>Regards,<br></div><div>Li Wang<br></div></div></div></div>