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