xref: /libuv/src/win/process-stdio.c (revision 9b3b61f6)
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  */
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__duplicate_handle(uv_loop_t * loop,HANDLE handle,HANDLE * dup)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 
uv__duplicate_fd(uv_loop_t * loop,int fd,HANDLE * dup)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 
uv__create_nul_handle(HANDLE * handle_ptr,DWORD access)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 
uv__stdio_create(uv_loop_t * loop,const uv_process_options_t * options,BYTE ** buffer_ptr)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 
uv__stdio_destroy(BYTE * buffer)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 
uv__stdio_noinherit(BYTE * buffer)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 
uv__stdio_verify(BYTE * buffer,WORD size)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 
uv__stdio_size(BYTE * buffer)410 WORD uv__stdio_size(BYTE* buffer) {
411   return (WORD) CHILD_STDIO_SIZE(CHILD_STDIO_COUNT((buffer)));
412 }
413 
414 
uv__stdio_handle(BYTE * buffer,int fd)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