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>
23 #define PAGE_SIZE 4096
25 static int try_to_remap(void *vdso_addr
, unsigned long size
)
27 void *dest_addr
, *new_addr
;
29 /* Searching for memory location where to remap */
30 dest_addr
= mmap(0, size
, PROT_NONE
, MAP_PRIVATE
|MAP_ANONYMOUS
, -1, 0);
31 if (dest_addr
== MAP_FAILED
) {
32 printf("[WARN]\tmmap failed (%d): %m\n", errno
);
36 printf("[NOTE]\tMoving vDSO: [%p, %#lx] -> [%p, %#lx]\n",
37 vdso_addr
, (unsigned long)vdso_addr
+ size
,
38 dest_addr
, (unsigned long)dest_addr
+ size
);
41 new_addr
= mremap(vdso_addr
, size
, size
,
42 MREMAP_FIXED
|MREMAP_MAYMOVE
, dest_addr
);
43 if ((unsigned long)new_addr
== (unsigned long)-1) {
44 munmap(dest_addr
, size
);
45 if (errno
== EINVAL
) {
46 printf("[NOTE]\tvDSO partial move failed, will try with bigger size\n");
47 return -1; /* Retry with larger */
49 printf("[FAIL]\tmremap failed (%d): %m\n", errno
);
57 int main(int argc
, char **argv
, char **envp
)
63 printf("[WARN]\tfailed to fork (%d): %m\n", errno
);
68 unsigned long vdso_size
= PAGE_SIZE
;
72 auxval
= getauxval(AT_SYSINFO_EHDR
);
73 printf("\tAT_SYSINFO_EHDR is %#lx\n", auxval
);
74 if (!auxval
|| auxval
== -ENOENT
) {
75 printf("[WARN]\tgetauxval failed\n");
79 /* Simpler than parsing ELF header */
81 ret
= try_to_remap((void *)auxval
, vdso_size
);
82 vdso_size
+= PAGE_SIZE
;
86 /* Glibc is likely to explode now - exit with raw syscall */
87 asm volatile ("int $0x80" : : "a" (__NR_exit
), "b" (!!ret
));
88 #else /* __x86_64__ */
89 syscall(SYS_exit
, ret
);
94 if (waitpid(child
, &status
, 0) != child
||
96 printf("[FAIL]\tmremap() of the vDSO does not work on this kernel!\n");
98 } else if (WEXITSTATUS(status
) != 0) {
99 printf("[FAIL]\tChild failed with %d\n",
100 WEXITSTATUS(status
));