forked from torvalds/linux
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
tools/testing/selftests/vm/map_fixed_noreplace.c: add test for MAP_FI…
…XED_NOREPLACE Add a test for MAP_FIXED_NOREPLACE, based on some code originally by Jann Horn. This would have caught the overlap bug reported by Daniel Micay. I originally suggested to Michal that we create MAP_FIXED_NOREPLACE, but instead of writing a selftest I spent my time bike-shedding whether it should be called MAP_FIXED_SAFE/NOCLOBBER/WEAK/NEW .. mea culpa. Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Michael Ellerman <[email protected]> Reviewed-by: Kees Cook <[email protected]> Reviewed-by: Khalid Aziz <[email protected]> Acked-by: Michal Hocko <[email protected]> Cc: Jann Horn <[email protected]> Cc: Andrea Arcangeli <[email protected]> Cc: Florian Weimer <[email protected]> Cc: John Hubbard <[email protected]> Cc: Matthew Wilcox <[email protected]> Cc: Abdul Haleem <[email protected]> Cc: Joel Stanley <[email protected]> Cc: Jason Evans <[email protected]> Cc: David Goldblatt <[email protected]> Cc: Daniel Micay <[email protected]> Cc: Shuah Khan <[email protected]> Signed-off-by: Andrew Morton <[email protected]> Signed-off-by: Linus Torvalds <[email protected]>
- Loading branch information
Showing
3 changed files
with
208 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,3 +13,4 @@ mlock-random-test | |
virtual_address_range | ||
gup_benchmark | ||
va_128TBswitch | ||
map_fixed_noreplace |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,206 @@ | ||
// SPDX-License-Identifier: GPL-2.0 | ||
|
||
/* | ||
* Test that MAP_FIXED_NOREPLACE works. | ||
* | ||
* Copyright 2018, Jann Horn <[email protected]> | ||
* Copyright 2018, Michael Ellerman, IBM Corporation. | ||
*/ | ||
|
||
#include <sys/mman.h> | ||
#include <errno.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <unistd.h> | ||
|
||
#ifndef MAP_FIXED_NOREPLACE | ||
#define MAP_FIXED_NOREPLACE 0x100000 | ||
#endif | ||
|
||
#define BASE_ADDRESS (256ul * 1024 * 1024) | ||
|
||
|
||
static void dump_maps(void) | ||
{ | ||
char cmd[32]; | ||
|
||
snprintf(cmd, sizeof(cmd), "cat /proc/%d/maps", getpid()); | ||
system(cmd); | ||
} | ||
|
||
int main(void) | ||
{ | ||
unsigned long flags, addr, size, page_size; | ||
char *p; | ||
|
||
page_size = sysconf(_SC_PAGE_SIZE); | ||
|
||
flags = MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED_NOREPLACE; | ||
|
||
// Check we can map all the areas we need below | ||
errno = 0; | ||
addr = BASE_ADDRESS; | ||
size = 5 * page_size; | ||
p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); | ||
|
||
printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); | ||
|
||
if (p == MAP_FAILED) { | ||
dump_maps(); | ||
printf("Error: couldn't map the space we need for the test\n"); | ||
return 1; | ||
} | ||
|
||
errno = 0; | ||
if (munmap((void *)addr, 5 * page_size) != 0) { | ||
dump_maps(); | ||
printf("Error: munmap failed!?\n"); | ||
return 1; | ||
} | ||
printf("unmap() successful\n"); | ||
|
||
errno = 0; | ||
addr = BASE_ADDRESS + page_size; | ||
size = 3 * page_size; | ||
p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); | ||
printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); | ||
|
||
if (p == MAP_FAILED) { | ||
dump_maps(); | ||
printf("Error: first mmap() failed unexpectedly\n"); | ||
return 1; | ||
} | ||
|
||
/* | ||
* Exact same mapping again: | ||
* base | free | new | ||
* +1 | mapped | new | ||
* +2 | mapped | new | ||
* +3 | mapped | new | ||
* +4 | free | new | ||
*/ | ||
errno = 0; | ||
addr = BASE_ADDRESS; | ||
size = 5 * page_size; | ||
p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); | ||
printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); | ||
|
||
if (p != MAP_FAILED) { | ||
dump_maps(); | ||
printf("Error:1: mmap() succeeded when it shouldn't have\n"); | ||
return 1; | ||
} | ||
|
||
/* | ||
* Second mapping contained within first: | ||
* | ||
* base | free | | ||
* +1 | mapped | | ||
* +2 | mapped | new | ||
* +3 | mapped | | ||
* +4 | free | | ||
*/ | ||
errno = 0; | ||
addr = BASE_ADDRESS + (2 * page_size); | ||
size = page_size; | ||
p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); | ||
printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); | ||
|
||
if (p != MAP_FAILED) { | ||
dump_maps(); | ||
printf("Error:2: mmap() succeeded when it shouldn't have\n"); | ||
return 1; | ||
} | ||
|
||
/* | ||
* Overlap end of existing mapping: | ||
* base | free | | ||
* +1 | mapped | | ||
* +2 | mapped | | ||
* +3 | mapped | new | ||
* +4 | free | new | ||
*/ | ||
errno = 0; | ||
addr = BASE_ADDRESS + (3 * page_size); | ||
size = 2 * page_size; | ||
p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); | ||
printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); | ||
|
||
if (p != MAP_FAILED) { | ||
dump_maps(); | ||
printf("Error:3: mmap() succeeded when it shouldn't have\n"); | ||
return 1; | ||
} | ||
|
||
/* | ||
* Overlap start of existing mapping: | ||
* base | free | new | ||
* +1 | mapped | new | ||
* +2 | mapped | | ||
* +3 | mapped | | ||
* +4 | free | | ||
*/ | ||
errno = 0; | ||
addr = BASE_ADDRESS; | ||
size = 2 * page_size; | ||
p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); | ||
printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); | ||
|
||
if (p != MAP_FAILED) { | ||
dump_maps(); | ||
printf("Error:4: mmap() succeeded when it shouldn't have\n"); | ||
return 1; | ||
} | ||
|
||
/* | ||
* Adjacent to start of existing mapping: | ||
* base | free | new | ||
* +1 | mapped | | ||
* +2 | mapped | | ||
* +3 | mapped | | ||
* +4 | free | | ||
*/ | ||
errno = 0; | ||
addr = BASE_ADDRESS; | ||
size = page_size; | ||
p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); | ||
printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); | ||
|
||
if (p == MAP_FAILED) { | ||
dump_maps(); | ||
printf("Error:5: mmap() failed when it shouldn't have\n"); | ||
return 1; | ||
} | ||
|
||
/* | ||
* Adjacent to end of existing mapping: | ||
* base | free | | ||
* +1 | mapped | | ||
* +2 | mapped | | ||
* +3 | mapped | | ||
* +4 | free | new | ||
*/ | ||
errno = 0; | ||
addr = BASE_ADDRESS + (4 * page_size); | ||
size = page_size; | ||
p = mmap((void *)addr, size, PROT_NONE, flags, -1, 0); | ||
printf("mmap() @ 0x%lx-0x%lx p=%p result=%m\n", addr, addr + size, p); | ||
|
||
if (p == MAP_FAILED) { | ||
dump_maps(); | ||
printf("Error:6: mmap() failed when it shouldn't have\n"); | ||
return 1; | ||
} | ||
|
||
addr = BASE_ADDRESS; | ||
size = 5 * page_size; | ||
if (munmap((void *)addr, size) != 0) { | ||
dump_maps(); | ||
printf("Error: munmap failed!?\n"); | ||
return 1; | ||
} | ||
printf("unmap() successful\n"); | ||
|
||
printf("OK\n"); | ||
return 0; | ||
} |