1f58a2dd8SAlexey Dobriyan #if defined __amd64__ || defined __i386__
25bc73bb3SAlexey Dobriyan /*
35bc73bb3SAlexey Dobriyan * Copyright (c) 2022 Alexey Dobriyan <[email protected]>
45bc73bb3SAlexey Dobriyan *
55bc73bb3SAlexey Dobriyan * Permission to use, copy, modify, and distribute this software for any
65bc73bb3SAlexey Dobriyan * purpose with or without fee is hereby granted, provided that the above
75bc73bb3SAlexey Dobriyan * copyright notice and this permission notice appear in all copies.
85bc73bb3SAlexey Dobriyan *
95bc73bb3SAlexey Dobriyan * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
105bc73bb3SAlexey Dobriyan * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
115bc73bb3SAlexey Dobriyan * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
125bc73bb3SAlexey Dobriyan * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
135bc73bb3SAlexey Dobriyan * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
145bc73bb3SAlexey Dobriyan * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
155bc73bb3SAlexey Dobriyan * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
165bc73bb3SAlexey Dobriyan */
175bc73bb3SAlexey Dobriyan /*
185bc73bb3SAlexey Dobriyan * Create a process without mappings by unmapping everything at once and
195bc73bb3SAlexey Dobriyan * holding it with ptrace(2). See what happens to
205bc73bb3SAlexey Dobriyan *
215bc73bb3SAlexey Dobriyan * /proc/${pid}/maps
225bc73bb3SAlexey Dobriyan * /proc/${pid}/numa_maps
235bc73bb3SAlexey Dobriyan * /proc/${pid}/smaps
245bc73bb3SAlexey Dobriyan * /proc/${pid}/smaps_rollup
255bc73bb3SAlexey Dobriyan */
26*bf5add39SSwarup Laxman Kotiaklapudi #undef _GNU_SOURCE
27*bf5add39SSwarup Laxman Kotiaklapudi #define _GNU_SOURCE
28*bf5add39SSwarup Laxman Kotiaklapudi
295bc73bb3SAlexey Dobriyan #undef NDEBUG
305bc73bb3SAlexey Dobriyan #include <assert.h>
315bc73bb3SAlexey Dobriyan #include <errno.h>
325316a017SAlexey Dobriyan #include <stdint.h>
335bc73bb3SAlexey Dobriyan #include <stdio.h>
345bc73bb3SAlexey Dobriyan #include <stdlib.h>
355bc73bb3SAlexey Dobriyan #include <string.h>
365bc73bb3SAlexey Dobriyan #include <fcntl.h>
375bc73bb3SAlexey Dobriyan #include <sys/mman.h>
385bc73bb3SAlexey Dobriyan #include <sys/ptrace.h>
395bc73bb3SAlexey Dobriyan #include <sys/resource.h>
40*bf5add39SSwarup Laxman Kotiaklapudi #include <sys/syscall.h>
415bc73bb3SAlexey Dobriyan #include <sys/types.h>
425bc73bb3SAlexey Dobriyan #include <sys/wait.h>
435bc73bb3SAlexey Dobriyan #include <unistd.h>
445bc73bb3SAlexey Dobriyan
454356b11eSAlexey Dobriyan #ifdef __amd64__
464356b11eSAlexey Dobriyan #define TEST_VSYSCALL
474356b11eSAlexey Dobriyan #endif
484356b11eSAlexey Dobriyan
49*bf5add39SSwarup Laxman Kotiaklapudi #if defined __amd64__
50*bf5add39SSwarup Laxman Kotiaklapudi #ifndef SYS_pkey_alloc
51*bf5add39SSwarup Laxman Kotiaklapudi #define SYS_pkey_alloc 330
52*bf5add39SSwarup Laxman Kotiaklapudi #endif
53*bf5add39SSwarup Laxman Kotiaklapudi #ifndef SYS_pkey_free
54*bf5add39SSwarup Laxman Kotiaklapudi #define SYS_pkey_free 331
55*bf5add39SSwarup Laxman Kotiaklapudi #endif
56*bf5add39SSwarup Laxman Kotiaklapudi #elif defined __i386__
57*bf5add39SSwarup Laxman Kotiaklapudi #ifndef SYS_pkey_alloc
58*bf5add39SSwarup Laxman Kotiaklapudi #define SYS_pkey_alloc 381
59*bf5add39SSwarup Laxman Kotiaklapudi #endif
60*bf5add39SSwarup Laxman Kotiaklapudi #ifndef SYS_pkey_free
61*bf5add39SSwarup Laxman Kotiaklapudi #define SYS_pkey_free 382
62*bf5add39SSwarup Laxman Kotiaklapudi #endif
63*bf5add39SSwarup Laxman Kotiaklapudi #else
64*bf5add39SSwarup Laxman Kotiaklapudi #error "SYS_pkey_alloc"
65*bf5add39SSwarup Laxman Kotiaklapudi #endif
66*bf5add39SSwarup Laxman Kotiaklapudi
67*bf5add39SSwarup Laxman Kotiaklapudi static int g_protection_key_support;
68*bf5add39SSwarup Laxman Kotiaklapudi
protection_key_support(void)69*bf5add39SSwarup Laxman Kotiaklapudi static int protection_key_support(void)
70*bf5add39SSwarup Laxman Kotiaklapudi {
71*bf5add39SSwarup Laxman Kotiaklapudi long rv = syscall(SYS_pkey_alloc, 0, 0);
72*bf5add39SSwarup Laxman Kotiaklapudi if (rv > 0) {
73*bf5add39SSwarup Laxman Kotiaklapudi syscall(SYS_pkey_free, (int)rv);
74*bf5add39SSwarup Laxman Kotiaklapudi return 1;
75*bf5add39SSwarup Laxman Kotiaklapudi } else if (rv == -1 && errno == ENOSYS) {
76*bf5add39SSwarup Laxman Kotiaklapudi return 0;
77*bf5add39SSwarup Laxman Kotiaklapudi } else if (rv == -1 && errno == EINVAL) {
78*bf5add39SSwarup Laxman Kotiaklapudi // ospke=n
79*bf5add39SSwarup Laxman Kotiaklapudi return 0;
80*bf5add39SSwarup Laxman Kotiaklapudi } else {
81*bf5add39SSwarup Laxman Kotiaklapudi fprintf(stderr, "%s: error: rv %ld, errno %d\n", __func__, rv, errno);
82*bf5add39SSwarup Laxman Kotiaklapudi exit(EXIT_FAILURE);
83*bf5add39SSwarup Laxman Kotiaklapudi }
84*bf5add39SSwarup Laxman Kotiaklapudi }
85*bf5add39SSwarup Laxman Kotiaklapudi
865bc73bb3SAlexey Dobriyan /*
875bc73bb3SAlexey Dobriyan * 0: vsyscall VMA doesn't exist vsyscall=none
885bc73bb3SAlexey Dobriyan * 1: vsyscall VMA is --xp vsyscall=xonly
895bc73bb3SAlexey Dobriyan * 2: vsyscall VMA is r-xp vsyscall=emulate
905bc73bb3SAlexey Dobriyan */
915316a017SAlexey Dobriyan static volatile int g_vsyscall;
925bc73bb3SAlexey Dobriyan static const char *g_proc_pid_maps_vsyscall;
935bc73bb3SAlexey Dobriyan static const char *g_proc_pid_smaps_vsyscall;
945bc73bb3SAlexey Dobriyan
955bc73bb3SAlexey Dobriyan static const char proc_pid_maps_vsyscall_0[] = "";
965bc73bb3SAlexey Dobriyan static const char proc_pid_maps_vsyscall_1[] =
975bc73bb3SAlexey Dobriyan "ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]\n";
985bc73bb3SAlexey Dobriyan static const char proc_pid_maps_vsyscall_2[] =
995bc73bb3SAlexey Dobriyan "ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]\n";
1005bc73bb3SAlexey Dobriyan
1015bc73bb3SAlexey Dobriyan static const char proc_pid_smaps_vsyscall_0[] = "";
1025bc73bb3SAlexey Dobriyan
1035bc73bb3SAlexey Dobriyan static const char proc_pid_smaps_vsyscall_1[] =
10420e34aa7SAlexey Dobriyan "ffffffffff600000-ffffffffff601000 --xp 00000000 00:00 0 [vsyscall]\n"
1055bc73bb3SAlexey Dobriyan "Size: 4 kB\n"
1065bc73bb3SAlexey Dobriyan "KernelPageSize: 4 kB\n"
1075bc73bb3SAlexey Dobriyan "MMUPageSize: 4 kB\n"
1085bc73bb3SAlexey Dobriyan "Rss: 0 kB\n"
1095bc73bb3SAlexey Dobriyan "Pss: 0 kB\n"
1105bc73bb3SAlexey Dobriyan "Pss_Dirty: 0 kB\n"
1115bc73bb3SAlexey Dobriyan "Shared_Clean: 0 kB\n"
1125bc73bb3SAlexey Dobriyan "Shared_Dirty: 0 kB\n"
1135bc73bb3SAlexey Dobriyan "Private_Clean: 0 kB\n"
1145bc73bb3SAlexey Dobriyan "Private_Dirty: 0 kB\n"
1155bc73bb3SAlexey Dobriyan "Referenced: 0 kB\n"
1165bc73bb3SAlexey Dobriyan "Anonymous: 0 kB\n"
11720e34aa7SAlexey Dobriyan "KSM: 0 kB\n"
1185bc73bb3SAlexey Dobriyan "LazyFree: 0 kB\n"
1195bc73bb3SAlexey Dobriyan "AnonHugePages: 0 kB\n"
1205bc73bb3SAlexey Dobriyan "ShmemPmdMapped: 0 kB\n"
1215bc73bb3SAlexey Dobriyan "FilePmdMapped: 0 kB\n"
1225bc73bb3SAlexey Dobriyan "Shared_Hugetlb: 0 kB\n"
1235bc73bb3SAlexey Dobriyan "Private_Hugetlb: 0 kB\n"
1245bc73bb3SAlexey Dobriyan "Swap: 0 kB\n"
1255bc73bb3SAlexey Dobriyan "SwapPss: 0 kB\n"
1265bc73bb3SAlexey Dobriyan "Locked: 0 kB\n"
1275bc73bb3SAlexey Dobriyan "THPeligible: 0\n"
1285bc73bb3SAlexey Dobriyan ;
1295bc73bb3SAlexey Dobriyan
1305bc73bb3SAlexey Dobriyan static const char proc_pid_smaps_vsyscall_2[] =
13120e34aa7SAlexey Dobriyan "ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]\n"
1325bc73bb3SAlexey Dobriyan "Size: 4 kB\n"
1335bc73bb3SAlexey Dobriyan "KernelPageSize: 4 kB\n"
1345bc73bb3SAlexey Dobriyan "MMUPageSize: 4 kB\n"
1355bc73bb3SAlexey Dobriyan "Rss: 0 kB\n"
1365bc73bb3SAlexey Dobriyan "Pss: 0 kB\n"
1375bc73bb3SAlexey Dobriyan "Pss_Dirty: 0 kB\n"
1385bc73bb3SAlexey Dobriyan "Shared_Clean: 0 kB\n"
1395bc73bb3SAlexey Dobriyan "Shared_Dirty: 0 kB\n"
1405bc73bb3SAlexey Dobriyan "Private_Clean: 0 kB\n"
1415bc73bb3SAlexey Dobriyan "Private_Dirty: 0 kB\n"
1425bc73bb3SAlexey Dobriyan "Referenced: 0 kB\n"
1435bc73bb3SAlexey Dobriyan "Anonymous: 0 kB\n"
14420e34aa7SAlexey Dobriyan "KSM: 0 kB\n"
1455bc73bb3SAlexey Dobriyan "LazyFree: 0 kB\n"
1465bc73bb3SAlexey Dobriyan "AnonHugePages: 0 kB\n"
1475bc73bb3SAlexey Dobriyan "ShmemPmdMapped: 0 kB\n"
1485bc73bb3SAlexey Dobriyan "FilePmdMapped: 0 kB\n"
1495bc73bb3SAlexey Dobriyan "Shared_Hugetlb: 0 kB\n"
1505bc73bb3SAlexey Dobriyan "Private_Hugetlb: 0 kB\n"
1515bc73bb3SAlexey Dobriyan "Swap: 0 kB\n"
1525bc73bb3SAlexey Dobriyan "SwapPss: 0 kB\n"
1535bc73bb3SAlexey Dobriyan "Locked: 0 kB\n"
1545bc73bb3SAlexey Dobriyan "THPeligible: 0\n"
1555bc73bb3SAlexey Dobriyan ;
1565bc73bb3SAlexey Dobriyan
sigaction_SIGSEGV(int _,siginfo_t * __,void * ___)1575bc73bb3SAlexey Dobriyan static void sigaction_SIGSEGV(int _, siginfo_t *__, void *___)
1585bc73bb3SAlexey Dobriyan {
1595bc73bb3SAlexey Dobriyan _exit(EXIT_FAILURE);
1605bc73bb3SAlexey Dobriyan }
1615bc73bb3SAlexey Dobriyan
1624356b11eSAlexey Dobriyan #ifdef TEST_VSYSCALL
sigaction_SIGSEGV_vsyscall(int _,siginfo_t * __,void * ___)1635bc73bb3SAlexey Dobriyan static void sigaction_SIGSEGV_vsyscall(int _, siginfo_t *__, void *___)
1645bc73bb3SAlexey Dobriyan {
1655bc73bb3SAlexey Dobriyan _exit(g_vsyscall);
1665bc73bb3SAlexey Dobriyan }
1675bc73bb3SAlexey Dobriyan
1685bc73bb3SAlexey Dobriyan /*
1695bc73bb3SAlexey Dobriyan * vsyscall page can't be unmapped, probe it directly.
1705bc73bb3SAlexey Dobriyan */
vsyscall(void)1715bc73bb3SAlexey Dobriyan static void vsyscall(void)
1725bc73bb3SAlexey Dobriyan {
1735bc73bb3SAlexey Dobriyan pid_t pid;
1745bc73bb3SAlexey Dobriyan int wstatus;
1755bc73bb3SAlexey Dobriyan
1765bc73bb3SAlexey Dobriyan pid = fork();
1775bc73bb3SAlexey Dobriyan if (pid < 0) {
1785bc73bb3SAlexey Dobriyan fprintf(stderr, "fork, errno %d\n", errno);
1795bc73bb3SAlexey Dobriyan exit(1);
1805bc73bb3SAlexey Dobriyan }
1815bc73bb3SAlexey Dobriyan if (pid == 0) {
1825bc73bb3SAlexey Dobriyan setrlimit(RLIMIT_CORE, &(struct rlimit){});
1835bc73bb3SAlexey Dobriyan
1845bc73bb3SAlexey Dobriyan /* Hide "segfault at ffffffffff600000" messages. */
1855bc73bb3SAlexey Dobriyan struct sigaction act = {};
1865bc73bb3SAlexey Dobriyan act.sa_flags = SA_SIGINFO;
1875bc73bb3SAlexey Dobriyan act.sa_sigaction = sigaction_SIGSEGV_vsyscall;
1885bc73bb3SAlexey Dobriyan sigaction(SIGSEGV, &act, NULL);
1895bc73bb3SAlexey Dobriyan
1905bc73bb3SAlexey Dobriyan g_vsyscall = 0;
1915bc73bb3SAlexey Dobriyan /* gettimeofday(NULL, NULL); */
1925316a017SAlexey Dobriyan uint64_t rax = 0xffffffffff600000;
1935bc73bb3SAlexey Dobriyan asm volatile (
1945316a017SAlexey Dobriyan "call *%[rax]"
1955316a017SAlexey Dobriyan : [rax] "+a" (rax)
1965316a017SAlexey Dobriyan : "D" (NULL), "S" (NULL)
1975316a017SAlexey Dobriyan : "rcx", "r11"
1985bc73bb3SAlexey Dobriyan );
1995bc73bb3SAlexey Dobriyan
2005bc73bb3SAlexey Dobriyan g_vsyscall = 1;
2015bc73bb3SAlexey Dobriyan *(volatile int *)0xffffffffff600000UL;
2025bc73bb3SAlexey Dobriyan
2035bc73bb3SAlexey Dobriyan g_vsyscall = 2;
2045bc73bb3SAlexey Dobriyan exit(g_vsyscall);
2055bc73bb3SAlexey Dobriyan }
2065bc73bb3SAlexey Dobriyan waitpid(pid, &wstatus, 0);
2075bc73bb3SAlexey Dobriyan if (WIFEXITED(wstatus)) {
2085bc73bb3SAlexey Dobriyan g_vsyscall = WEXITSTATUS(wstatus);
2095bc73bb3SAlexey Dobriyan } else {
2105bc73bb3SAlexey Dobriyan fprintf(stderr, "error: vsyscall wstatus %08x\n", wstatus);
2115bc73bb3SAlexey Dobriyan exit(1);
2125bc73bb3SAlexey Dobriyan }
2135bc73bb3SAlexey Dobriyan }
2144356b11eSAlexey Dobriyan #endif
2155bc73bb3SAlexey Dobriyan
test_proc_pid_maps(pid_t pid)2165bc73bb3SAlexey Dobriyan static int test_proc_pid_maps(pid_t pid)
2175bc73bb3SAlexey Dobriyan {
2185bc73bb3SAlexey Dobriyan char buf[4096];
2195bc73bb3SAlexey Dobriyan snprintf(buf, sizeof(buf), "/proc/%u/maps", pid);
2205bc73bb3SAlexey Dobriyan int fd = open(buf, O_RDONLY);
2215bc73bb3SAlexey Dobriyan if (fd == -1) {
2225bc73bb3SAlexey Dobriyan perror("open /proc/${pid}/maps");
2235bc73bb3SAlexey Dobriyan return EXIT_FAILURE;
2245bc73bb3SAlexey Dobriyan } else {
2255bc73bb3SAlexey Dobriyan ssize_t rv = read(fd, buf, sizeof(buf));
2265bc73bb3SAlexey Dobriyan close(fd);
2275bc73bb3SAlexey Dobriyan if (g_vsyscall == 0) {
2285bc73bb3SAlexey Dobriyan assert(rv == 0);
2295bc73bb3SAlexey Dobriyan } else {
2305bc73bb3SAlexey Dobriyan size_t len = strlen(g_proc_pid_maps_vsyscall);
2315bc73bb3SAlexey Dobriyan assert(rv == len);
2325bc73bb3SAlexey Dobriyan assert(memcmp(buf, g_proc_pid_maps_vsyscall, len) == 0);
2335bc73bb3SAlexey Dobriyan }
2345bc73bb3SAlexey Dobriyan return EXIT_SUCCESS;
2355bc73bb3SAlexey Dobriyan }
2365bc73bb3SAlexey Dobriyan }
2375bc73bb3SAlexey Dobriyan
test_proc_pid_numa_maps(pid_t pid)2385bc73bb3SAlexey Dobriyan static int test_proc_pid_numa_maps(pid_t pid)
2395bc73bb3SAlexey Dobriyan {
2405bc73bb3SAlexey Dobriyan char buf[4096];
2415bc73bb3SAlexey Dobriyan snprintf(buf, sizeof(buf), "/proc/%u/numa_maps", pid);
2425bc73bb3SAlexey Dobriyan int fd = open(buf, O_RDONLY);
2435bc73bb3SAlexey Dobriyan if (fd == -1) {
2445bc73bb3SAlexey Dobriyan if (errno == ENOENT) {
2455bc73bb3SAlexey Dobriyan /*
2465bc73bb3SAlexey Dobriyan * /proc/${pid}/numa_maps is under CONFIG_NUMA,
2475bc73bb3SAlexey Dobriyan * it doesn't necessarily exist.
2485bc73bb3SAlexey Dobriyan */
2495bc73bb3SAlexey Dobriyan return EXIT_SUCCESS;
2505bc73bb3SAlexey Dobriyan }
2515bc73bb3SAlexey Dobriyan perror("open /proc/${pid}/numa_maps");
2525bc73bb3SAlexey Dobriyan return EXIT_FAILURE;
2535bc73bb3SAlexey Dobriyan } else {
2545bc73bb3SAlexey Dobriyan ssize_t rv = read(fd, buf, sizeof(buf));
2555bc73bb3SAlexey Dobriyan close(fd);
2565bc73bb3SAlexey Dobriyan assert(rv == 0);
2575bc73bb3SAlexey Dobriyan return EXIT_SUCCESS;
2585bc73bb3SAlexey Dobriyan }
2595bc73bb3SAlexey Dobriyan }
2605bc73bb3SAlexey Dobriyan
test_proc_pid_smaps(pid_t pid)2615bc73bb3SAlexey Dobriyan static int test_proc_pid_smaps(pid_t pid)
2625bc73bb3SAlexey Dobriyan {
2635bc73bb3SAlexey Dobriyan char buf[4096];
2645bc73bb3SAlexey Dobriyan snprintf(buf, sizeof(buf), "/proc/%u/smaps", pid);
2655bc73bb3SAlexey Dobriyan int fd = open(buf, O_RDONLY);
2665bc73bb3SAlexey Dobriyan if (fd == -1) {
2675bc73bb3SAlexey Dobriyan if (errno == ENOENT) {
2685bc73bb3SAlexey Dobriyan /*
2695bc73bb3SAlexey Dobriyan * /proc/${pid}/smaps is under CONFIG_PROC_PAGE_MONITOR,
2705bc73bb3SAlexey Dobriyan * it doesn't necessarily exist.
2715bc73bb3SAlexey Dobriyan */
2725bc73bb3SAlexey Dobriyan return EXIT_SUCCESS;
2735bc73bb3SAlexey Dobriyan }
2745bc73bb3SAlexey Dobriyan perror("open /proc/${pid}/smaps");
2755bc73bb3SAlexey Dobriyan return EXIT_FAILURE;
276*bf5add39SSwarup Laxman Kotiaklapudi }
2775bc73bb3SAlexey Dobriyan ssize_t rv = read(fd, buf, sizeof(buf));
2785bc73bb3SAlexey Dobriyan close(fd);
279*bf5add39SSwarup Laxman Kotiaklapudi
280*bf5add39SSwarup Laxman Kotiaklapudi assert(0 <= rv);
281*bf5add39SSwarup Laxman Kotiaklapudi assert(rv <= sizeof(buf));
282*bf5add39SSwarup Laxman Kotiaklapudi
2835bc73bb3SAlexey Dobriyan if (g_vsyscall == 0) {
2845bc73bb3SAlexey Dobriyan assert(rv == 0);
2855bc73bb3SAlexey Dobriyan } else {
28620e34aa7SAlexey Dobriyan size_t len = strlen(g_proc_pid_smaps_vsyscall);
2875bc73bb3SAlexey Dobriyan assert(rv > len);
28820e34aa7SAlexey Dobriyan assert(memcmp(buf, g_proc_pid_smaps_vsyscall, len) == 0);
289*bf5add39SSwarup Laxman Kotiaklapudi
290*bf5add39SSwarup Laxman Kotiaklapudi if (g_protection_key_support) {
291*bf5add39SSwarup Laxman Kotiaklapudi #define PROTECTION_KEY "ProtectionKey: 0\n"
292*bf5add39SSwarup Laxman Kotiaklapudi assert(memmem(buf, rv, PROTECTION_KEY, strlen(PROTECTION_KEY)));
2935bc73bb3SAlexey Dobriyan }
294*bf5add39SSwarup Laxman Kotiaklapudi }
295*bf5add39SSwarup Laxman Kotiaklapudi
2965bc73bb3SAlexey Dobriyan return EXIT_SUCCESS;
2975bc73bb3SAlexey Dobriyan }
2985bc73bb3SAlexey Dobriyan
2995bc73bb3SAlexey Dobriyan static const char g_smaps_rollup[] =
3005bc73bb3SAlexey Dobriyan "00000000-00000000 ---p 00000000 00:00 0 [rollup]\n"
3015bc73bb3SAlexey Dobriyan "Rss: 0 kB\n"
3025bc73bb3SAlexey Dobriyan "Pss: 0 kB\n"
3035bc73bb3SAlexey Dobriyan "Pss_Dirty: 0 kB\n"
3045bc73bb3SAlexey Dobriyan "Pss_Anon: 0 kB\n"
3055bc73bb3SAlexey Dobriyan "Pss_File: 0 kB\n"
3065bc73bb3SAlexey Dobriyan "Pss_Shmem: 0 kB\n"
3075bc73bb3SAlexey Dobriyan "Shared_Clean: 0 kB\n"
3085bc73bb3SAlexey Dobriyan "Shared_Dirty: 0 kB\n"
3095bc73bb3SAlexey Dobriyan "Private_Clean: 0 kB\n"
3105bc73bb3SAlexey Dobriyan "Private_Dirty: 0 kB\n"
3115bc73bb3SAlexey Dobriyan "Referenced: 0 kB\n"
3125bc73bb3SAlexey Dobriyan "Anonymous: 0 kB\n"
3139d1be94dSAlexey Dobriyan "KSM: 0 kB\n"
3145bc73bb3SAlexey Dobriyan "LazyFree: 0 kB\n"
3155bc73bb3SAlexey Dobriyan "AnonHugePages: 0 kB\n"
3165bc73bb3SAlexey Dobriyan "ShmemPmdMapped: 0 kB\n"
3175bc73bb3SAlexey Dobriyan "FilePmdMapped: 0 kB\n"
3185bc73bb3SAlexey Dobriyan "Shared_Hugetlb: 0 kB\n"
3195bc73bb3SAlexey Dobriyan "Private_Hugetlb: 0 kB\n"
3205bc73bb3SAlexey Dobriyan "Swap: 0 kB\n"
3215bc73bb3SAlexey Dobriyan "SwapPss: 0 kB\n"
3225bc73bb3SAlexey Dobriyan "Locked: 0 kB\n"
3235bc73bb3SAlexey Dobriyan ;
3245bc73bb3SAlexey Dobriyan
test_proc_pid_smaps_rollup(pid_t pid)3255bc73bb3SAlexey Dobriyan static int test_proc_pid_smaps_rollup(pid_t pid)
3265bc73bb3SAlexey Dobriyan {
3275bc73bb3SAlexey Dobriyan char buf[4096];
3285bc73bb3SAlexey Dobriyan snprintf(buf, sizeof(buf), "/proc/%u/smaps_rollup", pid);
3295bc73bb3SAlexey Dobriyan int fd = open(buf, O_RDONLY);
3305bc73bb3SAlexey Dobriyan if (fd == -1) {
3315bc73bb3SAlexey Dobriyan if (errno == ENOENT) {
3325bc73bb3SAlexey Dobriyan /*
3335bc73bb3SAlexey Dobriyan * /proc/${pid}/smaps_rollup is under CONFIG_PROC_PAGE_MONITOR,
3345bc73bb3SAlexey Dobriyan * it doesn't necessarily exist.
3355bc73bb3SAlexey Dobriyan */
3365bc73bb3SAlexey Dobriyan return EXIT_SUCCESS;
3375bc73bb3SAlexey Dobriyan }
3385bc73bb3SAlexey Dobriyan perror("open /proc/${pid}/smaps_rollup");
3395bc73bb3SAlexey Dobriyan return EXIT_FAILURE;
3405bc73bb3SAlexey Dobriyan } else {
3415bc73bb3SAlexey Dobriyan ssize_t rv = read(fd, buf, sizeof(buf));
3425bc73bb3SAlexey Dobriyan close(fd);
3435bc73bb3SAlexey Dobriyan assert(rv == sizeof(g_smaps_rollup) - 1);
3445bc73bb3SAlexey Dobriyan assert(memcmp(buf, g_smaps_rollup, sizeof(g_smaps_rollup) - 1) == 0);
3455bc73bb3SAlexey Dobriyan return EXIT_SUCCESS;
3465bc73bb3SAlexey Dobriyan }
3475bc73bb3SAlexey Dobriyan }
3485bc73bb3SAlexey Dobriyan
parse_u64(const char * p,const char * const end,uint64_t * rv)3496e79b375SSwarup Laxman Kotiaklapudi static const char *parse_u64(const char *p, const char *const end, uint64_t *rv)
3506e79b375SSwarup Laxman Kotiaklapudi {
3516e79b375SSwarup Laxman Kotiaklapudi *rv = 0;
3526e79b375SSwarup Laxman Kotiaklapudi for (; p != end; p += 1) {
3536e79b375SSwarup Laxman Kotiaklapudi if ('0' <= *p && *p <= '9') {
3546e79b375SSwarup Laxman Kotiaklapudi assert(!__builtin_mul_overflow(*rv, 10, rv));
3556e79b375SSwarup Laxman Kotiaklapudi assert(!__builtin_add_overflow(*rv, *p - '0', rv));
3566e79b375SSwarup Laxman Kotiaklapudi } else {
3576e79b375SSwarup Laxman Kotiaklapudi break;
3586e79b375SSwarup Laxman Kotiaklapudi }
3596e79b375SSwarup Laxman Kotiaklapudi }
3606e79b375SSwarup Laxman Kotiaklapudi assert(p != end);
3616e79b375SSwarup Laxman Kotiaklapudi return p;
3626e79b375SSwarup Laxman Kotiaklapudi }
3636e79b375SSwarup Laxman Kotiaklapudi
3646e79b375SSwarup Laxman Kotiaklapudi /*
3656e79b375SSwarup Laxman Kotiaklapudi * There seems to be 2 types of valid output:
3666e79b375SSwarup Laxman Kotiaklapudi * "0 A A B 0 0 0\n" for dynamic exeuctables,
3676e79b375SSwarup Laxman Kotiaklapudi * "0 0 0 B 0 0 0\n" for static executables.
3686e79b375SSwarup Laxman Kotiaklapudi */
test_proc_pid_statm(pid_t pid)3696e79b375SSwarup Laxman Kotiaklapudi static int test_proc_pid_statm(pid_t pid)
3706e79b375SSwarup Laxman Kotiaklapudi {
3716e79b375SSwarup Laxman Kotiaklapudi char buf[4096];
3726e79b375SSwarup Laxman Kotiaklapudi snprintf(buf, sizeof(buf), "/proc/%u/statm", pid);
3736e79b375SSwarup Laxman Kotiaklapudi int fd = open(buf, O_RDONLY);
3746e79b375SSwarup Laxman Kotiaklapudi if (fd == -1) {
3756e79b375SSwarup Laxman Kotiaklapudi perror("open /proc/${pid}/statm");
3766e79b375SSwarup Laxman Kotiaklapudi return EXIT_FAILURE;
3776e79b375SSwarup Laxman Kotiaklapudi }
3786e79b375SSwarup Laxman Kotiaklapudi
3796e79b375SSwarup Laxman Kotiaklapudi ssize_t rv = read(fd, buf, sizeof(buf));
3806e79b375SSwarup Laxman Kotiaklapudi close(fd);
3816e79b375SSwarup Laxman Kotiaklapudi
3826e79b375SSwarup Laxman Kotiaklapudi assert(rv >= 0);
3836e79b375SSwarup Laxman Kotiaklapudi assert(rv <= sizeof(buf));
3846e79b375SSwarup Laxman Kotiaklapudi
3856e79b375SSwarup Laxman Kotiaklapudi const char *p = buf;
3866e79b375SSwarup Laxman Kotiaklapudi const char *const end = p + rv;
3876e79b375SSwarup Laxman Kotiaklapudi
3886e79b375SSwarup Laxman Kotiaklapudi /* size */
3896e79b375SSwarup Laxman Kotiaklapudi assert(p != end && *p++ == '0');
3906e79b375SSwarup Laxman Kotiaklapudi assert(p != end && *p++ == ' ');
3916e79b375SSwarup Laxman Kotiaklapudi
3926e79b375SSwarup Laxman Kotiaklapudi uint64_t resident;
3936e79b375SSwarup Laxman Kotiaklapudi p = parse_u64(p, end, &resident);
3946e79b375SSwarup Laxman Kotiaklapudi assert(p != end && *p++ == ' ');
3956e79b375SSwarup Laxman Kotiaklapudi
3966e79b375SSwarup Laxman Kotiaklapudi uint64_t shared;
3976e79b375SSwarup Laxman Kotiaklapudi p = parse_u64(p, end, &shared);
3986e79b375SSwarup Laxman Kotiaklapudi assert(p != end && *p++ == ' ');
3996e79b375SSwarup Laxman Kotiaklapudi
4006e79b375SSwarup Laxman Kotiaklapudi uint64_t text;
4016e79b375SSwarup Laxman Kotiaklapudi p = parse_u64(p, end, &text);
4026e79b375SSwarup Laxman Kotiaklapudi assert(p != end && *p++ == ' ');
4036e79b375SSwarup Laxman Kotiaklapudi
4046e79b375SSwarup Laxman Kotiaklapudi assert(p != end && *p++ == '0');
4056e79b375SSwarup Laxman Kotiaklapudi assert(p != end && *p++ == ' ');
4066e79b375SSwarup Laxman Kotiaklapudi
4076e79b375SSwarup Laxman Kotiaklapudi /* data */
4086e79b375SSwarup Laxman Kotiaklapudi assert(p != end && *p++ == '0');
4096e79b375SSwarup Laxman Kotiaklapudi assert(p != end && *p++ == ' ');
4106e79b375SSwarup Laxman Kotiaklapudi
4116e79b375SSwarup Laxman Kotiaklapudi assert(p != end && *p++ == '0');
4126e79b375SSwarup Laxman Kotiaklapudi assert(p != end && *p++ == '\n');
4136e79b375SSwarup Laxman Kotiaklapudi
4146e79b375SSwarup Laxman Kotiaklapudi assert(p == end);
4156e79b375SSwarup Laxman Kotiaklapudi
4166e79b375SSwarup Laxman Kotiaklapudi /*
4176e79b375SSwarup Laxman Kotiaklapudi * "text" is "mm->end_code - mm->start_code" at execve(2) time.
4186e79b375SSwarup Laxman Kotiaklapudi * munmap() doesn't change it. It can be anything (just link
4196e79b375SSwarup Laxman Kotiaklapudi * statically). It can't be 0 because executing to this point
4206e79b375SSwarup Laxman Kotiaklapudi * implies at least 1 page of code.
4216e79b375SSwarup Laxman Kotiaklapudi */
4226e79b375SSwarup Laxman Kotiaklapudi assert(text > 0);
4236e79b375SSwarup Laxman Kotiaklapudi
4246e79b375SSwarup Laxman Kotiaklapudi /*
4256e79b375SSwarup Laxman Kotiaklapudi * These two are always equal. Always 0 for statically linked
4266e79b375SSwarup Laxman Kotiaklapudi * executables and sometimes 0 for dynamically linked executables.
4276e79b375SSwarup Laxman Kotiaklapudi * There is no way to tell one from another without parsing ELF
4286e79b375SSwarup Laxman Kotiaklapudi * which is too much for this test.
4296e79b375SSwarup Laxman Kotiaklapudi */
4306e79b375SSwarup Laxman Kotiaklapudi assert(resident == shared);
4316e79b375SSwarup Laxman Kotiaklapudi
4326e79b375SSwarup Laxman Kotiaklapudi return EXIT_SUCCESS;
4336e79b375SSwarup Laxman Kotiaklapudi }
4346e79b375SSwarup Laxman Kotiaklapudi
main(void)4355bc73bb3SAlexey Dobriyan int main(void)
4365bc73bb3SAlexey Dobriyan {
4375bc73bb3SAlexey Dobriyan int rv = EXIT_SUCCESS;
4385bc73bb3SAlexey Dobriyan
4394356b11eSAlexey Dobriyan #ifdef TEST_VSYSCALL
4405bc73bb3SAlexey Dobriyan vsyscall();
4414356b11eSAlexey Dobriyan #endif
4425bc73bb3SAlexey Dobriyan
4435bc73bb3SAlexey Dobriyan switch (g_vsyscall) {
4445bc73bb3SAlexey Dobriyan case 0:
4455bc73bb3SAlexey Dobriyan g_proc_pid_maps_vsyscall = proc_pid_maps_vsyscall_0;
4465bc73bb3SAlexey Dobriyan g_proc_pid_smaps_vsyscall = proc_pid_smaps_vsyscall_0;
4475bc73bb3SAlexey Dobriyan break;
4485bc73bb3SAlexey Dobriyan case 1:
4495bc73bb3SAlexey Dobriyan g_proc_pid_maps_vsyscall = proc_pid_maps_vsyscall_1;
4505bc73bb3SAlexey Dobriyan g_proc_pid_smaps_vsyscall = proc_pid_smaps_vsyscall_1;
4515bc73bb3SAlexey Dobriyan break;
4525bc73bb3SAlexey Dobriyan case 2:
4535bc73bb3SAlexey Dobriyan g_proc_pid_maps_vsyscall = proc_pid_maps_vsyscall_2;
4545bc73bb3SAlexey Dobriyan g_proc_pid_smaps_vsyscall = proc_pid_smaps_vsyscall_2;
4555bc73bb3SAlexey Dobriyan break;
4565bc73bb3SAlexey Dobriyan default:
4575bc73bb3SAlexey Dobriyan abort();
4585bc73bb3SAlexey Dobriyan }
4595bc73bb3SAlexey Dobriyan
460*bf5add39SSwarup Laxman Kotiaklapudi g_protection_key_support = protection_key_support();
461*bf5add39SSwarup Laxman Kotiaklapudi
4625bc73bb3SAlexey Dobriyan pid_t pid = fork();
4635bc73bb3SAlexey Dobriyan if (pid == -1) {
4645bc73bb3SAlexey Dobriyan perror("fork");
4655bc73bb3SAlexey Dobriyan return EXIT_FAILURE;
4665bc73bb3SAlexey Dobriyan } else if (pid == 0) {
4675bc73bb3SAlexey Dobriyan rv = ptrace(PTRACE_TRACEME, 0, NULL, NULL);
4685bc73bb3SAlexey Dobriyan if (rv != 0) {
4695bc73bb3SAlexey Dobriyan if (errno == EPERM) {
4705bc73bb3SAlexey Dobriyan fprintf(stderr,
4715bc73bb3SAlexey Dobriyan "Did you know? ptrace(PTRACE_TRACEME) doesn't work under strace.\n"
4725bc73bb3SAlexey Dobriyan );
4735bc73bb3SAlexey Dobriyan kill(getppid(), SIGTERM);
4745bc73bb3SAlexey Dobriyan return EXIT_FAILURE;
4755bc73bb3SAlexey Dobriyan }
4765bc73bb3SAlexey Dobriyan perror("ptrace PTRACE_TRACEME");
4775bc73bb3SAlexey Dobriyan return EXIT_FAILURE;
4785bc73bb3SAlexey Dobriyan }
4795bc73bb3SAlexey Dobriyan
4805bc73bb3SAlexey Dobriyan /*
4815bc73bb3SAlexey Dobriyan * Hide "segfault at ..." messages. Signal handler won't run.
4825bc73bb3SAlexey Dobriyan */
4835bc73bb3SAlexey Dobriyan struct sigaction act = {};
4845bc73bb3SAlexey Dobriyan act.sa_flags = SA_SIGINFO;
4855bc73bb3SAlexey Dobriyan act.sa_sigaction = sigaction_SIGSEGV;
4865bc73bb3SAlexey Dobriyan sigaction(SIGSEGV, &act, NULL);
4875bc73bb3SAlexey Dobriyan
4885bc73bb3SAlexey Dobriyan #ifdef __amd64__
4895bc73bb3SAlexey Dobriyan munmap(NULL, ((size_t)1 << 47) - 4096);
4904356b11eSAlexey Dobriyan #elif defined __i386__
4914356b11eSAlexey Dobriyan {
4924356b11eSAlexey Dobriyan size_t len;
4934356b11eSAlexey Dobriyan
4944356b11eSAlexey Dobriyan for (len = -4096;; len -= 4096) {
4954356b11eSAlexey Dobriyan munmap(NULL, len);
4964356b11eSAlexey Dobriyan }
4974356b11eSAlexey Dobriyan }
4985bc73bb3SAlexey Dobriyan #else
4995bc73bb3SAlexey Dobriyan #error "implement 'unmap everything'"
5005bc73bb3SAlexey Dobriyan #endif
5015bc73bb3SAlexey Dobriyan return EXIT_FAILURE;
5025bc73bb3SAlexey Dobriyan } else {
5035bc73bb3SAlexey Dobriyan /*
5045bc73bb3SAlexey Dobriyan * TODO find reliable way to signal parent that munmap(2) completed.
5055bc73bb3SAlexey Dobriyan * Child can't do it directly because it effectively doesn't exist
5065bc73bb3SAlexey Dobriyan * anymore. Looking at child's VM files isn't 100% reliable either:
5075bc73bb3SAlexey Dobriyan * due to a bug they may not become empty or empty-like.
5085bc73bb3SAlexey Dobriyan */
5095bc73bb3SAlexey Dobriyan sleep(1);
5105bc73bb3SAlexey Dobriyan
5115bc73bb3SAlexey Dobriyan if (rv == EXIT_SUCCESS) {
5125bc73bb3SAlexey Dobriyan rv = test_proc_pid_maps(pid);
5135bc73bb3SAlexey Dobriyan }
5145bc73bb3SAlexey Dobriyan if (rv == EXIT_SUCCESS) {
5155bc73bb3SAlexey Dobriyan rv = test_proc_pid_numa_maps(pid);
5165bc73bb3SAlexey Dobriyan }
5175bc73bb3SAlexey Dobriyan if (rv == EXIT_SUCCESS) {
5185bc73bb3SAlexey Dobriyan rv = test_proc_pid_smaps(pid);
5195bc73bb3SAlexey Dobriyan }
5205bc73bb3SAlexey Dobriyan if (rv == EXIT_SUCCESS) {
5215bc73bb3SAlexey Dobriyan rv = test_proc_pid_smaps_rollup(pid);
5225bc73bb3SAlexey Dobriyan }
5236e79b375SSwarup Laxman Kotiaklapudi if (rv == EXIT_SUCCESS) {
5246e79b375SSwarup Laxman Kotiaklapudi rv = test_proc_pid_statm(pid);
5256e79b375SSwarup Laxman Kotiaklapudi }
5265bc73bb3SAlexey Dobriyan
5275bc73bb3SAlexey Dobriyan /* Cut the rope. */
5285bc73bb3SAlexey Dobriyan int wstatus;
5295bc73bb3SAlexey Dobriyan waitpid(pid, &wstatus, 0);
5305bc73bb3SAlexey Dobriyan assert(WIFSTOPPED(wstatus));
5315bc73bb3SAlexey Dobriyan assert(WSTOPSIG(wstatus) == SIGSEGV);
5325bc73bb3SAlexey Dobriyan }
5335bc73bb3SAlexey Dobriyan
5345bc73bb3SAlexey Dobriyan return rv;
5355bc73bb3SAlexey Dobriyan }
536f58a2dd8SAlexey Dobriyan #else
main(void)537f58a2dd8SAlexey Dobriyan int main(void)
538f58a2dd8SAlexey Dobriyan {
539f58a2dd8SAlexey Dobriyan return 4;
540f58a2dd8SAlexey Dobriyan }
541f58a2dd8SAlexey Dobriyan #endif
542