<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>