xref: /linux/tools/testing/selftests/proc/proc-maps-race.c (revision 6a45336b9b6fcc1d9ef3c6fe9a43252f9a20084b)
1beb69e81SSuren Baghdasaryan // SPDX-License-Identifier: GPL-2.0-only
2beb69e81SSuren Baghdasaryan /*
3beb69e81SSuren Baghdasaryan  * Copyright 2022 Google LLC.
4beb69e81SSuren Baghdasaryan  * Author: Suren Baghdasaryan <surenb@google.com>
5beb69e81SSuren Baghdasaryan  *
6beb69e81SSuren Baghdasaryan  * Permission to use, copy, modify, and distribute this software for any
7beb69e81SSuren Baghdasaryan  * purpose with or without fee is hereby granted, provided that the above
8beb69e81SSuren Baghdasaryan  * copyright notice and this permission notice appear in all copies.
9beb69e81SSuren Baghdasaryan  *
10beb69e81SSuren Baghdasaryan  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11beb69e81SSuren Baghdasaryan  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12beb69e81SSuren Baghdasaryan  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13beb69e81SSuren Baghdasaryan  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14beb69e81SSuren Baghdasaryan  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15beb69e81SSuren Baghdasaryan  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16beb69e81SSuren Baghdasaryan  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17beb69e81SSuren Baghdasaryan  */
18beb69e81SSuren Baghdasaryan /*
19beb69e81SSuren Baghdasaryan  * Fork a child that concurrently modifies address space while the main
20beb69e81SSuren Baghdasaryan  * process is reading /proc/$PID/maps and verifying the results. Address
21beb69e81SSuren Baghdasaryan  * space modifications include:
22beb69e81SSuren Baghdasaryan  *     VMA splitting and merging
23beb69e81SSuren Baghdasaryan  *
24beb69e81SSuren Baghdasaryan  */
25beb69e81SSuren Baghdasaryan #define _GNU_SOURCE
26beb69e81SSuren Baghdasaryan #include "../kselftest_harness.h"
27beb69e81SSuren Baghdasaryan #include <errno.h>
28beb69e81SSuren Baghdasaryan #include <fcntl.h>
29beb69e81SSuren Baghdasaryan #include <pthread.h>
30beb69e81SSuren Baghdasaryan #include <stdbool.h>
31beb69e81SSuren Baghdasaryan #include <stdio.h>
32beb69e81SSuren Baghdasaryan #include <stdlib.h>
33beb69e81SSuren Baghdasaryan #include <string.h>
34beb69e81SSuren Baghdasaryan #include <unistd.h>
35beb69e81SSuren Baghdasaryan #include <sys/mman.h>
36beb69e81SSuren Baghdasaryan #include <sys/stat.h>
37beb69e81SSuren Baghdasaryan #include <sys/types.h>
38beb69e81SSuren Baghdasaryan #include <sys/wait.h>
39beb69e81SSuren Baghdasaryan 
40beb69e81SSuren Baghdasaryan /* /proc/pid/maps parsing routines */
41beb69e81SSuren Baghdasaryan struct page_content {
42beb69e81SSuren Baghdasaryan 	char *data;
43beb69e81SSuren Baghdasaryan 	ssize_t size;
44beb69e81SSuren Baghdasaryan };
45beb69e81SSuren Baghdasaryan 
46beb69e81SSuren Baghdasaryan #define LINE_MAX_SIZE		256
47beb69e81SSuren Baghdasaryan 
48beb69e81SSuren Baghdasaryan struct line_content {
49beb69e81SSuren Baghdasaryan 	char text[LINE_MAX_SIZE];
50beb69e81SSuren Baghdasaryan 	unsigned long start_addr;
51beb69e81SSuren Baghdasaryan 	unsigned long end_addr;
52beb69e81SSuren Baghdasaryan };
53beb69e81SSuren Baghdasaryan 
54beb69e81SSuren Baghdasaryan enum test_state {
55beb69e81SSuren Baghdasaryan 	INIT,
56beb69e81SSuren Baghdasaryan 	CHILD_READY,
57beb69e81SSuren Baghdasaryan 	PARENT_READY,
58beb69e81SSuren Baghdasaryan 	SETUP_READY,
59beb69e81SSuren Baghdasaryan 	SETUP_MODIFY_MAPS,
60beb69e81SSuren Baghdasaryan 	SETUP_MAPS_MODIFIED,
61beb69e81SSuren Baghdasaryan 	SETUP_RESTORE_MAPS,
62beb69e81SSuren Baghdasaryan 	SETUP_MAPS_RESTORED,
63beb69e81SSuren Baghdasaryan 	TEST_READY,
64beb69e81SSuren Baghdasaryan 	TEST_DONE,
65beb69e81SSuren Baghdasaryan };
66beb69e81SSuren Baghdasaryan 
67beb69e81SSuren Baghdasaryan struct vma_modifier_info;
68beb69e81SSuren Baghdasaryan 
69beb69e81SSuren Baghdasaryan FIXTURE(proc_maps_race)
70beb69e81SSuren Baghdasaryan {
71beb69e81SSuren Baghdasaryan 	struct vma_modifier_info *mod_info;
72beb69e81SSuren Baghdasaryan 	struct page_content page1;
73beb69e81SSuren Baghdasaryan 	struct page_content page2;
74beb69e81SSuren Baghdasaryan 	struct line_content last_line;
75beb69e81SSuren Baghdasaryan 	struct line_content first_line;
76beb69e81SSuren Baghdasaryan 	unsigned long duration_sec;
77beb69e81SSuren Baghdasaryan 	int shared_mem_size;
78beb69e81SSuren Baghdasaryan 	int page_size;
79beb69e81SSuren Baghdasaryan 	int vma_count;
80beb69e81SSuren Baghdasaryan 	int maps_fd;
81beb69e81SSuren Baghdasaryan 	pid_t pid;
82beb69e81SSuren Baghdasaryan };
83beb69e81SSuren Baghdasaryan 
84beb69e81SSuren Baghdasaryan typedef bool (*vma_modifier_op)(FIXTURE_DATA(proc_maps_race) *self);
85beb69e81SSuren Baghdasaryan typedef bool (*vma_mod_result_check_op)(struct line_content *mod_last_line,
86beb69e81SSuren Baghdasaryan 					struct line_content *mod_first_line,
87beb69e81SSuren Baghdasaryan 					struct line_content *restored_last_line,
88beb69e81SSuren Baghdasaryan 					struct line_content *restored_first_line);
89beb69e81SSuren Baghdasaryan 
90beb69e81SSuren Baghdasaryan struct vma_modifier_info {
91beb69e81SSuren Baghdasaryan 	int vma_count;
92beb69e81SSuren Baghdasaryan 	void *addr;
93beb69e81SSuren Baghdasaryan 	int prot;
94beb69e81SSuren Baghdasaryan 	void *next_addr;
95beb69e81SSuren Baghdasaryan 	vma_modifier_op vma_modify;
96beb69e81SSuren Baghdasaryan 	vma_modifier_op vma_restore;
97beb69e81SSuren Baghdasaryan 	vma_mod_result_check_op vma_mod_check;
98beb69e81SSuren Baghdasaryan 	pthread_mutex_t sync_lock;
99beb69e81SSuren Baghdasaryan 	pthread_cond_t sync_cond;
100beb69e81SSuren Baghdasaryan 	enum test_state curr_state;
101beb69e81SSuren Baghdasaryan 	bool exit;
102beb69e81SSuren Baghdasaryan 	void *child_mapped_addr[];
103beb69e81SSuren Baghdasaryan };
104beb69e81SSuren Baghdasaryan 
105beb69e81SSuren Baghdasaryan 
106beb69e81SSuren Baghdasaryan static bool read_two_pages(FIXTURE_DATA(proc_maps_race) *self)
107beb69e81SSuren Baghdasaryan {
108beb69e81SSuren Baghdasaryan 	ssize_t  bytes_read;
109beb69e81SSuren Baghdasaryan 
110beb69e81SSuren Baghdasaryan 	if (lseek(self->maps_fd, 0, SEEK_SET) < 0)
111beb69e81SSuren Baghdasaryan 		return false;
112beb69e81SSuren Baghdasaryan 
113beb69e81SSuren Baghdasaryan 	bytes_read = read(self->maps_fd, self->page1.data, self->page_size);
114beb69e81SSuren Baghdasaryan 	if (bytes_read <= 0)
115beb69e81SSuren Baghdasaryan 		return false;
116beb69e81SSuren Baghdasaryan 
117beb69e81SSuren Baghdasaryan 	self->page1.size = bytes_read;
118beb69e81SSuren Baghdasaryan 
119beb69e81SSuren Baghdasaryan 	bytes_read = read(self->maps_fd, self->page2.data, self->page_size);
120beb69e81SSuren Baghdasaryan 	if (bytes_read <= 0)
121beb69e81SSuren Baghdasaryan 		return false;
122beb69e81SSuren Baghdasaryan 
123beb69e81SSuren Baghdasaryan 	self->page2.size = bytes_read;
124beb69e81SSuren Baghdasaryan 
125beb69e81SSuren Baghdasaryan 	return true;
126beb69e81SSuren Baghdasaryan }
127beb69e81SSuren Baghdasaryan 
128beb69e81SSuren Baghdasaryan static void copy_first_line(struct page_content *page, char *first_line)
129beb69e81SSuren Baghdasaryan {
130beb69e81SSuren Baghdasaryan 	char *pos = strchr(page->data, '\n');
131beb69e81SSuren Baghdasaryan 
132beb69e81SSuren Baghdasaryan 	strncpy(first_line, page->data, pos - page->data);
133beb69e81SSuren Baghdasaryan 	first_line[pos - page->data] = '\0';
134beb69e81SSuren Baghdasaryan }
135beb69e81SSuren Baghdasaryan 
136beb69e81SSuren Baghdasaryan static void copy_last_line(struct page_content *page, char *last_line)
137beb69e81SSuren Baghdasaryan {
138beb69e81SSuren Baghdasaryan 	/* Get the last line in the first page */
139beb69e81SSuren Baghdasaryan 	const char *end = page->data + page->size - 1;
140beb69e81SSuren Baghdasaryan 	/* skip last newline */
141beb69e81SSuren Baghdasaryan 	const char *pos = end - 1;
142beb69e81SSuren Baghdasaryan 
143beb69e81SSuren Baghdasaryan 	/* search previous newline */
144beb69e81SSuren Baghdasaryan 	while (pos[-1] != '\n')
145beb69e81SSuren Baghdasaryan 		pos--;
146beb69e81SSuren Baghdasaryan 	strncpy(last_line, pos, end - pos);
147beb69e81SSuren Baghdasaryan 	last_line[end - pos] = '\0';
148beb69e81SSuren Baghdasaryan }
149beb69e81SSuren Baghdasaryan 
150beb69e81SSuren Baghdasaryan /* Read the last line of the first page and the first line of the second page */
151beb69e81SSuren Baghdasaryan static bool read_boundary_lines(FIXTURE_DATA(proc_maps_race) *self,
152beb69e81SSuren Baghdasaryan 				struct line_content *last_line,
153beb69e81SSuren Baghdasaryan 				struct line_content *first_line)
154beb69e81SSuren Baghdasaryan {
155beb69e81SSuren Baghdasaryan 	if (!read_two_pages(self))
156beb69e81SSuren Baghdasaryan 		return false;
157beb69e81SSuren Baghdasaryan 
158beb69e81SSuren Baghdasaryan 	copy_last_line(&self->page1, last_line->text);
159beb69e81SSuren Baghdasaryan 	copy_first_line(&self->page2, first_line->text);
160beb69e81SSuren Baghdasaryan 
161beb69e81SSuren Baghdasaryan 	return sscanf(last_line->text, "%lx-%lx", &last_line->start_addr,
162beb69e81SSuren Baghdasaryan 		      &last_line->end_addr) == 2 &&
163beb69e81SSuren Baghdasaryan 	       sscanf(first_line->text, "%lx-%lx", &first_line->start_addr,
164beb69e81SSuren Baghdasaryan 		      &first_line->end_addr) == 2;
165beb69e81SSuren Baghdasaryan }
166beb69e81SSuren Baghdasaryan 
167beb69e81SSuren Baghdasaryan /* Thread synchronization routines */
168beb69e81SSuren Baghdasaryan static void wait_for_state(struct vma_modifier_info *mod_info, enum test_state state)
169beb69e81SSuren Baghdasaryan {
170beb69e81SSuren Baghdasaryan 	pthread_mutex_lock(&mod_info->sync_lock);
171beb69e81SSuren Baghdasaryan 	while (mod_info->curr_state != state)
172beb69e81SSuren Baghdasaryan 		pthread_cond_wait(&mod_info->sync_cond, &mod_info->sync_lock);
173beb69e81SSuren Baghdasaryan 	pthread_mutex_unlock(&mod_info->sync_lock);
174beb69e81SSuren Baghdasaryan }
175beb69e81SSuren Baghdasaryan 
176beb69e81SSuren Baghdasaryan static void signal_state(struct vma_modifier_info *mod_info, enum test_state state)
177beb69e81SSuren Baghdasaryan {
178beb69e81SSuren Baghdasaryan 	pthread_mutex_lock(&mod_info->sync_lock);
179beb69e81SSuren Baghdasaryan 	mod_info->curr_state = state;
180beb69e81SSuren Baghdasaryan 	pthread_cond_signal(&mod_info->sync_cond);
181beb69e81SSuren Baghdasaryan 	pthread_mutex_unlock(&mod_info->sync_lock);
182beb69e81SSuren Baghdasaryan }
183beb69e81SSuren Baghdasaryan 
184beb69e81SSuren Baghdasaryan static void stop_vma_modifier(struct vma_modifier_info *mod_info)
185beb69e81SSuren Baghdasaryan {
186beb69e81SSuren Baghdasaryan 	wait_for_state(mod_info, SETUP_READY);
187beb69e81SSuren Baghdasaryan 	mod_info->exit = true;
188beb69e81SSuren Baghdasaryan 	signal_state(mod_info, SETUP_MODIFY_MAPS);
189beb69e81SSuren Baghdasaryan }
190beb69e81SSuren Baghdasaryan 
191beb69e81SSuren Baghdasaryan static bool capture_mod_pattern(FIXTURE_DATA(proc_maps_race) *self,
192beb69e81SSuren Baghdasaryan 				struct line_content *mod_last_line,
193beb69e81SSuren Baghdasaryan 				struct line_content *mod_first_line,
194beb69e81SSuren Baghdasaryan 				struct line_content *restored_last_line,
195beb69e81SSuren Baghdasaryan 				struct line_content *restored_first_line)
196beb69e81SSuren Baghdasaryan {
197beb69e81SSuren Baghdasaryan 	signal_state(self->mod_info, SETUP_MODIFY_MAPS);
198beb69e81SSuren Baghdasaryan 	wait_for_state(self->mod_info, SETUP_MAPS_MODIFIED);
199beb69e81SSuren Baghdasaryan 
200beb69e81SSuren Baghdasaryan 	/* Copy last line of the first page and first line of the last page */
201beb69e81SSuren Baghdasaryan 	if (!read_boundary_lines(self, mod_last_line, mod_first_line))
202beb69e81SSuren Baghdasaryan 		return false;
203beb69e81SSuren Baghdasaryan 
204beb69e81SSuren Baghdasaryan 	signal_state(self->mod_info, SETUP_RESTORE_MAPS);
205beb69e81SSuren Baghdasaryan 	wait_for_state(self->mod_info, SETUP_MAPS_RESTORED);
206beb69e81SSuren Baghdasaryan 
207beb69e81SSuren Baghdasaryan 	/* Copy last line of the first page and first line of the last page */
208beb69e81SSuren Baghdasaryan 	if (!read_boundary_lines(self, restored_last_line, restored_first_line))
209beb69e81SSuren Baghdasaryan 		return false;
210beb69e81SSuren Baghdasaryan 
211beb69e81SSuren Baghdasaryan 	if (!self->mod_info->vma_mod_check(mod_last_line, mod_first_line,
212beb69e81SSuren Baghdasaryan 					   restored_last_line, restored_first_line))
213beb69e81SSuren Baghdasaryan 		return false;
214beb69e81SSuren Baghdasaryan 
215beb69e81SSuren Baghdasaryan 	/*
216beb69e81SSuren Baghdasaryan 	 * The content of these lines after modify+resore should be the same
217beb69e81SSuren Baghdasaryan 	 * as the original.
218beb69e81SSuren Baghdasaryan 	 */
219beb69e81SSuren Baghdasaryan 	return strcmp(restored_last_line->text, self->last_line.text) == 0 &&
220beb69e81SSuren Baghdasaryan 	       strcmp(restored_first_line->text, self->first_line.text) == 0;
221beb69e81SSuren Baghdasaryan }
222beb69e81SSuren Baghdasaryan 
223beb69e81SSuren Baghdasaryan static inline bool split_vma(FIXTURE_DATA(proc_maps_race) *self)
224beb69e81SSuren Baghdasaryan {
225beb69e81SSuren Baghdasaryan 	return mmap(self->mod_info->addr, self->page_size, self->mod_info->prot | PROT_EXEC,
226beb69e81SSuren Baghdasaryan 		    MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0) != MAP_FAILED;
227beb69e81SSuren Baghdasaryan }
228beb69e81SSuren Baghdasaryan 
229beb69e81SSuren Baghdasaryan static inline bool merge_vma(FIXTURE_DATA(proc_maps_race) *self)
230beb69e81SSuren Baghdasaryan {
231beb69e81SSuren Baghdasaryan 	return mmap(self->mod_info->addr, self->page_size, self->mod_info->prot,
232beb69e81SSuren Baghdasaryan 		    MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0) != MAP_FAILED;
233beb69e81SSuren Baghdasaryan }
234beb69e81SSuren Baghdasaryan 
235beb69e81SSuren Baghdasaryan static inline bool check_split_result(struct line_content *mod_last_line,
236beb69e81SSuren Baghdasaryan 				      struct line_content *mod_first_line,
237beb69e81SSuren Baghdasaryan 				      struct line_content *restored_last_line,
238beb69e81SSuren Baghdasaryan 				      struct line_content *restored_first_line)
239beb69e81SSuren Baghdasaryan {
240beb69e81SSuren Baghdasaryan 	/* Make sure vmas at the boundaries are changing */
241beb69e81SSuren Baghdasaryan 	return strcmp(mod_last_line->text, restored_last_line->text) != 0 &&
242beb69e81SSuren Baghdasaryan 	       strcmp(mod_first_line->text, restored_first_line->text) != 0;
243beb69e81SSuren Baghdasaryan }
244beb69e81SSuren Baghdasaryan 
245b11d9e2dSSuren Baghdasaryan static inline bool shrink_vma(FIXTURE_DATA(proc_maps_race) *self)
246b11d9e2dSSuren Baghdasaryan {
247b11d9e2dSSuren Baghdasaryan 	return mremap(self->mod_info->addr, self->page_size * 3,
248b11d9e2dSSuren Baghdasaryan 		      self->page_size, 0) != MAP_FAILED;
249b11d9e2dSSuren Baghdasaryan }
250b11d9e2dSSuren Baghdasaryan 
251b11d9e2dSSuren Baghdasaryan static inline bool expand_vma(FIXTURE_DATA(proc_maps_race) *self)
252b11d9e2dSSuren Baghdasaryan {
253b11d9e2dSSuren Baghdasaryan 	return mremap(self->mod_info->addr, self->page_size,
254b11d9e2dSSuren Baghdasaryan 		      self->page_size * 3, 0) != MAP_FAILED;
255b11d9e2dSSuren Baghdasaryan }
256b11d9e2dSSuren Baghdasaryan 
257b11d9e2dSSuren Baghdasaryan static inline bool check_shrink_result(struct line_content *mod_last_line,
258b11d9e2dSSuren Baghdasaryan 				       struct line_content *mod_first_line,
259b11d9e2dSSuren Baghdasaryan 				       struct line_content *restored_last_line,
260b11d9e2dSSuren Baghdasaryan 				       struct line_content *restored_first_line)
261b11d9e2dSSuren Baghdasaryan {
262b11d9e2dSSuren Baghdasaryan 	/* Make sure only the last vma of the first page is changing */
263b11d9e2dSSuren Baghdasaryan 	return strcmp(mod_last_line->text, restored_last_line->text) != 0 &&
264b11d9e2dSSuren Baghdasaryan 	       strcmp(mod_first_line->text, restored_first_line->text) == 0;
265b11d9e2dSSuren Baghdasaryan }
266b11d9e2dSSuren Baghdasaryan 
267*6a45336bSSuren Baghdasaryan static inline bool remap_vma(FIXTURE_DATA(proc_maps_race) *self)
268*6a45336bSSuren Baghdasaryan {
269*6a45336bSSuren Baghdasaryan 	/*
270*6a45336bSSuren Baghdasaryan 	 * Remap the last page of the next vma into the middle of the vma.
271*6a45336bSSuren Baghdasaryan 	 * This splits the current vma and the first and middle parts (the
272*6a45336bSSuren Baghdasaryan 	 * parts at lower addresses) become the last vma objserved in the
273*6a45336bSSuren Baghdasaryan 	 * first page and the first vma observed in the last page.
274*6a45336bSSuren Baghdasaryan 	 */
275*6a45336bSSuren Baghdasaryan 	return mremap(self->mod_info->next_addr + self->page_size * 2, self->page_size,
276*6a45336bSSuren Baghdasaryan 		      self->page_size, MREMAP_FIXED | MREMAP_MAYMOVE | MREMAP_DONTUNMAP,
277*6a45336bSSuren Baghdasaryan 		      self->mod_info->addr + self->page_size) != MAP_FAILED;
278*6a45336bSSuren Baghdasaryan }
279*6a45336bSSuren Baghdasaryan 
280*6a45336bSSuren Baghdasaryan static inline bool patch_vma(FIXTURE_DATA(proc_maps_race) *self)
281*6a45336bSSuren Baghdasaryan {
282*6a45336bSSuren Baghdasaryan 	return mprotect(self->mod_info->addr + self->page_size, self->page_size,
283*6a45336bSSuren Baghdasaryan 			self->mod_info->prot) == 0;
284*6a45336bSSuren Baghdasaryan }
285*6a45336bSSuren Baghdasaryan 
286*6a45336bSSuren Baghdasaryan static inline bool check_remap_result(struct line_content *mod_last_line,
287*6a45336bSSuren Baghdasaryan 				      struct line_content *mod_first_line,
288*6a45336bSSuren Baghdasaryan 				      struct line_content *restored_last_line,
289*6a45336bSSuren Baghdasaryan 				      struct line_content *restored_first_line)
290*6a45336bSSuren Baghdasaryan {
291*6a45336bSSuren Baghdasaryan 	/* Make sure vmas at the boundaries are changing */
292*6a45336bSSuren Baghdasaryan 	return strcmp(mod_last_line->text, restored_last_line->text) != 0 &&
293*6a45336bSSuren Baghdasaryan 	       strcmp(mod_first_line->text, restored_first_line->text) != 0;
294*6a45336bSSuren Baghdasaryan }
295*6a45336bSSuren Baghdasaryan 
296beb69e81SSuren Baghdasaryan FIXTURE_SETUP(proc_maps_race)
297beb69e81SSuren Baghdasaryan {
298beb69e81SSuren Baghdasaryan 	const char *duration = getenv("DURATION");
299beb69e81SSuren Baghdasaryan 	struct vma_modifier_info *mod_info;
300beb69e81SSuren Baghdasaryan 	pthread_mutexattr_t mutex_attr;
301beb69e81SSuren Baghdasaryan 	pthread_condattr_t cond_attr;
302beb69e81SSuren Baghdasaryan 	unsigned long duration_sec;
303beb69e81SSuren Baghdasaryan 	char fname[32];
304beb69e81SSuren Baghdasaryan 
305beb69e81SSuren Baghdasaryan 	self->page_size = (unsigned long)sysconf(_SC_PAGESIZE);
306beb69e81SSuren Baghdasaryan 	duration_sec = duration ? atol(duration) : 0;
307beb69e81SSuren Baghdasaryan 	self->duration_sec = duration_sec ? duration_sec : 5UL;
308beb69e81SSuren Baghdasaryan 
309beb69e81SSuren Baghdasaryan 	/*
310beb69e81SSuren Baghdasaryan 	 * Have to map enough vmas for /proc/pid/maps to contain more than one
311beb69e81SSuren Baghdasaryan 	 * page worth of vmas. Assume at least 32 bytes per line in maps output
312beb69e81SSuren Baghdasaryan 	 */
313beb69e81SSuren Baghdasaryan 	self->vma_count = self->page_size / 32 + 1;
314beb69e81SSuren Baghdasaryan 	self->shared_mem_size = sizeof(struct vma_modifier_info) + self->vma_count * sizeof(void *);
315beb69e81SSuren Baghdasaryan 
316beb69e81SSuren Baghdasaryan 	/* map shared memory for communication with the child process */
317beb69e81SSuren Baghdasaryan 	self->mod_info = (struct vma_modifier_info *)mmap(NULL, self->shared_mem_size,
318beb69e81SSuren Baghdasaryan 				PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
319beb69e81SSuren Baghdasaryan 	ASSERT_NE(self->mod_info, MAP_FAILED);
320beb69e81SSuren Baghdasaryan 	mod_info = self->mod_info;
321beb69e81SSuren Baghdasaryan 
322beb69e81SSuren Baghdasaryan 	/* Initialize shared members */
323beb69e81SSuren Baghdasaryan 	pthread_mutexattr_init(&mutex_attr);
324beb69e81SSuren Baghdasaryan 	pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED);
325beb69e81SSuren Baghdasaryan 	ASSERT_EQ(pthread_mutex_init(&mod_info->sync_lock, &mutex_attr), 0);
326beb69e81SSuren Baghdasaryan 	pthread_condattr_init(&cond_attr);
327beb69e81SSuren Baghdasaryan 	pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED);
328beb69e81SSuren Baghdasaryan 	ASSERT_EQ(pthread_cond_init(&mod_info->sync_cond, &cond_attr), 0);
329beb69e81SSuren Baghdasaryan 	mod_info->vma_count = self->vma_count;
330beb69e81SSuren Baghdasaryan 	mod_info->curr_state = INIT;
331beb69e81SSuren Baghdasaryan 	mod_info->exit = false;
332beb69e81SSuren Baghdasaryan 
333beb69e81SSuren Baghdasaryan 	self->pid = fork();
334beb69e81SSuren Baghdasaryan 	if (!self->pid) {
335beb69e81SSuren Baghdasaryan 		/* Child process modifying the address space */
336beb69e81SSuren Baghdasaryan 		int prot = PROT_READ | PROT_WRITE;
337beb69e81SSuren Baghdasaryan 		int i;
338beb69e81SSuren Baghdasaryan 
339beb69e81SSuren Baghdasaryan 		for (i = 0; i < mod_info->vma_count; i++) {
340beb69e81SSuren Baghdasaryan 			mod_info->child_mapped_addr[i] = mmap(NULL, self->page_size * 3, prot,
341beb69e81SSuren Baghdasaryan 					MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
342beb69e81SSuren Baghdasaryan 			ASSERT_NE(mod_info->child_mapped_addr[i], MAP_FAILED);
343beb69e81SSuren Baghdasaryan 			/* change protection in adjacent maps to prevent merging */
344beb69e81SSuren Baghdasaryan 			prot ^= PROT_WRITE;
345beb69e81SSuren Baghdasaryan 		}
346beb69e81SSuren Baghdasaryan 		signal_state(mod_info, CHILD_READY);
347beb69e81SSuren Baghdasaryan 		wait_for_state(mod_info, PARENT_READY);
348beb69e81SSuren Baghdasaryan 		while (true) {
349beb69e81SSuren Baghdasaryan 			signal_state(mod_info, SETUP_READY);
350beb69e81SSuren Baghdasaryan 			wait_for_state(mod_info, SETUP_MODIFY_MAPS);
351beb69e81SSuren Baghdasaryan 			if (mod_info->exit)
352beb69e81SSuren Baghdasaryan 				break;
353beb69e81SSuren Baghdasaryan 
354beb69e81SSuren Baghdasaryan 			ASSERT_TRUE(mod_info->vma_modify(self));
355beb69e81SSuren Baghdasaryan 			signal_state(mod_info, SETUP_MAPS_MODIFIED);
356beb69e81SSuren Baghdasaryan 			wait_for_state(mod_info, SETUP_RESTORE_MAPS);
357beb69e81SSuren Baghdasaryan 			ASSERT_TRUE(mod_info->vma_restore(self));
358beb69e81SSuren Baghdasaryan 			signal_state(mod_info, SETUP_MAPS_RESTORED);
359beb69e81SSuren Baghdasaryan 
360beb69e81SSuren Baghdasaryan 			wait_for_state(mod_info, TEST_READY);
361beb69e81SSuren Baghdasaryan 			while (mod_info->curr_state != TEST_DONE) {
362beb69e81SSuren Baghdasaryan 				ASSERT_TRUE(mod_info->vma_modify(self));
363beb69e81SSuren Baghdasaryan 				ASSERT_TRUE(mod_info->vma_restore(self));
364beb69e81SSuren Baghdasaryan 			}
365beb69e81SSuren Baghdasaryan 		}
366beb69e81SSuren Baghdasaryan 		for (i = 0; i < mod_info->vma_count; i++)
367beb69e81SSuren Baghdasaryan 			munmap(mod_info->child_mapped_addr[i], self->page_size * 3);
368beb69e81SSuren Baghdasaryan 
369beb69e81SSuren Baghdasaryan 		exit(0);
370beb69e81SSuren Baghdasaryan 	}
371beb69e81SSuren Baghdasaryan 
372beb69e81SSuren Baghdasaryan 	sprintf(fname, "/proc/%d/maps", self->pid);
373beb69e81SSuren Baghdasaryan 	self->maps_fd = open(fname, O_RDONLY);
374beb69e81SSuren Baghdasaryan 	ASSERT_NE(self->maps_fd, -1);
375beb69e81SSuren Baghdasaryan 
376beb69e81SSuren Baghdasaryan 	/* Wait for the child to map the VMAs */
377beb69e81SSuren Baghdasaryan 	wait_for_state(mod_info, CHILD_READY);
378beb69e81SSuren Baghdasaryan 
379beb69e81SSuren Baghdasaryan 	/* Read first two pages */
380beb69e81SSuren Baghdasaryan 	self->page1.data = malloc(self->page_size);
381beb69e81SSuren Baghdasaryan 	ASSERT_NE(self->page1.data, NULL);
382beb69e81SSuren Baghdasaryan 	self->page2.data = malloc(self->page_size);
383beb69e81SSuren Baghdasaryan 	ASSERT_NE(self->page2.data, NULL);
384beb69e81SSuren Baghdasaryan 
385beb69e81SSuren Baghdasaryan 	ASSERT_TRUE(read_boundary_lines(self, &self->last_line, &self->first_line));
386beb69e81SSuren Baghdasaryan 
387beb69e81SSuren Baghdasaryan 	/*
388beb69e81SSuren Baghdasaryan 	 * Find the addresses corresponding to the last line in the first page
389beb69e81SSuren Baghdasaryan 	 * and the first line in the last page.
390beb69e81SSuren Baghdasaryan 	 */
391beb69e81SSuren Baghdasaryan 	mod_info->addr = NULL;
392beb69e81SSuren Baghdasaryan 	mod_info->next_addr = NULL;
393beb69e81SSuren Baghdasaryan 	for (int i = 0; i < mod_info->vma_count; i++) {
394beb69e81SSuren Baghdasaryan 		if (mod_info->child_mapped_addr[i] == (void *)self->last_line.start_addr) {
395beb69e81SSuren Baghdasaryan 			mod_info->addr = mod_info->child_mapped_addr[i];
396beb69e81SSuren Baghdasaryan 			mod_info->prot = PROT_READ;
397beb69e81SSuren Baghdasaryan 			/* Even VMAs have write permission */
398beb69e81SSuren Baghdasaryan 			if ((i % 2) == 0)
399beb69e81SSuren Baghdasaryan 				mod_info->prot |= PROT_WRITE;
400beb69e81SSuren Baghdasaryan 		} else if (mod_info->child_mapped_addr[i] == (void *)self->first_line.start_addr) {
401beb69e81SSuren Baghdasaryan 			mod_info->next_addr = mod_info->child_mapped_addr[i];
402beb69e81SSuren Baghdasaryan 		}
403beb69e81SSuren Baghdasaryan 
404beb69e81SSuren Baghdasaryan 		if (mod_info->addr && mod_info->next_addr)
405beb69e81SSuren Baghdasaryan 			break;
406beb69e81SSuren Baghdasaryan 	}
407beb69e81SSuren Baghdasaryan 	ASSERT_TRUE(mod_info->addr && mod_info->next_addr);
408beb69e81SSuren Baghdasaryan 
409beb69e81SSuren Baghdasaryan 	signal_state(mod_info, PARENT_READY);
410beb69e81SSuren Baghdasaryan 
411beb69e81SSuren Baghdasaryan }
412beb69e81SSuren Baghdasaryan 
413beb69e81SSuren Baghdasaryan FIXTURE_TEARDOWN(proc_maps_race)
414beb69e81SSuren Baghdasaryan {
415beb69e81SSuren Baghdasaryan 	int status;
416beb69e81SSuren Baghdasaryan 
417beb69e81SSuren Baghdasaryan 	stop_vma_modifier(self->mod_info);
418beb69e81SSuren Baghdasaryan 
419beb69e81SSuren Baghdasaryan 	free(self->page2.data);
420beb69e81SSuren Baghdasaryan 	free(self->page1.data);
421beb69e81SSuren Baghdasaryan 
422beb69e81SSuren Baghdasaryan 	for (int i = 0; i < self->vma_count; i++)
423beb69e81SSuren Baghdasaryan 		munmap(self->mod_info->child_mapped_addr[i], self->page_size);
424beb69e81SSuren Baghdasaryan 	close(self->maps_fd);
425beb69e81SSuren Baghdasaryan 	waitpid(self->pid, &status, 0);
426beb69e81SSuren Baghdasaryan 	munmap(self->mod_info, self->shared_mem_size);
427beb69e81SSuren Baghdasaryan }
428beb69e81SSuren Baghdasaryan 
429beb69e81SSuren Baghdasaryan TEST_F(proc_maps_race, test_maps_tearing_from_split)
430beb69e81SSuren Baghdasaryan {
431beb69e81SSuren Baghdasaryan 	struct vma_modifier_info *mod_info = self->mod_info;
432beb69e81SSuren Baghdasaryan 
433beb69e81SSuren Baghdasaryan 	struct line_content split_last_line;
434beb69e81SSuren Baghdasaryan 	struct line_content split_first_line;
435beb69e81SSuren Baghdasaryan 	struct line_content restored_last_line;
436beb69e81SSuren Baghdasaryan 	struct line_content restored_first_line;
437beb69e81SSuren Baghdasaryan 
438beb69e81SSuren Baghdasaryan 	wait_for_state(mod_info, SETUP_READY);
439beb69e81SSuren Baghdasaryan 
440beb69e81SSuren Baghdasaryan 	/* re-read the file to avoid using stale data from previous test */
441beb69e81SSuren Baghdasaryan 	ASSERT_TRUE(read_boundary_lines(self, &self->last_line, &self->first_line));
442beb69e81SSuren Baghdasaryan 
443beb69e81SSuren Baghdasaryan 	mod_info->vma_modify = split_vma;
444beb69e81SSuren Baghdasaryan 	mod_info->vma_restore = merge_vma;
445beb69e81SSuren Baghdasaryan 	mod_info->vma_mod_check = check_split_result;
446beb69e81SSuren Baghdasaryan 
447beb69e81SSuren Baghdasaryan 	ASSERT_TRUE(capture_mod_pattern(self, &split_last_line, &split_first_line,
448beb69e81SSuren Baghdasaryan 					&restored_last_line, &restored_first_line));
449beb69e81SSuren Baghdasaryan 
450beb69e81SSuren Baghdasaryan 	/* Now start concurrent modifications for self->duration_sec */
451beb69e81SSuren Baghdasaryan 	signal_state(mod_info, TEST_READY);
452beb69e81SSuren Baghdasaryan 
453beb69e81SSuren Baghdasaryan 	struct line_content new_last_line;
454beb69e81SSuren Baghdasaryan 	struct line_content new_first_line;
455beb69e81SSuren Baghdasaryan 	struct timespec start_ts, end_ts;
456beb69e81SSuren Baghdasaryan 
457beb69e81SSuren Baghdasaryan 	clock_gettime(CLOCK_MONOTONIC_COARSE, &start_ts);
458beb69e81SSuren Baghdasaryan 	do {
459beb69e81SSuren Baghdasaryan 		bool last_line_changed;
460beb69e81SSuren Baghdasaryan 		bool first_line_changed;
461beb69e81SSuren Baghdasaryan 
462beb69e81SSuren Baghdasaryan 		ASSERT_TRUE(read_boundary_lines(self, &new_last_line, &new_first_line));
463beb69e81SSuren Baghdasaryan 
464beb69e81SSuren Baghdasaryan 		/* Check if we read vmas after split */
465beb69e81SSuren Baghdasaryan 		if (!strcmp(new_last_line.text, split_last_line.text)) {
466beb69e81SSuren Baghdasaryan 			/*
467beb69e81SSuren Baghdasaryan 			 * The vmas should be consistent with split results,
468beb69e81SSuren Baghdasaryan 			 * however if vma was concurrently restored after a
469beb69e81SSuren Baghdasaryan 			 * split, it can be reported twice (first the original
470beb69e81SSuren Baghdasaryan 			 * split one, then the same vma but extended after the
471beb69e81SSuren Baghdasaryan 			 * merge) because we found it as the next vma again.
472beb69e81SSuren Baghdasaryan 			 * In that case new first line will be the same as the
473beb69e81SSuren Baghdasaryan 			 * last restored line.
474beb69e81SSuren Baghdasaryan 			 */
475beb69e81SSuren Baghdasaryan 			ASSERT_FALSE(strcmp(new_first_line.text, split_first_line.text) &&
476beb69e81SSuren Baghdasaryan 				     strcmp(new_first_line.text, restored_last_line.text));
477beb69e81SSuren Baghdasaryan 		} else {
478beb69e81SSuren Baghdasaryan 			/* The vmas should be consistent with merge results */
479beb69e81SSuren Baghdasaryan 			ASSERT_FALSE(strcmp(new_last_line.text, restored_last_line.text));
480beb69e81SSuren Baghdasaryan 			ASSERT_FALSE(strcmp(new_first_line.text, restored_first_line.text));
481beb69e81SSuren Baghdasaryan 		}
482beb69e81SSuren Baghdasaryan 		/*
483beb69e81SSuren Baghdasaryan 		 * First and last lines should change in unison. If the last
484beb69e81SSuren Baghdasaryan 		 * line changed then the first line should change as well and
485beb69e81SSuren Baghdasaryan 		 * vice versa.
486beb69e81SSuren Baghdasaryan 		 */
487beb69e81SSuren Baghdasaryan 		last_line_changed = strcmp(new_last_line.text, self->last_line.text) != 0;
488beb69e81SSuren Baghdasaryan 		first_line_changed = strcmp(new_first_line.text, self->first_line.text) != 0;
489beb69e81SSuren Baghdasaryan 		ASSERT_EQ(last_line_changed, first_line_changed);
490beb69e81SSuren Baghdasaryan 
491beb69e81SSuren Baghdasaryan 		clock_gettime(CLOCK_MONOTONIC_COARSE, &end_ts);
492beb69e81SSuren Baghdasaryan 	} while (end_ts.tv_sec - start_ts.tv_sec < self->duration_sec);
493beb69e81SSuren Baghdasaryan 
494beb69e81SSuren Baghdasaryan 	/* Signal the modifyer thread to stop and wait until it exits */
495beb69e81SSuren Baghdasaryan 	signal_state(mod_info, TEST_DONE);
496beb69e81SSuren Baghdasaryan }
497beb69e81SSuren Baghdasaryan 
498b11d9e2dSSuren Baghdasaryan TEST_F(proc_maps_race, test_maps_tearing_from_resize)
499b11d9e2dSSuren Baghdasaryan {
500b11d9e2dSSuren Baghdasaryan 	struct vma_modifier_info *mod_info = self->mod_info;
501b11d9e2dSSuren Baghdasaryan 
502b11d9e2dSSuren Baghdasaryan 	struct line_content shrunk_last_line;
503b11d9e2dSSuren Baghdasaryan 	struct line_content shrunk_first_line;
504b11d9e2dSSuren Baghdasaryan 	struct line_content restored_last_line;
505b11d9e2dSSuren Baghdasaryan 	struct line_content restored_first_line;
506b11d9e2dSSuren Baghdasaryan 
507b11d9e2dSSuren Baghdasaryan 	wait_for_state(mod_info, SETUP_READY);
508b11d9e2dSSuren Baghdasaryan 
509b11d9e2dSSuren Baghdasaryan 	/* re-read the file to avoid using stale data from previous test */
510b11d9e2dSSuren Baghdasaryan 	ASSERT_TRUE(read_boundary_lines(self, &self->last_line, &self->first_line));
511b11d9e2dSSuren Baghdasaryan 
512b11d9e2dSSuren Baghdasaryan 	mod_info->vma_modify = shrink_vma;
513b11d9e2dSSuren Baghdasaryan 	mod_info->vma_restore = expand_vma;
514b11d9e2dSSuren Baghdasaryan 	mod_info->vma_mod_check = check_shrink_result;
515b11d9e2dSSuren Baghdasaryan 
516b11d9e2dSSuren Baghdasaryan 	ASSERT_TRUE(capture_mod_pattern(self, &shrunk_last_line, &shrunk_first_line,
517b11d9e2dSSuren Baghdasaryan 					&restored_last_line, &restored_first_line));
518b11d9e2dSSuren Baghdasaryan 
519b11d9e2dSSuren Baghdasaryan 	/* Now start concurrent modifications for self->duration_sec */
520b11d9e2dSSuren Baghdasaryan 	signal_state(mod_info, TEST_READY);
521b11d9e2dSSuren Baghdasaryan 
522b11d9e2dSSuren Baghdasaryan 	struct line_content new_last_line;
523b11d9e2dSSuren Baghdasaryan 	struct line_content new_first_line;
524b11d9e2dSSuren Baghdasaryan 	struct timespec start_ts, end_ts;
525b11d9e2dSSuren Baghdasaryan 
526b11d9e2dSSuren Baghdasaryan 	clock_gettime(CLOCK_MONOTONIC_COARSE, &start_ts);
527b11d9e2dSSuren Baghdasaryan 	do {
528b11d9e2dSSuren Baghdasaryan 		ASSERT_TRUE(read_boundary_lines(self, &new_last_line, &new_first_line));
529b11d9e2dSSuren Baghdasaryan 
530b11d9e2dSSuren Baghdasaryan 		/* Check if we read vmas after shrinking it */
531b11d9e2dSSuren Baghdasaryan 		if (!strcmp(new_last_line.text, shrunk_last_line.text)) {
532b11d9e2dSSuren Baghdasaryan 			/*
533b11d9e2dSSuren Baghdasaryan 			 * The vmas should be consistent with shrunk results,
534b11d9e2dSSuren Baghdasaryan 			 * however if the vma was concurrently restored, it
535b11d9e2dSSuren Baghdasaryan 			 * can be reported twice (first as shrunk one, then
536b11d9e2dSSuren Baghdasaryan 			 * as restored one) because we found it as the next vma
537b11d9e2dSSuren Baghdasaryan 			 * again. In that case new first line will be the same
538b11d9e2dSSuren Baghdasaryan 			 * as the last restored line.
539b11d9e2dSSuren Baghdasaryan 			 */
540b11d9e2dSSuren Baghdasaryan 			ASSERT_FALSE(strcmp(new_first_line.text, shrunk_first_line.text) &&
541b11d9e2dSSuren Baghdasaryan 				     strcmp(new_first_line.text, restored_last_line.text));
542b11d9e2dSSuren Baghdasaryan 		} else {
543b11d9e2dSSuren Baghdasaryan 			/* The vmas should be consistent with the original/resored state */
544b11d9e2dSSuren Baghdasaryan 			ASSERT_FALSE(strcmp(new_last_line.text, restored_last_line.text));
545b11d9e2dSSuren Baghdasaryan 			ASSERT_FALSE(strcmp(new_first_line.text, restored_first_line.text));
546b11d9e2dSSuren Baghdasaryan 		}
547b11d9e2dSSuren Baghdasaryan 
548b11d9e2dSSuren Baghdasaryan 		clock_gettime(CLOCK_MONOTONIC_COARSE, &end_ts);
549b11d9e2dSSuren Baghdasaryan 	} while (end_ts.tv_sec - start_ts.tv_sec < self->duration_sec);
550b11d9e2dSSuren Baghdasaryan 
551b11d9e2dSSuren Baghdasaryan 	/* Signal the modifyer thread to stop and wait until it exits */
552b11d9e2dSSuren Baghdasaryan 	signal_state(mod_info, TEST_DONE);
553b11d9e2dSSuren Baghdasaryan }
554b11d9e2dSSuren Baghdasaryan 
555*6a45336bSSuren Baghdasaryan TEST_F(proc_maps_race, test_maps_tearing_from_remap)
556*6a45336bSSuren Baghdasaryan {
557*6a45336bSSuren Baghdasaryan 	struct vma_modifier_info *mod_info = self->mod_info;
558*6a45336bSSuren Baghdasaryan 
559*6a45336bSSuren Baghdasaryan 	struct line_content remapped_last_line;
560*6a45336bSSuren Baghdasaryan 	struct line_content remapped_first_line;
561*6a45336bSSuren Baghdasaryan 	struct line_content restored_last_line;
562*6a45336bSSuren Baghdasaryan 	struct line_content restored_first_line;
563*6a45336bSSuren Baghdasaryan 
564*6a45336bSSuren Baghdasaryan 	wait_for_state(mod_info, SETUP_READY);
565*6a45336bSSuren Baghdasaryan 
566*6a45336bSSuren Baghdasaryan 	/* re-read the file to avoid using stale data from previous test */
567*6a45336bSSuren Baghdasaryan 	ASSERT_TRUE(read_boundary_lines(self, &self->last_line, &self->first_line));
568*6a45336bSSuren Baghdasaryan 
569*6a45336bSSuren Baghdasaryan 	mod_info->vma_modify = remap_vma;
570*6a45336bSSuren Baghdasaryan 	mod_info->vma_restore = patch_vma;
571*6a45336bSSuren Baghdasaryan 	mod_info->vma_mod_check = check_remap_result;
572*6a45336bSSuren Baghdasaryan 
573*6a45336bSSuren Baghdasaryan 	ASSERT_TRUE(capture_mod_pattern(self, &remapped_last_line, &remapped_first_line,
574*6a45336bSSuren Baghdasaryan 					&restored_last_line, &restored_first_line));
575*6a45336bSSuren Baghdasaryan 
576*6a45336bSSuren Baghdasaryan 	/* Now start concurrent modifications for self->duration_sec */
577*6a45336bSSuren Baghdasaryan 	signal_state(mod_info, TEST_READY);
578*6a45336bSSuren Baghdasaryan 
579*6a45336bSSuren Baghdasaryan 	struct line_content new_last_line;
580*6a45336bSSuren Baghdasaryan 	struct line_content new_first_line;
581*6a45336bSSuren Baghdasaryan 	struct timespec start_ts, end_ts;
582*6a45336bSSuren Baghdasaryan 
583*6a45336bSSuren Baghdasaryan 	clock_gettime(CLOCK_MONOTONIC_COARSE, &start_ts);
584*6a45336bSSuren Baghdasaryan 	do {
585*6a45336bSSuren Baghdasaryan 		ASSERT_TRUE(read_boundary_lines(self, &new_last_line, &new_first_line));
586*6a45336bSSuren Baghdasaryan 
587*6a45336bSSuren Baghdasaryan 		/* Check if we read vmas after remapping it */
588*6a45336bSSuren Baghdasaryan 		if (!strcmp(new_last_line.text, remapped_last_line.text)) {
589*6a45336bSSuren Baghdasaryan 			/*
590*6a45336bSSuren Baghdasaryan 			 * The vmas should be consistent with remap results,
591*6a45336bSSuren Baghdasaryan 			 * however if the vma was concurrently restored, it
592*6a45336bSSuren Baghdasaryan 			 * can be reported twice (first as split one, then
593*6a45336bSSuren Baghdasaryan 			 * as restored one) because we found it as the next vma
594*6a45336bSSuren Baghdasaryan 			 * again. In that case new first line will be the same
595*6a45336bSSuren Baghdasaryan 			 * as the last restored line.
596*6a45336bSSuren Baghdasaryan 			 */
597*6a45336bSSuren Baghdasaryan 			ASSERT_FALSE(strcmp(new_first_line.text, remapped_first_line.text) &&
598*6a45336bSSuren Baghdasaryan 				     strcmp(new_first_line.text, restored_last_line.text));
599*6a45336bSSuren Baghdasaryan 		} else {
600*6a45336bSSuren Baghdasaryan 			/* The vmas should be consistent with the original/resored state */
601*6a45336bSSuren Baghdasaryan 			ASSERT_FALSE(strcmp(new_last_line.text, restored_last_line.text));
602*6a45336bSSuren Baghdasaryan 			ASSERT_FALSE(strcmp(new_first_line.text, restored_first_line.text));
603*6a45336bSSuren Baghdasaryan 		}
604*6a45336bSSuren Baghdasaryan 
605*6a45336bSSuren Baghdasaryan 		clock_gettime(CLOCK_MONOTONIC_COARSE, &end_ts);
606*6a45336bSSuren Baghdasaryan 	} while (end_ts.tv_sec - start_ts.tv_sec < self->duration_sec);
607*6a45336bSSuren Baghdasaryan 
608*6a45336bSSuren Baghdasaryan 	/* Signal the modifyer thread to stop and wait until it exits */
609*6a45336bSSuren Baghdasaryan 	signal_state(mod_info, TEST_DONE);
610*6a45336bSSuren Baghdasaryan }
611*6a45336bSSuren Baghdasaryan 
612beb69e81SSuren Baghdasaryan TEST_HARNESS_MAIN
613