Rizin
unix-like reverse engineering framework and cli tools
process-stdio.c
Go to the documentation of this file.
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  */
75  HANDLE handle;
76  STARTUPINFOW si;
77 
78  /* Make the windows stdio handles non-inheritable. */
79  handle = GetStdHandle(STD_INPUT_HANDLE);
81  SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
82 
83  handle = GetStdHandle(STD_OUTPUT_HANDLE);
85  SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
86 
87  handle = GetStdHandle(STD_ERROR_HANDLE);
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 
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. */
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 
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) {
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)) {
220  return GetLastError();
221  }
222 
223  return 0;
224 }
225 
226 
228  HANDLE handle;
229 
230  if (fd == -1) {
232  return ERROR_INVALID_HANDLE;
233  }
234 
237 }
238 
239 
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 
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 */
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. */
291  for (i = 0; i < count; i++) {
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 |
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 
318  access);
319  if (err)
320  goto error;
321 
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 
340  parent_pipe,
341  &child_pipe,
342  fdopt.flags);
343  if (err)
344  goto error;
345 
346  CHILD_STDIO_HANDLE(buffer, i) = child_pipe;
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) {
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:
372  break;
373 
374  case FILE_TYPE_PIPE:
376  break;
377 
378  case FILE_TYPE_CHAR:
379  case FILE_TYPE_REMOTE:
381  break;
382 
383  case FILE_TYPE_UNKNOWN:
384  if (GetLastError() != 0) {
385  err = GetLastError();
386  CloseHandle(child_handle);
387  goto error;
388  }
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:
449  return err;
450 }
451 
452 
454  int i, count;
455 
457  for (i = 0; i < count; i++) {
459  if (handle != INVALID_HANDLE_VALUE) {
460  CloseHandle(handle);
461  }
462  }
463 
464  uv__free(buffer);
465 }
466 
467 
469  int i, count;
470 
472  for (i = 0; i < count; i++) {
474  if (handle != INVALID_HANDLE_VALUE) {
475  SetHandleInformation(handle, HANDLE_FLAG_INHERIT, 0);
476  }
477  }
478 }
479 
480 
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. */
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 
506  return (WORD) CHILD_STDIO_SIZE(CHILD_STDIO_COUNT((buffer)));
507 }
508 
509 
511  return CHILD_STDIO_HANDLE(buffer, fd);
512 }
si
lzma_index ** i
Definition: index.h:629
static bool err
Definition: armass.c:435
static mcore_handle handle
Definition: asm_mcore.c:8
struct buffer buffer
#define NULL
Definition: cris-opc.c:27
#define r
Definition: crypto_rc6.c:12
static static sync static getppid static getegid const char static filename char static len const char char static bufsiz static mask static vfork const void static prot static getpgrp const char static swapflags static arg static fd static protocol static who struct sockaddr static addrlen static backlog struct timeval struct timezone static tz const struct iovec static count static mode const void const struct sockaddr static tolen const char static pathname void count
Definition: sflib.h:98
static INLINE HANDLE uv__get_osfhandle(int fd)
Definition: handle-inl.h:166
voidpf void uLong size
Definition: ioapi.h:138
voidpf stream
Definition: ioapi.h:138
const char int mode
Definition: ioapi.h:137
#define INVALID_HANDLE_VALUE
Definition: iowin32.c:21
static static fork const void static count static fd const char const char static newpath char char char static envp time_t static t const char static mode static whence const char static dir time_t static t unsigned static seconds const char struct utimbuf static buf static inc static sig const char static mode dup
Definition: sflib.h:68
static static fork const void static count static fd const char static mode const char static pathname const char static path const char static dev const char static group static getpid static getuid void void static data static pause access
Definition: sflib.h:64
static const char struct stat static buf struct stat static buf static vhangup int options
Definition: sflib.h:145
unsigned char BYTE
Definition: lz4.c:286
assert(limit<=UINT32_MAX/2)
#define TRUE
Definition: mybfd.h:103
static int uv__create_stdio_pipe_pair(uv_loop_t *loop, uv_pipe_t *server_pipe, HANDLE *child_pipe_ptr, unsigned int flags)
Definition: process-stdio.c:98
#define CHILD_STDIO_CRT_FLAGS(buffer, fd)
Definition: process-stdio.c:46
static int uv__duplicate_handle(uv_loop_t *loop, HANDLE handle, HANDLE *dup)
void uv__stdio_noinherit(BYTE *buffer)
void uv__stdio_destroy(BYTE *buffer)
void uv_disable_stdio_inheritance(void)
Definition: process-stdio.c:74
static int uv__duplicate_fd(uv_loop_t *loop, int fd, HANDLE *dup)
#define FPIPE
Definition: process-stdio.c:61
#define FOPEN
Definition: process-stdio.c:58
WORD uv__stdio_size(BYTE *buffer)
int uv__stdio_create(uv_loop_t *loop, const uv_process_options_t *options, BYTE **buffer_ptr)
#define FDEV
Definition: process-stdio.c:64
int uv__create_nul_handle(HANDLE *handle_ptr, DWORD access)
#define CHILD_STDIO_COUNT(buffer)
Definition: process-stdio.c:43
int uv__stdio_verify(BYTE *buffer, WORD size)
#define CHILD_STDIO_HANDLE(buffer, fd)
Definition: process-stdio.c:49
HANDLE uv__stdio_handle(BYTE *buffer, int fd)
#define CHILD_STDIO_SIZE(count)
Definition: process-stdio.c:38
static struct sockaddr static addrlen static backlog const void static flags void flags
Definition: sfsocketcall.h:123
Definition: buffer.h:15
Definition: uv.h:1780
Definition: uv.h:767
UV_HANDLE_FIELDS UV_STREAM_FIELDS int ipc
Definition: uv.h:770
uv_stream_t * stream
Definition: uv.h:946
uv_stdio_flags flags
Definition: uv.h:943
union uv_stdio_container_s::@397 data
Definition: uv.h:714
uv_loop_t * loop
Definition: main.c:7
int uv_stdio_pipe_server(uv_loop_t *loop, uv_pipe_t *handle, DWORD access, char *name, size_t nameSize)
Definition: pipe.c:205
void uv_pipe_cleanup(uv_loop_t *loop, uv_pipe_t *handle)
Definition: pipe.c:785
void error(const char *msg)
Definition: untgz.c:593
void * uv__malloc(size_t size)
Definition: uv-common.c:75
void uv__free(void *ptr)
Definition: uv-common.c:81
@ UV_HANDLE_PIPESERVER
Definition: uv-common.h:119
@ UV_HANDLE_CONNECTION
Definition: uv-common.h:83
@ UV_HANDLE_WRITABLE
Definition: uv-common.h:93
@ UV_HANDLE_READABLE
Definition: uv-common.h:92
@ UV_INHERIT_FD
Definition: uv.h:924
@ UV_CREATE_PIPE
Definition: uv.h:923
@ UV_WRITABLE_PIPE
Definition: uv.h:933
@ UV_IGNORE
Definition: uv.h:922
@ UV_OVERLAPPED_PIPE
Definition: uv.h:939
@ UV_INHERIT_STREAM
Definition: uv.h:925
@ UV_READABLE_PIPE
Definition: uv.h:932
DWORD * HANDLE
DWORD
static const z80_opcode fd[]
Definition: z80_tab.h:997
#define L
Definition: zip_err_str.c:7