• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  *
3  *   Copyright (c) International Business Machines  Corp., 2001
4  *   Copyright (c) Red Hat Inc., 2007
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  *   You should have received a copy of the GNU General Public License
17  *   along with this program;  if not, write to the Free Software
18  *   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
19  */
20 
21 /*
22  * NAME
23  *	sendfile04.c
24  *
25  * DESCRIPTION
26  *	Testcase to test that sendfile(2) system call returns EFAULT
27  *	when passing wrong buffer.
28  *
29  * ALGORITHM
30  *     Given wrong address or protected buffer as OFFSET argument to sendfile.
31  *     A wrong address is created by munmap a buffer allocated by mmap.
32  *     A protected buffer is created by mmap with specifying protection.
33  *
34  * USAGE:  <for command-line>
35  *  sendfile04 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
36  *     where,
37  *             -f   : Turn off functionality Testing.
38  *             -i n : Execute test n times.
39  *             -I x : Execute test for x seconds.
40  *             -P x : Pause for x seconds between iterations.
41  *             -t   : Turn on syscall timing.
42  *
43  * HISTORY
44  *	11/2007 Copyed from sendfile02.c by Masatake YAMATO
45  *
46  * RESTRICTIONS
47  *	NONE
48  */
49 #include <stdio.h>
50 #include <errno.h>
51 #include <fcntl.h>
52 #include <sys/stat.h>
53 #include <sys/sendfile.h>
54 #include <sys/types.h>
55 #include <sys/socket.h>
56 #include <sys/mman.h>
57 #include <netinet/in.h>
58 #include <arpa/inet.h>
59 #include "test.h"
60 #include "safe_macros.h"
61 
62 #ifndef OFF_T
63 #define OFF_T off_t
64 #endif /* Not def: OFF_T */
65 
66 TCID_DEFINE(sendfile04);
67 
68 char in_file[100];
69 char out_file[100];
70 int out_fd;
71 pid_t child_pid;
72 static int sockfd, s;
73 static struct sockaddr_in sin1;	/* shared between do_child and create_server */
74 
75 void cleanup(void);
76 void do_child(void);
77 void setup(void);
78 int create_server(void);
79 
80 #define PASS_MAPPED_BUFFER 0
81 #define PASS_UNMAPPED_BUFFER 1
82 
83 struct test_case_t {
84 	int protection;
85 	int pass_unmapped_buffer;
86 } testcases[] = {
87 	{
88 	PROT_NONE, PASS_MAPPED_BUFFER}, {
89 	PROT_READ, PASS_MAPPED_BUFFER}, {
90 	PROT_EXEC, PASS_MAPPED_BUFFER}, {
91 	PROT_EXEC | PROT_READ, PASS_MAPPED_BUFFER}, {
92 PROT_READ | PROT_WRITE, PASS_UNMAPPED_BUFFER},};
93 
94 int TST_TOTAL = sizeof(testcases) / sizeof(testcases[0]);
95 
96 #ifdef UCLINUX
97 static char *argv0;
98 #endif
99 
do_sendfile(int prot,int pass_unmapped_buffer)100 void do_sendfile(int prot, int pass_unmapped_buffer)
101 {
102 	OFF_T *protected_buffer;
103 	int in_fd;
104 	struct stat sb;
105 
106 	protected_buffer = mmap(NULL,
107 				sizeof(*protected_buffer),
108 				prot, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
109 	if (protected_buffer == MAP_FAILED) {
110 		tst_brkm(TBROK, cleanup, "mmap failed: %d", errno);
111 	}
112 
113 	out_fd = create_server();
114 
115 	if ((in_fd = open(in_file, O_RDONLY)) < 0) {
116 		tst_brkm(TBROK, cleanup, "open failed: %d", errno);
117 	}
118 	SAFE_STAT(cleanup, in_file, &sb);
119 
120 	if (pass_unmapped_buffer) {
121 		SAFE_MUNMAP(cleanup, protected_buffer,
122 			    sizeof(*protected_buffer));
123 	}
124 
125 	TEST(sendfile(out_fd, in_fd, protected_buffer, sb.st_size));
126 
127 	if (TEST_RETURN != -1) {
128 		tst_resm(TFAIL, "call succeeded unexpectedly");
129 	} else {
130 		if (TEST_ERRNO != EFAULT) {
131 			tst_resm(TFAIL, "sendfile returned unexpected "
132 				 "errno, expected: %d, got: %d",
133 				 EFAULT, TEST_ERRNO);
134 		} else {
135 			tst_resm(TPASS, "sendfile() returned %d : %s",
136 				 TEST_ERRNO, strerror(TEST_ERRNO));
137 		}
138 	}
139 
140 	shutdown(sockfd, SHUT_RDWR);
141 	shutdown(s, SHUT_RDWR);
142 	kill(child_pid, SIGKILL);
143 	close(in_fd);
144 
145 	if (!pass_unmapped_buffer) {
146 		/* Not unmapped yet. So do it now. */
147 		munmap(protected_buffer, sizeof(*protected_buffer));
148 	}
149 }
150 
151 /*
152  * do_child
153  */
do_child(void)154 void do_child(void)
155 {
156 	int lc;
157 	socklen_t length;
158 	char rbuf[4096];
159 
160 	for (lc = 0; TEST_LOOPING(lc); lc++) {
161 		length = sizeof(sin1);
162 		recvfrom(sockfd, rbuf, 4096, 0, (struct sockaddr *)&sin1,
163 			 &length);
164 	}
165 	exit(0);
166 }
167 
168 /*
169  * setup() - performs all ONE TIME setup for this test.
170  */
setup(void)171 void setup(void)
172 {
173 	int fd;
174 	char buf[100];
175 
176 	tst_sig(FORK, DEF_HANDLER, cleanup);
177 
178 	TEST_PAUSE;
179 
180 	/* make a temporary directory and cd to it */
181 	tst_tmpdir();
182 	sprintf(in_file, "in.%d", getpid());
183 	if ((fd = creat(in_file, 00700)) < 0) {
184 		tst_brkm(TBROK, cleanup, "creat failed in setup, errno: %d",
185 			 errno);
186 	}
187 	sprintf(buf, "abcdefghijklmnopqrstuvwxyz");
188 	if (write(fd, buf, strlen(buf)) < 0) {
189 		tst_brkm(TBROK, cleanup, "write failed, errno: %d", errno);
190 	}
191 	close(fd);
192 	sprintf(out_file, "out.%d", getpid());
193 }
194 
195 /*
196  * cleanup() - performs all ONE TIME cleanup for this test at
197  *	       completion or premature exit.
198  */
cleanup(void)199 void cleanup(void)
200 {
201 
202 	close(out_fd);
203 	/* delete the test directory created in setup() */
204 	tst_rmdir();
205 
206 }
207 
create_server(void)208 int create_server(void)
209 {
210 	static int count = 0;
211 	socklen_t slen = sizeof(sin1);
212 
213 	sockfd = socket(PF_INET, SOCK_DGRAM, 0);
214 	if (sockfd < 0) {
215 		tst_brkm(TBROK, cleanup, "call to socket() failed: %s",
216 			 strerror(errno));
217 		return -1;
218 	}
219 	sin1.sin_family = AF_INET;
220 	sin1.sin_port = 0; /* pick random free port */
221 	sin1.sin_addr.s_addr = INADDR_ANY;
222 	count++;
223 	if (bind(sockfd, (struct sockaddr *)&sin1, sizeof(sin1)) < 0) {
224 		tst_brkm(TBROK, cleanup, "call to bind() failed: %s",
225 			 strerror(errno));
226 		return -1;
227 	}
228 	SAFE_GETSOCKNAME(cleanup, sockfd, (struct sockaddr *)&sin1, &slen);
229 
230 	child_pid = FORK_OR_VFORK();
231 	if (child_pid < 0) {
232 		tst_brkm(TBROK, cleanup, "client/server fork failed: %s",
233 			 strerror(errno));
234 		return -1;
235 	}
236 	if (!child_pid) {	/* child */
237 #ifdef UCLINUX
238 		if (self_exec(argv0, "") < 0) {
239 			tst_brkm(TBROK, cleanup, "self_exec failed");
240 			return -1;
241 
242 		}
243 #else
244 		do_child();
245 #endif
246 	}
247 
248 	s = socket(PF_INET, SOCK_DGRAM, 0);
249 	inet_aton("127.0.0.1", &sin1.sin_addr);
250 	if (s < 0) {
251 		tst_brkm(TBROK, cleanup, "call to socket() failed: %s",
252 			 strerror(errno));
253 		return -1;
254 	}
255 	SAFE_CONNECT(cleanup, s, (struct sockaddr *)&sin1, sizeof(sin1));
256 	return s;
257 
258 }
259 
main(int ac,char ** av)260 int main(int ac, char **av)
261 {
262 	int i;
263 	int lc;
264 
265 	tst_parse_opts(ac, av, NULL, NULL);
266 #ifdef UCLINUX
267 	argv0 = av[0];
268 	maybe_run_child(&do_child, "");
269 #endif
270 
271 	setup();
272 
273 	/*
274 	 * The following loop checks looping state if -c option given
275 	 */
276 	for (lc = 0; TEST_LOOPING(lc); lc++) {
277 		tst_count = 0;
278 
279 		for (i = 0; i < TST_TOTAL; ++i) {
280 			do_sendfile(testcases[i].protection,
281 				    testcases[i].pass_unmapped_buffer);
282 		}
283 	}
284 	cleanup();
285 
286 	tst_exit();
287 }
288