xref: /aosp_15_r20/external/ltp/testcases/kernel/syscalls/madvise/madvise10.c (revision 49cdfc7efb34551c7342be41a7384b9c40d7cab7)
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