1 /* 2 * This file and its contents are supplied under the terms of the 3 * Common Development and Distribution License ("CDDL"), version 1.0. 4 * You may only use this file in accordance with the terms of version 5 * 1.0 of the CDDL. 6 * 7 * A full copy of the text of the CDDL should have accompanied this 8 * source. A copy of the CDDL is also available via the Internet at 9 * http://www.illumos.org/license/CDDL. 10 */ 11 12 /* 13 * Copyright 2024 Oxide Computer Company 14 */ 15 16 /* 17 * Verify that unsupported flags will properly generate errors across the 18 * functions that we know perform strict error checking. This includes: 19 * 20 * o fcntl(..., F_DUP3FD, ...) 21 * o dup3() 22 * o pipe2() 23 * o socket() 24 * o accept4() 25 */ 26 27 #include <stdlib.h> 28 #include <err.h> 29 #include <stdio.h> 30 #include <unistd.h> 31 #include <sys/stdbool.h> 32 #include <errno.h> 33 #include <string.h> 34 #include <fcntl.h> 35 #include <limits.h> 36 #include <sys/socket.h> 37 38 static bool 39 oclo_check(const char *desc, const char *act, int ret, int e) 40 { 41 if (ret >= 0) { 42 warnx("TEST FAILED: %s: fd was %s!", desc, act); 43 return (false); 44 } else if (errno != EINVAL) { 45 int e = errno; 46 warnx("TEST FAILED: %s: failed with %s, expected " 47 "EINVAL", desc, strerrorname_np(e)); 48 return (false); 49 } 50 51 (void) printf("TEST PASSED: %s: correctly failed with EINVAL\n", 52 desc); 53 return (true); 54 } 55 56 static bool 57 oclo_dup3(const char *desc, int flags) 58 { 59 int fd = dup3(STDERR_FILENO, 23, flags); 60 return (oclo_check(desc, "duplicated", fd, errno)); 61 } 62 63 static bool 64 oclo_dup3fd(const char *desc, int flags) 65 { 66 int fd = fcntl(STDERR_FILENO, F_DUP3FD, 23, flags); 67 return (oclo_check(desc, "duplicated", fd, errno)); 68 } 69 70 71 static bool 72 oclo_pipe2(const char *desc, int flags) 73 { 74 int fds[2], ret; 75 76 ret = pipe2(fds, flags); 77 return (oclo_check(desc, "piped", ret, errno)); 78 } 79 80 static bool 81 oclo_socket(const char *desc, int type) 82 { 83 int fd = socket(PF_UNIX, SOCK_STREAM | type, 0); 84 return (oclo_check(desc, "created", fd, errno)); 85 } 86 87 static bool 88 oclo_accept(const char *desc, int flags) 89 { 90 int sock, fd, e; 91 struct sockaddr_in in; 92 93 sock = socket(PF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); 94 if (sock < 0) { 95 warn("TEST FAILED: %s: failed to create listen socket", desc); 96 return (false); 97 } 98 99 (void) memset(&in, 0, sizeof (in)); 100 in.sin_family = AF_INET; 101 in.sin_port = 0; 102 in.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 103 104 if (bind(sock, (struct sockaddr *)&in, sizeof (in)) != 0) { 105 warn("TEST FAILED: %s: failed to bind socket", desc); 106 (void) close(sock); 107 return (false); 108 } 109 110 if (listen(sock, 5) < 0) { 111 warn("TEST FAILED: %s: failed to listen on socket", desc); 112 (void) close(sock); 113 return (false); 114 } 115 116 117 fd = accept4(sock, NULL, NULL, flags); 118 e = errno; 119 (void) close(sock); 120 return (oclo_check(desc, "accepted", fd, e)); 121 } 122 123 int 124 main(void) 125 { 126 int ret = EXIT_SUCCESS; 127 128 closefrom(STDERR_FILENO + 1); 129 130 if (!oclo_dup3("dup3(): O_RDWR", O_RDWR)) { 131 ret = EXIT_FAILURE; 132 } 133 134 if (!oclo_dup3("dup3(): O_NONBLOCK|O_CLOXEC", O_NONBLOCK | O_CLOEXEC)) { 135 ret = EXIT_FAILURE; 136 } 137 138 if (!oclo_dup3("dup3(): O_CLOFORK|O_WRONLY", O_CLOFORK | O_WRONLY)) { 139 ret = EXIT_FAILURE; 140 } 141 142 if (!oclo_dup3fd("fcntl(FDUP3FD): 0x7777", 0x7777)) { 143 ret = EXIT_FAILURE; 144 } 145 146 if (!oclo_dup3fd("fcntl(FDUP3FD): FD_CLOEXEC|FD_CLOFORK + 1", 147 (FD_CLOEXEC | FD_CLOFORK) + 1)) { 148 ret = EXIT_FAILURE; 149 } 150 151 if (!oclo_dup3fd("fcntl(FDUP3FD): INT_MAX", INT_MAX)) { 152 ret = EXIT_FAILURE; 153 } 154 155 156 if (!oclo_pipe2("pipe2(): O_RDWR", O_RDWR)) { 157 ret = EXIT_FAILURE; 158 } 159 160 if (!oclo_pipe2("pipe2(): O_SYNC|O_CLOXEC", O_SYNC | O_CLOEXEC)) { 161 ret = EXIT_FAILURE; 162 } 163 164 if (!oclo_pipe2("pipe2(): O_CLOFORK|O_WRONLY", O_CLOFORK | O_WRONLY)) { 165 ret = EXIT_FAILURE; 166 } 167 168 if (!oclo_pipe2("pipe2(): INT32_MAX", INT32_MAX)) { 169 ret = EXIT_FAILURE; 170 } 171 172 if (!oclo_socket("socket(): INT32_MAX", INT32_MAX)) { 173 ret = EXIT_FAILURE; 174 } 175 176 if (!oclo_socket("socket(): 3 << 25", 3 << 25)) { 177 ret = EXIT_FAILURE; 178 } 179 180 if (!oclo_accept("accept4(): INT32_MAX", INT32_MAX)) { 181 ret = EXIT_FAILURE; 182 } 183 184 if (!oclo_accept("accept4(): 3 << 25", 3 << 25)) { 185 ret = EXIT_FAILURE; 186 } 187 188 if (ret == EXIT_SUCCESS) { 189 (void) printf("All tests completed successfully\n"); 190 } 191 192 return (ret); 193 } 194