xref: /linux/tools/testing/selftests/proc/proc-pid-vm.c (revision 68545aa1cda847c4fdda7e49331807f99f799838)
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