Home | History | Annotate | Line # | Download | only in win
      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