Home | History | Annotate | Download | only in mmap
      1 /*
      2  * Copyright (c) 2013 FNST, DAN LI <li.dan (at) cn.fujitsu.com>
      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  *  Verify error signal SIGBUS.
     22  *  "Attempted access to a portion of the buffer that does not correspond
     23  *   to the file."
     24  *
     25  * Expected Result:
     26  *  mmap() should succeed returning the address of the mapped region,
     27  *  and an attempt to access the memory which does not correspond to the file
     28  *  should rise the signal SIGBUS.
     29  */
     30 #include <stdio.h>
     31 #include <stdlib.h>
     32 #include <sys/types.h>
     33 #include <errno.h>
     34 #include <unistd.h>
     35 #include <fcntl.h>
     36 #include <string.h>
     37 #include <signal.h>
     38 #include <sys/stat.h>
     39 #include <sys/mman.h>
     40 #include <setjmp.h>
     41 
     42 #include "test.h"
     43 
     44 #define TEMPFILE	"mmapfile"
     45 
     46 char *TCID = "mmap13";
     47 int TST_TOTAL = 1;
     48 
     49 static size_t page_sz;
     50 static char *addr;
     51 static int fildes;
     52 static volatile sig_atomic_t pass;
     53 static sigjmp_buf env;
     54 
     55 static void setup(void);
     56 static void cleanup(void);
     57 static void sig_handler(int sig);
     58 
     59 int main(int argc, char *argv[])
     60 {
     61 	int lc;
     62 	char *ch;
     63 
     64 	tst_parse_opts(argc, argv, NULL, NULL);
     65 
     66 	setup();
     67 
     68 	for (lc = 0; TEST_LOOPING(lc); lc++) {
     69 		tst_count = 0;
     70 
     71 		addr = mmap(NULL, page_sz * 2, PROT_READ | PROT_WRITE,
     72 			    MAP_FILE | MAP_SHARED, fildes, 0);
     73 
     74 		if (addr == MAP_FAILED) {
     75 			tst_resm(TFAIL | TERRNO, "mmap() failed on %s",
     76 				 TEMPFILE);
     77 			continue;
     78 		}
     79 
     80 		if (sigsetjmp(env, 1) == 0) {
     81 			ch = addr + page_sz + 1;
     82 			*ch = 0;
     83 		}
     84 
     85 		if (pass)
     86 			tst_resm(TPASS, "Got SIGBUS "
     87 					"as expected");
     88 		else
     89 			tst_resm(TFAIL, "Invalid access not "
     90 						"rise SIGBUS");
     91 
     92 		if (munmap(addr, page_sz * 2) != 0)
     93 			tst_brkm(TFAIL | TERRNO, cleanup,
     94 				 "failed to unmap the mmapped pages");
     95 
     96 		pass = 0;
     97 	}
     98 
     99 	cleanup();
    100 	tst_exit();
    101 }
    102 
    103 static void setup(void)
    104 {
    105 	tst_sig(NOFORK, sig_handler, cleanup);
    106 
    107 	TEST_PAUSE;
    108 
    109 	page_sz = getpagesize();
    110 
    111 	tst_tmpdir();
    112 
    113 	fildes = open(TEMPFILE, O_RDWR | O_CREAT, 0766);
    114 	if (fildes < 0)
    115 		tst_brkm(TFAIL | TERRNO, cleanup, "opening %s failed",
    116 			 TEMPFILE);
    117 
    118 	if (ftruncate(fildes, page_sz / 2) == -1)
    119 		tst_brkm(TFAIL | TERRNO, cleanup, "ftruncate %s failed",
    120 			 TEMPFILE);
    121 }
    122 
    123 /*
    124  *   This function gets executed when the test process receives
    125  *   the signal SIGBUS while trying to access the memory which
    126  *   does not correspond to the file.
    127  */
    128 static void sig_handler(int sig)
    129 {
    130 	if (sig == SIGBUS) {
    131 		pass = 1;
    132 		siglongjmp(env, 1);
    133 	} else {
    134 		tst_brkm(TBROK, cleanup, "received an unexpected signal");
    135 	}
    136 }
    137 
    138 static void cleanup(void)
    139 {
    140 	close(fildes);
    141 	tst_rmdir();
    142 }
    143