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  * NAME
21  *	mprotect03.c
22  *
23  * DESCRIPTION
24  *	Testcase to check the mprotect(2) system call.
25  *
26  * ALGORITHM
27  *	Create a shared mapped file region with PROT_READ | PROT_WRITE
28  *	using the mmap(2) call. Then, use mprotect(2) to disable the
29  *	write permission on the mapped region. Then, attempt to write to
30  *	the mapped region using memcpy(). This would generate a sigsegv.
31  *	Since the sigsegv is generated, this needs to be done in a child
32  *	process (as sigsegv would repeatedly be generated). The testcase
33  *	succeeds only when this sigsegv is generated while attempting to
34  *	memcpy() on a shared region with only read permission.
35  *
36  * HISTORY
37  *	07/2001 Ported by Wayne Boyer
38  *      05/2002 changed over to use tst_sig instead of sigaction
39  */
40 
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <sys/mman.h>
44 #include <limits.h>
45 #include <signal.h>
46 #include <wait.h>
47 #include "test.h"
48 
49 #include "safe_macros.h"
50 
51 #ifndef PAGESIZE
52 #define PAGESIZE 4096
53 #endif
54 #define FAILED 1
55 
56 static void cleanup(void);
57 static void setup(void);
58 
59 char *TCID = "mprotect03";
60 int TST_TOTAL = 1;
61 int status;
62 char file1[BUFSIZ];
63 
main(int ac,char ** av)64 int main(int ac, char **av)
65 {
66 	int lc;
67 
68 	char *addr;
69 	int fd, pid;
70 	char *buf = "abcdefghijklmnopqrstuvwxyz";
71 
72 	tst_parse_opts(ac, av, NULL, NULL);
73 
74 	setup();
75 
76 	for (lc = 0; TEST_LOOPING(lc); lc++) {
77 		tst_count = 0;
78 
79 		if ((fd = open(file1, O_RDWR | O_CREAT, 0777)) < 0)
80 			tst_brkm(TBROK, cleanup, "open failed");
81 
82 		SAFE_WRITE(cleanup, 1, fd, buf, strlen(buf));
83 
84 		/*
85 		 * mmap the PAGESIZE bytes as read only.
86 		 */
87 		addr = mmap(0, strlen(buf), PROT_READ | PROT_WRITE, MAP_SHARED,
88 			    fd, 0);
89 		if (addr == MAP_FAILED)
90 			tst_brkm(TBROK, cleanup, "mmap failed");
91 
92 		/*
93 		 * Try to change the protection to WRITE.
94 		 */
95 		TEST(mprotect(addr, strlen(buf), PROT_READ));
96 
97 		if (TEST_RETURN != -1) {
98 			if ((pid = FORK_OR_VFORK()) == -1) {
99 				tst_brkm(TBROK, cleanup, "fork failed");
100 			}
101 
102 			if (pid == 0) {
103 				memcpy(addr, buf, strlen(buf));
104 				tst_resm(TINFO, "memcpy() did "
105 					 "not generate SIGSEGV");
106 				exit(1);
107 			}
108 
109 			waitpid(pid, &status, 0);
110 			if (WEXITSTATUS(status) != 0) {
111 				tst_resm(TFAIL, "child returned "
112 					 "unexpected status");
113 			} else {
114 				tst_resm(TPASS, "SIGSEGV generated "
115 					 "as expected");
116 			}
117 		} else {
118 			tst_resm(TFAIL, "mprotect failed "
119 				 "unexpectedly, errno: %d", errno);
120 		}
121 
122 		/* clean up things in case we are looping */
123 		if (munmap(addr, strlen(buf)) == -1) {
124 			tst_brkm(TBROK, cleanup, "munamp failed");
125 		}
126 		if (close(fd) == -1) {
127 			tst_brkm(TBROK, cleanup, "close failed");
128 		}
129 		if (unlink(file1) == -1) {
130 			tst_brkm(TBROK, cleanup, "unlink failed");
131 		}
132 	}
133 
134 	cleanup();
135 	tst_exit();
136 }
137 
sighandler(int sig)138 static void sighandler(int sig)
139 {
140 	if (sig == SIGSEGV) {
141 		tst_resm(TINFO, "received signal: SIGSEGV");
142 		tst_exit();
143 	} else
144 		tst_brkm(TBROK, 0, "Unexpected signal %d received.", sig);
145 }
146 
setup(void)147 static void setup(void)
148 {
149 	tst_sig(FORK, sighandler, NULL);
150 
151 	TEST_PAUSE;
152 
153 	tst_tmpdir();
154 
155 	sprintf(file1, "mprotect03.tmp.%d", getpid());
156 }
157 
cleanup(void)158 static void cleanup(void)
159 {
160 	tst_rmdir();
161 }
162