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 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 */ 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 */ 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 */ 199 void cleanup(void) 200 { 201 202 close(out_fd); 203 /* delete the test directory created in setup() */ 204 tst_rmdir(); 205 206 } 207 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 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