• 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 
61 #ifndef OFF_T
62 #define OFF_T off_t
63 #endif /* Not def: OFF_T */
64 
65 TCID_DEFINE(sendfile04);
66 
67 char in_file[100];
68 char out_file[100];
69 int out_fd;
70 pid_t child_pid;
71 static int sockfd, s;
72 static struct sockaddr_in sin1;	/* shared between do_child and create_server */
73 
74 void cleanup(void);
75 void do_child(void);
76 void setup(void);
77 int create_server(void);
78 
79 #define PASS_MAPPED_BUFFER 0
80 #define PASS_UNMAPPED_BUFFER 1
81 
82 struct test_case_t {
83 	int protection;
84 	int pass_unmapped_buffer;
85 } testcases[] = {
86 	{
87 	PROT_NONE, PASS_MAPPED_BUFFER}, {
88 	PROT_READ, PASS_MAPPED_BUFFER}, {
89 	PROT_EXEC, PASS_MAPPED_BUFFER}, {
90 	PROT_EXEC | PROT_READ, PASS_MAPPED_BUFFER}, {
91 PROT_READ | PROT_WRITE, PASS_UNMAPPED_BUFFER},};
92 
93 int TST_TOTAL = sizeof(testcases) / sizeof(testcases[0]);
94 
95 #ifdef UCLINUX
96 static char *argv0;
97 #endif
98 
do_sendfile(int prot,int pass_unmapped_buffer)99 void do_sendfile(int prot, int pass_unmapped_buffer)
100 {
101 	OFF_T *protected_buffer;
102 	int in_fd;
103 	struct stat sb;
104 
105 	protected_buffer = mmap(NULL,
106 				sizeof(*protected_buffer),
107 				prot, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
108 	if (protected_buffer == MAP_FAILED) {
109 		tst_brkm(TBROK, cleanup, "mmap failed: %d", errno);
110 	}
111 
112 	out_fd = create_server();
113 
114 	if ((in_fd = open(in_file, O_RDONLY)) < 0) {
115 		tst_brkm(TBROK, cleanup, "open failed: %d", errno);
116 	}
117 	if (stat(in_file, &sb) < 0) {
118 		tst_brkm(TBROK, cleanup, "stat failed: %d", errno);
119 	}
120 
121 	if (pass_unmapped_buffer) {
122 		if (munmap(protected_buffer, sizeof(*protected_buffer)) < 0) {
123 			tst_brkm(TBROK, cleanup, "munmap failed: %d", errno);
124 		}
125 	}
126 
127 	TEST(sendfile(out_fd, in_fd, protected_buffer, sb.st_size));
128 
129 	if (TEST_RETURN != -1) {
130 		tst_resm(TFAIL, "call succeeded unexpectedly");
131 	} else {
132 		if (TEST_ERRNO != EFAULT) {
133 			tst_resm(TFAIL, "sendfile returned unexpected "
134 				 "errno, expected: %d, got: %d",
135 				 EFAULT, TEST_ERRNO);
136 		} else {
137 			tst_resm(TPASS, "sendfile() returned %d : %s",
138 				 TEST_ERRNO, strerror(TEST_ERRNO));
139 		}
140 	}
141 
142 	shutdown(sockfd, SHUT_RDWR);
143 	shutdown(s, SHUT_RDWR);
144 	kill(child_pid, SIGKILL);
145 	close(in_fd);
146 
147 	if (!pass_unmapped_buffer) {
148 		/* Not unmapped yet. So do it now. */
149 		munmap(protected_buffer, sizeof(*protected_buffer));
150 	}
151 }
152 
153 /*
154  * do_child
155  */
do_child(void)156 void do_child(void)
157 {
158 	int lc;
159 	socklen_t length;
160 	char rbuf[4096];
161 
162 	for (lc = 0; TEST_LOOPING(lc); lc++) {
163 		length = sizeof(sin1);
164 		recvfrom(sockfd, rbuf, 4096, 0, (struct sockaddr *)&sin1,
165 			 &length);
166 	}
167 	exit(0);
168 }
169 
170 /*
171  * setup() - performs all ONE TIME setup for this test.
172  */
setup(void)173 void setup(void)
174 {
175 	int fd;
176 	char buf[100];
177 
178 	tst_sig(FORK, DEF_HANDLER, cleanup);
179 
180 	TEST_PAUSE;
181 
182 	/* make a temporary directory and cd to it */
183 	tst_tmpdir();
184 	sprintf(in_file, "in.%d", getpid());
185 	if ((fd = creat(in_file, 00700)) < 0) {
186 		tst_brkm(TBROK, cleanup, "creat failed in setup, errno: %d",
187 			 errno);
188 	}
189 	sprintf(buf, "abcdefghijklmnopqrstuvwxyz");
190 	if (write(fd, buf, strlen(buf)) < 0) {
191 		tst_brkm(TBROK, cleanup, "write failed, errno: %d", errno);
192 	}
193 	close(fd);
194 	sprintf(out_file, "out.%d", getpid());
195 }
196 
197 /*
198  * cleanup() - performs all ONE TIME cleanup for this test at
199  *	       completion or premature exit.
200  */
cleanup(void)201 void cleanup(void)
202 {
203 
204 	close(out_fd);
205 	/* delete the test directory created in setup() */
206 	tst_rmdir();
207 
208 }
209 
create_server(void)210 int create_server(void)
211 {
212 	static int count = 0;
213 	socklen_t slen = sizeof(sin1);
214 
215 	sockfd = socket(PF_INET, SOCK_DGRAM, 0);
216 	if (sockfd < 0) {
217 		tst_brkm(TBROK, cleanup, "call to socket() failed: %s",
218 			 strerror(errno));
219 		return -1;
220 	}
221 	sin1.sin_family = AF_INET;
222 	sin1.sin_port = 0; /* pick random free port */
223 	sin1.sin_addr.s_addr = INADDR_ANY;
224 	count++;
225 	if (bind(sockfd, (struct sockaddr *)&sin1, sizeof(sin1)) < 0) {
226 		tst_brkm(TBROK, cleanup, "call to bind() failed: %s",
227 			 strerror(errno));
228 		return -1;
229 	}
230 	if (getsockname(sockfd, (struct sockaddr *)&sin1, &slen) == -1)
231 		tst_brkm(TBROK | TERRNO, cleanup, "getsockname failed");
232 
233 	child_pid = FORK_OR_VFORK();
234 	if (child_pid < 0) {
235 		tst_brkm(TBROK, cleanup, "client/server fork failed: %s",
236 			 strerror(errno));
237 		return -1;
238 	}
239 	if (!child_pid) {	/* child */
240 #ifdef UCLINUX
241 		if (self_exec(argv0, "") < 0) {
242 			tst_brkm(TBROK, cleanup, "self_exec failed");
243 			return -1;
244 
245 		}
246 #else
247 		do_child();
248 #endif
249 	}
250 
251 	s = socket(PF_INET, SOCK_DGRAM, 0);
252 	inet_aton("127.0.0.1", &sin1.sin_addr);
253 	if (s < 0) {
254 		tst_brkm(TBROK, cleanup, "call to socket() failed: %s",
255 			 strerror(errno));
256 		return -1;
257 	}
258 	if (connect(s, (struct sockaddr *)&sin1, sizeof(sin1)) < 0) {
259 		tst_brkm(TBROK, cleanup, "call to connect() failed: %s",
260 			 strerror(errno));
261 	}
262 	return s;
263 
264 }
265 
main(int ac,char ** av)266 int main(int ac, char **av)
267 {
268 	int i;
269 	int lc;
270 
271 	tst_parse_opts(ac, av, NULL, NULL);
272 #ifdef UCLINUX
273 	argv0 = av[0];
274 	maybe_run_child(&do_child, "");
275 #endif
276 
277 	setup();
278 
279 	/*
280 	 * The following loop checks looping state if -c option given
281 	 */
282 	for (lc = 0; TEST_LOOPING(lc); lc++) {
283 		tst_count = 0;
284 
285 		for (i = 0; i < TST_TOTAL; ++i) {
286 			do_sendfile(testcases[i].protection,
287 				    testcases[i].pass_unmapped_buffer);
288 		}
289 	}
290 	cleanup();
291 
292 	tst_exit();
293 }
294