1 /* Copyright Joyent, Inc. and other Node contributors. All rights reserved. 2 * 3 * Permission is hereby granted, free of charge, to any person obtaining a copy 4 * of this software and associated documentation files (the "Software"), to 5 * deal in the Software without restriction, including without limitation the 6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 7 * sell copies of the Software, and to permit persons to whom the Software is 8 * furnished to do so, subject to the following conditions: 9 * 10 * The above copyright notice and this permission notice shall be included in 11 * all copies or substantial portions of the Software. 12 * 13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 19 * IN THE SOFTWARE. 20 */ 21 22 #include <assert.h> 23 #include <io.h> 24 #include <stdio.h> 25 #include <stdlib.h> 26 27 #include "uv.h" 28 #include "internal.h" 29 #include "handle-inl.h" 30 31 32 /* 33 * The `child_stdio_buffer` buffer has the following layout: 34 * int number_of_fds 35 * unsigned char crt_flags[number_of_fds] 36 * HANDLE os_handle[number_of_fds] 37 */ 38 #define CHILD_STDIO_SIZE(count) \ 39 (sizeof(int) + \ 40 sizeof(unsigned char) * (count) + \ 41 sizeof(uintptr_t) * (count)) 42 43 #define CHILD_STDIO_COUNT(buffer) \ 44 *((unsigned int*) (buffer)) 45 46 #define CHILD_STDIO_CRT_FLAGS(buffer, fd) \ 47 *((unsigned char*) (buffer) + sizeof(int) + fd) 48 49 #define CHILD_STDIO_HANDLE(buffer, fd) \ 50 ((void*) ((unsigned char*) (buffer) + \ 51 sizeof(int) + \ 52 sizeof(unsigned char) * \ 53 CHILD_STDIO_COUNT((buffer)) + \ 54 sizeof(HANDLE) * (fd))) 55 56 57 /* CRT file descriptor mode flags */ 58 #define FOPEN 0x01 59 #define FEOFLAG 0x02 60 #define FCRLF 0x04 61 #define FPIPE 0x08 62 #define FNOINHERIT 0x10 63 #define FAPPEND 0x20 64 #define FDEV 0x40 65 #define FTEXT 0x80 66 67 68 /* 69 * Clear the HANDLE_FLAG_INHERIT flag from all HANDLEs that were inherited 70 * the parent process. Don't check for errors - the stdio handles may not be 71 * valid, or may be closed already. There is no guarantee that this function 72 * does a perfect job. 73 */ 74 void uv_disable_stdio_inheritance(void) { 75 HANDLE handle; 76 STARTUPINFOW si; 77 78 /* Make the windows stdio handles non-inheritable. */ 79 handle = GetStdHandle(STD_INPUT_HANDLE); 80 if (handle != NULL && handle != INVALID_HANDLE_VALUE) 81 SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0); 82 83 handle = GetStdHandle(STD_OUTPUT_HANDLE); 84 if (handle != NULL && handle != INVALID_HANDLE_VALUE) 85 SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0); 86 87 handle = GetStdHandle(STD_ERROR_HANDLE); 88 if (handle != NULL && handle != INVALID_HANDLE_VALUE) 89 SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0); 90 91 /* Make inherited CRT FDs non-inheritable. */ 92 GetStartupInfoW(&si); 93 if (uv__stdio_verify(si.lpReserved2, si.cbReserved2)) 94 uv__stdio_noinherit(si.lpReserved2); 95 } 96 97 98 static int uv__duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) { 99 HANDLE current_process; 100 101 102 /* _get_osfhandle will sometimes return -2 in case of an error. This seems to 103 * happen when fd <= 2 and the process' corresponding stdio handle is set to 104 * NULL. Unfortunately DuplicateHandle will happily duplicate (HANDLE) -2, so 105 * this situation goes unnoticed until someone tries to use the duplicate. 106 * Therefore we filter out known-invalid handles here. */ 107 if (handle == INVALID_HANDLE_VALUE || 108 handle == NULL || 109 handle == (HANDLE) -2) { 110 *dup = INVALID_HANDLE_VALUE; 111 return ERROR_INVALID_HANDLE; 112 } 113 114 current_process = GetCurrentProcess(); 115 116 if (!DuplicateHandle(current_process, 117 handle, 118 current_process, 119 dup, 120 0, 121 TRUE, 122 DUPLICATE_SAME_ACCESS)) { 123 *dup = INVALID_HANDLE_VALUE; 124 return GetLastError(); 125 } 126 127 return 0; 128 } 129 130 131 static int uv__duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) { 132 HANDLE handle; 133 134 if (fd == -1) { 135 *dup = INVALID_HANDLE_VALUE; 136 return ERROR_INVALID_HANDLE; 137 } 138 139 handle = uv__get_osfhandle(fd); 140 return uv__duplicate_handle(loop, handle, dup); 141 } 142 143 144 int uv__create_nul_handle(HANDLE* handle_ptr, 145 DWORD access) { 146 HANDLE handle; 147 SECURITY_ATTRIBUTES sa; 148 149 sa.nLength = sizeof sa; 150 sa.lpSecurityDescriptor = NULL; 151 sa.bInheritHandle = TRUE; 152 153 handle = CreateFileW(L"NUL", 154 access, 155 FILE_SHARE_READ | FILE_SHARE_WRITE, 156 &sa, 157 OPEN_EXISTING, 158 0, 159 NULL); 160 if (handle == INVALID_HANDLE_VALUE) { 161 return GetLastError(); 162 } 163 164 *handle_ptr = handle; 165 return 0; 166 } 167 168 169 int uv__stdio_create(uv_loop_t* loop, 170 const uv_process_options_t* options, 171 BYTE** buffer_ptr) { 172 BYTE* buffer; 173 int count, i; 174 int err; 175 176 count = options->stdio_count; 177 178 if (count < 0 || count > 255) { 179 /* Only support FDs 0-255 */ 180 return ERROR_NOT_SUPPORTED; 181 } else if (count < 3) { 182 /* There should always be at least 3 stdio handles. */ 183 count = 3; 184 } 185 186 /* Allocate the child stdio buffer */ 187 buffer = (BYTE*) uv__malloc(CHILD_STDIO_SIZE(count)); 188 if (buffer == NULL) { 189 return ERROR_OUTOFMEMORY; 190 } 191 192 /* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can clean 193 * up on failure. */ 194 CHILD_STDIO_COUNT(buffer) = count; 195 for (i = 0; i < count; i++) { 196 CHILD_STDIO_CRT_FLAGS(buffer, i) = 0; 197 memset(CHILD_STDIO_HANDLE(buffer, i), 0xFF, sizeof(HANDLE)); 198 } 199 200 for (i = 0; i < count; i++) { 201 uv_stdio_container_t fdopt; 202 if (i < options->stdio_count) { 203 fdopt = options->stdio[i]; 204 } else { 205 fdopt.flags = UV_IGNORE; 206 } 207 208 switch (fdopt.flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD | 209 UV_INHERIT_STREAM)) { 210 case UV_IGNORE: 211 /* Starting a process with no stdin/stout/stderr can confuse it. So no 212 * matter what the user specified, we make sure the first three FDs are 213 * always open in their typical modes, e. g. stdin be readable and 214 * stdout/err should be writable. For FDs > 2, don't do anything - all 215 * handles in the stdio buffer are initialized with. 216 * INVALID_HANDLE_VALUE, which should be okay. */ 217 if (i <= 2) { 218 HANDLE nul; 219 DWORD access = (i == 0) ? FILE_GENERIC_READ : 220 FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES; 221 222 err = uv__create_nul_handle(&nul, access); 223 if (err) 224 goto error; 225 226 memcpy(CHILD_STDIO_HANDLE(buffer, i), &nul, sizeof(HANDLE)); 227 CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV; 228 } 229 break; 230 231 case UV_CREATE_PIPE: { 232 /* Create a pair of two connected pipe ends; one end is turned into an 233 * uv_pipe_t for use by the parent. The other one is given to the 234 * child. */ 235 uv_pipe_t* parent_pipe = (uv_pipe_t*) fdopt.data.stream; 236 HANDLE child_pipe = INVALID_HANDLE_VALUE; 237 238 /* Create a new, connected pipe pair. stdio[i]. stream should point to 239 * an uninitialized, but not connected pipe handle. */ 240 assert(fdopt.data.stream->type == UV_NAMED_PIPE); 241 assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION)); 242 assert(!(fdopt.data.stream->flags & UV_HANDLE_PIPESERVER)); 243 244 err = uv__create_stdio_pipe_pair(loop, 245 parent_pipe, 246 &child_pipe, 247 fdopt.flags); 248 if (err) 249 goto error; 250 251 memcpy(CHILD_STDIO_HANDLE(buffer, i), &child_pipe, sizeof(HANDLE)); 252 CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE; 253 break; 254 } 255 256 case UV_INHERIT_FD: { 257 /* Inherit a raw FD. */ 258 HANDLE child_handle; 259 260 /* Make an inheritable duplicate of the handle. */ 261 err = uv__duplicate_fd(loop, fdopt.data.fd, &child_handle); 262 if (err) { 263 /* If fdopt. data. fd is not valid and fd <= 2, then ignore the 264 * error. */ 265 if (fdopt.data.fd <= 2 && err == ERROR_INVALID_HANDLE) { 266 CHILD_STDIO_CRT_FLAGS(buffer, i) = 0; 267 memset(CHILD_STDIO_HANDLE(buffer, i), 0xFF, sizeof(HANDLE)); 268 break; 269 } 270 goto error; 271 } 272 273 /* Figure out what the type is. */ 274 switch (GetFileType(child_handle)) { 275 case FILE_TYPE_DISK: 276 CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN; 277 break; 278 279 case FILE_TYPE_PIPE: 280 CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE; 281 break; 282 283 case FILE_TYPE_CHAR: 284 case FILE_TYPE_REMOTE: 285 CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV; 286 break; 287 288 case FILE_TYPE_UNKNOWN: 289 if (GetLastError() != 0) { 290 err = GetLastError(); 291 CloseHandle(child_handle); 292 goto error; 293 } 294 CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV; 295 break; 296 297 default: 298 assert(0); 299 return -1; 300 } 301 302 memcpy(CHILD_STDIO_HANDLE(buffer, i), &child_handle, sizeof(HANDLE)); 303 break; 304 } 305 306 case UV_INHERIT_STREAM: { 307 /* Use an existing stream as the stdio handle for the child. */ 308 HANDLE stream_handle, child_handle; 309 unsigned char crt_flags; 310 uv_stream_t* stream = fdopt.data.stream; 311 312 /* Leech the handle out of the stream. */ 313 if (stream->type == UV_TTY) { 314 stream_handle = ((uv_tty_t*) stream)->handle; 315 crt_flags = FOPEN | FDEV; 316 } else if (stream->type == UV_NAMED_PIPE && 317 stream->flags & UV_HANDLE_CONNECTION) { 318 stream_handle = ((uv_pipe_t*) stream)->handle; 319 crt_flags = FOPEN | FPIPE; 320 } else { 321 stream_handle = INVALID_HANDLE_VALUE; 322 crt_flags = 0; 323 } 324 325 if (stream_handle == NULL || 326 stream_handle == INVALID_HANDLE_VALUE) { 327 /* The handle is already closed, or not yet created, or the stream 328 * type is not supported. */ 329 err = ERROR_NOT_SUPPORTED; 330 goto error; 331 } 332 333 /* Make an inheritable copy of the handle. */ 334 err = uv__duplicate_handle(loop, stream_handle, &child_handle); 335 if (err) 336 goto error; 337 338 memcpy(CHILD_STDIO_HANDLE(buffer, i), &child_handle, sizeof(HANDLE)); 339 CHILD_STDIO_CRT_FLAGS(buffer, i) = crt_flags; 340 break; 341 } 342 343 default: 344 assert(0); 345 return -1; 346 } 347 } 348 349 *buffer_ptr = buffer; 350 return 0; 351 352 error: 353 uv__stdio_destroy(buffer); 354 return err; 355 } 356 357 358 void uv__stdio_destroy(BYTE* buffer) { 359 int i, count; 360 361 count = CHILD_STDIO_COUNT(buffer); 362 for (i = 0; i < count; i++) { 363 HANDLE handle = uv__stdio_handle(buffer, i); 364 if (handle != INVALID_HANDLE_VALUE) { 365 CloseHandle(handle); 366 } 367 } 368 369 uv__free(buffer); 370 } 371 372 373 void uv__stdio_noinherit(BYTE* buffer) { 374 int i, count; 375 376 count = CHILD_STDIO_COUNT(buffer); 377 for (i = 0; i < count; i++) { 378 HANDLE handle = uv__stdio_handle(buffer, i); 379 if (handle != INVALID_HANDLE_VALUE) { 380 SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0); 381 } 382 } 383 } 384 385 386 int uv__stdio_verify(BYTE* buffer, WORD size) { 387 unsigned int count; 388 389 /* Check the buffer pointer. */ 390 if (buffer == NULL) 391 return 0; 392 393 /* Verify that the buffer is at least big enough to hold the count. */ 394 if (size < CHILD_STDIO_SIZE(0)) 395 return 0; 396 397 /* Verify if the count is within range. */ 398 count = CHILD_STDIO_COUNT(buffer); 399 if (count > 256) 400 return 0; 401 402 /* Verify that the buffer size is big enough to hold info for N FDs. */ 403 if (size < CHILD_STDIO_SIZE(count)) 404 return 0; 405 406 return 1; 407 } 408 409 410 WORD uv__stdio_size(BYTE* buffer) { 411 return (WORD) CHILD_STDIO_SIZE(CHILD_STDIO_COUNT((buffer))); 412 } 413 414 415 HANDLE uv__stdio_handle(BYTE* buffer, int fd) { 416 HANDLE handle; 417 memcpy(&handle, CHILD_STDIO_HANDLE(buffer, fd), sizeof(HANDLE)); 418 return handle; 419 } 420