Re: [PATCH 2/4] selftest/vm: verify remap destination address in mremap_test

From: Shuah Khan
Date: Thu Apr 14 2022 - 17:47:52 EST


On 4/14/22 11:15 AM, Sidhartha Kumar wrote:
Because mremap does not have a NOREPLACE flag,
it can destroy existing mappings. This can
cause a segfault if regions such as text are
destroyed.

Please explain the reason for segfault.

Add a blank line here. Makes it easier to read.

Verify the requested mremap destination
address does not overlap any existing mappings
by using mmap's FIXED_NOREPLACE flag and checking

Spell this out fully - MAP_FIXED_NOREPLACE
for the EEXIST error code. Keep incrementing the
destination address until a valid mapping is found
or max address is reached.


Essentially mremap() doesn't check for overlaps and removes
or overwrites existing mappings? The way you are fixing it
is by verifying by calling mremap() with MAP_FIXED_NOREPLACE
flag and check for EEXIST.

What happens when max address is reached?

Same comment on # of chars per line in commit log. Also

Signed-off-by: Sidhartha Kumar <sidhartha.kumar@xxxxxxxxxx>
---
tools/testing/selftests/vm/mremap_test.c | 36 ++++++++++++++++++++++++
1 file changed, 36 insertions(+)

diff --git a/tools/testing/selftests/vm/mremap_test.c b/tools/testing/selftests/vm/mremap_test.c
index 58600fee4b81..98e9cff34aa7 100644
--- a/tools/testing/selftests/vm/mremap_test.c
+++ b/tools/testing/selftests/vm/mremap_test.c
@@ -10,6 +10,7 @@
#include <string.h>
#include <sys/mman.h>
#include <time.h>
+#include <limits.h>
#include "../kselftest.h"
@@ -65,6 +66,34 @@ enum {
.expect_failure = should_fail \
}
+/*
+ * Returns 0 if the requested remap region overlaps with an
+ * existing mapping (e.g text, stack) else returns 1.
+ */
+static int remap_region_valid(void *addr, unsigned long long size)

This returns bool 0 (false) 1 (true)

Please name the routine - is_remap_region_valid() and change it to
return bool.

+{
+ void *remap_addr = NULL;
+ int ret = 1;
+
+ if ((unsigned long long) addr > ULLONG_MAX - size) {
+ ksft_print_msg("Can't find a valid region to remap to\n");

Change it to "Couldn't" - also this message doesn't look right. We hav't
looked for valid region yet and it just exceeds the limits?


+ exit(KSFT_SKIP);> + }
+
+ /* Use MAP_FIXED_NOREPLACE flag to ensure region is not mapped */
+ remap_addr = mmap(addr, size, PROT_READ | PROT_WRITE,
+ MAP_FIXED_NOREPLACE | MAP_ANONYMOUS | MAP_SHARED,
+ -1, 0);

Alignment should match open parenthesis here and in other places. Makes it
easier to read the code.

+ if (remap_addr == MAP_FAILED) {
+ if (errno == EEXIST)
+ ret = 0;
+ } else {
+ munmap(remap_addr, size);
+ }
+
+ return ret;
+}
+
/* Returns mmap_min_addr sysctl */
static unsigned long long get_mmap_min_addr(void)
{
@@ -180,6 +209,13 @@ static long long remap_region(struct config c, unsigned int threshold_mb,
if (!((unsigned long long) addr & c.dest_alignment))
addr = (void *) ((unsigned long long) addr | c.dest_alignment);
+ /* Don't destroy existing mappings unless expected to overlap */
+ while (!remap_region_valid(addr, c.region_size)) {
+ if (c.overlapping)
+ break;
+ addr += c.src_alignment;
+ }
+
clock_gettime(CLOCK_MONOTONIC, &t_start);
dest_addr = mremap(src_addr, c.region_size, c.region_size,
MREMAP_MAYMOVE|MREMAP_FIXED, (char *) addr);


thanks,
-- Shuah