1 // SPDX-License-Identifier: GPL-2.0-only
3 * 32-bit test to check vDSO mremap.
5 * Copyright (c) 2016 Dmitry Safonov
6 * Suggested-by: Andrew Lutomirski
9 * Can be built statically:
10 * gcc -Os -Wall -static -m32 test_mremap_vdso.c
20 #include <sys/syscall.h>
22 #include "../kselftest.h"
24 #define PAGE_SIZE 4096
26 static int try_to_remap(void *vdso_addr
, unsigned long size
)
28 void *dest_addr
, *new_addr
;
30 /* Searching for memory location where to remap */
31 dest_addr
= mmap(0, size
, PROT_NONE
, MAP_PRIVATE
|MAP_ANONYMOUS
, -1, 0);
32 if (dest_addr
== MAP_FAILED
) {
33 ksft_print_msg("WARN: mmap failed (%d): %m\n", errno
);
37 ksft_print_msg("Moving vDSO: [%p, %#lx] -> [%p, %#lx]\n",
38 vdso_addr
, (unsigned long)vdso_addr
+ size
,
39 dest_addr
, (unsigned long)dest_addr
+ size
);
42 new_addr
= mremap(vdso_addr
, size
, size
,
43 MREMAP_FIXED
|MREMAP_MAYMOVE
, dest_addr
);
44 if ((unsigned long)new_addr
== (unsigned long)-1) {
45 munmap(dest_addr
, size
);
46 if (errno
== EINVAL
) {
47 ksft_print_msg("vDSO partial move failed, will try with bigger size\n");
48 return -1; /* Retry with larger */
50 ksft_print_msg("[FAIL]\tmremap failed (%d): %m\n", errno
);
58 int main(int argc
, char **argv
, char **envp
)
67 ksft_exit_fail_msg("failed to fork (%d): %m\n", errno
);
70 unsigned long vdso_size
= PAGE_SIZE
;
74 auxval
= getauxval(AT_SYSINFO_EHDR
);
75 ksft_print_msg("AT_SYSINFO_EHDR is %#lx\n", auxval
);
76 if (!auxval
|| auxval
== -ENOENT
) {
77 ksft_print_msg("WARN: getauxval failed\n");
81 /* Simpler than parsing ELF header */
83 ret
= try_to_remap((void *)auxval
, vdso_size
);
84 vdso_size
+= PAGE_SIZE
;
88 /* Glibc is likely to explode now - exit with raw syscall */
89 asm volatile ("int $0x80" : : "a" (__NR_exit
), "b" (!!ret
));
90 #else /* __x86_64__ */
91 syscall(SYS_exit
, ret
);
96 if (waitpid(child
, &status
, 0) != child
||
98 ksft_test_result_fail("mremap() of the vDSO does not work on this kernel!\n");
99 else if (WEXITSTATUS(status
) != 0)
100 ksft_test_result_fail("Child failed with %d\n", WEXITSTATUS(status
));
102 ksft_test_result_pass("%s\n", __func__
);