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     *((HANDLE*) ((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  */
uv_disable_stdio_inheritance(void)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 
uv__create_stdio_pipe_pair(uv_loop_t * loop,uv_pipe_t * server_pipe,HANDLE * child_pipe_ptr,unsigned int flags)98 static int uv__create_stdio_pipe_pair(uv_loop_t* loop,
99     uv_pipe_t* server_pipe, HANDLE* child_pipe_ptr, unsigned int flags) {
100   char pipe_name[64];
101   SECURITY_ATTRIBUTES sa;
102   DWORD server_access = 0;
103   DWORD client_access = 0;
104   HANDLE child_pipe = INVALID_HANDLE_VALUE;
105   int err;
106   int overlap;
107 
108   if (flags & UV_READABLE_PIPE) {
109     /* The server needs inbound access too, otherwise CreateNamedPipe() won't
110      * give us the FILE_READ_ATTRIBUTES permission. We need that to probe the
111      * state of the write buffer when we're trying to shutdown the pipe. */
112     server_access |= PIPE_ACCESS_OUTBOUND | PIPE_ACCESS_INBOUND;
113     client_access |= GENERIC_READ | FILE_WRITE_ATTRIBUTES;
114   }
115   if (flags & UV_WRITABLE_PIPE) {
116     server_access |= PIPE_ACCESS_INBOUND;
117     client_access |= GENERIC_WRITE | FILE_READ_ATTRIBUTES;
118   }
119 
120   /* Create server pipe handle. */
121   err = uv_stdio_pipe_server(loop,
122                              server_pipe,
123                              server_access,
124                              pipe_name,
125                              sizeof(pipe_name));
126   if (err)
127     goto error;
128 
129   /* Create child pipe handle. */
130   sa.nLength = sizeof sa;
131   sa.lpSecurityDescriptor = NULL;
132   sa.bInheritHandle = TRUE;
133 
134   overlap = server_pipe->ipc || (flags & UV_OVERLAPPED_PIPE);
135   child_pipe = CreateFileA(pipe_name,
136                            client_access,
137                            0,
138                            &sa,
139                            OPEN_EXISTING,
140                            overlap ? FILE_FLAG_OVERLAPPED : 0,
141                            NULL);
142   if (child_pipe == INVALID_HANDLE_VALUE) {
143     err = GetLastError();
144     goto error;
145   }
146 
147 #ifndef NDEBUG
148   /* Validate that the pipe was opened in the right mode. */
149   {
150     DWORD mode;
151     BOOL r = GetNamedPipeHandleState(child_pipe,
152                                      &mode,
153                                      NULL,
154                                      NULL,
155                                      NULL,
156                                      NULL,
157                                      0);
158     assert(r == TRUE);
159     assert(mode == (PIPE_READMODE_BYTE | PIPE_WAIT));
160   }
161 #endif
162 
163   /* Do a blocking ConnectNamedPipe. This should not block because we have both
164    * ends of the pipe created. */
165   if (!ConnectNamedPipe(server_pipe->handle, NULL)) {
166     if (GetLastError() != ERROR_PIPE_CONNECTED) {
167       err = GetLastError();
168       goto error;
169     }
170   }
171 
172   /* The server end is now readable and/or writable. */
173   if (flags & UV_READABLE_PIPE)
174     server_pipe->flags |= UV_HANDLE_WRITABLE;
175   if (flags & UV_WRITABLE_PIPE)
176     server_pipe->flags |= UV_HANDLE_READABLE;
177 
178   *child_pipe_ptr = child_pipe;
179   return 0;
180 
181  error:
182   if (server_pipe->handle != INVALID_HANDLE_VALUE) {
183     uv_pipe_cleanup(loop, server_pipe);
184   }
185 
186   if (child_pipe != INVALID_HANDLE_VALUE) {
187     CloseHandle(child_pipe);
188   }
189 
190   return err;
191 }
192 
193 
uv__duplicate_handle(uv_loop_t * loop,HANDLE handle,HANDLE * dup)194 static int uv__duplicate_handle(uv_loop_t* loop, HANDLE handle, HANDLE* dup) {
195   HANDLE current_process;
196 
197 
198   /* _get_osfhandle will sometimes return -2 in case of an error. This seems to
199    * happen when fd <= 2 and the process' corresponding stdio handle is set to
200    * NULL. Unfortunately DuplicateHandle will happily duplicate (HANDLE) -2, so
201    * this situation goes unnoticed until someone tries to use the duplicate.
202    * Therefore we filter out known-invalid handles here. */
203   if (handle == INVALID_HANDLE_VALUE ||
204       handle == NULL ||
205       handle == (HANDLE) -2) {
206     *dup = INVALID_HANDLE_VALUE;
207     return ERROR_INVALID_HANDLE;
208   }
209 
210   current_process = GetCurrentProcess();
211 
212   if (!DuplicateHandle(current_process,
213                        handle,
214                        current_process,
215                        dup,
216                        0,
217                        TRUE,
218                        DUPLICATE_SAME_ACCESS)) {
219     *dup = INVALID_HANDLE_VALUE;
220     return GetLastError();
221   }
222 
223   return 0;
224 }
225 
226 
uv__duplicate_fd(uv_loop_t * loop,int fd,HANDLE * dup)227 static int uv__duplicate_fd(uv_loop_t* loop, int fd, HANDLE* dup) {
228   HANDLE handle;
229 
230   if (fd == -1) {
231     *dup = INVALID_HANDLE_VALUE;
232     return ERROR_INVALID_HANDLE;
233   }
234 
235   handle = uv__get_osfhandle(fd);
236   return uv__duplicate_handle(loop, handle, dup);
237 }
238 
239 
uv__create_nul_handle(HANDLE * handle_ptr,DWORD access)240 int uv__create_nul_handle(HANDLE* handle_ptr,
241     DWORD access) {
242   HANDLE handle;
243   SECURITY_ATTRIBUTES sa;
244 
245   sa.nLength = sizeof sa;
246   sa.lpSecurityDescriptor = NULL;
247   sa.bInheritHandle = TRUE;
248 
249   handle = CreateFileW(L"NUL",
250                        access,
251                        FILE_SHARE_READ | FILE_SHARE_WRITE,
252                        &sa,
253                        OPEN_EXISTING,
254                        0,
255                        NULL);
256   if (handle == INVALID_HANDLE_VALUE) {
257     return GetLastError();
258   }
259 
260   *handle_ptr = handle;
261   return 0;
262 }
263 
264 
uv__stdio_create(uv_loop_t * loop,const uv_process_options_t * options,BYTE ** buffer_ptr)265 int uv__stdio_create(uv_loop_t* loop,
266                      const uv_process_options_t* options,
267                      BYTE** buffer_ptr) {
268   BYTE* buffer;
269   int count, i;
270   int err;
271 
272   count = options->stdio_count;
273 
274   if (count < 0 || count > 255) {
275     /* Only support FDs 0-255 */
276     return ERROR_NOT_SUPPORTED;
277   } else if (count < 3) {
278     /* There should always be at least 3 stdio handles. */
279     count = 3;
280   }
281 
282   /* Allocate the child stdio buffer */
283   buffer = (BYTE*) uv__malloc(CHILD_STDIO_SIZE(count));
284   if (buffer == NULL) {
285     return ERROR_OUTOFMEMORY;
286   }
287 
288   /* Prepopulate the buffer with INVALID_HANDLE_VALUE handles so we can clean
289    * up on failure. */
290   CHILD_STDIO_COUNT(buffer) = count;
291   for (i = 0; i < count; i++) {
292     CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
293     CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
294   }
295 
296   for (i = 0; i < count; i++) {
297     uv_stdio_container_t fdopt;
298     if (i < options->stdio_count) {
299       fdopt = options->stdio[i];
300     } else {
301       fdopt.flags = UV_IGNORE;
302     }
303 
304     switch (fdopt.flags & (UV_IGNORE | UV_CREATE_PIPE | UV_INHERIT_FD |
305             UV_INHERIT_STREAM)) {
306       case UV_IGNORE:
307         /* Starting a process with no stdin/stout/stderr can confuse it. So no
308          * matter what the user specified, we make sure the first three FDs are
309          * always open in their typical modes, e. g. stdin be readable and
310          * stdout/err should be writable. For FDs > 2, don't do anything - all
311          * handles in the stdio buffer are initialized with.
312          * INVALID_HANDLE_VALUE, which should be okay. */
313         if (i <= 2) {
314           DWORD access = (i == 0) ? FILE_GENERIC_READ :
315                                     FILE_GENERIC_WRITE | FILE_READ_ATTRIBUTES;
316 
317           err = uv__create_nul_handle(&CHILD_STDIO_HANDLE(buffer, i),
318                                       access);
319           if (err)
320             goto error;
321 
322           CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
323         }
324         break;
325 
326       case UV_CREATE_PIPE: {
327         /* Create a pair of two connected pipe ends; one end is turned into an
328          * uv_pipe_t for use by the parent. The other one is given to the
329          * child. */
330         uv_pipe_t* parent_pipe = (uv_pipe_t*) fdopt.data.stream;
331         HANDLE child_pipe = INVALID_HANDLE_VALUE;
332 
333         /* Create a new, connected pipe pair. stdio[i]. stream should point to
334          * an uninitialized, but not connected pipe handle. */
335         assert(fdopt.data.stream->type == UV_NAMED_PIPE);
336         assert(!(fdopt.data.stream->flags & UV_HANDLE_CONNECTION));
337         assert(!(fdopt.data.stream->flags & UV_HANDLE_PIPESERVER));
338 
339         err = uv__create_stdio_pipe_pair(loop,
340                                          parent_pipe,
341                                          &child_pipe,
342                                          fdopt.flags);
343         if (err)
344           goto error;
345 
346         CHILD_STDIO_HANDLE(buffer, i) = child_pipe;
347         CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
348         break;
349       }
350 
351       case UV_INHERIT_FD: {
352         /* Inherit a raw FD. */
353         HANDLE child_handle;
354 
355         /* Make an inheritable duplicate of the handle. */
356         err = uv__duplicate_fd(loop, fdopt.data.fd, &child_handle);
357         if (err) {
358           /* If fdopt. data. fd is not valid and fd <= 2, then ignore the
359            * error. */
360           if (fdopt.data.fd <= 2 && err == ERROR_INVALID_HANDLE) {
361             CHILD_STDIO_CRT_FLAGS(buffer, i) = 0;
362             CHILD_STDIO_HANDLE(buffer, i) = INVALID_HANDLE_VALUE;
363             break;
364           }
365           goto error;
366         }
367 
368         /* Figure out what the type is. */
369         switch (GetFileType(child_handle)) {
370           case FILE_TYPE_DISK:
371             CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN;
372             break;
373 
374           case FILE_TYPE_PIPE:
375             CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FPIPE;
376             break;
377 
378           case FILE_TYPE_CHAR:
379           case FILE_TYPE_REMOTE:
380             CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
381             break;
382 
383           case FILE_TYPE_UNKNOWN:
384             if (GetLastError() != 0) {
385               err = GetLastError();
386               CloseHandle(child_handle);
387               goto error;
388             }
389             CHILD_STDIO_CRT_FLAGS(buffer, i) = FOPEN | FDEV;
390             break;
391 
392           default:
393             assert(0);
394             return -1;
395         }
396 
397         CHILD_STDIO_HANDLE(buffer, i) = child_handle;
398         break;
399       }
400 
401       case UV_INHERIT_STREAM: {
402         /* Use an existing stream as the stdio handle for the child. */
403         HANDLE stream_handle, child_handle;
404         unsigned char crt_flags;
405         uv_stream_t* stream = fdopt.data.stream;
406 
407         /* Leech the handle out of the stream. */
408         if (stream->type == UV_TTY) {
409           stream_handle = ((uv_tty_t*) stream)->handle;
410           crt_flags = FOPEN | FDEV;
411         } else if (stream->type == UV_NAMED_PIPE &&
412                    stream->flags & UV_HANDLE_CONNECTION) {
413           stream_handle = ((uv_pipe_t*) stream)->handle;
414           crt_flags = FOPEN | FPIPE;
415         } else {
416           stream_handle = INVALID_HANDLE_VALUE;
417           crt_flags = 0;
418         }
419 
420         if (stream_handle == NULL ||
421             stream_handle == INVALID_HANDLE_VALUE) {
422           /* The handle is already closed, or not yet created, or the stream
423            * type is not supported. */
424           err = ERROR_NOT_SUPPORTED;
425           goto error;
426         }
427 
428         /* Make an inheritable copy of the handle. */
429         err = uv__duplicate_handle(loop, stream_handle, &child_handle);
430         if (err)
431           goto error;
432 
433         CHILD_STDIO_HANDLE(buffer, i) = child_handle;
434         CHILD_STDIO_CRT_FLAGS(buffer, i) = crt_flags;
435         break;
436       }
437 
438       default:
439         assert(0);
440         return -1;
441     }
442   }
443 
444   *buffer_ptr  = buffer;
445   return 0;
446 
447  error:
448   uv__stdio_destroy(buffer);
449   return err;
450 }
451 
452 
uv__stdio_destroy(BYTE * buffer)453 void uv__stdio_destroy(BYTE* buffer) {
454   int i, count;
455 
456   count = CHILD_STDIO_COUNT(buffer);
457   for (i = 0; i < count; i++) {
458     HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
459     if (handle != INVALID_HANDLE_VALUE) {
460       CloseHandle(handle);
461     }
462   }
463 
464   uv__free(buffer);
465 }
466 
467 
uv__stdio_noinherit(BYTE * buffer)468 void uv__stdio_noinherit(BYTE* buffer) {
469   int i, count;
470 
471   count = CHILD_STDIO_COUNT(buffer);
472   for (i = 0; i < count; i++) {
473     HANDLE handle = CHILD_STDIO_HANDLE(buffer, i);
474     if (handle != INVALID_HANDLE_VALUE) {
475       SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
476     }
477   }
478 }
479 
480 
uv__stdio_verify(BYTE * buffer,WORD size)481 int uv__stdio_verify(BYTE* buffer, WORD size) {
482   unsigned int count;
483 
484   /* Check the buffer pointer. */
485   if (buffer == NULL)
486     return 0;
487 
488   /* Verify that the buffer is at least big enough to hold the count. */
489   if (size < CHILD_STDIO_SIZE(0))
490     return 0;
491 
492   /* Verify if the count is within range. */
493   count = CHILD_STDIO_COUNT(buffer);
494   if (count > 256)
495     return 0;
496 
497   /* Verify that the buffer size is big enough to hold info for N FDs. */
498   if (size < CHILD_STDIO_SIZE(count))
499     return 0;
500 
501   return 1;
502 }
503 
504 
uv__stdio_size(BYTE * buffer)505 WORD uv__stdio_size(BYTE* buffer) {
506   return (WORD) CHILD_STDIO_SIZE(CHILD_STDIO_COUNT((buffer)));
507 }
508 
509 
uv__stdio_handle(BYTE * buffer,int fd)510 HANDLE uv__stdio_handle(BYTE* buffer, int fd) {
511   return CHILD_STDIO_HANDLE(buffer, fd);
512 }
513