1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) 2021 Liam R. Howlett <[email protected]>
4 */
5
6 /*\
7 * [Description]
8 *
9 * Expand brk() by at least 2 pages to ensure there is a newly created VMA
10 * and not expanding the original due to multiple anon pages. mprotect() that
11 * new VMA then brk() back to the original address therefore causing a munmap of
12 * at least one full VMA.
13 */
14
15 #include <unistd.h>
16 #include <sys/mman.h>
17 #include "tst_test.h"
18 #include "lapi/syscalls.h"
19
brk_variants(void * addr)20 static void *brk_variants(void *addr)
21 {
22 void *brk_addr;
23
24 if (tst_variant) {
25 brk_addr = (void *)tst_syscall(__NR_brk, addr);
26 } else {
27 TST_EXP_PASS_SILENT(brk(addr), "brk()");
28 brk_addr = (void *)sbrk(0);
29 }
30
31 return brk_addr;
32 }
33
brk_down_vmas(void)34 static void brk_down_vmas(void)
35 {
36 void *brk_addr;
37
38 if (tst_variant) {
39 tst_res(TINFO, "Testing syscall variant");
40 brk_addr = (void *)tst_syscall(__NR_brk, 0);
41 } else {
42 tst_res(TINFO, "Testing libc variant");
43 brk_addr = (void *)sbrk(0);
44
45 if (brk_addr == (void *)-1)
46 tst_brk(TCONF, "sbrk() not implemented");
47
48 /*
49 * Check if brk itself is implemented: updating to the current break
50 * should be a no-op.
51 */
52 if (brk(brk_addr) != 0)
53 tst_brk(TCONF, "brk() not implemented");
54 }
55
56 unsigned long page_size = getpagesize();
57 void *addr = brk_addr + page_size;
58
59 if (brk_variants(addr) < addr) {
60 tst_res(TFAIL | TERRNO, "Cannot expand brk() by page size");
61 return;
62 }
63
64 addr += page_size;
65 if (brk_variants(addr) < addr) {
66 tst_res(TFAIL | TERRNO, "Cannot expand brk() by 2x page size");
67 return;
68 }
69
70 if (mprotect(addr - page_size, page_size, PROT_READ)) {
71 tst_res(TFAIL | TERRNO, "Cannot mprotect new VMA");
72 return;
73 }
74
75 addr += page_size;
76 if (brk_variants(addr) < addr) {
77 tst_res(TFAIL | TERRNO, "Cannot expand brk() after mprotect");
78 return;
79 }
80
81 if (brk_variants(brk_addr) != brk_addr) {
82 tst_res(TFAIL | TERRNO, "Cannot restore brk() to start address");
83 return;
84 }
85
86 tst_res(TPASS, "munmap at least two VMAs of brk() passed");
87 }
88
89 static struct tst_test test = {
90 .test_all = brk_down_vmas,
91 .test_variants = 2,
92 };
93