1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#define _GNU_SOURCE
21#include <stdio.h>
22#include <errno.h>
23#include <unistd.h>
24#include <string.h>
25
26#include <sys/mman.h>
27#include <sys/auxv.h>
28#include <sys/syscall.h>
29#include <sys/wait.h>
30
31#define PAGE_SIZE 4096
32
33static int try_to_remap(void *vdso_addr, unsigned long size)
34{
35 void *dest_addr, *new_addr;
36
37
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);
41 return 0;
42 }
43
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);
47 fflush(stdout);
48
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;
56 }
57 printf("[FAIL]\tmremap failed (%d): %m\n", errno);
58 return 1;
59 }
60
61 return 0;
62
63}
64
65int main(int argc, char **argv, char **envp)
66{
67 pid_t child;
68
69 child = fork();
70 if (child == -1) {
71 printf("[WARN]\tfailed to fork (%d): %m\n", errno);
72 return 1;
73 }
74
75 if (child == 0) {
76 unsigned long vdso_size = PAGE_SIZE;
77 unsigned long auxval;
78 int ret = -1;
79
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");
84 return 0;
85 }
86
87
88 while (ret < 0) {
89 ret = try_to_remap((void *)auxval, vdso_size);
90 vdso_size += PAGE_SIZE;
91 }
92
93
94 asm volatile ("int $0x80" : : "a" (__NR_exit), "b" (!!ret));
95 } else {
96 int status;
97
98 if (waitpid(child, &status, 0) != child ||
99 !WIFEXITED(status)) {
100 printf("[FAIL]\tmremap() of the vDSO does not work on this kernel!\n");
101 return 1;
102 } else if (WEXITSTATUS(status) != 0) {
103 printf("[FAIL]\tChild failed with %d\n",
104 WEXITSTATUS(status));
105 return 1;
106 }
107 printf("[OK]\n");
108 }
109
110 return 0;
111}
112