blob: bcbf01522500b966d3cf91aab4da80bfa0d7446d [file] [log] [blame]
subrata_modakb752e852007-11-28 11:20:03 +00001/*
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
Wanlong Gao4548c6c2012-10-19 18:03:36 +080018 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
subrata_modakb752e852007-11-28 11:20:03 +000019 */
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>
subrata_modak498546d2007-12-05 08:44:26 +000035 * sendfile04 [-c n] [-f] [-i n] [-I x] [-P x] [-t]
subrata_modak56207ce2009-03-23 13:35:39 +000036 * where,
subrata_modakb752e852007-11-28 11:20:03 +000037 * -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>
subrata_modakb752e852007-11-28 11:20:03 +000059#include "test.h"
60
61#ifndef OFF_T
62#define OFF_T off_t
63#endif /* Not def: OFF_T */
64
subrata_modak585950c2008-08-20 10:55:19 +000065TCID_DEFINE(sendfile04);
subrata_modakb752e852007-11-28 11:20:03 +000066
67char in_file[100];
68char out_file[100];
69int out_fd;
70pid_t child_pid;
71static int sockfd, s;
subrata_modak56207ce2009-03-23 13:35:39 +000072static struct sockaddr_in sin1; /* shared between do_child and create_server */
subrata_modakb752e852007-11-28 11:20:03 +000073
74void cleanup(void);
75void do_child(void);
76void setup(void);
77int create_server(void);
78
79#define PASS_MAPPED_BUFFER 0
80#define PASS_UNMAPPED_BUFFER 1
81
82struct test_case_t {
subrata_modak56207ce2009-03-23 13:35:39 +000083 int protection;
84 int pass_unmapped_buffer;
subrata_modakb752e852007-11-28 11:20:03 +000085} testcases[] = {
subrata_modak56207ce2009-03-23 13:35:39 +000086 {
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}, {
91PROT_READ | PROT_WRITE, PASS_UNMAPPED_BUFFER},};
subrata_modakb752e852007-11-28 11:20:03 +000092
subrata_modak56207ce2009-03-23 13:35:39 +000093int TST_TOTAL = sizeof(testcases) / sizeof(testcases[0]);
subrata_modakb752e852007-11-28 11:20:03 +000094
95#ifdef UCLINUX
subrata_modak56207ce2009-03-23 13:35:39 +000096static char *argv0;
subrata_modakb752e852007-11-28 11:20:03 +000097#endif
98
99void do_sendfile(int prot, int pass_unmapped_buffer)
100{
101 OFF_T *protected_buffer;
102 int in_fd;
103 struct stat sb;
104
subrata_modak4bb656a2009-02-26 12:02:09 +0000105 protected_buffer = mmap(NULL,
subrata_modak56207ce2009-03-23 13:35:39 +0000106 sizeof(*protected_buffer),
107 prot, MAP_SHARED | MAP_ANONYMOUS, -1, 0);
subrata_modakb752e852007-11-28 11:20:03 +0000108 if (protected_buffer == MAP_FAILED) {
109 tst_brkm(TBROK, cleanup, "mmap failed: %d", errno);
Wanlong Gao354ebb42012-12-07 10:10:04 +0800110 }
subrata_modakb752e852007-11-28 11:20:03 +0000111
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);
Wanlong Gao354ebb42012-12-07 10:10:04 +0800116 }
subrata_modakb752e852007-11-28 11:20:03 +0000117 if (stat(in_file, &sb) < 0) {
118 tst_brkm(TBROK, cleanup, "stat failed: %d", errno);
Wanlong Gao354ebb42012-12-07 10:10:04 +0800119 }
subrata_modakb752e852007-11-28 11:20:03 +0000120
121 if (pass_unmapped_buffer) {
122 if (munmap(protected_buffer, sizeof(*protected_buffer)) < 0) {
123 tst_brkm(TBROK, cleanup, "munmap failed: %d", errno);
Wanlong Gao354ebb42012-12-07 10:10:04 +0800124 }
subrata_modakb752e852007-11-28 11:20:03 +0000125 }
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 {
subrata_modakb752e852007-11-28 11:20:03 +0000132 if (TEST_ERRNO != EFAULT) {
subrata_modak498546d2007-12-05 08:44:26 +0000133 tst_resm(TFAIL, "sendfile returned unexpected "
subrata_modakb752e852007-11-28 11:20:03 +0000134 "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) {
subrata_modak56207ce2009-03-23 13:35:39 +0000148 /* Not unmapped yet. So do it now. */
subrata_modakb752e852007-11-28 11:20:03 +0000149 munmap(protected_buffer, sizeof(*protected_buffer));
150 }
151}
152
153/*
154 * do_child
155 */
Mike Frysingerc57fba52014-04-09 18:56:30 -0400156void do_child(void)
subrata_modakb752e852007-11-28 11:20:03 +0000157{
158 int lc;
159 socklen_t length;
160 char rbuf[4096];
161
162 for (lc = 0; TEST_LOOPING(lc); lc++) {
163 length = sizeof(sin1);
subrata_modak56207ce2009-03-23 13:35:39 +0000164 recvfrom(sockfd, rbuf, 4096, 0, (struct sockaddr *)&sin1,
165 &length);
subrata_modakb752e852007-11-28 11:20:03 +0000166 }
167 exit(0);
168}
169
170/*
171 * setup() - performs all ONE TIME setup for this test.
172 */
Mike Frysingerc57fba52014-04-09 18:56:30 -0400173void setup(void)
subrata_modakb752e852007-11-28 11:20:03 +0000174{
175 int fd;
176 char buf[100];
177
subrata_modakb752e852007-11-28 11:20:03 +0000178 tst_sig(FORK, DEF_HANDLER, cleanup);
179
subrata_modakb752e852007-11-28 11:20:03 +0000180 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);
Wanlong Gao354ebb42012-12-07 10:10:04 +0800188 }
subrata_modakb752e852007-11-28 11:20:03 +0000189 sprintf(buf, "abcdefghijklmnopqrstuvwxyz");
190 if (write(fd, buf, strlen(buf)) < 0) {
191 tst_brkm(TBROK, cleanup, "write failed, errno: %d", errno);
Wanlong Gao354ebb42012-12-07 10:10:04 +0800192 }
subrata_modakb752e852007-11-28 11:20:03 +0000193 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 */
Mike Frysingerc57fba52014-04-09 18:56:30 -0400201void cleanup(void)
subrata_modakb752e852007-11-28 11:20:03 +0000202{
subrata_modakb752e852007-11-28 11:20:03 +0000203
204 close(out_fd);
205 /* delete the test directory created in setup() */
206 tst_rmdir();
207
subrata_modakb752e852007-11-28 11:20:03 +0000208}
209
subrata_modak56207ce2009-03-23 13:35:39 +0000210int create_server(void)
211{
212 static int count = 0;
Jan Stancek6e4e77a2014-03-07 11:39:56 +0100213 socklen_t slen = sizeof(sin1);
subrata_modakb752e852007-11-28 11:20:03 +0000214
215 sockfd = socket(PF_INET, SOCK_DGRAM, 0);
subrata_modak56207ce2009-03-23 13:35:39 +0000216 if (sockfd < 0) {
subrata_modakb752e852007-11-28 11:20:03 +0000217 tst_brkm(TBROK, cleanup, "call to socket() failed: %s",
subrata_modak56207ce2009-03-23 13:35:39 +0000218 strerror(errno));
subrata_modakb752e852007-11-28 11:20:03 +0000219 return -1;
220 }
221 sin1.sin_family = AF_INET;
Jan Stancek6e4e77a2014-03-07 11:39:56 +0100222 sin1.sin_port = 0; /* pick random free port */
subrata_modakb752e852007-11-28 11:20:03 +0000223 sin1.sin_addr.s_addr = INADDR_ANY;
224 count++;
subrata_modak56207ce2009-03-23 13:35:39 +0000225 if (bind(sockfd, (struct sockaddr *)&sin1, sizeof(sin1)) < 0) {
subrata_modakb752e852007-11-28 11:20:03 +0000226 tst_brkm(TBROK, cleanup, "call to bind() failed: %s",
subrata_modak56207ce2009-03-23 13:35:39 +0000227 strerror(errno));
subrata_modakb752e852007-11-28 11:20:03 +0000228 return -1;
229 }
Jan Stancek6e4e77a2014-03-07 11:39:56 +0100230 if (getsockname(sockfd, (struct sockaddr *)&sin1, &slen) == -1)
231 tst_brkm(TBROK | TERRNO, cleanup, "getsockname failed");
232
subrata_modakb752e852007-11-28 11:20:03 +0000233 child_pid = FORK_OR_VFORK();
subrata_modak56207ce2009-03-23 13:35:39 +0000234 if (child_pid < 0) {
subrata_modakb752e852007-11-28 11:20:03 +0000235 tst_brkm(TBROK, cleanup, "client/server fork failed: %s",
subrata_modak56207ce2009-03-23 13:35:39 +0000236 strerror(errno));
subrata_modakb752e852007-11-28 11:20:03 +0000237 return -1;
238 }
subrata_modak56207ce2009-03-23 13:35:39 +0000239 if (!child_pid) { /* child */
subrata_modakb752e852007-11-28 11:20:03 +0000240#ifdef UCLINUX
subrata_modak56207ce2009-03-23 13:35:39 +0000241 if (self_exec(argv0, "") < 0) {
subrata_modakb752e852007-11-28 11:20:03 +0000242 tst_brkm(TBROK, cleanup, "self_exec failed");
243 return -1;
subrata_modak56207ce2009-03-23 13:35:39 +0000244
subrata_modakb752e852007-11-28 11:20:03 +0000245 }
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);
subrata_modak56207ce2009-03-23 13:35:39 +0000253 if (s < 0) {
subrata_modakb752e852007-11-28 11:20:03 +0000254 tst_brkm(TBROK, cleanup, "call to socket() failed: %s",
subrata_modak56207ce2009-03-23 13:35:39 +0000255 strerror(errno));
subrata_modakb752e852007-11-28 11:20:03 +0000256 return -1;
257 }
subrata_modak56207ce2009-03-23 13:35:39 +0000258 if (connect(s, (struct sockaddr *)&sin1, sizeof(sin1)) < 0) {
subrata_modakb752e852007-11-28 11:20:03 +0000259 tst_brkm(TBROK, cleanup, "call to connect() failed: %s",
subrata_modak56207ce2009-03-23 13:35:39 +0000260 strerror(errno));
subrata_modakb752e852007-11-28 11:20:03 +0000261 }
262 return s;
263
264}
265
266int main(int ac, char **av)
267{
268 int i;
Cyril Hrubis89af32a2012-10-24 16:39:11 +0200269 int lc;
Cyril Hrubis0b9589f2014-05-27 17:40:33 +0200270 const char *msg; /* parse_opts() return message */
subrata_modakb752e852007-11-28 11:20:03 +0000271
Garrett Cooper45e285d2010-11-22 12:19:25 -0800272 if ((msg = parse_opts(ac, av, NULL, NULL)) != NULL) {
Garrett Cooper60fa8012010-11-22 13:50:58 -0800273 tst_brkm(TBROK, NULL, "OPTION PARSING ERROR - %s", msg);
Wanlong Gao354ebb42012-12-07 10:10:04 +0800274 }
subrata_modakb752e852007-11-28 11:20:03 +0000275#ifdef UCLINUX
276 argv0 = av[0];
277 maybe_run_child(&do_child, "");
278#endif
279
280 setup();
281
282 /*
283 * The following loop checks looping state if -c option given
284 */
285 for (lc = 0; TEST_LOOPING(lc); lc++) {
Caspar Zhangd59a6592013-03-07 14:59:12 +0800286 tst_count = 0;
subrata_modakb752e852007-11-28 11:20:03 +0000287
288 for (i = 0; i < TST_TOTAL; ++i) {
289 do_sendfile(testcases[i].protection,
290 testcases[i].pass_unmapped_buffer);
291 }
292 }
293 cleanup();
294
Garrett Cooper53740502010-12-16 00:04:01 -0800295 tst_exit();
Chris Dearmanec6edca2012-10-17 19:54:01 -0700296}