1 /* 2 * Copyright 2024-2025 The OpenSSL Project Authors. All Rights Reserved. 3 * 4 * Licensed under the Apache License 2.0 (the "License"). You may not use 5 * this file except in compliance with the License. You can obtain a copy 6 * in the file LICENSE in the source distribution or at 7 * https://www.openssl.org/source/license.html 8 */ 9 10 #include "internal/sockets.h" 11 #include <openssl/bio.h> 12 #include <openssl/err.h> 13 #include "internal/thread_once.h" 14 #include "internal/rio_notifier.h" 15 16 /* 17 * Sets a socket as close-on-exec, except that this is a no-op if we are certain 18 * we do not need to do this or the OS does not support the concept. 19 */ 20 static int set_cloexec(int fd) 21 { 22 #if !defined(SOCK_CLOEXEC) && defined(FD_CLOEXEC) 23 return fcntl(fd, F_SETFD, FD_CLOEXEC) >= 0; 24 #else 25 return 1; 26 #endif 27 } 28 29 #if defined(OPENSSL_SYS_WINDOWS) 30 31 static CRYPTO_ONCE ensure_wsa_startup_once = CRYPTO_ONCE_STATIC_INIT; 32 static int wsa_started; 33 34 static void ossl_wsa_cleanup(void) 35 { 36 if (wsa_started) { 37 wsa_started = 0; 38 WSACleanup(); 39 } 40 } 41 42 DEFINE_RUN_ONCE_STATIC(do_wsa_startup) 43 { 44 WORD versionreq = 0x0202; /* Version 2.2 */ 45 WSADATA wsadata; 46 47 if (WSAStartup(versionreq, &wsadata) != 0) 48 return 0; 49 wsa_started = 1; 50 OPENSSL_atexit(ossl_wsa_cleanup); 51 return 1; 52 } 53 54 static ossl_inline int ensure_wsa_startup(void) 55 { 56 return RUN_ONCE(&ensure_wsa_startup_once, do_wsa_startup); 57 } 58 59 #endif 60 61 #if RIO_NOTIFIER_METHOD == RIO_NOTIFIER_METHOD_SOCKET 62 63 /* Create a close-on-exec socket. */ 64 static int create_socket(int domain, int socktype, int protocol) 65 { 66 int fd; 67 # if defined(OPENSSL_SYS_WINDOWS) 68 static const int on = 1; 69 70 /* 71 * Use WSASocketA to create a socket which is immediately marked as 72 * non-inheritable, avoiding race conditions if another thread is about to 73 * call CreateProcess. 74 * NOTE: windows xp (0x501) doesn't support the non-inheritance flag here 75 * but preventing inheritance isn't mandatory, just a safety precaution 76 * so we can get away with not including it for older platforms 77 */ 78 79 # ifdef WSA_FLAG_NO_HANDLE_INHERIT 80 fd = (int)WSASocketA(domain, socktype, protocol, NULL, 0, 81 WSA_FLAG_NO_HANDLE_INHERIT); 82 83 /* 84 * Its also possible that someone is building a binary on a newer windows 85 * SDK, but running it on a runtime that doesn't support inheritance 86 * supression. In that case the above will return INVALID_SOCKET, and 87 * our response for those older platforms is to try the call again 88 * without the flag 89 */ 90 if (fd == INVALID_SOCKET) 91 fd = (int)WSASocketA(domain, socktype, protocol, NULL, 0, 0); 92 # else 93 fd = (int)WSASocketA(domain, socktype, protocol, NULL, 0, 0); 94 # endif 95 if (fd == INVALID_SOCKET) { 96 int err = get_last_socket_error(); 97 98 ERR_raise_data(ERR_LIB_SYS, err, 99 "calling WSASocketA() = %d", err); 100 return INVALID_SOCKET; 101 } 102 103 /* Prevent interference with the socket from other processes on Windows. */ 104 if (setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE, (void *)&on, sizeof(on)) < 0) { 105 ERR_raise_data(ERR_LIB_SYS, get_last_socket_error(), 106 "calling setsockopt()"); 107 BIO_closesocket(fd); 108 return INVALID_SOCKET; 109 } 110 111 # else 112 # if defined(SOCK_CLOEXEC) 113 socktype |= SOCK_CLOEXEC; 114 # endif 115 116 fd = BIO_socket(domain, socktype, protocol, 0); 117 if (fd == INVALID_SOCKET) { 118 ERR_raise_data(ERR_LIB_SYS, get_last_sys_error(), 119 "calling BIO_socket()"); 120 return INVALID_SOCKET; 121 } 122 123 /* 124 * Make socket close-on-exec unless this was already done above at socket 125 * creation time. 126 */ 127 if (!set_cloexec(fd)) { 128 ERR_raise_data(ERR_LIB_SYS, get_last_sys_error(), 129 "calling set_cloexec()"); 130 BIO_closesocket(fd); 131 return INVALID_SOCKET; 132 } 133 # endif 134 135 return fd; 136 } 137 138 /* 139 * The SOCKET notifier method manually creates a connected TCP socket pair by 140 * temporarily creating a TCP listener on a random port and connecting back to 141 * it. 142 * 143 * Win32 does not support socketpair(2), and Win32 pipes are not compatible with 144 * Winsock select(2). This means our only means of making select(2) wakeable is 145 * to artifically create a loopback TCP connection and send bytes to it. 146 */ 147 int ossl_rio_notifier_init(RIO_NOTIFIER *nfy) 148 { 149 int rc, lfd = -1, rfd = -1, wfd = -1; 150 struct sockaddr_in sa = {0}, accept_sa; 151 socklen_t sa_len = sizeof(sa), accept_sa_len = sizeof(accept_sa); 152 153 # if defined(OPENSSL_SYS_WINDOWS) 154 if (!ensure_wsa_startup()) { 155 ERR_raise_data(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR, 156 "Cannot start Windows sockets"); 157 return 0; 158 } 159 # endif 160 /* Create a close-on-exec socket. */ 161 lfd = create_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 162 if (lfd == INVALID_SOCKET) { 163 ERR_raise_data(ERR_LIB_SYS, get_last_sys_error(), 164 "calling create_socket()"); 165 return 0; 166 } 167 168 /* Bind the socket to a random loopback port. */ 169 sa.sin_family = AF_INET; 170 sa.sin_addr.s_addr = htonl(INADDR_LOOPBACK); 171 rc = bind(lfd, (const struct sockaddr *)&sa, sizeof(sa)); 172 if (rc < 0) { 173 ERR_raise_data(ERR_LIB_SYS, get_last_sys_error(), 174 "calling bind()"); 175 goto err; 176 } 177 178 /* Determine what random port was allocated. */ 179 rc = getsockname(lfd, (struct sockaddr *)&sa, &sa_len); 180 if (rc < 0) { 181 ERR_raise_data(ERR_LIB_SYS, get_last_sys_error(), 182 "calling getsockname()"); 183 goto err; 184 } 185 186 /* Start listening. */ 187 rc = listen(lfd, 1); 188 if (rc < 0) { 189 ERR_raise_data(ERR_LIB_SYS, get_last_sys_error(), 190 "calling listen()"); 191 goto err; 192 } 193 194 /* Create another socket to connect to the listener. */ 195 wfd = create_socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); 196 if (wfd == INVALID_SOCKET) { 197 ERR_raise_data(ERR_LIB_SYS, get_last_sys_error(), 198 "calling create_socket()"); 199 goto err; 200 } 201 202 /* 203 * Disable Nagle's algorithm on the writer so that wakeups happen 204 * immediately. 205 */ 206 if (!BIO_set_tcp_ndelay(wfd, 1)) { 207 ERR_raise_data(ERR_LIB_SYS, get_last_sys_error(), 208 "calling BIO_set_tcp_ndelay()"); 209 goto err; 210 } 211 212 /* 213 * Connect the writer to the listener. 214 */ 215 rc = connect(wfd, (struct sockaddr *)&sa, sizeof(sa)); 216 if (rc < 0) { 217 ERR_raise_data(ERR_LIB_SYS, get_last_sys_error(), 218 "calling connect()"); 219 goto err; 220 } 221 222 /* 223 * The connection accepted from the listener is the read side. 224 */ 225 rfd = accept(lfd, (struct sockaddr *)&accept_sa, &accept_sa_len); 226 if (rfd == INVALID_SOCKET) { 227 ERR_raise_data(ERR_LIB_SYS, get_last_sys_error(), 228 "calling accept()"); 229 goto err; 230 } 231 232 rc = getsockname(wfd, (struct sockaddr *)&sa, &sa_len); 233 if (rc < 0) { 234 ERR_raise_data(ERR_LIB_SYS, get_last_sys_error(), 235 "calling getsockname()"); 236 goto err; 237 } 238 239 /* Close the listener, which we don't need anymore. */ 240 BIO_closesocket(lfd); 241 lfd = -1; 242 243 /* 244 * Sanity check - ensure someone else didn't connect to our listener during 245 * the brief window of possibility above. 246 */ 247 if (accept_sa.sin_family != AF_INET || accept_sa.sin_port != sa.sin_port) { 248 ERR_raise_data(ERR_LIB_SSL, ERR_R_INTERNAL_ERROR, 249 "connected address differs from accepted address"); 250 goto err; 251 } 252 253 /* Make both sides of the connection non-blocking. */ 254 if (!BIO_socket_nbio(rfd, 1)) { 255 ERR_raise_data(ERR_LIB_SYS, get_last_sys_error(), 256 "calling BIO_socket_nbio()"); 257 goto err; 258 } 259 260 if (!BIO_socket_nbio(wfd, 1)) { 261 ERR_raise_data(ERR_LIB_SYS, get_last_sys_error(), 262 "calling BIO_socket_nbio()"); 263 goto err; 264 } 265 266 nfy->rfd = rfd; 267 nfy->wfd = wfd; 268 return 1; 269 270 err: 271 if (lfd != INVALID_SOCKET) 272 BIO_closesocket(lfd); 273 if (wfd != INVALID_SOCKET) 274 BIO_closesocket(wfd); 275 if (rfd != INVALID_SOCKET) 276 BIO_closesocket(rfd); 277 return 0; 278 } 279 280 #elif RIO_NOTIFIER_METHOD == RIO_NOTIFIER_METHOD_SOCKETPAIR 281 282 int ossl_rio_notifier_init(RIO_NOTIFIER *nfy) 283 { 284 int fds[2], domain = AF_INET, type = SOCK_STREAM; 285 286 # if defined(SOCK_CLOEXEC) 287 type |= SOCK_CLOEXEC; 288 # endif 289 # if defined(SOCK_NONBLOCK) 290 type |= SOCK_NONBLOCK; 291 # endif 292 293 # if defined(OPENSSL_SYS_UNIX) && defined(AF_UNIX) 294 domain = AF_UNIX; 295 # endif 296 297 if (socketpair(domain, type, 0, fds) < 0) { 298 ERR_raise_data(ERR_LIB_SYS, get_last_sys_error(), 299 "calling socketpair()"); 300 return 0; 301 } 302 303 if (!set_cloexec(fds[0]) || !set_cloexec(fds[1])) { 304 ERR_raise_data(ERR_LIB_SYS, get_last_sys_error(), 305 "calling set_cloexec()"); 306 goto err; 307 } 308 309 # if !defined(SOCK_NONBLOCK) 310 if (!BIO_socket_nbio(fds[0], 1) || !BIO_socket_nbio(fds[1], 1)) { 311 ERR_raise_data(ERR_LIB_SYS, get_last_sys_error(), 312 "calling BIO_socket_nbio()"); 313 goto err; 314 } 315 # endif 316 317 if (domain == AF_INET && !BIO_set_tcp_ndelay(fds[1], 1)) { 318 ERR_raise_data(ERR_LIB_SYS, get_last_sys_error(), 319 "calling BIO_set_tcp_ndelay()"); 320 goto err; 321 } 322 323 nfy->rfd = fds[0]; 324 nfy->wfd = fds[1]; 325 return 1; 326 327 err: 328 BIO_closesocket(fds[1]); 329 BIO_closesocket(fds[0]); 330 return 0; 331 } 332 333 #endif 334 335 void ossl_rio_notifier_cleanup(RIO_NOTIFIER *nfy) 336 { 337 if (nfy->rfd < 0) 338 return; 339 340 BIO_closesocket(nfy->wfd); 341 BIO_closesocket(nfy->rfd); 342 nfy->rfd = nfy->wfd = -1; 343 } 344 345 int ossl_rio_notifier_signal(RIO_NOTIFIER *nfy) 346 { 347 static const unsigned char ch = 0; 348 ossl_ssize_t wr; 349 350 do 351 /* 352 * Note: If wr returns 0 the buffer is already full so we don't need to 353 * do anything. 354 */ 355 wr = writesocket(nfy->wfd, (void *)&ch, sizeof(ch)); 356 while (wr < 0 && get_last_socket_error_is_eintr()); 357 358 return 1; 359 } 360 361 int ossl_rio_notifier_unsignal(RIO_NOTIFIER *nfy) 362 { 363 unsigned char buf[16]; 364 ossl_ssize_t rd; 365 366 /* 367 * signal() might have been called multiple times. Drain the buffer until 368 * it's empty. 369 */ 370 do 371 rd = readsocket(nfy->rfd, (void *)buf, sizeof(buf)); 372 while (rd == sizeof(buf) 373 || (rd < 0 && get_last_socket_error_is_eintr())); 374 375 if (rd < 0 && !BIO_fd_non_fatal_error(get_last_socket_error())) 376 return 0; 377 378 return 1; 379 } 380