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