1 /* 2 * 3 * Copyright (c) International Business Machines Corp., 2001 4 * 5 * This program is free software; you can redistribute it and/or modify 6 * it under the terms of the GNU General Public License as published by 7 * the Free Software Foundation; either version 2 of the License, or 8 * (at your option) any later version. 9 * 10 * This program is distributed in the hope that it will be useful, 11 * but WITHOUT ANY WARRANTY; without even the implied warranty of 12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 13 * the GNU General Public License for more details. 14 * 15 * You should have received a copy of the GNU General Public License 16 * along with this program; if not, write to the Free Software 17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 18 */ 19 20 /* 21 * Test Description: 22 * Verify that, 23 * 1. munmap() fails with -1 return value and sets errno to EINVAL 24 * if addresses in the range [addr,addr+len) are outside the valid 25 * range for the address space of a process. 26 * 2. munmap() fails with -1 return value and sets errno to EINVAL 27 * if the len argument is 0. 28 * 3. munmap() fails with -1 return value and sets errno to EINVAL 29 * if the addr argument is not a multiple of the page size as 30 * returned by sysconf(). 31 * 32 * HISTORY 33 * 07/2001 Ported by Wayne Boyer 34 */ 35 36 #include <errno.h> 37 #include <unistd.h> 38 #include <fcntl.h> 39 #include <sys/mman.h> 40 #include <sys/resource.h> 41 #include <sys/stat.h> 42 43 #include "test.h" 44 #include "safe_macros.h" 45 46 char *TCID = "munmap03"; 47 48 static size_t page_sz; 49 static char *global_addr; 50 static size_t global_maplen; 51 52 static void setup(void); 53 static void cleanup(void); 54 55 static void test_einval1(void); 56 static void test_einval2(void); 57 static void test_einval3(void); 58 static void (*testfunc[])(void) = { test_einval1, test_einval2, test_einval3 }; 59 int TST_TOTAL = ARRAY_SIZE(testfunc); 60 61 int main(int ac, char **av) 62 { 63 int i, lc; 64 65 tst_parse_opts(ac, av, NULL, NULL); 66 67 setup(); 68 69 for (lc = 0; TEST_LOOPING(lc); lc++) { 70 tst_count = 0; 71 72 for (i = 0; i < TST_TOTAL; i++) 73 (*testfunc[i])(); 74 } 75 76 cleanup(); 77 tst_exit(); 78 } 79 80 static void setup(void) 81 { 82 tst_sig(NOFORK, DEF_HANDLER, cleanup); 83 84 TEST_PAUSE; 85 86 page_sz = (size_t)sysconf(_SC_PAGESIZE); 87 88 global_maplen = page_sz * 2; 89 global_addr = SAFE_MMAP(cleanup, NULL, global_maplen, PROT_READ | 90 PROT_WRITE, MAP_PRIVATE_EXCEPT_UCLINUX | 91 MAP_ANONYMOUS, -1, 0); 92 } 93 94 static void check_and_print(int expected_errno) 95 { 96 if (TEST_RETURN == -1) { 97 if (TEST_ERRNO == expected_errno) { 98 tst_resm(TPASS | TTERRNO, "failed as expected"); 99 } else { 100 tst_resm(TFAIL | TTERRNO, 101 "failed unexpectedly; expected - %d : %s", 102 expected_errno, strerror(expected_errno)); 103 } 104 } else { 105 tst_resm(TFAIL, "munmap succeeded unexpectedly"); 106 } 107 } 108 109 static void test_einval1(void) 110 { 111 struct rlimit brkval; 112 char *addr; 113 size_t map_len; 114 115 SAFE_GETRLIMIT(cleanup, RLIMIT_DATA, &brkval); 116 117 addr = (char *)brkval.rlim_max; 118 map_len = page_sz * 2; 119 120 TEST(munmap(addr, map_len)); 121 122 check_and_print(EINVAL); 123 } 124 125 static void test_einval2(void) 126 { 127 char *addr = global_addr; 128 size_t map_len = 0; 129 130 if (tst_kvercmp(2, 6, 12) < 0) { 131 tst_resm(TCONF, 132 "EINVAL error value test for this condition needs " 133 "kernel 2.6.12 or higher"); 134 return; 135 } 136 137 TEST(munmap(addr, map_len)); 138 139 check_and_print(EINVAL); 140 } 141 142 static void test_einval3(void) 143 { 144 char *addr = (char *)(global_addr + 1); 145 size_t map_len = page_sz; 146 147 TEST(munmap(addr, map_len)); 148 149 check_and_print(EINVAL); 150 } 151 152 static void cleanup(void) 153 { 154 if (munmap(global_addr, global_maplen) == -1) 155 tst_resm(TWARN | TERRNO, "munmap failed"); 156 } 157