1 /* 2 * $OpenBSD: dup2test.c,v 1.3 2003/07/31 21:48:08 deraadt Exp $ 3 * $OpenBSD: dup2_self.c,v 1.3 2003/07/31 21:48:08 deraadt Exp $ 4 * $OpenBSD: fcntl_dup.c,v 1.2 2003/07/31 21:48:08 deraadt Exp $ 5 * 6 * Written by Artur Grabowski <art@openbsd.org> 2002 Public Domain. 7 */ 8 9 /* 10 * Test #1: check if dup(2) works. 11 * Test #2: check if dup2(2) works. 12 * Test #3: check if dup2(2) returned a fd we asked for. 13 * Test #4: check if dup2(2) cleared close-on-exec flag for duped fd. 14 * Test #5: check if dup2(2) allows to dup fd to itself. 15 * Test #6: check if dup2(2) returned a fd we asked for. 16 * Test #7: check if dup2(2) did not clear close-on-exec flag for duped fd. 17 * Test #8: check if fcntl(F_DUPFD) works. 18 * Test #9: check if fcntl(F_DUPFD) cleared close-on-exec flag for duped fd. 19 * Test #10: check if dup2() to a fd > current maximum number of open files 20 * limit work. 21 * Test #11: check if fcntl(F_DUP2FD) works. 22 * Test #12: check if fcntl(F_DUP2FD) returned a fd we asked for. 23 * Test #13: check if fcntl(F_DUP2FD) cleared close-on-exec flag for duped fd. 24 * Test #14: check if fcntl(F_DUP2FD) allows to dup fd to itself. 25 * Test #15: check if fcntl(F_DUP2FD) returned a fd we asked for. 26 * Test #16: check if fcntl(F_DUP2FD) did not clear close-on-exec flag for 27 * duped fd. 28 * Test #17: check if fcntl(F_DUP2FD) to a fd > current maximum number of open 29 * files limit work. 30 * Test #18: check if fcntl(F_DUPFD_CLOEXEC) works. 31 * Test #19: check if fcntl(F_DUPFD_CLOEXEC) set close-on-exec flag for duped 32 * fd. 33 * Test #20: check if fcntl(F_DUP2FD_CLOEXEC) works. 34 * Test #21: check if fcntl(F_DUP2FD_CLOEXEC) returned a fd we asked for. 35 * Test #22: check if fcntl(F_DUP2FD_CLOEXEC) set close-on-exec flag for duped 36 * fd. 37 * Test #23: check if fcntl(F_DUP2FD_CLOEXEC) to a fd > current maximum number 38 * of open files limit work. 39 * Test #24: check if dup3(O_CLOEXEC) works. 40 * Test #25: check if dup3(O_CLOEXEC) returned a fd we asked for. 41 * Test #26: check if dup3(O_CLOEXEC) set close-on-exec flag for duped fd. 42 * Test #27: check if dup3(0) works. 43 * Test #28: check if dup3(0) returned a fd we asked for. 44 * Test #29: check if dup3(0) cleared close-on-exec flag for duped fd. 45 * Test #30: check if dup3(O_CLOEXEC) fails if oldfd == newfd. 46 * Test #31: check if dup3(0) fails if oldfd == newfd. 47 * Test #32: check if dup3(O_CLOEXEC) to a fd > current maximum number of 48 * open files limit work. 49 */ 50 51 #include <sys/types.h> 52 #include <sys/time.h> 53 #include <sys/resource.h> 54 55 #include <err.h> 56 #include <fcntl.h> 57 #include <stdio.h> 58 #include <stdlib.h> 59 #include <unistd.h> 60 61 static int getafile(void); 62 63 static int 64 getafile(void) 65 { 66 int fd; 67 68 char temp[] = "/tmp/dup2XXXXXXXXX"; 69 if ((fd = mkstemp(temp)) < 0) 70 err(1, "mkstemp"); 71 remove(temp); 72 if (ftruncate(fd, 1024) != 0) 73 err(1, "ftruncate"); 74 return (fd); 75 } 76 77 int 78 main(int __unused argc, char __unused *argv[]) 79 { 80 struct rlimit rlp; 81 int orgfd, fd1, fd2, test = 0; 82 83 orgfd = getafile(); 84 85 printf("1..32\n"); 86 87 /* If dup(2) ever work? */ 88 if ((fd1 = dup(orgfd)) < 0) 89 err(1, "dup"); 90 printf("ok %d - dup(2) works\n", ++test); 91 92 /* Set close-on-exec */ 93 if (fcntl(fd1, F_SETFD, 1) != 0) 94 err(1, "fcntl(F_SETFD)"); 95 96 /* If dup2(2) ever work? */ 97 if ((fd2 = dup2(fd1, fd1 + 1)) < 0) 98 err(1, "dup2"); 99 printf("ok %d - dup2(2) works\n", ++test); 100 101 /* Do we get the right fd? */ 102 ++test; 103 if (fd2 != fd1 + 1) 104 printf("no ok %d - dup2(2) didn't give us the right fd\n", 105 test); 106 else 107 printf("ok %d - dup2(2) returned a correct fd\n", test); 108 109 /* Was close-on-exec cleared? */ 110 ++test; 111 if (fcntl(fd2, F_GETFD) != 0) 112 printf("not ok %d - dup2(2) didn't clear close-on-exec\n", 113 test); 114 else 115 printf("ok %d - dup2(2) cleared close-on-exec\n", test); 116 117 /* 118 * Dup to itself. 119 * 120 * We're testing a small tweak in dup2 semantics. 121 * Normally dup and dup2 will clear the close-on-exec 122 * flag on the new fd (which appears to be an implementation 123 * mistake from start and not some planned behavior). 124 * In today's implementations of dup and dup2 we have to make 125 * an effort to really clear that flag. But all tested 126 * implementations of dup2 have another tweak. If we 127 * dup2(old, new) when old == new, the syscall short-circuits 128 * and returns early (because there is no need to do all the 129 * work (and there is a risk for serious mistakes)). 130 * So although the docs say that dup2 should "take 'old', 131 * close 'new' perform a dup(2) of 'old' into 'new'" 132 * the docs are not really followed because close-on-exec 133 * is not cleared on 'new'. 134 * 135 * Since everyone has this bug, we pretend that this is 136 * the way it is supposed to be and test here that it really 137 * works that way. 138 * 139 * This is a fine example on where two separate implementation 140 * fuckups take out each other and make the end-result the way 141 * it was meant to be. 142 */ 143 if ((fd2 = dup2(fd1, fd1)) < 0) 144 err(1, "dup2"); 145 printf("ok %d - dup2(2) to itself works\n", ++test); 146 147 /* Do we get the right fd? */ 148 ++test; 149 if (fd2 != fd1) 150 printf("not ok %d - dup2(2) didn't give us the right fd\n", 151 test); 152 else 153 printf("ok %d - dup2(2) to itself returned a correct fd\n", 154 test); 155 156 /* Was close-on-exec cleared? */ 157 ++test; 158 if (fcntl(fd2, F_GETFD) == 0) 159 printf("not ok %d - dup2(2) cleared close-on-exec\n", test); 160 else 161 printf("ok %d - dup2(2) didn't clear close-on-exec\n", test); 162 163 /* Does fcntl(F_DUPFD) work? */ 164 if ((fd2 = fcntl(fd1, F_DUPFD, 10)) < 0) 165 err(1, "fcntl(F_DUPFD)"); 166 if (fd2 < 10) 167 printf("not ok %d - fcntl(F_DUPFD) returned wrong fd %d\n", 168 ++test, fd2); 169 else 170 printf("ok %d - fcntl(F_DUPFD) works\n", ++test); 171 172 /* Was close-on-exec cleared? */ 173 ++test; 174 if (fcntl(fd2, F_GETFD) != 0) 175 printf( 176 "not ok %d - fcntl(F_DUPFD) didn't clear close-on-exec\n", 177 test); 178 else 179 printf("ok %d - fcntl(F_DUPFD) cleared close-on-exec\n", test); 180 181 ++test; 182 if (getrlimit(RLIMIT_NOFILE, &rlp) < 0) 183 err(1, "getrlimit"); 184 if ((fd2 = dup2(fd1, rlp.rlim_cur + 1)) >= 0) 185 printf("not ok %d - dup2(2) bypassed NOFILE limit\n", test); 186 else 187 printf("ok %d - dup2(2) didn't bypass NOFILE limit\n", test); 188 189 /* If fcntl(F_DUP2FD) ever work? */ 190 if ((fd2 = fcntl(fd1, F_DUP2FD, fd1 + 1)) < 0) 191 err(1, "fcntl(F_DUP2FD)"); 192 printf("ok %d - fcntl(F_DUP2FD) works\n", ++test); 193 194 /* Do we get the right fd? */ 195 ++test; 196 if (fd2 != fd1 + 1) 197 printf( 198 "no ok %d - fcntl(F_DUP2FD) didn't give us the right fd\n", 199 test); 200 else 201 printf("ok %d - fcntl(F_DUP2FD) returned a correct fd\n", 202 test); 203 204 /* Was close-on-exec cleared? */ 205 ++test; 206 if (fcntl(fd2, F_GETFD) != 0) 207 printf( 208 "not ok %d - fcntl(F_DUP2FD) didn't clear close-on-exec\n", 209 test); 210 else 211 printf("ok %d - fcntl(F_DUP2FD) cleared close-on-exec\n", 212 test); 213 214 /* Dup to itself */ 215 if ((fd2 = fcntl(fd1, F_DUP2FD, fd1)) < 0) 216 err(1, "fcntl(F_DUP2FD)"); 217 printf("ok %d - fcntl(F_DUP2FD) to itself works\n", ++test); 218 219 /* Do we get the right fd? */ 220 ++test; 221 if (fd2 != fd1) 222 printf( 223 "not ok %d - fcntl(F_DUP2FD) didn't give us the right fd\n", 224 test); 225 else 226 printf( 227 "ok %d - fcntl(F_DUP2FD) to itself returned a correct fd\n", 228 test); 229 230 /* Was close-on-exec cleared? */ 231 ++test; 232 if (fcntl(fd2, F_GETFD) == 0) 233 printf("not ok %d - fcntl(F_DUP2FD) cleared close-on-exec\n", 234 test); 235 else 236 printf("ok %d - fcntl(F_DUP2FD) didn't clear close-on-exec\n", 237 test); 238 239 ++test; 240 if (getrlimit(RLIMIT_NOFILE, &rlp) < 0) 241 err(1, "getrlimit"); 242 if ((fd2 = fcntl(fd1, F_DUP2FD, rlp.rlim_cur + 1)) >= 0) 243 printf("not ok %d - fcntl(F_DUP2FD) bypassed NOFILE limit\n", 244 test); 245 else 246 printf("ok %d - fcntl(F_DUP2FD) didn't bypass NOFILE limit\n", 247 test); 248 249 /* Does fcntl(F_DUPFD_CLOEXEC) work? */ 250 if ((fd2 = fcntl(fd1, F_DUPFD_CLOEXEC, 10)) < 0) 251 err(1, "fcntl(F_DUPFD_CLOEXEC)"); 252 if (fd2 < 10) 253 printf("not ok %d - fcntl(F_DUPFD_CLOEXEC) returned wrong fd %d\n", 254 ++test, fd2); 255 else 256 printf("ok %d - fcntl(F_DUPFD_CLOEXEC) works\n", ++test); 257 258 /* Was close-on-exec cleared? */ 259 ++test; 260 if (fcntl(fd2, F_GETFD) != 1) 261 printf( 262 "not ok %d - fcntl(F_DUPFD_CLOEXEC) didn't set close-on-exec\n", 263 test); 264 else 265 printf("ok %d - fcntl(F_DUPFD_CLOEXEC) set close-on-exec\n", 266 test); 267 268 /* If fcntl(F_DUP2FD_CLOEXEC) ever work? */ 269 if ((fd2 = fcntl(fd1, F_DUP2FD_CLOEXEC, fd1 + 1)) < 0) 270 err(1, "fcntl(F_DUP2FD_CLOEXEC)"); 271 printf("ok %d - fcntl(F_DUP2FD_CLOEXEC) works\n", ++test); 272 273 /* Do we get the right fd? */ 274 ++test; 275 if (fd2 != fd1 + 1) 276 printf( 277 "no ok %d - fcntl(F_DUP2FD_CLOEXEC) didn't give us the right fd\n", 278 test); 279 else 280 printf("ok %d - fcntl(F_DUP2FD_CLOEXEC) returned a correct fd\n", 281 test); 282 283 /* Was close-on-exec set? */ 284 ++test; 285 if (fcntl(fd2, F_GETFD) != FD_CLOEXEC) 286 printf( 287 "not ok %d - fcntl(F_DUP2FD_CLOEXEC) didn't set close-on-exec\n", 288 test); 289 else 290 printf("ok %d - fcntl(F_DUP2FD_CLOEXEC) set close-on-exec\n", 291 test); 292 293 /* 294 * It is unclear what F_DUP2FD_CLOEXEC should do when duplicating a 295 * file descriptor onto itself. 296 */ 297 298 ++test; 299 if (getrlimit(RLIMIT_NOFILE, &rlp) < 0) 300 err(1, "getrlimit"); 301 if ((fd2 = fcntl(fd1, F_DUP2FD_CLOEXEC, rlp.rlim_cur + 1)) >= 0) 302 printf("not ok %d - fcntl(F_DUP2FD_CLOEXEC) bypassed NOFILE limit\n", 303 test); 304 else 305 printf("ok %d - fcntl(F_DUP2FD_CLOEXEC) didn't bypass NOFILE limit\n", 306 test); 307 308 /* Does dup3(O_CLOEXEC) ever work? */ 309 if ((fd2 = dup3(fd1, fd1 + 1, O_CLOEXEC)) < 0) 310 err(1, "dup3(O_CLOEXEC)"); 311 printf("ok %d - dup3(O_CLOEXEC) works\n", ++test); 312 313 /* Do we get the right fd? */ 314 ++test; 315 if (fd2 != fd1 + 1) 316 printf( 317 "no ok %d - dup3(O_CLOEXEC) didn't give us the right fd\n", 318 test); 319 else 320 printf("ok %d - dup3(O_CLOEXEC) returned a correct fd\n", 321 test); 322 323 /* Was close-on-exec set? */ 324 ++test; 325 if (fcntl(fd2, F_GETFD) != FD_CLOEXEC) 326 printf( 327 "not ok %d - dup3(O_CLOEXEC) didn't set close-on-exec\n", 328 test); 329 else 330 printf("ok %d - dup3(O_CLOEXEC) set close-on-exec\n", 331 test); 332 333 /* Does dup3(0) ever work? */ 334 if ((fd2 = dup3(fd1, fd1 + 1, 0)) < 0) 335 err(1, "dup3(0)"); 336 printf("ok %d - dup3(0) works\n", ++test); 337 338 /* Do we get the right fd? */ 339 ++test; 340 if (fd2 != fd1 + 1) 341 printf( 342 "no ok %d - dup3(0) didn't give us the right fd\n", 343 test); 344 else 345 printf("ok %d - dup3(0) returned a correct fd\n", 346 test); 347 348 /* Was close-on-exec cleared? */ 349 ++test; 350 if (fcntl(fd2, F_GETFD) != 0) 351 printf( 352 "not ok %d - dup3(0) didn't clear close-on-exec\n", 353 test); 354 else 355 printf("ok %d - dup3(0) cleared close-on-exec\n", 356 test); 357 358 /* dup3() does not allow duplicating to the same fd */ 359 ++test; 360 if (dup3(fd1, fd1, O_CLOEXEC) != -1) 361 printf( 362 "not ok %d - dup3(fd1, fd1, O_CLOEXEC) succeeded\n", test); 363 else 364 printf("ok %d - dup3(fd1, fd1, O_CLOEXEC) failed\n", test); 365 366 ++test; 367 if (dup3(fd1, fd1, 0) != -1) 368 printf( 369 "not ok %d - dup3(fd1, fd1, 0) succeeded\n", test); 370 else 371 printf("ok %d - dup3(fd1, fd1, 0) failed\n", test); 372 373 ++test; 374 if (getrlimit(RLIMIT_NOFILE, &rlp) < 0) 375 err(1, "getrlimit"); 376 if ((fd2 = dup3(fd1, rlp.rlim_cur + 1, O_CLOEXEC)) >= 0) 377 printf("not ok %d - dup3(O_CLOEXEC) bypassed NOFILE limit\n", 378 test); 379 else 380 printf("ok %d - dup3(O_CLOEXEC) didn't bypass NOFILE limit\n", 381 test); 382 383 return (0); 384 } 385