1*5bc73bb3SAlexey Dobriyan /* 2*5bc73bb3SAlexey Dobriyan * Copyright (c) 2022 Alexey Dobriyan <[email protected]> 3*5bc73bb3SAlexey Dobriyan * 4*5bc73bb3SAlexey Dobriyan * Permission to use, copy, modify, and distribute this software for any 5*5bc73bb3SAlexey Dobriyan * purpose with or without fee is hereby granted, provided that the above 6*5bc73bb3SAlexey Dobriyan * copyright notice and this permission notice appear in all copies. 7*5bc73bb3SAlexey Dobriyan * 8*5bc73bb3SAlexey Dobriyan * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9*5bc73bb3SAlexey Dobriyan * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10*5bc73bb3SAlexey Dobriyan * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11*5bc73bb3SAlexey Dobriyan * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12*5bc73bb3SAlexey Dobriyan * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13*5bc73bb3SAlexey Dobriyan * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14*5bc73bb3SAlexey Dobriyan * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15*5bc73bb3SAlexey Dobriyan */ 16*5bc73bb3SAlexey Dobriyan /* 17*5bc73bb3SAlexey Dobriyan * Create a process without mappings by unmapping everything at once and 18*5bc73bb3SAlexey Dobriyan * holding it with ptrace(2). See what happens to 19*5bc73bb3SAlexey Dobriyan * 20*5bc73bb3SAlexey Dobriyan * /proc/${pid}/maps 21*5bc73bb3SAlexey Dobriyan * /proc/${pid}/numa_maps 22*5bc73bb3SAlexey Dobriyan * /proc/${pid}/smaps 23*5bc73bb3SAlexey Dobriyan * /proc/${pid}/smaps_rollup 24*5bc73bb3SAlexey Dobriyan */ 25*5bc73bb3SAlexey Dobriyan #undef NDEBUG 26*5bc73bb3SAlexey Dobriyan #include <assert.h> 27*5bc73bb3SAlexey Dobriyan #include <errno.h> 28*5bc73bb3SAlexey Dobriyan #include <stdio.h> 29*5bc73bb3SAlexey Dobriyan #include <stdlib.h> 30*5bc73bb3SAlexey Dobriyan #include <string.h> 31*5bc73bb3SAlexey Dobriyan #include <fcntl.h> 32*5bc73bb3SAlexey Dobriyan #include <sys/mman.h> 33*5bc73bb3SAlexey Dobriyan #include <sys/ptrace.h> 34*5bc73bb3SAlexey Dobriyan #include <sys/resource.h> 35*5bc73bb3SAlexey Dobriyan #include <sys/types.h> 36*5bc73bb3SAlexey Dobriyan #include <sys/wait.h> 37*5bc73bb3SAlexey Dobriyan #include <unistd.h> 38*5bc73bb3SAlexey Dobriyan 39*5bc73bb3SAlexey Dobriyan /* 40*5bc73bb3SAlexey Dobriyan * 0: vsyscall VMA doesn't exist vsyscall=none 41*5bc73bb3SAlexey Dobriyan * 1: vsyscall VMA is --xp vsyscall=xonly 42*5bc73bb3SAlexey Dobriyan * 2: vsyscall VMA is r-xp vsyscall=emulate 43*5bc73bb3SAlexey Dobriyan */ 44*5bc73bb3SAlexey Dobriyan static int g_vsyscall; 45*5bc73bb3SAlexey Dobriyan static const char *g_proc_pid_maps_vsyscall; 46*5bc73bb3SAlexey Dobriyan static const char *g_proc_pid_smaps_vsyscall; 47*5bc73bb3SAlexey Dobriyan 48*5bc73bb3SAlexey Dobriyan static const char proc_pid_maps_vsyscall_0[] = ""; 49*5bc73bb3SAlexey Dobriyan static const char proc_pid_maps_vsyscall_1[] = 50*5bc73bb3SAlexey Dobriyan "ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]\n"; 51*5bc73bb3SAlexey Dobriyan static const char proc_pid_maps_vsyscall_2[] = 52*5bc73bb3SAlexey Dobriyan "ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]\n"; 53*5bc73bb3SAlexey Dobriyan 54*5bc73bb3SAlexey Dobriyan static const char proc_pid_smaps_vsyscall_0[] = ""; 55*5bc73bb3SAlexey Dobriyan 56*5bc73bb3SAlexey Dobriyan static const char proc_pid_smaps_vsyscall_1[] = 57*5bc73bb3SAlexey Dobriyan "ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]\n" 58*5bc73bb3SAlexey Dobriyan "Size: 4 kB\n" 59*5bc73bb3SAlexey Dobriyan "KernelPageSize: 4 kB\n" 60*5bc73bb3SAlexey Dobriyan "MMUPageSize: 4 kB\n" 61*5bc73bb3SAlexey Dobriyan "Rss: 0 kB\n" 62*5bc73bb3SAlexey Dobriyan "Pss: 0 kB\n" 63*5bc73bb3SAlexey Dobriyan "Pss_Dirty: 0 kB\n" 64*5bc73bb3SAlexey Dobriyan "Shared_Clean: 0 kB\n" 65*5bc73bb3SAlexey Dobriyan "Shared_Dirty: 0 kB\n" 66*5bc73bb3SAlexey Dobriyan "Private_Clean: 0 kB\n" 67*5bc73bb3SAlexey Dobriyan "Private_Dirty: 0 kB\n" 68*5bc73bb3SAlexey Dobriyan "Referenced: 0 kB\n" 69*5bc73bb3SAlexey Dobriyan "Anonymous: 0 kB\n" 70*5bc73bb3SAlexey Dobriyan "LazyFree: 0 kB\n" 71*5bc73bb3SAlexey Dobriyan "AnonHugePages: 0 kB\n" 72*5bc73bb3SAlexey Dobriyan "ShmemPmdMapped: 0 kB\n" 73*5bc73bb3SAlexey Dobriyan "FilePmdMapped: 0 kB\n" 74*5bc73bb3SAlexey Dobriyan "Shared_Hugetlb: 0 kB\n" 75*5bc73bb3SAlexey Dobriyan "Private_Hugetlb: 0 kB\n" 76*5bc73bb3SAlexey Dobriyan "Swap: 0 kB\n" 77*5bc73bb3SAlexey Dobriyan "SwapPss: 0 kB\n" 78*5bc73bb3SAlexey Dobriyan "Locked: 0 kB\n" 79*5bc73bb3SAlexey Dobriyan "THPeligible: 0\n" 80*5bc73bb3SAlexey Dobriyan /* 81*5bc73bb3SAlexey Dobriyan * "ProtectionKey:" field is conditional. It is possible to check it as well, 82*5bc73bb3SAlexey Dobriyan * but I don't have such machine. 83*5bc73bb3SAlexey Dobriyan */ 84*5bc73bb3SAlexey Dobriyan ; 85*5bc73bb3SAlexey Dobriyan 86*5bc73bb3SAlexey Dobriyan static const char proc_pid_smaps_vsyscall_2[] = 87*5bc73bb3SAlexey Dobriyan "ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]\n" 88*5bc73bb3SAlexey Dobriyan "Size: 4 kB\n" 89*5bc73bb3SAlexey Dobriyan "KernelPageSize: 4 kB\n" 90*5bc73bb3SAlexey Dobriyan "MMUPageSize: 4 kB\n" 91*5bc73bb3SAlexey Dobriyan "Rss: 0 kB\n" 92*5bc73bb3SAlexey Dobriyan "Pss: 0 kB\n" 93*5bc73bb3SAlexey Dobriyan "Pss_Dirty: 0 kB\n" 94*5bc73bb3SAlexey Dobriyan "Shared_Clean: 0 kB\n" 95*5bc73bb3SAlexey Dobriyan "Shared_Dirty: 0 kB\n" 96*5bc73bb3SAlexey Dobriyan "Private_Clean: 0 kB\n" 97*5bc73bb3SAlexey Dobriyan "Private_Dirty: 0 kB\n" 98*5bc73bb3SAlexey Dobriyan "Referenced: 0 kB\n" 99*5bc73bb3SAlexey Dobriyan "Anonymous: 0 kB\n" 100*5bc73bb3SAlexey Dobriyan "LazyFree: 0 kB\n" 101*5bc73bb3SAlexey Dobriyan "AnonHugePages: 0 kB\n" 102*5bc73bb3SAlexey Dobriyan "ShmemPmdMapped: 0 kB\n" 103*5bc73bb3SAlexey Dobriyan "FilePmdMapped: 0 kB\n" 104*5bc73bb3SAlexey Dobriyan "Shared_Hugetlb: 0 kB\n" 105*5bc73bb3SAlexey Dobriyan "Private_Hugetlb: 0 kB\n" 106*5bc73bb3SAlexey Dobriyan "Swap: 0 kB\n" 107*5bc73bb3SAlexey Dobriyan "SwapPss: 0 kB\n" 108*5bc73bb3SAlexey Dobriyan "Locked: 0 kB\n" 109*5bc73bb3SAlexey Dobriyan "THPeligible: 0\n" 110*5bc73bb3SAlexey Dobriyan /* 111*5bc73bb3SAlexey Dobriyan * "ProtectionKey:" field is conditional. It is possible to check it as well, 112*5bc73bb3SAlexey Dobriyan * but I'm too tired. 113*5bc73bb3SAlexey Dobriyan */ 114*5bc73bb3SAlexey Dobriyan ; 115*5bc73bb3SAlexey Dobriyan 116*5bc73bb3SAlexey Dobriyan static void sigaction_SIGSEGV(int _, siginfo_t *__, void *___) 117*5bc73bb3SAlexey Dobriyan { 118*5bc73bb3SAlexey Dobriyan _exit(EXIT_FAILURE); 119*5bc73bb3SAlexey Dobriyan } 120*5bc73bb3SAlexey Dobriyan 121*5bc73bb3SAlexey Dobriyan static void sigaction_SIGSEGV_vsyscall(int _, siginfo_t *__, void *___) 122*5bc73bb3SAlexey Dobriyan { 123*5bc73bb3SAlexey Dobriyan _exit(g_vsyscall); 124*5bc73bb3SAlexey Dobriyan } 125*5bc73bb3SAlexey Dobriyan 126*5bc73bb3SAlexey Dobriyan /* 127*5bc73bb3SAlexey Dobriyan * vsyscall page can't be unmapped, probe it directly. 128*5bc73bb3SAlexey Dobriyan */ 129*5bc73bb3SAlexey Dobriyan static void vsyscall(void) 130*5bc73bb3SAlexey Dobriyan { 131*5bc73bb3SAlexey Dobriyan pid_t pid; 132*5bc73bb3SAlexey Dobriyan int wstatus; 133*5bc73bb3SAlexey Dobriyan 134*5bc73bb3SAlexey Dobriyan pid = fork(); 135*5bc73bb3SAlexey Dobriyan if (pid < 0) { 136*5bc73bb3SAlexey Dobriyan fprintf(stderr, "fork, errno %d\n", errno); 137*5bc73bb3SAlexey Dobriyan exit(1); 138*5bc73bb3SAlexey Dobriyan } 139*5bc73bb3SAlexey Dobriyan if (pid == 0) { 140*5bc73bb3SAlexey Dobriyan setrlimit(RLIMIT_CORE, &(struct rlimit){}); 141*5bc73bb3SAlexey Dobriyan 142*5bc73bb3SAlexey Dobriyan /* Hide "segfault at ffffffffff600000" messages. */ 143*5bc73bb3SAlexey Dobriyan struct sigaction act = {}; 144*5bc73bb3SAlexey Dobriyan act.sa_flags = SA_SIGINFO; 145*5bc73bb3SAlexey Dobriyan act.sa_sigaction = sigaction_SIGSEGV_vsyscall; 146*5bc73bb3SAlexey Dobriyan sigaction(SIGSEGV, &act, NULL); 147*5bc73bb3SAlexey Dobriyan 148*5bc73bb3SAlexey Dobriyan g_vsyscall = 0; 149*5bc73bb3SAlexey Dobriyan /* gettimeofday(NULL, NULL); */ 150*5bc73bb3SAlexey Dobriyan asm volatile ( 151*5bc73bb3SAlexey Dobriyan "call %P0" 152*5bc73bb3SAlexey Dobriyan : 153*5bc73bb3SAlexey Dobriyan : "i" (0xffffffffff600000), "D" (NULL), "S" (NULL) 154*5bc73bb3SAlexey Dobriyan : "rax", "rcx", "r11" 155*5bc73bb3SAlexey Dobriyan ); 156*5bc73bb3SAlexey Dobriyan 157*5bc73bb3SAlexey Dobriyan g_vsyscall = 1; 158*5bc73bb3SAlexey Dobriyan *(volatile int *)0xffffffffff600000UL; 159*5bc73bb3SAlexey Dobriyan 160*5bc73bb3SAlexey Dobriyan g_vsyscall = 2; 161*5bc73bb3SAlexey Dobriyan exit(g_vsyscall); 162*5bc73bb3SAlexey Dobriyan } 163*5bc73bb3SAlexey Dobriyan waitpid(pid, &wstatus, 0); 164*5bc73bb3SAlexey Dobriyan if (WIFEXITED(wstatus)) { 165*5bc73bb3SAlexey Dobriyan g_vsyscall = WEXITSTATUS(wstatus); 166*5bc73bb3SAlexey Dobriyan } else { 167*5bc73bb3SAlexey Dobriyan fprintf(stderr, "error: vsyscall wstatus %08x\n", wstatus); 168*5bc73bb3SAlexey Dobriyan exit(1); 169*5bc73bb3SAlexey Dobriyan } 170*5bc73bb3SAlexey Dobriyan } 171*5bc73bb3SAlexey Dobriyan 172*5bc73bb3SAlexey Dobriyan static int test_proc_pid_maps(pid_t pid) 173*5bc73bb3SAlexey Dobriyan { 174*5bc73bb3SAlexey Dobriyan char buf[4096]; 175*5bc73bb3SAlexey Dobriyan snprintf(buf, sizeof(buf), "/proc/%u/maps", pid); 176*5bc73bb3SAlexey Dobriyan int fd = open(buf, O_RDONLY); 177*5bc73bb3SAlexey Dobriyan if (fd == -1) { 178*5bc73bb3SAlexey Dobriyan perror("open /proc/${pid}/maps"); 179*5bc73bb3SAlexey Dobriyan return EXIT_FAILURE; 180*5bc73bb3SAlexey Dobriyan } else { 181*5bc73bb3SAlexey Dobriyan ssize_t rv = read(fd, buf, sizeof(buf)); 182*5bc73bb3SAlexey Dobriyan close(fd); 183*5bc73bb3SAlexey Dobriyan if (g_vsyscall == 0) { 184*5bc73bb3SAlexey Dobriyan assert(rv == 0); 185*5bc73bb3SAlexey Dobriyan } else { 186*5bc73bb3SAlexey Dobriyan size_t len = strlen(g_proc_pid_maps_vsyscall); 187*5bc73bb3SAlexey Dobriyan assert(rv == len); 188*5bc73bb3SAlexey Dobriyan assert(memcmp(buf, g_proc_pid_maps_vsyscall, len) == 0); 189*5bc73bb3SAlexey Dobriyan } 190*5bc73bb3SAlexey Dobriyan return EXIT_SUCCESS; 191*5bc73bb3SAlexey Dobriyan } 192*5bc73bb3SAlexey Dobriyan } 193*5bc73bb3SAlexey Dobriyan 194*5bc73bb3SAlexey Dobriyan static int test_proc_pid_numa_maps(pid_t pid) 195*5bc73bb3SAlexey Dobriyan { 196*5bc73bb3SAlexey Dobriyan char buf[4096]; 197*5bc73bb3SAlexey Dobriyan snprintf(buf, sizeof(buf), "/proc/%u/numa_maps", pid); 198*5bc73bb3SAlexey Dobriyan int fd = open(buf, O_RDONLY); 199*5bc73bb3SAlexey Dobriyan if (fd == -1) { 200*5bc73bb3SAlexey Dobriyan if (errno == ENOENT) { 201*5bc73bb3SAlexey Dobriyan /* 202*5bc73bb3SAlexey Dobriyan * /proc/${pid}/numa_maps is under CONFIG_NUMA, 203*5bc73bb3SAlexey Dobriyan * it doesn't necessarily exist. 204*5bc73bb3SAlexey Dobriyan */ 205*5bc73bb3SAlexey Dobriyan return EXIT_SUCCESS; 206*5bc73bb3SAlexey Dobriyan } 207*5bc73bb3SAlexey Dobriyan perror("open /proc/${pid}/numa_maps"); 208*5bc73bb3SAlexey Dobriyan return EXIT_FAILURE; 209*5bc73bb3SAlexey Dobriyan } else { 210*5bc73bb3SAlexey Dobriyan ssize_t rv = read(fd, buf, sizeof(buf)); 211*5bc73bb3SAlexey Dobriyan close(fd); 212*5bc73bb3SAlexey Dobriyan assert(rv == 0); 213*5bc73bb3SAlexey Dobriyan return EXIT_SUCCESS; 214*5bc73bb3SAlexey Dobriyan } 215*5bc73bb3SAlexey Dobriyan } 216*5bc73bb3SAlexey Dobriyan 217*5bc73bb3SAlexey Dobriyan static int test_proc_pid_smaps(pid_t pid) 218*5bc73bb3SAlexey Dobriyan { 219*5bc73bb3SAlexey Dobriyan char buf[4096]; 220*5bc73bb3SAlexey Dobriyan snprintf(buf, sizeof(buf), "/proc/%u/smaps", pid); 221*5bc73bb3SAlexey Dobriyan int fd = open(buf, O_RDONLY); 222*5bc73bb3SAlexey Dobriyan if (fd == -1) { 223*5bc73bb3SAlexey Dobriyan if (errno == ENOENT) { 224*5bc73bb3SAlexey Dobriyan /* 225*5bc73bb3SAlexey Dobriyan * /proc/${pid}/smaps is under CONFIG_PROC_PAGE_MONITOR, 226*5bc73bb3SAlexey Dobriyan * it doesn't necessarily exist. 227*5bc73bb3SAlexey Dobriyan */ 228*5bc73bb3SAlexey Dobriyan return EXIT_SUCCESS; 229*5bc73bb3SAlexey Dobriyan } 230*5bc73bb3SAlexey Dobriyan perror("open /proc/${pid}/smaps"); 231*5bc73bb3SAlexey Dobriyan return EXIT_FAILURE; 232*5bc73bb3SAlexey Dobriyan } else { 233*5bc73bb3SAlexey Dobriyan ssize_t rv = read(fd, buf, sizeof(buf)); 234*5bc73bb3SAlexey Dobriyan close(fd); 235*5bc73bb3SAlexey Dobriyan if (g_vsyscall == 0) { 236*5bc73bb3SAlexey Dobriyan assert(rv == 0); 237*5bc73bb3SAlexey Dobriyan } else { 238*5bc73bb3SAlexey Dobriyan size_t len = strlen(g_proc_pid_maps_vsyscall); 239*5bc73bb3SAlexey Dobriyan /* TODO "ProtectionKey:" */ 240*5bc73bb3SAlexey Dobriyan assert(rv > len); 241*5bc73bb3SAlexey Dobriyan assert(memcmp(buf, g_proc_pid_maps_vsyscall, len) == 0); 242*5bc73bb3SAlexey Dobriyan } 243*5bc73bb3SAlexey Dobriyan return EXIT_SUCCESS; 244*5bc73bb3SAlexey Dobriyan } 245*5bc73bb3SAlexey Dobriyan } 246*5bc73bb3SAlexey Dobriyan 247*5bc73bb3SAlexey Dobriyan static const char g_smaps_rollup[] = 248*5bc73bb3SAlexey Dobriyan "00000000-00000000 ---p 00000000 00:00 0 [rollup]\n" 249*5bc73bb3SAlexey Dobriyan "Rss: 0 kB\n" 250*5bc73bb3SAlexey Dobriyan "Pss: 0 kB\n" 251*5bc73bb3SAlexey Dobriyan "Pss_Dirty: 0 kB\n" 252*5bc73bb3SAlexey Dobriyan "Pss_Anon: 0 kB\n" 253*5bc73bb3SAlexey Dobriyan "Pss_File: 0 kB\n" 254*5bc73bb3SAlexey Dobriyan "Pss_Shmem: 0 kB\n" 255*5bc73bb3SAlexey Dobriyan "Shared_Clean: 0 kB\n" 256*5bc73bb3SAlexey Dobriyan "Shared_Dirty: 0 kB\n" 257*5bc73bb3SAlexey Dobriyan "Private_Clean: 0 kB\n" 258*5bc73bb3SAlexey Dobriyan "Private_Dirty: 0 kB\n" 259*5bc73bb3SAlexey Dobriyan "Referenced: 0 kB\n" 260*5bc73bb3SAlexey Dobriyan "Anonymous: 0 kB\n" 261*5bc73bb3SAlexey Dobriyan "LazyFree: 0 kB\n" 262*5bc73bb3SAlexey Dobriyan "AnonHugePages: 0 kB\n" 263*5bc73bb3SAlexey Dobriyan "ShmemPmdMapped: 0 kB\n" 264*5bc73bb3SAlexey Dobriyan "FilePmdMapped: 0 kB\n" 265*5bc73bb3SAlexey Dobriyan "Shared_Hugetlb: 0 kB\n" 266*5bc73bb3SAlexey Dobriyan "Private_Hugetlb: 0 kB\n" 267*5bc73bb3SAlexey Dobriyan "Swap: 0 kB\n" 268*5bc73bb3SAlexey Dobriyan "SwapPss: 0 kB\n" 269*5bc73bb3SAlexey Dobriyan "Locked: 0 kB\n" 270*5bc73bb3SAlexey Dobriyan ; 271*5bc73bb3SAlexey Dobriyan 272*5bc73bb3SAlexey Dobriyan static int test_proc_pid_smaps_rollup(pid_t pid) 273*5bc73bb3SAlexey Dobriyan { 274*5bc73bb3SAlexey Dobriyan char buf[4096]; 275*5bc73bb3SAlexey Dobriyan snprintf(buf, sizeof(buf), "/proc/%u/smaps_rollup", pid); 276*5bc73bb3SAlexey Dobriyan int fd = open(buf, O_RDONLY); 277*5bc73bb3SAlexey Dobriyan if (fd == -1) { 278*5bc73bb3SAlexey Dobriyan if (errno == ENOENT) { 279*5bc73bb3SAlexey Dobriyan /* 280*5bc73bb3SAlexey Dobriyan * /proc/${pid}/smaps_rollup is under CONFIG_PROC_PAGE_MONITOR, 281*5bc73bb3SAlexey Dobriyan * it doesn't necessarily exist. 282*5bc73bb3SAlexey Dobriyan */ 283*5bc73bb3SAlexey Dobriyan return EXIT_SUCCESS; 284*5bc73bb3SAlexey Dobriyan } 285*5bc73bb3SAlexey Dobriyan perror("open /proc/${pid}/smaps_rollup"); 286*5bc73bb3SAlexey Dobriyan return EXIT_FAILURE; 287*5bc73bb3SAlexey Dobriyan } else { 288*5bc73bb3SAlexey Dobriyan ssize_t rv = read(fd, buf, sizeof(buf)); 289*5bc73bb3SAlexey Dobriyan close(fd); 290*5bc73bb3SAlexey Dobriyan assert(rv == sizeof(g_smaps_rollup) - 1); 291*5bc73bb3SAlexey Dobriyan assert(memcmp(buf, g_smaps_rollup, sizeof(g_smaps_rollup) - 1) == 0); 292*5bc73bb3SAlexey Dobriyan return EXIT_SUCCESS; 293*5bc73bb3SAlexey Dobriyan } 294*5bc73bb3SAlexey Dobriyan } 295*5bc73bb3SAlexey Dobriyan 296*5bc73bb3SAlexey Dobriyan int main(void) 297*5bc73bb3SAlexey Dobriyan { 298*5bc73bb3SAlexey Dobriyan int rv = EXIT_SUCCESS; 299*5bc73bb3SAlexey Dobriyan 300*5bc73bb3SAlexey Dobriyan vsyscall(); 301*5bc73bb3SAlexey Dobriyan 302*5bc73bb3SAlexey Dobriyan switch (g_vsyscall) { 303*5bc73bb3SAlexey Dobriyan case 0: 304*5bc73bb3SAlexey Dobriyan g_proc_pid_maps_vsyscall = proc_pid_maps_vsyscall_0; 305*5bc73bb3SAlexey Dobriyan g_proc_pid_smaps_vsyscall = proc_pid_smaps_vsyscall_0; 306*5bc73bb3SAlexey Dobriyan break; 307*5bc73bb3SAlexey Dobriyan case 1: 308*5bc73bb3SAlexey Dobriyan g_proc_pid_maps_vsyscall = proc_pid_maps_vsyscall_1; 309*5bc73bb3SAlexey Dobriyan g_proc_pid_smaps_vsyscall = proc_pid_smaps_vsyscall_1; 310*5bc73bb3SAlexey Dobriyan break; 311*5bc73bb3SAlexey Dobriyan case 2: 312*5bc73bb3SAlexey Dobriyan g_proc_pid_maps_vsyscall = proc_pid_maps_vsyscall_2; 313*5bc73bb3SAlexey Dobriyan g_proc_pid_smaps_vsyscall = proc_pid_smaps_vsyscall_2; 314*5bc73bb3SAlexey Dobriyan break; 315*5bc73bb3SAlexey Dobriyan default: 316*5bc73bb3SAlexey Dobriyan abort(); 317*5bc73bb3SAlexey Dobriyan } 318*5bc73bb3SAlexey Dobriyan 319*5bc73bb3SAlexey Dobriyan pid_t pid = fork(); 320*5bc73bb3SAlexey Dobriyan if (pid == -1) { 321*5bc73bb3SAlexey Dobriyan perror("fork"); 322*5bc73bb3SAlexey Dobriyan return EXIT_FAILURE; 323*5bc73bb3SAlexey Dobriyan } else if (pid == 0) { 324*5bc73bb3SAlexey Dobriyan rv = ptrace(PTRACE_TRACEME, 0, NULL, NULL); 325*5bc73bb3SAlexey Dobriyan if (rv != 0) { 326*5bc73bb3SAlexey Dobriyan if (errno == EPERM) { 327*5bc73bb3SAlexey Dobriyan fprintf(stderr, 328*5bc73bb3SAlexey Dobriyan "Did you know? ptrace(PTRACE_TRACEME) doesn't work under strace.\n" 329*5bc73bb3SAlexey Dobriyan ); 330*5bc73bb3SAlexey Dobriyan kill(getppid(), SIGTERM); 331*5bc73bb3SAlexey Dobriyan return EXIT_FAILURE; 332*5bc73bb3SAlexey Dobriyan } 333*5bc73bb3SAlexey Dobriyan perror("ptrace PTRACE_TRACEME"); 334*5bc73bb3SAlexey Dobriyan return EXIT_FAILURE; 335*5bc73bb3SAlexey Dobriyan } 336*5bc73bb3SAlexey Dobriyan 337*5bc73bb3SAlexey Dobriyan /* 338*5bc73bb3SAlexey Dobriyan * Hide "segfault at ..." messages. Signal handler won't run. 339*5bc73bb3SAlexey Dobriyan */ 340*5bc73bb3SAlexey Dobriyan struct sigaction act = {}; 341*5bc73bb3SAlexey Dobriyan act.sa_flags = SA_SIGINFO; 342*5bc73bb3SAlexey Dobriyan act.sa_sigaction = sigaction_SIGSEGV; 343*5bc73bb3SAlexey Dobriyan sigaction(SIGSEGV, &act, NULL); 344*5bc73bb3SAlexey Dobriyan 345*5bc73bb3SAlexey Dobriyan #ifdef __amd64__ 346*5bc73bb3SAlexey Dobriyan munmap(NULL, ((size_t)1 << 47) - 4096); 347*5bc73bb3SAlexey Dobriyan #else 348*5bc73bb3SAlexey Dobriyan #error "implement 'unmap everything'" 349*5bc73bb3SAlexey Dobriyan #endif 350*5bc73bb3SAlexey Dobriyan return EXIT_FAILURE; 351*5bc73bb3SAlexey Dobriyan } else { 352*5bc73bb3SAlexey Dobriyan /* 353*5bc73bb3SAlexey Dobriyan * TODO find reliable way to signal parent that munmap(2) completed. 354*5bc73bb3SAlexey Dobriyan * Child can't do it directly because it effectively doesn't exist 355*5bc73bb3SAlexey Dobriyan * anymore. Looking at child's VM files isn't 100% reliable either: 356*5bc73bb3SAlexey Dobriyan * due to a bug they may not become empty or empty-like. 357*5bc73bb3SAlexey Dobriyan */ 358*5bc73bb3SAlexey Dobriyan sleep(1); 359*5bc73bb3SAlexey Dobriyan 360*5bc73bb3SAlexey Dobriyan if (rv == EXIT_SUCCESS) { 361*5bc73bb3SAlexey Dobriyan rv = test_proc_pid_maps(pid); 362*5bc73bb3SAlexey Dobriyan } 363*5bc73bb3SAlexey Dobriyan if (rv == EXIT_SUCCESS) { 364*5bc73bb3SAlexey Dobriyan rv = test_proc_pid_numa_maps(pid); 365*5bc73bb3SAlexey Dobriyan } 366*5bc73bb3SAlexey Dobriyan if (rv == EXIT_SUCCESS) { 367*5bc73bb3SAlexey Dobriyan rv = test_proc_pid_smaps(pid); 368*5bc73bb3SAlexey Dobriyan } 369*5bc73bb3SAlexey Dobriyan if (rv == EXIT_SUCCESS) { 370*5bc73bb3SAlexey Dobriyan rv = test_proc_pid_smaps_rollup(pid); 371*5bc73bb3SAlexey Dobriyan } 372*5bc73bb3SAlexey Dobriyan /* 373*5bc73bb3SAlexey Dobriyan * TODO test /proc/${pid}/statm, task_statm() 374*5bc73bb3SAlexey Dobriyan * ->start_code, ->end_code aren't updated by munmap(). 375*5bc73bb3SAlexey Dobriyan * Output can be "0 0 0 2 0 0 0\n" where "2" can be anything. 376*5bc73bb3SAlexey Dobriyan */ 377*5bc73bb3SAlexey Dobriyan 378*5bc73bb3SAlexey Dobriyan /* Cut the rope. */ 379*5bc73bb3SAlexey Dobriyan int wstatus; 380*5bc73bb3SAlexey Dobriyan waitpid(pid, &wstatus, 0); 381*5bc73bb3SAlexey Dobriyan assert(WIFSTOPPED(wstatus)); 382*5bc73bb3SAlexey Dobriyan assert(WSTOPSIG(wstatus) == SIGSEGV); 383*5bc73bb3SAlexey Dobriyan } 384*5bc73bb3SAlexey Dobriyan 385*5bc73bb3SAlexey Dobriyan return rv; 386*5bc73bb3SAlexey Dobriyan } 387