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