1 /* 2 * Copyright (c) International Business Machines Corp., 2001 3 * 4 * This program is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * This program is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See 12 * the GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 17 */ 18 19 /* 20 * Test Description: 21 * Call mmap() to map a file creating a mapped region with execute access 22 * under the following conditions - 23 * - The prot parameter is set to PROT_EXE 24 * - The file descriptor is open for read 25 * - The file being mapped has execute permission bit set. 26 * - The minimum file permissions should be 0555. 27 * 28 * The call should succeed to map the file creating mapped memory with the 29 * required attributes. 30 * 31 * Expected Result: 32 * mmap() should succeed returning the address of the mapped region, 33 * and the mapped region should contain the contents of the mapped file. 34 * but with ia64 and PARISC/hppa, 35 * an attempt to access the contents of the mapped region should give 36 * rise to the signal SIGSEGV. 37 * 38 * HISTORY 39 * 07/2001 Ported by Wayne Boyer 40 */ 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <sys/types.h> 44 #include <errno.h> 45 #include <unistd.h> 46 #include <fcntl.h> 47 #include <string.h> 48 #include <signal.h> 49 #include <sys/stat.h> 50 #include <sys/mman.h> 51 #include <setjmp.h> 52 53 #include "test.h" 54 55 #define TEMPFILE "mmapfile" 56 57 char *TCID = "mmap03"; 58 int TST_TOTAL = 1; 59 60 static size_t page_sz; 61 static char *addr; 62 static char *dummy; 63 static int fildes; 64 static volatile int pass = 0; 65 static sigjmp_buf env; 66 67 static void setup(void); 68 static void cleanup(void); 69 static void sig_handler(int sig); 70 71 int main(int ac, char **av) 72 { 73 int lc; 74 75 tst_parse_opts(ac, av, NULL, NULL); 76 77 setup(); 78 79 for (lc = 0; TEST_LOOPING(lc); lc++) { 80 81 tst_count = 0; 82 83 /* 84 * Call mmap to map the temporary file 'TEMPFILE' 85 * with execute access. 86 */ 87 errno = 0; 88 addr = mmap(0, page_sz, PROT_EXEC, 89 MAP_FILE | MAP_SHARED, fildes, 0); 90 91 /* Check for the return value of mmap() */ 92 if (addr == MAP_FAILED) { 93 tst_resm(TFAIL | TERRNO, "mmap() failed on %s", 94 TEMPFILE); 95 continue; 96 } 97 98 /* 99 * Read the file contents into the dummy 100 * variable. 101 */ 102 if (read(fildes, dummy, page_sz) < 0) { 103 tst_brkm(TFAIL | TERRNO, cleanup, 104 "reading %s failed", TEMPFILE); 105 } 106 107 /* 108 * Check whether the mapped memory region 109 * has the file contents. 110 * 111 * with ia64 and PARISC/hppa, this should 112 * generate a SIGSEGV which will be caught below. 113 * 114 */ 115 116 if (sigsetjmp(env, 1) == 0) { 117 if (memcmp(dummy, addr, page_sz)) { 118 tst_resm(TFAIL, 119 "mapped memory region " 120 "contains invalid data"); 121 } else { 122 tst_resm(TPASS, 123 "mmap() functionality is " 124 "correct"); 125 } 126 } 127 #if defined(__ia64__) || defined(__hppa__) 128 if (pass) { 129 tst_resm(TPASS, "Got SIGSEGV as expected"); 130 } else { 131 tst_resm(TFAIL, "Mapped memory region with NO " 132 "access is accessible"); 133 } 134 #endif 135 136 /* Clean up things in case we are looping */ 137 /* Unmap the mapped memory */ 138 if (munmap(addr, page_sz) != 0) { 139 tst_brkm(TFAIL | TERRNO, cleanup, 140 "failed to unmap the mmapped pages"); 141 } 142 pass = 0; 143 144 } 145 146 cleanup(); 147 tst_exit(); 148 } 149 150 static void setup(void) 151 { 152 char *tst_buff; 153 154 tst_sig(NOFORK, sig_handler, cleanup); 155 156 TEST_PAUSE; 157 158 page_sz = getpagesize(); 159 160 /* Allocate space for the test buffer */ 161 if ((tst_buff = calloc(page_sz, sizeof(char))) == NULL) { 162 tst_brkm(TFAIL, NULL, "calloc failed (tst_buff)"); 163 } 164 165 /* Fill the test buffer with the known data */ 166 memset(tst_buff, 'A', page_sz); 167 168 tst_tmpdir(); 169 170 /* Creat a temporary file used for mapping */ 171 if ((fildes = open(TEMPFILE, O_WRONLY | O_CREAT, 0666)) < 0) { 172 free(tst_buff); 173 tst_brkm(TFAIL | TERRNO, cleanup, "opening %s failed", 174 TEMPFILE); 175 } 176 177 /* Write test buffer contents into temporary file */ 178 if (write(fildes, tst_buff, page_sz) < page_sz) { 179 free(tst_buff); 180 tst_brkm(TFAIL | TERRNO, cleanup, "writing to %s failed", 181 TEMPFILE); 182 } 183 184 /* Free the memory allocated for test buffer */ 185 free(tst_buff); 186 187 /* Make sure proper permissions set on file */ 188 if (fchmod(fildes, 0555) < 0) { 189 tst_brkm(TFAIL, cleanup, "fchmod of %s failed", TEMPFILE); 190 } 191 192 /* Close the temporary file opened for write */ 193 if (close(fildes) < 0) { 194 tst_brkm(TFAIL | TERRNO, cleanup, "closing %s failed", 195 TEMPFILE); 196 } 197 198 /* Allocate and initialize dummy string of system page size bytes */ 199 if ((dummy = calloc(page_sz, sizeof(char))) == NULL) { 200 tst_brkm(TFAIL, cleanup, "calloc failed (dummy)"); 201 } 202 203 /* Open the temporary file again for reading */ 204 if ((fildes = open(TEMPFILE, O_RDONLY)) < 0) { 205 tst_brkm(TFAIL | TERRNO, cleanup, 206 "opening %s read-only failed", TEMPFILE); 207 } 208 } 209 210 /* 211 * This function gets executed when the test process receives 212 * the signal SIGSEGV while trying to access the contents of memory which 213 * is not accessible. 214 */ 215 static void sig_handler(int sig) 216 { 217 if (sig == SIGSEGV) { 218 /* set the global variable and jump back */ 219 pass = 1; 220 siglongjmp(env, 1); 221 } else 222 tst_brkm(TBROK, cleanup, "received an unexpected signal"); 223 } 224 225 static void cleanup(void) 226 { 227 close(fildes); 228 free(dummy); 229 tst_rmdir(); 230 } 231