* [LTP] [PATCH v1] Add a test case for mmap() MAP_GROWSDOWN flag
@ 2020-06-30 5:44 pravin
2020-06-30 9:55 ` Cyril Hrubis
2020-06-30 10:56 ` Li Wang
0 siblings, 2 replies; 4+ messages in thread
From: pravin @ 2020-06-30 5:44 UTC (permalink / raw)
To: ltp
We assign the memory region allocated using MAP_GROWSDOWN to a thread,
as a stack, to test the effect of MAP_GROWSDOWN. This is because the
kernel only grows the memory region when the stack pointer, is within
guard page, when the guard page is touched.
1. Map an anyonymous memory region of size X, and unmap it.
2. Split the unmapped memory region into two.
3. The lower memory region is left unmapped.
4. The higher memory region is mapped for use as stack, using MAP_FIXED | MAP_GROWSDOWN.
5. The higher memory region is provided as stack to a thread, where
a recursive function is invoked.
6. The stack grows beyond the allocated region, into the lower memory area.
7. If this results in the memory region being extended, into the
unmapped region, the test is considered to have passed.
Resolves #300
Signed-off-by: Pravin Raghul S. <pravinraghul@zilogic.com>
Reviewed-by: Vijay Kumar B. <vijaykumar@zilogic.com>
---
runtest/syscalls | 1 +
testcases/kernel/syscalls/mmap/.gitignore | 1 +
testcases/kernel/syscalls/mmap/Makefile | 7 ++
testcases/kernel/syscalls/mmap/mmap18.c | 146 ++++++++++++++++++++++
4 files changed, 155 insertions(+)
create mode 100644 testcases/kernel/syscalls/mmap/mmap18.c
diff --git a/runtest/syscalls b/runtest/syscalls
index b4d523319..d8c9dbe92 100644
--- a/runtest/syscalls
+++ b/runtest/syscalls
@@ -747,6 +747,7 @@ mmap14 mmap14
mmap15 mmap15
mmap16 mmap16
mmap17 mmap17
+mmap18 mmap18
modify_ldt01 modify_ldt01
modify_ldt02 modify_ldt02
diff --git a/testcases/kernel/syscalls/mmap/.gitignore b/testcases/kernel/syscalls/mmap/.gitignore
index c5c083d4b..4fd90ab5f 100644
--- a/testcases/kernel/syscalls/mmap/.gitignore
+++ b/testcases/kernel/syscalls/mmap/.gitignore
@@ -16,3 +16,4 @@
/mmap15
/mmap16
/mmap17
+/mmap18
diff --git a/testcases/kernel/syscalls/mmap/Makefile b/testcases/kernel/syscalls/mmap/Makefile
index 743ca36e7..bdc49e4be 100644
--- a/testcases/kernel/syscalls/mmap/Makefile
+++ b/testcases/kernel/syscalls/mmap/Makefile
@@ -8,3 +8,10 @@ include $(top_srcdir)/include/mk/testcases.mk
include $(top_srcdir)/include/mk/generic_leaf_target.mk
LDLIBS += -lpthread
+#
+# We use recursive calls to to grow the stack, to test the
+# MAP_GROSWDOWN flag. But tail call optimization by the compiler
+# can prevent the recusive call and stack growth. Disable tail
+# call optmization using -fno-optimize-sibling-calls
+#
+mmap18: CFLAGS += -fno-optimize-sibling-calls
diff --git a/testcases/kernel/syscalls/mmap/mmap18.c b/testcases/kernel/syscalls/mmap/mmap18.c
new file mode 100644
index 000000000..01a456bfc
--- /dev/null
+++ b/testcases/kernel/syscalls/mmap/mmap18.c
@@ -0,0 +1,146 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/*
+ * Copyright (c) Zilogic Systems Pvt. Ltd., 2020
+ * Email: code@zilogic.com
+ */
+
+/*
+ * Test mmap() MAP_GROWSDOWN flag
+ *
+ * We assign the memory region allocated using MAP_GROWSDOWN to a thread,
+ * as a stack, to test the effect of MAP_GROWSDOWN. This is because the
+ * kernel only grows the memory region when the stack pointer, is within
+ * guard page, when the guard page is touched.
+ *
+ * 1. Map an anyonymous memory region of size X, and unmap it.
+ * 2. Split the unmapped memory region into two.
+ * 3. The lower memory region is left unmapped.
+ * 4. The higher memory region is mapped for use as stack, using
+ * MAP_FIXED | MAP_GROWSDOWN.
+ * 5. The higher memory region is provided as stack to a thread, where
+ * a recursive function is invoked.
+ * 6. The stack grows beyond the allocated region, into the lower memory area.
+ * 7. If this results in the memory region being extended, into the
+ * unmapped region, the test is considered to have passed.
+ */
+
+#include <unistd.h>
+#include <sys/wait.h>
+#include <pthread.h>
+#include <sys/mman.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+
+#include "tst_test.h"
+#include "tst_safe_pthread.h"
+
+#define UNITS(x) ((x) * PTHREAD_STACK_MIN)
+
+static void *stack = NULL;
+
+bool check_stackgrow_up(int *local_var_1)
+{
+ int local_var_2;
+
+ if (local_var_1 < &local_var_2)
+ return false;
+ else
+ return true;
+}
+
+void setup(void)
+{
+ int local_var_1;
+ bool stackgrow_up;
+
+ stackgrow_up = check_stackgrow_up(&local_var_1);
+ if (stackgrow_up)
+ tst_brk(TCONF, "Test can't be performed with stack grows up architecture");
+}
+
+void cleanup(void)
+{
+ if (stack != NULL)
+ SAFE_MUNMAP(stack, UNITS(8));
+}
+
+void *find_free_range(size_t size)
+{
+ void *mem;
+
+ mem = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE,
+ MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+ SAFE_MUNMAP(mem, size);
+
+ return mem;
+}
+
+void split_unmapped_plus_stack(void *start, size_t size, void **stack)
+{
+ /*
+ * +---------------------+----------------------+
+ * + unmapped | stack |
+ * +---------------------+----------------------+
+ */
+ *stack = SAFE_MMAP(start, size, PROT_READ | PROT_WRITE,
+ MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN,
+ -1, 0);
+}
+
+static void *check_depth_recursive(void *limit)
+{
+ if ((off_t) &limit < (off_t) limit)
+ return NULL;
+
+ return check_depth_recursive(limit);
+}
+
+void grow_stack(void *stack, size_t size, void *limit)
+{
+ pthread_t test_thread;
+ pthread_attr_t attr;
+ int ret;
+
+ ret = pthread_attr_init(&attr);
+ if (ret != 0)
+ tst_brk(TBROK, "pthread_attr_init failed during setup");
+
+ ret = pthread_attr_setstack(&attr, stack, size);
+ if (ret != 0)
+ tst_brk(TBROK, "pthread_attr_setstack failed during setup");
+
+ SAFE_PTHREAD_CREATE(&test_thread, &attr, check_depth_recursive, limit);
+ SAFE_PTHREAD_JOIN(test_thread, NULL);
+
+ exit(0);
+}
+
+static void run_test(void)
+{
+ void *mem;
+ pid_t child_pid;
+ int wstatus;
+
+ mem = find_free_range(UNITS(16));
+ split_unmapped_plus_stack(mem, UNITS(16), &stack);
+
+ child_pid = SAFE_FORK();
+ if (child_pid == 0) {
+ grow_stack(stack, UNITS(8), mem + UNITS(1));
+ } else {
+ SAFE_WAIT(&wstatus);
+ if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0)
+ tst_res(TPASS, "stack grows in unmapped region");
+ else
+ tst_res(TFAIL, "child exited with %d", wstatus);
+ }
+}
+
+static struct tst_test test = {
+ .setup = setup,
+ .cleanup = cleanup,
+ .test_all = run_test,
+ .forks_child = 1,
+};
--
2.25.1
^ permalink raw reply related [flat|nested] 4+ messages in thread
* [LTP] [PATCH v1] Add a test case for mmap() MAP_GROWSDOWN flag
2020-06-30 5:44 [LTP] [PATCH v1] Add a test case for mmap() MAP_GROWSDOWN flag pravin
@ 2020-06-30 9:55 ` Cyril Hrubis
[not found] ` <50c6d8d9-7a79-ab71-1e88-ab693403b25e@zilogic.com>
2020-06-30 10:56 ` Li Wang
1 sibling, 1 reply; 4+ messages in thread
From: Cyril Hrubis @ 2020-06-30 9:55 UTC (permalink / raw)
To: ltp
Hi!
> We assign the memory region allocated using MAP_GROWSDOWN to a thread,
> as a stack, to test the effect of MAP_GROWSDOWN. This is because the
> kernel only grows the memory region when the stack pointer, is within
> guard page, when the guard page is touched.
>
> 1. Map an anyonymous memory region of size X, and unmap it.
> 2. Split the unmapped memory region into two.
> 3. The lower memory region is left unmapped.
> 4. The higher memory region is mapped for use as stack, using MAP_FIXED | MAP_GROWSDOWN.
> 5. The higher memory region is provided as stack to a thread, where
> a recursive function is invoked.
> 6. The stack grows beyond the allocated region, into the lower memory area.
> 7. If this results in the memory region being extended, into the
> unmapped region, the test is considered to have passed.
>
> Resolves #300
> Signed-off-by: Pravin Raghul S. <pravinraghul@zilogic.com>
> Reviewed-by: Vijay Kumar B. <vijaykumar@zilogic.com>
>
> ---
> runtest/syscalls | 1 +
> testcases/kernel/syscalls/mmap/.gitignore | 1 +
> testcases/kernel/syscalls/mmap/Makefile | 7 ++
> testcases/kernel/syscalls/mmap/mmap18.c | 146 ++++++++++++++++++++++
> 4 files changed, 155 insertions(+)
> create mode 100644 testcases/kernel/syscalls/mmap/mmap18.c
>
> diff --git a/runtest/syscalls b/runtest/syscalls
> index b4d523319..d8c9dbe92 100644
> --- a/runtest/syscalls
> +++ b/runtest/syscalls
> @@ -747,6 +747,7 @@ mmap14 mmap14
> mmap15 mmap15
> mmap16 mmap16
> mmap17 mmap17
> +mmap18 mmap18
>
> modify_ldt01 modify_ldt01
> modify_ldt02 modify_ldt02
> diff --git a/testcases/kernel/syscalls/mmap/.gitignore b/testcases/kernel/syscalls/mmap/.gitignore
> index c5c083d4b..4fd90ab5f 100644
> --- a/testcases/kernel/syscalls/mmap/.gitignore
> +++ b/testcases/kernel/syscalls/mmap/.gitignore
> @@ -16,3 +16,4 @@
> /mmap15
> /mmap16
> /mmap17
> +/mmap18
> diff --git a/testcases/kernel/syscalls/mmap/Makefile b/testcases/kernel/syscalls/mmap/Makefile
> index 743ca36e7..bdc49e4be 100644
> --- a/testcases/kernel/syscalls/mmap/Makefile
> +++ b/testcases/kernel/syscalls/mmap/Makefile
> @@ -8,3 +8,10 @@ include $(top_srcdir)/include/mk/testcases.mk
> include $(top_srcdir)/include/mk/generic_leaf_target.mk
>
> LDLIBS += -lpthread
> +#
> +# We use recursive calls to to grow the stack, to test the
> +# MAP_GROSWDOWN flag. But tail call optimization by the compiler
> +# can prevent the recusive call and stack growth. Disable tail
> +# call optmization using -fno-optimize-sibling-calls
> +#
> +mmap18: CFLAGS += -fno-optimize-sibling-calls
> diff --git a/testcases/kernel/syscalls/mmap/mmap18.c b/testcases/kernel/syscalls/mmap/mmap18.c
> new file mode 100644
> index 000000000..01a456bfc
> --- /dev/null
> +++ b/testcases/kernel/syscalls/mmap/mmap18.c
> @@ -0,0 +1,146 @@
> +// SPDX-License-Identifier: GPL-2.0-or-later
> +/*
> + * Copyright (c) Zilogic Systems Pvt. Ltd., 2020
> + * Email: code@zilogic.com
> + */
> +
> +/*
> + * Test mmap() MAP_GROWSDOWN flag
> + *
> + * We assign the memory region allocated using MAP_GROWSDOWN to a thread,
> + * as a stack, to test the effect of MAP_GROWSDOWN. This is because the
> + * kernel only grows the memory region when the stack pointer, is within
> + * guard page, when the guard page is touched.
> + *
> + * 1. Map an anyonymous memory region of size X, and unmap it.
> + * 2. Split the unmapped memory region into two.
> + * 3. The lower memory region is left unmapped.
> + * 4. The higher memory region is mapped for use as stack, using
^
Trailing whitespace.
You can use the checkpatch.pl from Linux kernel git repostory to check
for minor mistakes like these before sending a patch.
> + * MAP_FIXED | MAP_GROWSDOWN.
> + * 5. The higher memory region is provided as stack to a thread, where
> + * a recursive function is invoked.
> + * 6. The stack grows beyond the allocated region, into the lower memory area.
> + * 7. If this results in the memory region being extended, into the
> + * unmapped region, the test is considered to have passed.
> + */
> +
> +#include <unistd.h>
> +#include <sys/wait.h>
> +#include <pthread.h>
> +#include <sys/mman.h>
> +#include <sys/wait.h>
> +#include <unistd.h>
> +#include <stdlib.h>
> +#include <stdbool.h>
> +
> +#include "tst_test.h"
> +#include "tst_safe_pthread.h"
> +
> +#define UNITS(x) ((x) * PTHREAD_STACK_MIN)
> +
> +static void *stack = NULL;
Global variables are zeroed at the program start, there is no point to
set them to NULL like that.
> +bool check_stackgrow_up(int *local_var_1)
Missing static.
> +{
> + int local_var_2;
> +
> + if (local_var_1 < &local_var_2)
> + return false;
> + else
> + return true;
Just do return !(local_var_1 < &local_var_2);
> +}
> +
> +void setup(void)
Here as well.
> +{
> + int local_var_1;
> + bool stackgrow_up;
> +
> + stackgrow_up = check_stackgrow_up(&local_var_1);
> + if (stackgrow_up)
Why not just if (stackgrow_up(&local_var_1)) here instead?
> + tst_brk(TCONF, "Test can't be performed with stack grows up architecture");
> +}
> +
> +void cleanup(void)
And here as well.
> +{
> + if (stack != NULL)
Just if (stack)
> + SAFE_MUNMAP(stack, UNITS(8));
> +}
> +
> +void *find_free_range(size_t size)
Here as well.
> +{
> + void *mem;
> +
> + mem = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE,
> + MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
> + SAFE_MUNMAP(mem, size);
> +
> + return mem;
> +}
> +
> +void split_unmapped_plus_stack(void *start, size_t size, void **stack)
Here as well.
> +{
> + /*
> + * +---------------------+----------------------+
> + * + unmapped | stack |
> + * +---------------------+----------------------+
> + */
> + *stack = SAFE_MMAP(start, size, PROT_READ | PROT_WRITE,
> + MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN,
> + -1, 0);
Why can't this function return void * instead?
Also I do not get what the ascii art means here. We just mmap(0 the
whole thing here with MAP_GROWSDOWN what do we split?
Also why can't we just use multiple of page_size instead of some pthread
magic constant? Why don't we just allocate 10 pages then touch them in
order?
> +}
> +
> +static void *check_depth_recursive(void *limit)
> +{
> + if ((off_t) &limit < (off_t) limit)
> + return NULL;
> +
> + return check_depth_recursive(limit);
> +}
> +
> +void grow_stack(void *stack, size_t size, void *limit)
> +{
> + pthread_t test_thread;
> + pthread_attr_t attr;
> + int ret;
> +
> + ret = pthread_attr_init(&attr);
> + if (ret != 0)
> + tst_brk(TBROK, "pthread_attr_init failed during setup");
> +
> + ret = pthread_attr_setstack(&attr, stack, size);
> + if (ret != 0)
> + tst_brk(TBROK, "pthread_attr_setstack failed during setup");
> +
> + SAFE_PTHREAD_CREATE(&test_thread, &attr, check_depth_recursive, limit);
> + SAFE_PTHREAD_JOIN(test_thread, NULL);
Do we really have to use pthreads here? Can't we just touch the guard
page by writing to it? I guess that we can just do for () loop over the
mapping with something as:
for (i = 0; i < size; i++)
((char*)stack)[i] = 'a';
> + exit(0);
> +}
> +
> +static void run_test(void)
> +{
> + void *mem;
> + pid_t child_pid;
> + int wstatus;
> +
> + mem = find_free_range(UNITS(16));
> + split_unmapped_plus_stack(mem, UNITS(16), &stack);
> +
> + child_pid = SAFE_FORK();
> + if (child_pid == 0) {
Use just if (!child_pid)
> + grow_stack(stack, UNITS(8), mem + UNITS(1));
> + } else {
The grow_stack() function calls exit(0) there is no point in having the
else branch here.
> + SAFE_WAIT(&wstatus);
> + if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0)
> + tst_res(TPASS, "stack grows in unmapped region");
> + else
> + tst_res(TFAIL, "child exited with %d", wstatus);
> + }
No test result propagation, the child should report the test result
using the tst_res() itself.
> +}
> +
> +static struct tst_test test = {
> + .setup = setup,
> + .cleanup = cleanup,
> + .test_all = run_test,
> + .forks_child = 1,
> +};
--
Cyril Hrubis
chrubis@suse.cz
^ permalink raw reply [flat|nested] 4+ messages in thread
* [LTP] [PATCH v1] Add a test case for mmap() MAP_GROWSDOWN flag
2020-06-30 5:44 [LTP] [PATCH v1] Add a test case for mmap() MAP_GROWSDOWN flag pravin
2020-06-30 9:55 ` Cyril Hrubis
@ 2020-06-30 10:56 ` Li Wang
1 sibling, 0 replies; 4+ messages in thread
From: Li Wang @ 2020-06-30 10:56 UTC (permalink / raw)
To: ltp
On Tue, Jun 30, 2020 at 1:45 PM pravin <pravinraghul@zilogic.com> wrote:
>
> We assign the memory region allocated using MAP_GROWSDOWN to a thread,
> as a stack, to test the effect of MAP_GROWSDOWN. This is because the
> kernel only grows the memory region when the stack pointer, is within
> guard page, when the guard page is touched.
>
> 1. Map an anyonymous memory region of size X, and unmap it.
> 2. Split the unmapped memory region into two.
> 3. The lower memory region is left unmapped.
> 4. The higher memory region is mapped for use as stack, using MAP_FIXED
> | MAP_GROWSDOWN.
> 5. The higher memory region is provided as stack to a thread, where
> a recursive function is invoked.
> 6. The stack grows beyond the allocated region, into the lower memory
> area.
> 7. If this results in the memory region being extended, into the
> unmapped region, the test is considered to have passed.
>
> ...
> +
> +void split_unmapped_plus_stack(void *start, size_t size, void **stack)
> +{
> + /*
> + * +---------------------+----------------------+
> + * + unmapped | stack |
> + * +---------------------+----------------------+
> + */
> + *stack = SAFE_MMAP(start, size, PROT_READ | PROT_WRITE,
>
This does not match what you describe in the code comments, here we still
map the total size of the memory area, and stack can not grow into an
unmapped region.
Looking at the address which printed from your code, the mem == stack and
&limit grows down in mapped address.
# ./mmap18
tst_test.c:1247: INFO: Timeout per run is 0h 05m 00s
mmap18.c:132: INFO: mem = 0x7ffff7fa5000, stack = 0x7ffff7fa5000
mmap18.c:96: INFO: &limit = 0x7ffff7fa8fe8, limit = 0x7ffff7fa9000
mmap18.c:141: PASS: stack grows in unmapped region
Maybe this below could achieve your method, or you can take the way which
Cyril suggests using multiple page_size.
--- a/testcases/kernel/syscalls/mmap/mmap18.c
+++ b/testcases/kernel/syscalls/mmap/mmap18.c
@@ -84,15 +84,17 @@ void split_unmapped_plus_stack(void *start, size_t
size, void **stack)
* + unmapped | stack |
* +---------------------+----------------------+
*/
- *stack = SAFE_MMAP(start, size, PROT_READ | PROT_WRITE,
+ *stack = SAFE_MMAP(start + size/2, size/2, PROT_READ | PROT_WRITE,
MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS |
MAP_GROWSDOWN,
-1, 0);
}
static void *check_depth_recursive(void *limit)
{
- if ((off_t) &limit < (off_t) limit)
+ if ((off_t) &limit < (off_t) limit) {
+ tst_res(TINFO, "&limit = %p, limit = %p", &limit, limit);
return NULL;
+ }
return check_depth_recursive(limit);
}
@@ -125,10 +127,11 @@ static void run_test(void)
mem = find_free_range(UNITS(16));
split_unmapped_plus_stack(mem, UNITS(16), &stack);
+ tst_res(TINFO, "mem = %p, stack = %p", mem, stack);
child_pid = SAFE_FORK();
if (child_pid == 0) {
- grow_stack(stack, UNITS(8), mem + UNITS(1));
+ grow_stack(stack, UNITS(8), stack - UNITS(1));
} else {
SAFE_WAIT(&wstatus);
if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0)
--
Regards,
Li Wang
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.linux.it/pipermail/ltp/attachments/20200630/5cc35b18/attachment.htm>
^ permalink raw reply [flat|nested] 4+ messages in thread
* [LTP] [PATCH v1] Add a test case for mmap() MAP_GROWSDOWN flag
[not found] ` <50c6d8d9-7a79-ab71-1e88-ab693403b25e@zilogic.com>
@ 2020-07-02 14:08 ` Cyril Hrubis
0 siblings, 0 replies; 4+ messages in thread
From: Cyril Hrubis @ 2020-07-02 14:08 UTC (permalink / raw)
To: ltp
Hi!
I've added ltp mailing list back to CC, please always keep it in the CC
when sending patches/discussing testcases.
> >> +static void *check_depth_recursive(void *limit)
> >> +{
> >> + if ((off_t) &limit < (off_t) limit)
> >> + return NULL;
> >> +
> >> + return check_depth_recursive(limit);
> >> +}
> >> +
> >> +void grow_stack(void *stack, size_t size, void *limit)
> >> +{
> >> + pthread_t test_thread;
> >> + pthread_attr_t attr;
> >> + int ret;
> >> +
> >> + ret = pthread_attr_init(&attr);
> >> + if (ret != 0)
> >> + tst_brk(TBROK, "pthread_attr_init failed during setup");
> >> +
> >> + ret = pthread_attr_setstack(&attr, stack, size);
> >> + if (ret != 0)
> >> + tst_brk(TBROK, "pthread_attr_setstack failed during setup");
> >> +
> >> + SAFE_PTHREAD_CREATE(&test_thread, &attr, check_depth_recursive,
> >> limit);
> >> + SAFE_PTHREAD_JOIN(test_thread, NULL);
> > Do we really have to use pthreads here? Can't we just touch the guard
> > page by writing to it? I guess that we can just do for () loop over the
> > mapping with something as:
> >
> > for (i = 0; i < size; i++)
> > ((char*)stack)[i] = 'a';
> >
> I have attached a code below for your reference regarding the method that
> you have suggested. Please have a look.
Can you please send v2 patch instead?
> Here we are writing the pages with char 'a' where pages, doesn't
> grow in the unmapped region, thereby doesn't satify the mmap flag
> MAP_GROWSDOWN.
> MAP_GROWSDOWN doesn't work when guard page is touched by the regular
> pointer.we use pthread to grow stacks via stack pointer.
Looks like you are right, we have to move the RSP in order to reserve
stack space before we touch it to cause page fault. So I guess that
setting thread stack may be easiest option.
Also for the tail call, I guess that it would be easier to setup an
array on the stack then fill it with a for loop or something like that.
> >> + SAFE_WAIT(&wstatus);
> >> + if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0)
> >> + tst_res(TPASS, "stack grows in unmapped region");
> >> + else
> >> + tst_res(TFAIL, "child exited with %d", wstatus);
> >> + }
> > No test result propagation, the child should report the test result
> > using the tst_res() itself.
> >
> we are the testing the stack growth in unmapped region with child process,
> so test result depends on the child status that's why we are checking
> the exit status. Handling the child report accordingly If the stack grows
> properly in unmapped region the test is considered to be passed, otherwise
> test failed with the return status.
>
> Please let me know your thoughts..!
> Will update a new patch with changes made regarding other mistakes, after
> yours thoughts.
The results are propagated from the child process automatically, all we
need to do here is to check that the child haven't crashed, i.e. that it
exitted with 0.
We usually do:
if (!WIFEXITTED(status) || WEXITSTATUS(status) != 0)
tst_brk(TBROK, "Child %s", tst_strstatus(status));
> /*
> * Algorithm:
> * 1) In this test case we allocated 16 pages.
> * 2) Then we split the stack space into two and mapped the upper region.
> * 3) The lower region left unmapped.
> * 4) Now trying to write the pages with character 'a'.
> * 5) Writing the page on unmapped region as well.
> *
> * The result of the output will show the mapped and unmapped region.
> *
> * Here we are writing the pages with char 'a' where pages, doesn't
> * grow in the unmapped region, thereby doesn't satify the mmap flag
> * MAP_GROWSDOWN.
> *
> */
>
> #include <unistd.h>
> #include <sys/wait.h>
> #include <pthread.h>
> #include <sys/mman.h>
> #include <sys/wait.h>
> #include <unistd.h>
> #include <stdlib.h>
> #include <stdbool.h>
>
> #include "tst_test.h"
>
> #define PAGESIZE 4096
> #define UNITS(x) ((x) * PAGESIZE)
>
> static void *stack;
>
> static bool check_stackgrow_up(int *local_var_1)
> {
> int local_var_2;
>
> return !(local_var_1 < &local_var_2);
> }
>
> static void setup(void)
> {
> int local_var_1;
>
> if (check_stackgrow_up(&local_var_1))
> tst_brk(TCONF, "Test can't be performed with stack grows up architecture");
> }
>
> static void cleanup(void)
> {
> if (stack)
> SAFE_MUNMAP(stack, UNITS(8));
> }
>
> static void *find_free_range(size_t size)
> {
> void *mem;
>
> mem = SAFE_MMAP(NULL, size, PROT_READ | PROT_WRITE,
> MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
> SAFE_MUNMAP(mem, size);
>
> return mem;
> }
>
> static void split_unmapped_plus_stack(void *start, size_t size)
> {
> /* start start + size
> * +---------------------+----------------------+
> * + unmapped | mapped |
> * +---------------------+----------------------+
> * stack
> */
> stack = SAFE_MMAP(start + size, size, PROT_READ | PROT_WRITE,
> MAP_FIXED | MAP_PRIVATE | MAP_ANONYMOUS | MAP_GROWSDOWN,
> -1, 0);
> tst_res(TINFO, "mapped = %p", stack + UNITS(8));
> tst_res(TINFO, "mapped = %p", stack);
> }
>
> static void grow_stack(void *start, size_t size)
> {
> volatile char *ptr1 = start;
>
> for (int i = 0; i < size; i++) {
> ptr1 -= UNITS(1);
> *ptr1 = 'a';
> tst_res(TINFO, "addr = %p", ptr1);
> }
>
> exit(0);
> }
>
> static void run_test(void)
> {
> void *mem;
> pid_t child_pid;
> int wstatus;
>
> mem = find_free_range(UNITS(16));
> tst_res(TINFO, "unmap = %p", mem + UNITS(16));
> tst_res(TINFO, "unmap = %p", mem);
> split_unmapped_plus_stack(mem, UNITS(8));
>
> child_pid = SAFE_FORK();
> if (!child_pid)
> grow_stack(stack + UNITS(8), UNITS(16) / UNITS(1));
>
> SAFE_WAIT(child_pid, &wstatus, 0);
> if (WIFEXITED(wstatus) && WEXITSTATUS(wstatus) == 0)
> tst_res(TPASS, "stack grows in unmapped region");
> else
> tst_res(TFAIL, "child exited with %d", wstatus);
> }
>
> static struct tst_test test = {
> .setup = setup,
> .cleanup = cleanup,
> .test_all = run_test,
> .forks_child = 1,
> };
--
Cyril Hrubis
chrubis@suse.cz
^ permalink raw reply [flat|nested] 4+ messages in thread
end of thread, other threads:[~2020-07-02 14:08 UTC | newest]
Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2020-06-30 5:44 [LTP] [PATCH v1] Add a test case for mmap() MAP_GROWSDOWN flag pravin
2020-06-30 9:55 ` Cyril Hrubis
[not found] ` <50c6d8d9-7a79-ab71-1e88-ab693403b25e@zilogic.com>
2020-07-02 14:08 ` Cyril Hrubis
2020-06-30 10:56 ` Li Wang
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox