1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) Zilogic Systems Pvt. Ltd., 2018
4 * Email : [email protected]
5 */
6
7 /*
8 * test cases for madvise(2) system call, advise value as "MADV_WIPEONFORK".
9 *
10 * DESCRIPTION
11 * Present the child process with zero-filled memory in this
12 * range after a fork(2).
13 * The MADV_WIPEONFORK operation can be applied only to
14 * private anonymous pages.
15 * Within the child created by fork(2), the MADV_WIPEONFORK
16 * setting remains in place on the specified map_address range.
17 * The MADV_KEEPONFORK operation undo the effect of MADV_WIPEONFORK.
18 *
19 * Test-Case 1 : madvise with "MADV_WIPEONFORK"
20 * flow : Map memory area as private anonymous page.
21 * Mark memory area as wipe-on-fork.
22 * On fork, child process memory should be zeroed.
23 *
24 * Test-Case 2 : madvise with "MADV_WIPEONFORK" and "ZERO" length
25 * flow : Map memory area as private anonymous page.
26 * Mark memory area as wipe-on-fork, with length zero.
27 * On fork, child process memory should be accessible.
28 *
29 * Test-Case 3 : "MADV_WIPEONFORK" on Grand child
30 * flow : Map memory area as private anonymous.
31 * Mark memory areas as wipe-on-fork.
32 * On fork, child process memory should be zeroed.
33 * In child, fork to create grand-child,
34 * memory should be zeroed.
35 *
36 * Test-Case 4 : Undo "MADV_WIPEONFORK" by "MADV_KEEPONFORK"
37 * flow : Map memory area as private anonymous page.
38 * Mark memory area as wipe-on-fork.
39 * Mark memory area as keep-on-fork.
40 * On fork, child process memory should be retained.
41 **/
42
43 #include <stdio.h>
44 #include <errno.h>
45 #include <unistd.h>
46 #include <stdlib.h>
47
48 #include "lapi/mmap.h"
49 #include "tst_test.h"
50 #include "tst_safe_macros.h"
51
52 #define MAP_SIZE (16 * 1024)
53
54 static char pattern[MAP_SIZE];
55 static char zero[MAP_SIZE];
56
57 static const struct test_case {
58 int size;
59 int advise1;
60 int advise2;
61 char *exp;
62 int grand_child;
63 const char *desc;
64 } tcases[] = {
65 {MAP_SIZE, MADV_NORMAL, MADV_WIPEONFORK, zero, 0,
66 "MADV_WIPEONFORK zeroes memory in child"},
67 {0, MADV_NORMAL, MADV_WIPEONFORK, pattern, 0,
68 "MADV_WIPEONFORK with zero length does nothing"},
69 {MAP_SIZE, MADV_NORMAL, MADV_WIPEONFORK, zero, 1,
70 "MADV_WIPEONFORK zeroes memory in grand-child"},
71 {MAP_SIZE, MADV_WIPEONFORK, MADV_KEEPONFORK, pattern, 0,
72 "MADV_KEEPONFORK will undo MADV_WIPEONFORK"},
73 };
74
cmp_area(char * addr,const struct test_case * tc)75 static void cmp_area(char *addr, const struct test_case *tc)
76 {
77 int i;
78
79 for (i = 0; i < tc->size; i++) {
80 if (addr[i] != tc->exp[i]) {
81 tst_res(TFAIL, "In PID %d, addr[%d] = 0x%02x, "
82 "expected[%d] = 0x%02x", getpid(),
83 i, addr[i], i, tc->exp[i]);
84 break;
85 }
86 }
87
88 tst_res(TPASS, "In PID %d, Matched expected pattern", getpid());
89 }
90
set_advice(char * addr,int size,int advise)91 static int set_advice(char *addr, int size, int advise)
92 {
93 TEST(madvise(addr, size, advise));
94
95 if (TST_RET == -1) {
96 if (TST_ERR == EINVAL) {
97 tst_res(TCONF, "madvise(%p, %d, 0x%x) is not supported",
98 addr, size, advise);
99 } else {
100 tst_res(TFAIL | TTERRNO, "madvise(%p, %d, 0x%x)",
101 addr, size, advise);
102 }
103
104 return 1;
105 }
106
107 tst_res(TPASS, "madvise(%p, %d, 0x%x)", addr, size, advise);
108 return 0;
109 }
110
mem_map(void)111 static char *mem_map(void)
112 {
113 char *ptr;
114
115 ptr = SAFE_MMAP(NULL, MAP_SIZE,
116 PROT_READ | PROT_WRITE,
117 MAP_PRIVATE | MAP_ANONYMOUS,
118 -1, 0);
119
120 memcpy(ptr, pattern, MAP_SIZE);
121
122 return ptr;
123 }
124
test_madvise(unsigned int test_nr)125 static void test_madvise(unsigned int test_nr)
126 {
127 const struct test_case *tc = &tcases[test_nr];
128 char *addr;
129 pid_t pid;
130
131 addr = mem_map();
132
133 tst_res(TINFO, "%s", tc->desc);
134 if (set_advice(addr, tc->size, tc->advise1))
135 goto un_map;
136
137 if (!set_advice(addr, tc->size, tc->advise2)) {
138 pid = SAFE_FORK();
139
140 if (!pid) {
141 if (tc->grand_child) {
142 pid = SAFE_FORK();
143
144 if (!pid) {
145 cmp_area(addr, tc);
146 exit(0);
147 }
148 } else {
149 cmp_area(addr, tc);
150 exit(0);
151 }
152 }
153 tst_reap_children();
154 }
155
156 un_map:
157 SAFE_MUNMAP(addr, MAP_SIZE);
158 }
159
setup(void)160 static void setup(void)
161 {
162 unsigned int i;
163
164 for (i = 0; i < MAP_SIZE; i++)
165 pattern[i] = i % 0x03;
166 }
167
168 static struct tst_test test = {
169 .tcnt = ARRAY_SIZE(tcases),
170 .forks_child = 1,
171 .test = test_madvise,
172 .setup = setup,
173 };
174