1e483b020SAlexey Dobriyan /* 2e483b020SAlexey Dobriyan * Copyright (c) 2019 Alexey Dobriyan <adobriyan@gmail.com> 3e483b020SAlexey Dobriyan * 4e483b020SAlexey Dobriyan * Permission to use, copy, modify, and distribute this software for any 5e483b020SAlexey Dobriyan * purpose with or without fee is hereby granted, provided that the above 6e483b020SAlexey Dobriyan * copyright notice and this permission notice appear in all copies. 7e483b020SAlexey Dobriyan * 8e483b020SAlexey Dobriyan * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9e483b020SAlexey Dobriyan * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10e483b020SAlexey Dobriyan * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11e483b020SAlexey Dobriyan * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12e483b020SAlexey Dobriyan * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13e483b020SAlexey Dobriyan * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14e483b020SAlexey Dobriyan * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15e483b020SAlexey Dobriyan */ 16e483b020SAlexey Dobriyan /* 17e483b020SAlexey Dobriyan * Fork and exec tiny 1 page executable which precisely controls its VM. 18e483b020SAlexey Dobriyan * Test /proc/$PID/maps 19e483b020SAlexey Dobriyan * Test /proc/$PID/smaps 20e483b020SAlexey Dobriyan * Test /proc/$PID/smaps_rollup 21e483b020SAlexey Dobriyan * Test /proc/$PID/statm 22e483b020SAlexey Dobriyan * 23e483b020SAlexey Dobriyan * FIXME require CONFIG_TMPFS which can be disabled 24e483b020SAlexey Dobriyan * FIXME test other values from "smaps" 25e483b020SAlexey Dobriyan * FIXME support other archs 26e483b020SAlexey Dobriyan */ 27e483b020SAlexey Dobriyan #undef NDEBUG 28e483b020SAlexey Dobriyan #include <assert.h> 29e483b020SAlexey Dobriyan #include <errno.h> 30e483b020SAlexey Dobriyan #include <sched.h> 31e483b020SAlexey Dobriyan #include <signal.h> 3217415606SAlexey Dobriyan #include <stdbool.h> 33e483b020SAlexey Dobriyan #include <stdint.h> 34e483b020SAlexey Dobriyan #include <stdio.h> 35e483b020SAlexey Dobriyan #include <string.h> 36e483b020SAlexey Dobriyan #include <stdlib.h> 37e483b020SAlexey Dobriyan #include <sys/mount.h> 38e483b020SAlexey Dobriyan #include <sys/types.h> 39e483b020SAlexey Dobriyan #include <sys/stat.h> 4017415606SAlexey Dobriyan #include <sys/wait.h> 41e483b020SAlexey Dobriyan #include <fcntl.h> 42e483b020SAlexey Dobriyan #include <unistd.h> 43e483b020SAlexey Dobriyan #include <sys/syscall.h> 44e483b020SAlexey Dobriyan #include <sys/uio.h> 45e483b020SAlexey Dobriyan #include <linux/kdev_t.h> 4617415606SAlexey Dobriyan #include <sys/time.h> 4717415606SAlexey Dobriyan #include <sys/resource.h> 48e483b020SAlexey Dobriyan 49e483b020SAlexey Dobriyan static inline long sys_execveat(int dirfd, const char *pathname, char **argv, char **envp, int flags) 50e483b020SAlexey Dobriyan { 51e483b020SAlexey Dobriyan return syscall(SYS_execveat, dirfd, pathname, argv, envp, flags); 52e483b020SAlexey Dobriyan } 53e483b020SAlexey Dobriyan 54e483b020SAlexey Dobriyan static void make_private_tmp(void) 55e483b020SAlexey Dobriyan { 56e483b020SAlexey Dobriyan if (unshare(CLONE_NEWNS) == -1) { 57e483b020SAlexey Dobriyan if (errno == ENOSYS || errno == EPERM) { 58e483b020SAlexey Dobriyan exit(4); 59e483b020SAlexey Dobriyan } 60e483b020SAlexey Dobriyan exit(1); 61e483b020SAlexey Dobriyan } 62e483b020SAlexey Dobriyan if (mount(NULL, "/", NULL, MS_PRIVATE|MS_REC, NULL) == -1) { 63e483b020SAlexey Dobriyan exit(1); 64e483b020SAlexey Dobriyan } 65e483b020SAlexey Dobriyan if (mount(NULL, "/tmp", "tmpfs", 0, NULL) == -1) { 66e483b020SAlexey Dobriyan exit(1); 67e483b020SAlexey Dobriyan } 68e483b020SAlexey Dobriyan } 69e483b020SAlexey Dobriyan 70e483b020SAlexey Dobriyan static pid_t pid = -1; 71e483b020SAlexey Dobriyan static void ate(void) 72e483b020SAlexey Dobriyan { 73e483b020SAlexey Dobriyan if (pid > 0) { 74e483b020SAlexey Dobriyan kill(pid, SIGTERM); 75e483b020SAlexey Dobriyan } 76e483b020SAlexey Dobriyan } 77e483b020SAlexey Dobriyan 78e483b020SAlexey Dobriyan struct elf64_hdr { 79e483b020SAlexey Dobriyan uint8_t e_ident[16]; 80e483b020SAlexey Dobriyan uint16_t e_type; 81e483b020SAlexey Dobriyan uint16_t e_machine; 82e483b020SAlexey Dobriyan uint32_t e_version; 83e483b020SAlexey Dobriyan uint64_t e_entry; 84e483b020SAlexey Dobriyan uint64_t e_phoff; 85e483b020SAlexey Dobriyan uint64_t e_shoff; 86e483b020SAlexey Dobriyan uint32_t e_flags; 87e483b020SAlexey Dobriyan uint16_t e_ehsize; 88e483b020SAlexey Dobriyan uint16_t e_phentsize; 89e483b020SAlexey Dobriyan uint16_t e_phnum; 90e483b020SAlexey Dobriyan uint16_t e_shentsize; 91e483b020SAlexey Dobriyan uint16_t e_shnum; 92e483b020SAlexey Dobriyan uint16_t e_shstrndx; 93e483b020SAlexey Dobriyan }; 94e483b020SAlexey Dobriyan 95e483b020SAlexey Dobriyan struct elf64_phdr { 96e483b020SAlexey Dobriyan uint32_t p_type; 97e483b020SAlexey Dobriyan uint32_t p_flags; 98e483b020SAlexey Dobriyan uint64_t p_offset; 99e483b020SAlexey Dobriyan uint64_t p_vaddr; 100e483b020SAlexey Dobriyan uint64_t p_paddr; 101e483b020SAlexey Dobriyan uint64_t p_filesz; 102e483b020SAlexey Dobriyan uint64_t p_memsz; 103e483b020SAlexey Dobriyan uint64_t p_align; 104e483b020SAlexey Dobriyan }; 105e483b020SAlexey Dobriyan 106e483b020SAlexey Dobriyan #ifdef __x86_64__ 107e483b020SAlexey Dobriyan #define PAGE_SIZE 4096 108e483b020SAlexey Dobriyan #define VADDR (1UL << 32) 109e483b020SAlexey Dobriyan #define MAPS_OFFSET 73 110e483b020SAlexey Dobriyan 111e483b020SAlexey Dobriyan #define syscall 0x0f, 0x05 112e483b020SAlexey Dobriyan #define mov_rdi(x) \ 113e483b020SAlexey Dobriyan 0x48, 0xbf, \ 114e483b020SAlexey Dobriyan (x)&0xff, ((x)>>8)&0xff, ((x)>>16)&0xff, ((x)>>24)&0xff, \ 115e483b020SAlexey Dobriyan ((x)>>32)&0xff, ((x)>>40)&0xff, ((x)>>48)&0xff, ((x)>>56)&0xff 116e483b020SAlexey Dobriyan 117e483b020SAlexey Dobriyan #define mov_rsi(x) \ 118e483b020SAlexey Dobriyan 0x48, 0xbe, \ 119e483b020SAlexey Dobriyan (x)&0xff, ((x)>>8)&0xff, ((x)>>16)&0xff, ((x)>>24)&0xff, \ 120e483b020SAlexey Dobriyan ((x)>>32)&0xff, ((x)>>40)&0xff, ((x)>>48)&0xff, ((x)>>56)&0xff 121e483b020SAlexey Dobriyan 122e483b020SAlexey Dobriyan #define mov_eax(x) \ 123e483b020SAlexey Dobriyan 0xb8, (x)&0xff, ((x)>>8)&0xff, ((x)>>16)&0xff, ((x)>>24)&0xff 124e483b020SAlexey Dobriyan 125e483b020SAlexey Dobriyan static const uint8_t payload[] = { 126e483b020SAlexey Dobriyan /* Casually unmap stack, vDSO and everything else. */ 127e483b020SAlexey Dobriyan /* munmap */ 128e483b020SAlexey Dobriyan mov_rdi(VADDR + 4096), 129e483b020SAlexey Dobriyan mov_rsi((1ULL << 47) - 4096 - VADDR - 4096), 130e483b020SAlexey Dobriyan mov_eax(11), 131e483b020SAlexey Dobriyan syscall, 132e483b020SAlexey Dobriyan 133e483b020SAlexey Dobriyan /* Ping parent. */ 134e483b020SAlexey Dobriyan /* write(0, &c, 1); */ 135e483b020SAlexey Dobriyan 0x31, 0xff, /* xor edi, edi */ 136e483b020SAlexey Dobriyan 0x48, 0x8d, 0x35, 0x00, 0x00, 0x00, 0x00, /* lea rsi, [rip] */ 137e483b020SAlexey Dobriyan 0xba, 0x01, 0x00, 0x00, 0x00, /* mov edx, 1 */ 138e483b020SAlexey Dobriyan mov_eax(1), 139e483b020SAlexey Dobriyan syscall, 140e483b020SAlexey Dobriyan 141e483b020SAlexey Dobriyan /* 1: pause(); */ 142e483b020SAlexey Dobriyan mov_eax(34), 143e483b020SAlexey Dobriyan syscall, 144e483b020SAlexey Dobriyan 145e483b020SAlexey Dobriyan 0xeb, 0xf7, /* jmp 1b */ 146e483b020SAlexey Dobriyan }; 147e483b020SAlexey Dobriyan 148e483b020SAlexey Dobriyan static int make_exe(const uint8_t *payload, size_t len) 149e483b020SAlexey Dobriyan { 150e483b020SAlexey Dobriyan struct elf64_hdr h; 151e483b020SAlexey Dobriyan struct elf64_phdr ph; 152e483b020SAlexey Dobriyan 153e483b020SAlexey Dobriyan struct iovec iov[3] = { 154e483b020SAlexey Dobriyan {&h, sizeof(struct elf64_hdr)}, 155e483b020SAlexey Dobriyan {&ph, sizeof(struct elf64_phdr)}, 156e483b020SAlexey Dobriyan {(void *)payload, len}, 157e483b020SAlexey Dobriyan }; 158e483b020SAlexey Dobriyan int fd, fd1; 159e483b020SAlexey Dobriyan char buf[64]; 160e483b020SAlexey Dobriyan 161e483b020SAlexey Dobriyan memset(&h, 0, sizeof(h)); 162e483b020SAlexey Dobriyan h.e_ident[0] = 0x7f; 163e483b020SAlexey Dobriyan h.e_ident[1] = 'E'; 164e483b020SAlexey Dobriyan h.e_ident[2] = 'L'; 165e483b020SAlexey Dobriyan h.e_ident[3] = 'F'; 166e483b020SAlexey Dobriyan h.e_ident[4] = 2; 167e483b020SAlexey Dobriyan h.e_ident[5] = 1; 168e483b020SAlexey Dobriyan h.e_ident[6] = 1; 169e483b020SAlexey Dobriyan h.e_ident[7] = 0; 170e483b020SAlexey Dobriyan h.e_type = 2; 171e483b020SAlexey Dobriyan h.e_machine = 0x3e; 172e483b020SAlexey Dobriyan h.e_version = 1; 173e483b020SAlexey Dobriyan h.e_entry = VADDR + sizeof(struct elf64_hdr) + sizeof(struct elf64_phdr); 174e483b020SAlexey Dobriyan h.e_phoff = sizeof(struct elf64_hdr); 175e483b020SAlexey Dobriyan h.e_shoff = 0; 176e483b020SAlexey Dobriyan h.e_flags = 0; 177e483b020SAlexey Dobriyan h.e_ehsize = sizeof(struct elf64_hdr); 178e483b020SAlexey Dobriyan h.e_phentsize = sizeof(struct elf64_phdr); 179e483b020SAlexey Dobriyan h.e_phnum = 1; 180e483b020SAlexey Dobriyan h.e_shentsize = 0; 181e483b020SAlexey Dobriyan h.e_shnum = 0; 182e483b020SAlexey Dobriyan h.e_shstrndx = 0; 183e483b020SAlexey Dobriyan 184e483b020SAlexey Dobriyan memset(&ph, 0, sizeof(ph)); 185e483b020SAlexey Dobriyan ph.p_type = 1; 186e483b020SAlexey Dobriyan ph.p_flags = (1<<2)|1; 187e483b020SAlexey Dobriyan ph.p_offset = 0; 188e483b020SAlexey Dobriyan ph.p_vaddr = VADDR; 189e483b020SAlexey Dobriyan ph.p_paddr = 0; 190*68545aa1SAlexey Dobriyan ph.p_filesz = sizeof(struct elf64_hdr) + sizeof(struct elf64_phdr) + len; 191*68545aa1SAlexey Dobriyan ph.p_memsz = sizeof(struct elf64_hdr) + sizeof(struct elf64_phdr) + len; 192e483b020SAlexey Dobriyan ph.p_align = 4096; 193e483b020SAlexey Dobriyan 194e483b020SAlexey Dobriyan fd = openat(AT_FDCWD, "/tmp", O_WRONLY|O_EXCL|O_TMPFILE, 0700); 195e483b020SAlexey Dobriyan if (fd == -1) { 196e483b020SAlexey Dobriyan exit(1); 197e483b020SAlexey Dobriyan } 198e483b020SAlexey Dobriyan 199e483b020SAlexey Dobriyan if (writev(fd, iov, 3) != sizeof(struct elf64_hdr) + sizeof(struct elf64_phdr) + len) { 200e483b020SAlexey Dobriyan exit(1); 201e483b020SAlexey Dobriyan } 202e483b020SAlexey Dobriyan 203e483b020SAlexey Dobriyan /* Avoid ETXTBSY on exec. */ 204e483b020SAlexey Dobriyan snprintf(buf, sizeof(buf), "/proc/self/fd/%u", fd); 205e483b020SAlexey Dobriyan fd1 = open(buf, O_RDONLY|O_CLOEXEC); 206e483b020SAlexey Dobriyan close(fd); 207e483b020SAlexey Dobriyan 208e483b020SAlexey Dobriyan return fd1; 209e483b020SAlexey Dobriyan } 210e483b020SAlexey Dobriyan #endif 211e483b020SAlexey Dobriyan 21217415606SAlexey Dobriyan static bool g_vsyscall = false; 21317415606SAlexey Dobriyan 21417415606SAlexey Dobriyan static const char str_vsyscall[] = 21517415606SAlexey Dobriyan "ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]\n"; 21617415606SAlexey Dobriyan 217e483b020SAlexey Dobriyan #ifdef __x86_64__ 21817415606SAlexey Dobriyan /* 21917415606SAlexey Dobriyan * vsyscall page can't be unmapped, probe it with memory load. 22017415606SAlexey Dobriyan */ 22117415606SAlexey Dobriyan static void vsyscall(void) 22217415606SAlexey Dobriyan { 22317415606SAlexey Dobriyan pid_t pid; 22417415606SAlexey Dobriyan int wstatus; 22517415606SAlexey Dobriyan 22617415606SAlexey Dobriyan pid = fork(); 22717415606SAlexey Dobriyan if (pid < 0) { 22817415606SAlexey Dobriyan fprintf(stderr, "fork, errno %d\n", errno); 22917415606SAlexey Dobriyan exit(1); 23017415606SAlexey Dobriyan } 23117415606SAlexey Dobriyan if (pid == 0) { 23217415606SAlexey Dobriyan struct rlimit rlim = {0, 0}; 23317415606SAlexey Dobriyan (void)setrlimit(RLIMIT_CORE, &rlim); 23417415606SAlexey Dobriyan *(volatile int *)0xffffffffff600000UL; 23517415606SAlexey Dobriyan exit(0); 23617415606SAlexey Dobriyan } 23717415606SAlexey Dobriyan wait(&wstatus); 23817415606SAlexey Dobriyan if (WIFEXITED(wstatus)) { 23917415606SAlexey Dobriyan g_vsyscall = true; 24017415606SAlexey Dobriyan } 24117415606SAlexey Dobriyan } 24217415606SAlexey Dobriyan 243e483b020SAlexey Dobriyan int main(void) 244e483b020SAlexey Dobriyan { 245e483b020SAlexey Dobriyan int pipefd[2]; 246e483b020SAlexey Dobriyan int exec_fd; 247e483b020SAlexey Dobriyan 24817415606SAlexey Dobriyan vsyscall(); 24917415606SAlexey Dobriyan 250e483b020SAlexey Dobriyan atexit(ate); 251e483b020SAlexey Dobriyan 252e483b020SAlexey Dobriyan make_private_tmp(); 253e483b020SAlexey Dobriyan 254e483b020SAlexey Dobriyan /* Reserve fd 0 for 1-byte pipe ping from child. */ 255e483b020SAlexey Dobriyan close(0); 256e483b020SAlexey Dobriyan if (open("/", O_RDONLY|O_DIRECTORY|O_PATH) != 0) { 257e483b020SAlexey Dobriyan return 1; 258e483b020SAlexey Dobriyan } 259e483b020SAlexey Dobriyan 260e483b020SAlexey Dobriyan exec_fd = make_exe(payload, sizeof(payload)); 261e483b020SAlexey Dobriyan 262e483b020SAlexey Dobriyan if (pipe(pipefd) == -1) { 263e483b020SAlexey Dobriyan return 1; 264e483b020SAlexey Dobriyan } 265e483b020SAlexey Dobriyan if (dup2(pipefd[1], 0) != 0) { 266e483b020SAlexey Dobriyan return 1; 267e483b020SAlexey Dobriyan } 268e483b020SAlexey Dobriyan 269e483b020SAlexey Dobriyan pid = fork(); 270e483b020SAlexey Dobriyan if (pid == -1) { 271e483b020SAlexey Dobriyan return 1; 272e483b020SAlexey Dobriyan } 273e483b020SAlexey Dobriyan if (pid == 0) { 274e483b020SAlexey Dobriyan sys_execveat(exec_fd, "", NULL, NULL, AT_EMPTY_PATH); 275e483b020SAlexey Dobriyan return 1; 276e483b020SAlexey Dobriyan } 277e483b020SAlexey Dobriyan 278e483b020SAlexey Dobriyan char _; 279e483b020SAlexey Dobriyan if (read(pipefd[0], &_, 1) != 1) { 280e483b020SAlexey Dobriyan return 1; 281e483b020SAlexey Dobriyan } 282e483b020SAlexey Dobriyan 283e483b020SAlexey Dobriyan struct stat st; 284e483b020SAlexey Dobriyan if (fstat(exec_fd, &st) == -1) { 285e483b020SAlexey Dobriyan return 1; 286e483b020SAlexey Dobriyan } 287e483b020SAlexey Dobriyan 288e483b020SAlexey Dobriyan /* Generate "head -n1 /proc/$PID/maps" */ 289e483b020SAlexey Dobriyan char buf0[256]; 290e483b020SAlexey Dobriyan memset(buf0, ' ', sizeof(buf0)); 291e483b020SAlexey Dobriyan int len = snprintf(buf0, sizeof(buf0), 292e483b020SAlexey Dobriyan "%08lx-%08lx r-xp 00000000 %02lx:%02lx %llu", 293e483b020SAlexey Dobriyan VADDR, VADDR + PAGE_SIZE, 294e483b020SAlexey Dobriyan MAJOR(st.st_dev), MINOR(st.st_dev), 295e483b020SAlexey Dobriyan (unsigned long long)st.st_ino); 296e483b020SAlexey Dobriyan buf0[len] = ' '; 297e483b020SAlexey Dobriyan snprintf(buf0 + MAPS_OFFSET, sizeof(buf0) - MAPS_OFFSET, 298e483b020SAlexey Dobriyan "/tmp/#%llu (deleted)\n", (unsigned long long)st.st_ino); 299e483b020SAlexey Dobriyan 300e483b020SAlexey Dobriyan /* Test /proc/$PID/maps */ 301e483b020SAlexey Dobriyan { 30217415606SAlexey Dobriyan const size_t len = strlen(buf0) + (g_vsyscall ? strlen(str_vsyscall) : 0); 303e483b020SAlexey Dobriyan char buf[256]; 304e483b020SAlexey Dobriyan ssize_t rv; 305e483b020SAlexey Dobriyan int fd; 306e483b020SAlexey Dobriyan 307e483b020SAlexey Dobriyan snprintf(buf, sizeof(buf), "/proc/%u/maps", pid); 308e483b020SAlexey Dobriyan fd = open(buf, O_RDONLY); 309e483b020SAlexey Dobriyan if (fd == -1) { 310e483b020SAlexey Dobriyan return 1; 311e483b020SAlexey Dobriyan } 312e483b020SAlexey Dobriyan rv = read(fd, buf, sizeof(buf)); 31317415606SAlexey Dobriyan assert(rv == len); 314e483b020SAlexey Dobriyan assert(memcmp(buf, buf0, strlen(buf0)) == 0); 31517415606SAlexey Dobriyan if (g_vsyscall) { 31617415606SAlexey Dobriyan assert(memcmp(buf + strlen(buf0), str_vsyscall, strlen(str_vsyscall)) == 0); 31717415606SAlexey Dobriyan } 318e483b020SAlexey Dobriyan } 319e483b020SAlexey Dobriyan 320e483b020SAlexey Dobriyan /* Test /proc/$PID/smaps */ 321e483b020SAlexey Dobriyan { 32217415606SAlexey Dobriyan char buf[4096]; 323e483b020SAlexey Dobriyan ssize_t rv; 324e483b020SAlexey Dobriyan int fd; 325e483b020SAlexey Dobriyan 326e483b020SAlexey Dobriyan snprintf(buf, sizeof(buf), "/proc/%u/smaps", pid); 327e483b020SAlexey Dobriyan fd = open(buf, O_RDONLY); 328e483b020SAlexey Dobriyan if (fd == -1) { 329e483b020SAlexey Dobriyan return 1; 330e483b020SAlexey Dobriyan } 331e483b020SAlexey Dobriyan rv = read(fd, buf, sizeof(buf)); 332e483b020SAlexey Dobriyan assert(0 <= rv && rv <= sizeof(buf)); 333e483b020SAlexey Dobriyan 334e483b020SAlexey Dobriyan assert(rv >= strlen(buf0)); 335e483b020SAlexey Dobriyan assert(memcmp(buf, buf0, strlen(buf0)) == 0); 336e483b020SAlexey Dobriyan 337e483b020SAlexey Dobriyan #define RSS1 "Rss: 4 kB\n" 338e483b020SAlexey Dobriyan #define RSS2 "Rss: 0 kB\n" 339e483b020SAlexey Dobriyan #define PSS1 "Pss: 4 kB\n" 340e483b020SAlexey Dobriyan #define PSS2 "Pss: 0 kB\n" 341e483b020SAlexey Dobriyan assert(memmem(buf, rv, RSS1, strlen(RSS1)) || 342e483b020SAlexey Dobriyan memmem(buf, rv, RSS2, strlen(RSS2))); 343e483b020SAlexey Dobriyan assert(memmem(buf, rv, PSS1, strlen(PSS1)) || 344e483b020SAlexey Dobriyan memmem(buf, rv, PSS2, strlen(PSS2))); 345e483b020SAlexey Dobriyan 346e483b020SAlexey Dobriyan static const char *S[] = { 347e483b020SAlexey Dobriyan "Size: 4 kB\n", 348e483b020SAlexey Dobriyan "KernelPageSize: 4 kB\n", 349e483b020SAlexey Dobriyan "MMUPageSize: 4 kB\n", 350e483b020SAlexey Dobriyan "Anonymous: 0 kB\n", 351e483b020SAlexey Dobriyan "AnonHugePages: 0 kB\n", 352e483b020SAlexey Dobriyan "Shared_Hugetlb: 0 kB\n", 353e483b020SAlexey Dobriyan "Private_Hugetlb: 0 kB\n", 354e483b020SAlexey Dobriyan "Locked: 0 kB\n", 355e483b020SAlexey Dobriyan }; 356e483b020SAlexey Dobriyan int i; 357e483b020SAlexey Dobriyan 358e483b020SAlexey Dobriyan for (i = 0; i < sizeof(S)/sizeof(S[0]); i++) { 359e483b020SAlexey Dobriyan assert(memmem(buf, rv, S[i], strlen(S[i]))); 360e483b020SAlexey Dobriyan } 36117415606SAlexey Dobriyan 36217415606SAlexey Dobriyan if (g_vsyscall) { 36317415606SAlexey Dobriyan assert(memmem(buf, rv, str_vsyscall, strlen(str_vsyscall))); 36417415606SAlexey Dobriyan } 365e483b020SAlexey Dobriyan } 366e483b020SAlexey Dobriyan 367e483b020SAlexey Dobriyan /* Test /proc/$PID/smaps_rollup */ 368e483b020SAlexey Dobriyan { 369e483b020SAlexey Dobriyan char bufr[256]; 370e483b020SAlexey Dobriyan memset(bufr, ' ', sizeof(bufr)); 371e483b020SAlexey Dobriyan len = snprintf(bufr, sizeof(bufr), 372e483b020SAlexey Dobriyan "%08lx-%08lx ---p 00000000 00:00 0", 373e483b020SAlexey Dobriyan VADDR, VADDR + PAGE_SIZE); 374e483b020SAlexey Dobriyan bufr[len] = ' '; 375e483b020SAlexey Dobriyan snprintf(bufr + MAPS_OFFSET, sizeof(bufr) - MAPS_OFFSET, 376e483b020SAlexey Dobriyan "[rollup]\n"); 377e483b020SAlexey Dobriyan 378e483b020SAlexey Dobriyan char buf[1024]; 379e483b020SAlexey Dobriyan ssize_t rv; 380e483b020SAlexey Dobriyan int fd; 381e483b020SAlexey Dobriyan 382e483b020SAlexey Dobriyan snprintf(buf, sizeof(buf), "/proc/%u/smaps_rollup", pid); 383e483b020SAlexey Dobriyan fd = open(buf, O_RDONLY); 384e483b020SAlexey Dobriyan if (fd == -1) { 385e483b020SAlexey Dobriyan return 1; 386e483b020SAlexey Dobriyan } 387e483b020SAlexey Dobriyan rv = read(fd, buf, sizeof(buf)); 388e483b020SAlexey Dobriyan assert(0 <= rv && rv <= sizeof(buf)); 389e483b020SAlexey Dobriyan 390e483b020SAlexey Dobriyan assert(rv >= strlen(bufr)); 391e483b020SAlexey Dobriyan assert(memcmp(buf, bufr, strlen(bufr)) == 0); 392e483b020SAlexey Dobriyan 393e483b020SAlexey Dobriyan assert(memmem(buf, rv, RSS1, strlen(RSS1)) || 394e483b020SAlexey Dobriyan memmem(buf, rv, RSS2, strlen(RSS2))); 395e483b020SAlexey Dobriyan assert(memmem(buf, rv, PSS1, strlen(PSS1)) || 396e483b020SAlexey Dobriyan memmem(buf, rv, PSS2, strlen(PSS2))); 397e483b020SAlexey Dobriyan 398e483b020SAlexey Dobriyan static const char *S[] = { 399e483b020SAlexey Dobriyan "Anonymous: 0 kB\n", 400e483b020SAlexey Dobriyan "AnonHugePages: 0 kB\n", 401e483b020SAlexey Dobriyan "Shared_Hugetlb: 0 kB\n", 402e483b020SAlexey Dobriyan "Private_Hugetlb: 0 kB\n", 403e483b020SAlexey Dobriyan "Locked: 0 kB\n", 404e483b020SAlexey Dobriyan }; 405e483b020SAlexey Dobriyan int i; 406e483b020SAlexey Dobriyan 407e483b020SAlexey Dobriyan for (i = 0; i < sizeof(S)/sizeof(S[0]); i++) { 408e483b020SAlexey Dobriyan assert(memmem(buf, rv, S[i], strlen(S[i]))); 409e483b020SAlexey Dobriyan } 410e483b020SAlexey Dobriyan } 411e483b020SAlexey Dobriyan 412e483b020SAlexey Dobriyan /* Test /proc/$PID/statm */ 413e483b020SAlexey Dobriyan { 414e483b020SAlexey Dobriyan char buf[64]; 415e483b020SAlexey Dobriyan ssize_t rv; 416e483b020SAlexey Dobriyan int fd; 417e483b020SAlexey Dobriyan 418e483b020SAlexey Dobriyan snprintf(buf, sizeof(buf), "/proc/%u/statm", pid); 419e483b020SAlexey Dobriyan fd = open(buf, O_RDONLY); 420e483b020SAlexey Dobriyan if (fd == -1) { 421e483b020SAlexey Dobriyan return 1; 422e483b020SAlexey Dobriyan } 423e483b020SAlexey Dobriyan rv = read(fd, buf, sizeof(buf)); 424e483b020SAlexey Dobriyan assert(rv == 7 * 2); 425e483b020SAlexey Dobriyan 426e483b020SAlexey Dobriyan assert(buf[0] == '1'); /* ->total_vm */ 427e483b020SAlexey Dobriyan assert(buf[1] == ' '); 428e483b020SAlexey Dobriyan assert(buf[2] == '0' || buf[2] == '1'); /* rss */ 429e483b020SAlexey Dobriyan assert(buf[3] == ' '); 430e483b020SAlexey Dobriyan assert(buf[4] == '0' || buf[2] == '1'); /* file rss */ 431e483b020SAlexey Dobriyan assert(buf[5] == ' '); 432e483b020SAlexey Dobriyan assert(buf[6] == '1'); /* ELF executable segments */ 433e483b020SAlexey Dobriyan assert(buf[7] == ' '); 434e483b020SAlexey Dobriyan assert(buf[8] == '0'); 435e483b020SAlexey Dobriyan assert(buf[9] == ' '); 436e483b020SAlexey Dobriyan assert(buf[10] == '0'); /* ->data_vm + ->stack_vm */ 437e483b020SAlexey Dobriyan assert(buf[11] == ' '); 438e483b020SAlexey Dobriyan assert(buf[12] == '0'); 439e483b020SAlexey Dobriyan assert(buf[13] == '\n'); 440e483b020SAlexey Dobriyan } 441e483b020SAlexey Dobriyan 442e483b020SAlexey Dobriyan return 0; 443e483b020SAlexey Dobriyan } 444e483b020SAlexey Dobriyan #else 445e483b020SAlexey Dobriyan int main(void) 446e483b020SAlexey Dobriyan { 447e483b020SAlexey Dobriyan return 4; 448e483b020SAlexey Dobriyan } 449e483b020SAlexey Dobriyan #endif 450