2 * 32-bit test to check vDSO mremap.
4 * Copyright (c) 2016 Dmitry Safonov
5 * Suggested-by: Andrew Lutomirski
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms and conditions of the GNU General Public License,
9 * version 2, as published by the Free Software Foundation.
11 * This program is distributed in the hope it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
17 * Can be built statically:
18 * gcc -Os -Wall -static -m32 test_mremap_vdso.c
28 #include <sys/syscall.h>
31 #define PAGE_SIZE 4096
33 static int try_to_remap(void *vdso_addr
, unsigned long size
)
35 void *dest_addr
, *new_addr
;
37 /* Searching for memory location where to remap */
38 dest_addr
= mmap(0, size
, PROT_NONE
, MAP_PRIVATE
|MAP_ANONYMOUS
, -1, 0);
39 if (dest_addr
== MAP_FAILED
) {
40 printf("[WARN]\tmmap failed (%d): %m\n", errno
);
44 printf("[NOTE]\tMoving vDSO: [%p, %#lx] -> [%p, %#lx]\n",
45 vdso_addr
, (unsigned long)vdso_addr
+ size
,
46 dest_addr
, (unsigned long)dest_addr
+ size
);
49 new_addr
= mremap(vdso_addr
, size
, size
,
50 MREMAP_FIXED
|MREMAP_MAYMOVE
, dest_addr
);
51 if ((unsigned long)new_addr
== (unsigned long)-1) {
52 munmap(dest_addr
, size
);
53 if (errno
== EINVAL
) {
54 printf("[NOTE]\tvDSO partial move failed, will try with bigger size\n");
55 return -1; /* Retry with larger */
57 printf("[FAIL]\tmremap failed (%d): %m\n", errno
);
65 int main(int argc
, char **argv
, char **envp
)
71 printf("[WARN]\tfailed to fork (%d): %m\n", errno
);
76 unsigned long vdso_size
= PAGE_SIZE
;
80 auxval
= getauxval(AT_SYSINFO_EHDR
);
81 printf("\tAT_SYSINFO_EHDR is %#lx\n", auxval
);
82 if (!auxval
|| auxval
== -ENOENT
) {
83 printf("[WARN]\tgetauxval failed\n");
87 /* Simpler than parsing ELF header */
89 ret
= try_to_remap((void *)auxval
, vdso_size
);
90 vdso_size
+= PAGE_SIZE
;
93 /* Glibc is likely to explode now - exit with raw syscall */
94 asm volatile ("int $0x80" : : "a" (__NR_exit
), "b" (!!ret
));
98 if (waitpid(child
, &status
, 0) != child
||
100 printf("[FAIL]\tmremap() of the vDSO does not work on this kernel!\n");
102 } else if (WEXITSTATUS(status
) != 0) {
103 printf("[FAIL]\tChild failed with %d\n",
104 WEXITSTATUS(status
));