proc-maps-race.c 25 KB

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