ntdll: Fix use-after-free.
[wine.git] / dlls / ntdll / unix / process.c
blobf5b8b5315cdbe421eb15d9b2f4dd741872f4c9bf
1 /*
2 * NT process handling
4 * Copyright 1996-1998 Marcus Meissner
5 * Copyright 2018, 2020 Alexandre Julliard
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
22 #if 0
23 #pragma makedep unix
24 #endif
26 #include "config.h"
27 #include "wine/port.h"
29 #include <errno.h>
30 #include <fcntl.h>
31 #include <signal.h>
32 #include <stdarg.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <time.h>
37 #ifdef HAVE_SYS_SOCKET_H
38 #include <sys/socket.h>
39 #endif
40 #ifdef HAVE_SYS_TIME_H
41 # include <sys/time.h>
42 #endif
43 #ifdef HAVE_SYS_TIMES_H
44 # include <sys/times.h>
45 #endif
46 #include <sys/types.h>
47 #ifdef HAVE_SYS_WAIT_H
48 # include <sys/wait.h>
49 #endif
50 #ifdef HAVE_UNISTD_H
51 # include <unistd.h>
52 #endif
53 #ifdef HAVE_MACH_MACH_H
54 # include <mach/mach.h>
55 #endif
57 #include "ntstatus.h"
58 #define WIN32_NO_STATUS
59 #include "windef.h"
60 #include "winternl.h"
61 #include "winioctl.h"
62 #include "unix_private.h"
63 #include "wine/condrv.h"
64 #include "wine/exception.h"
65 #include "wine/server.h"
66 #include "wine/debug.h"
68 WINE_DEFAULT_DEBUG_CHANNEL(process);
71 static ULONG execute_flags = MEM_EXECUTE_OPTION_DISABLE | (sizeof(void *) > sizeof(int) ?
72 MEM_EXECUTE_OPTION_DISABLE_THUNK_EMULATION |
73 MEM_EXECUTE_OPTION_PERMANENT : 0);
75 static UINT process_error_mode;
77 static char **build_argv( const UNICODE_STRING *cmdline, int reserved )
79 char **argv, *arg, *src, *dst;
80 int argc, in_quotes = 0, bcount = 0, len = cmdline->Length / sizeof(WCHAR);
82 if (!(src = malloc( len * 3 + 1 ))) return NULL;
83 len = ntdll_wcstoumbs( cmdline->Buffer, len, src, len * 3, FALSE );
84 src[len++] = 0;
86 argc = reserved + 2 + len / 2;
87 argv = malloc( argc * sizeof(*argv) + len );
88 arg = dst = (char *)(argv + argc);
89 argc = reserved;
90 while (*src)
92 if ((*src == ' ' || *src == '\t') && !in_quotes)
94 /* skip the remaining spaces */
95 while (*src == ' ' || *src == '\t') src++;
96 if (!*src) break;
97 /* close the argument and copy it */
98 *dst++ = 0;
99 argv[argc++] = arg;
100 /* start with a new argument */
101 arg = dst;
102 bcount = 0;
104 else if (*src == '\\')
106 *dst++ = *src++;
107 bcount++;
109 else if (*src == '"')
111 if ((bcount & 1) == 0)
113 /* Preceded by an even number of '\', this is half that
114 * number of '\', plus a '"' which we discard.
116 dst -= bcount / 2;
117 src++;
118 if (in_quotes && *src == '"') *dst++ = *src++;
119 else in_quotes = !in_quotes;
121 else
123 /* Preceded by an odd number of '\', this is half that
124 * number of '\' followed by a '"'
126 dst -= bcount / 2 + 1;
127 *dst++ = *src++;
129 bcount = 0;
131 else /* a regular character */
133 *dst++ = *src++;
134 bcount = 0;
137 *dst = 0;
138 argv[argc++] = arg;
139 argv[argc] = NULL;
140 return argv;
144 /***********************************************************************
145 * get_so_file_info
147 static BOOL get_so_file_info( int fd, pe_image_info_t *info )
149 union
151 struct
153 unsigned char magic[4];
154 unsigned char class;
155 unsigned char data;
156 unsigned char version;
157 unsigned char ignored1[9];
158 unsigned short type;
159 unsigned short machine;
160 unsigned char ignored2[8];
161 unsigned int phoff;
162 unsigned char ignored3[12];
163 unsigned short phnum;
164 } elf;
165 struct
167 unsigned char magic[4];
168 unsigned char class;
169 unsigned char data;
170 unsigned char ignored1[10];
171 unsigned short type;
172 unsigned short machine;
173 unsigned char ignored2[12];
174 unsigned __int64 phoff;
175 unsigned char ignored3[16];
176 unsigned short phnum;
177 } elf64;
178 struct
180 unsigned int magic;
181 unsigned int cputype;
182 unsigned int cpusubtype;
183 unsigned int filetype;
184 } macho;
185 IMAGE_DOS_HEADER mz;
186 } header;
188 off_t pos;
190 if (pread( fd, &header, sizeof(header), 0 ) != sizeof(header)) return FALSE;
192 if (!memcmp( header.elf.magic, "\177ELF", 4 ))
194 unsigned int type;
195 unsigned short phnum;
197 if (header.elf.version != 1 /* EV_CURRENT */) return FALSE;
198 #ifdef WORDS_BIGENDIAN
199 if (header.elf.data != 2 /* ELFDATA2MSB */) return FALSE;
200 #else
201 if (header.elf.data != 1 /* ELFDATA2LSB */) return FALSE;
202 #endif
203 switch (header.elf.machine)
205 case 3: info->machine = IMAGE_FILE_MACHINE_I386; break;
206 case 40: info->machine = IMAGE_FILE_MACHINE_ARMNT; break;
207 case 62: info->machine = IMAGE_FILE_MACHINE_AMD64; break;
208 case 183: info->machine = IMAGE_FILE_MACHINE_ARM64; break;
210 if (header.elf.type != 3 /* ET_DYN */) return FALSE;
211 if (header.elf.class == 2 /* ELFCLASS64 */)
213 pos = header.elf64.phoff;
214 phnum = header.elf64.phnum;
216 else
218 pos = header.elf.phoff;
219 phnum = header.elf.phnum;
221 while (phnum--)
223 if (pread( fd, &type, sizeof(type), pos ) != sizeof(type)) return FALSE;
224 if (type == 3 /* PT_INTERP */) return FALSE;
225 pos += (header.elf.class == 2) ? 56 : 32;
227 return TRUE;
229 else if (header.macho.magic == 0xfeedface || header.macho.magic == 0xfeedfacf)
231 switch (header.macho.cputype)
233 case 0x00000007: info->machine = IMAGE_FILE_MACHINE_I386; break;
234 case 0x01000007: info->machine = IMAGE_FILE_MACHINE_AMD64; break;
235 case 0x0000000c: info->machine = IMAGE_FILE_MACHINE_ARMNT; break;
236 case 0x0100000c: info->machine = IMAGE_FILE_MACHINE_ARM64; break;
238 if (header.macho.filetype == 8) return TRUE;
240 return FALSE;
244 /***********************************************************************
245 * get_pe_file_info
247 static NTSTATUS get_pe_file_info( OBJECT_ATTRIBUTES *attr, HANDLE *handle, pe_image_info_t *info )
249 NTSTATUS status;
250 HANDLE mapping;
251 char *unix_name;
253 *handle = 0;
254 memset( info, 0, sizeof(*info) );
255 if (!(status = nt_to_unix_file_name( attr, &unix_name, FILE_OPEN )))
257 status = open_unix_file( handle, unix_name, GENERIC_READ, attr, 0,
258 FILE_SHARE_READ | FILE_SHARE_DELETE,
259 FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 );
260 free( unix_name );
262 if (status)
264 if (is_builtin_path( attr->ObjectName, &info->machine ))
266 TRACE( "assuming %04x builtin for %s\n", info->machine, debugstr_us(attr->ObjectName));
267 return STATUS_SUCCESS;
269 return status;
272 if (!(status = NtCreateSection( &mapping, STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
273 SECTION_MAP_READ | SECTION_MAP_EXECUTE,
274 NULL, NULL, PAGE_EXECUTE_READ, SEC_IMAGE, *handle )))
276 SERVER_START_REQ( get_mapping_info )
278 req->handle = wine_server_obj_handle( mapping );
279 req->access = SECTION_QUERY;
280 wine_server_set_reply( req, info, sizeof(*info) );
281 status = wine_server_call( req );
283 SERVER_END_REQ;
284 NtClose( mapping );
285 if (info->image_charact & IMAGE_FILE_DLL) return STATUS_INVALID_IMAGE_FORMAT;
287 else if (status == STATUS_INVALID_IMAGE_NOT_MZ)
289 int unix_fd, needs_close;
291 if (!server_get_unix_fd( *handle, FILE_READ_DATA, &unix_fd, &needs_close, NULL, NULL ))
293 if (get_so_file_info( unix_fd, info )) status = STATUS_SUCCESS;
294 if (needs_close) close( unix_fd );
297 return status;
301 /***********************************************************************
302 * get_env_size
304 static ULONG get_env_size( const RTL_USER_PROCESS_PARAMETERS *params, char **winedebug )
306 WCHAR *ptr = params->Environment;
308 while (*ptr)
310 static const WCHAR WINEDEBUG[] = {'W','I','N','E','D','E','B','U','G','=',0};
311 if (!*winedebug && !wcsncmp( ptr, WINEDEBUG, ARRAY_SIZE( WINEDEBUG ) - 1 ))
313 DWORD len = wcslen(ptr) * 3 + 1;
314 if ((*winedebug = malloc( len )))
315 ntdll_wcstoumbs( ptr, wcslen(ptr) + 1, *winedebug, len, FALSE );
317 ptr += wcslen(ptr) + 1;
319 ptr++;
320 return (ptr - params->Environment) * sizeof(WCHAR);
324 /***********************************************************************
325 * get_nt_pathname
327 * Simplified version of RtlDosPathNameToNtPathName_U.
329 static WCHAR *get_nt_pathname( const UNICODE_STRING *str )
331 static const WCHAR ntprefixW[] = {'\\','?','?','\\',0};
332 static const WCHAR uncprefixW[] = {'U','N','C','\\',0};
333 const WCHAR *name = str->Buffer;
334 WCHAR *ret;
336 if (!(ret = malloc( str->Length + 8 * sizeof(WCHAR) ))) return NULL;
338 wcscpy( ret, ntprefixW );
339 if (name[0] == '\\' && name[1] == '\\')
341 if ((name[2] == '.' || name[2] == '?') && name[3] == '\\') name += 4;
342 else
344 wcscat( ret, uncprefixW );
345 name += 2;
348 wcscat( ret, name );
349 return ret;
353 /***********************************************************************
354 * get_unix_curdir
356 static int get_unix_curdir( const RTL_USER_PROCESS_PARAMETERS *params )
358 UNICODE_STRING nt_name, redir;
359 OBJECT_ATTRIBUTES attr;
360 NTSTATUS status;
361 HANDLE handle;
362 int fd = -1;
363 char *unix_name;
365 if (!(nt_name.Buffer = get_nt_pathname( &params->CurrentDirectory.DosPath ))) return -1;
366 nt_name.Length = wcslen( nt_name.Buffer ) * sizeof(WCHAR);
368 InitializeObjectAttributes( &attr, &nt_name, OBJ_CASE_INSENSITIVE, 0, NULL );
369 get_redirect( &attr, &redir );
370 status = nt_to_unix_file_name( &attr, &unix_name, FILE_OPEN );
371 if (status) goto done;
372 status = open_unix_file( &handle, unix_name, FILE_TRAVERSE | SYNCHRONIZE, &attr, 0,
373 FILE_SHARE_READ | FILE_SHARE_DELETE,
374 FILE_OPEN, FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0 );
375 free( unix_name );
376 if (status) goto done;
377 wine_server_handle_to_fd( handle, FILE_TRAVERSE, &fd, NULL );
378 NtClose( handle );
380 done:
381 free( nt_name.Buffer );
382 free( redir.Buffer );
383 return fd;
387 /***********************************************************************
388 * set_stdio_fd
390 static void set_stdio_fd( int stdin_fd, int stdout_fd )
392 int fd = -1;
394 if (stdin_fd == -1 || stdout_fd == -1)
396 fd = open( "/dev/null", O_RDWR );
397 if (stdin_fd == -1) stdin_fd = fd;
398 if (stdout_fd == -1) stdout_fd = fd;
401 if (stdin_fd != 0) dup2( stdin_fd, 0 );
402 if (stdout_fd != 1) dup2( stdout_fd, 1 );
403 if (fd != -1) close( fd );
407 /***********************************************************************
408 * is_unix_console_handle
410 static BOOL is_unix_console_handle( HANDLE handle )
412 IO_STATUS_BLOCK io = {0};
413 return !NtDeviceIoControlFile( handle, NULL, NULL, NULL, &io, IOCTL_CONDRV_IS_UNIX,
414 NULL, 0, NULL, 0 );
418 /***********************************************************************
419 * spawn_process
421 static NTSTATUS spawn_process( const RTL_USER_PROCESS_PARAMETERS *params, int socketfd,
422 int unixdir, char *winedebug, const pe_image_info_t *pe_info )
424 NTSTATUS status = STATUS_SUCCESS;
425 int stdin_fd = -1, stdout_fd = -1;
426 pid_t pid;
427 char **argv;
429 if (wine_server_handle_to_fd( params->hStdInput, FILE_READ_DATA, &stdin_fd, NULL ) &&
430 isatty(0) && is_unix_console_handle( params->hStdInput ))
431 stdin_fd = 0;
433 if (wine_server_handle_to_fd( params->hStdOutput, FILE_WRITE_DATA, &stdout_fd, NULL ) &&
434 isatty(1) && is_unix_console_handle( params->hStdOutput ))
435 stdout_fd = 1;
437 if (!(pid = fork())) /* child */
439 if (!(pid = fork())) /* grandchild */
441 if (params->ConsoleFlags ||
442 params->ConsoleHandle == (HANDLE)1 /* KERNEL32_CONSOLE_ALLOC */ ||
443 (params->hStdInput == INVALID_HANDLE_VALUE && params->hStdOutput == INVALID_HANDLE_VALUE))
445 setsid();
446 set_stdio_fd( -1, -1 ); /* close stdin and stdout */
448 else set_stdio_fd( stdin_fd, stdout_fd );
450 if (stdin_fd != -1 && stdin_fd != 0) close( stdin_fd );
451 if (stdout_fd != -1 && stdout_fd != 1) close( stdout_fd );
453 if (winedebug) putenv( winedebug );
454 if (unixdir != -1)
456 fchdir( unixdir );
457 close( unixdir );
459 argv = build_argv( &params->CommandLine, 2 );
461 exec_wineloader( argv, socketfd, pe_info );
462 _exit(1);
465 _exit(pid == -1);
468 if (pid != -1)
470 /* reap child */
471 pid_t wret;
472 do {
473 wret = waitpid(pid, NULL, 0);
474 } while (wret < 0 && errno == EINTR);
476 else status = STATUS_NO_MEMORY;
478 if (stdin_fd != -1 && stdin_fd != 0) close( stdin_fd );
479 if (stdout_fd != -1 && stdout_fd != 1) close( stdout_fd );
480 return status;
484 /***********************************************************************
485 * fork_and_exec
487 * Fork and exec a new Unix binary, checking for errors.
489 static NTSTATUS fork_and_exec( OBJECT_ATTRIBUTES *attr, int unixdir,
490 const RTL_USER_PROCESS_PARAMETERS *params )
492 pid_t pid;
493 int fd[2], stdin_fd = -1, stdout_fd = -1;
494 char **argv, **envp;
495 char *unix_name;
496 NTSTATUS status;
498 status = nt_to_unix_file_name( attr, &unix_name, FILE_OPEN );
499 if (status) return status;
501 #ifdef HAVE_PIPE2
502 if (pipe2( fd, O_CLOEXEC ) == -1)
503 #endif
505 if (pipe(fd) == -1)
507 status = STATUS_TOO_MANY_OPENED_FILES;
508 goto done;
510 fcntl( fd[0], F_SETFD, FD_CLOEXEC );
511 fcntl( fd[1], F_SETFD, FD_CLOEXEC );
514 if (wine_server_handle_to_fd( params->hStdInput, FILE_READ_DATA, &stdin_fd, NULL ) &&
515 isatty(0) && is_unix_console_handle( params->hStdInput ))
516 stdin_fd = 0;
518 if (wine_server_handle_to_fd( params->hStdOutput, FILE_WRITE_DATA, &stdout_fd, NULL ) &&
519 isatty(1) && is_unix_console_handle( params->hStdOutput ))
520 stdout_fd = 1;
522 if (!(pid = fork())) /* child */
524 if (!(pid = fork())) /* grandchild */
526 close( fd[0] );
528 if (params->ConsoleFlags ||
529 params->ConsoleHandle == CONSOLE_HANDLE_ALLOC ||
530 (params->hStdInput == INVALID_HANDLE_VALUE && params->hStdOutput == INVALID_HANDLE_VALUE))
532 setsid();
533 set_stdio_fd( -1, -1 ); /* close stdin and stdout */
535 else set_stdio_fd( stdin_fd, stdout_fd );
537 if (stdin_fd != -1 && stdin_fd != 0) close( stdin_fd );
538 if (stdout_fd != -1 && stdout_fd != 1) close( stdout_fd );
540 /* Reset signals that we previously set to SIG_IGN */
541 signal( SIGPIPE, SIG_DFL );
543 argv = build_argv( &params->CommandLine, 0 );
544 envp = build_envp( params->Environment );
545 if (unixdir != -1)
547 fchdir( unixdir );
548 close( unixdir );
550 execve( unix_name, argv, envp );
553 if (pid <= 0) /* grandchild if exec failed or child if fork failed */
555 switch (errno)
557 case EPERM:
558 case EACCES: status = STATUS_ACCESS_DENIED; break;
559 case ENOENT: status = STATUS_OBJECT_NAME_NOT_FOUND; break;
560 case EMFILE:
561 case ENFILE: status = STATUS_TOO_MANY_OPENED_FILES; break;
562 case ENOEXEC:
563 case EINVAL: status = STATUS_INVALID_IMAGE_FORMAT; break;
564 default: status = STATUS_NO_MEMORY; break;
566 write( fd[1], &status, sizeof(status) );
567 _exit(1);
569 _exit(0); /* child if fork succeeded */
571 close( fd[1] );
573 if (pid != -1)
575 /* reap child */
576 pid_t wret;
577 do {
578 wret = waitpid(pid, NULL, 0);
579 } while (wret < 0 && errno == EINTR);
580 read( fd[0], &status, sizeof(status) ); /* if we read something, exec or second fork failed */
582 else status = STATUS_NO_MEMORY;
584 close( fd[0] );
585 if (stdin_fd != -1 && stdin_fd != 0) close( stdin_fd );
586 if (stdout_fd != -1 && stdout_fd != 1) close( stdout_fd );
587 done:
588 free( unix_name );
589 return status;
592 static NTSTATUS alloc_handle_list( const PS_ATTRIBUTE *handles_attr, obj_handle_t **handles, data_size_t *handles_len )
594 SIZE_T count, i;
595 HANDLE *src;
597 *handles = NULL;
598 *handles_len = 0;
600 if (!handles_attr) return STATUS_SUCCESS;
602 count = handles_attr->Size / sizeof(HANDLE);
604 if (!(*handles = calloc( sizeof(**handles), count ))) return STATUS_NO_MEMORY;
606 src = handles_attr->ValuePtr;
607 for (i = 0; i < count; ++i)
608 (*handles)[i] = wine_server_obj_handle( src[i] );
610 *handles_len = count * sizeof(**handles);
612 return STATUS_SUCCESS;
615 /**********************************************************************
616 * NtCreateUserProcess (NTDLL.@)
618 NTSTATUS WINAPI NtCreateUserProcess( HANDLE *process_handle_ptr, HANDLE *thread_handle_ptr,
619 ACCESS_MASK process_access, ACCESS_MASK thread_access,
620 OBJECT_ATTRIBUTES *process_attr, OBJECT_ATTRIBUTES *thread_attr,
621 ULONG process_flags, ULONG thread_flags,
622 RTL_USER_PROCESS_PARAMETERS *params, PS_CREATE_INFO *info,
623 PS_ATTRIBUTE_LIST *ps_attr )
625 NTSTATUS status;
626 BOOL success = FALSE;
627 HANDLE file_handle, process_info = 0, process_handle = 0, thread_handle = 0;
628 struct object_attributes *objattr;
629 data_size_t attr_len;
630 char *winedebug = NULL;
631 startup_info_t *startup_info = NULL;
632 ULONG startup_info_size, env_size;
633 int unixdir, socketfd[2] = { -1, -1 };
634 pe_image_info_t pe_info;
635 CLIENT_ID id;
636 HANDLE parent = 0, debug = 0, token = 0;
637 UNICODE_STRING redir, path = {0};
638 OBJECT_ATTRIBUTES attr, empty_attr = { sizeof(empty_attr) };
639 SIZE_T i, attr_count = (ps_attr->TotalLength - sizeof(ps_attr->TotalLength)) / sizeof(PS_ATTRIBUTE);
640 const PS_ATTRIBUTE *handles_attr = NULL, *jobs_attr = NULL;
641 data_size_t handles_size, jobs_size;
642 obj_handle_t *handles, *jobs;
644 for (i = 0; i < attr_count; i++)
646 switch (ps_attr->Attributes[i].Attribute)
648 case PS_ATTRIBUTE_PARENT_PROCESS:
649 parent = ps_attr->Attributes[i].ValuePtr;
650 break;
651 case PS_ATTRIBUTE_DEBUG_PORT:
652 debug = ps_attr->Attributes[i].ValuePtr;
653 break;
654 case PS_ATTRIBUTE_IMAGE_NAME:
655 path.Length = ps_attr->Attributes[i].Size;
656 path.Buffer = ps_attr->Attributes[i].ValuePtr;
657 break;
658 case PS_ATTRIBUTE_TOKEN:
659 token = ps_attr->Attributes[i].ValuePtr;
660 break;
661 case PS_ATTRIBUTE_HANDLE_LIST:
662 if (process_flags & PROCESS_CREATE_FLAGS_INHERIT_HANDLES)
663 handles_attr = &ps_attr->Attributes[i];
664 break;
665 case PS_ATTRIBUTE_JOB_LIST:
666 jobs_attr = &ps_attr->Attributes[i];
667 break;
668 default:
669 if (ps_attr->Attributes[i].Attribute & PS_ATTRIBUTE_INPUT)
670 FIXME( "unhandled input attribute %lx\n", ps_attr->Attributes[i].Attribute );
671 break;
674 if (!process_attr) process_attr = &empty_attr;
676 TRACE( "%s image %s cmdline %s parent %p\n", debugstr_us( &path ),
677 debugstr_us( &params->ImagePathName ), debugstr_us( &params->CommandLine ), parent );
679 unixdir = get_unix_curdir( params );
681 InitializeObjectAttributes( &attr, &path, OBJ_CASE_INSENSITIVE, 0, 0 );
682 get_redirect( &attr, &redir );
684 if ((status = get_pe_file_info( &attr, &file_handle, &pe_info )))
686 if (status == STATUS_INVALID_IMAGE_NOT_MZ && !fork_and_exec( &attr, unixdir, params ))
688 memset( info, 0, sizeof(*info) );
689 free( redir.Buffer );
690 return STATUS_SUCCESS;
692 goto done;
694 if (!(startup_info = create_startup_info( attr.ObjectName, params, &startup_info_size ))) goto done;
695 env_size = get_env_size( params, &winedebug );
697 if ((status = alloc_object_attributes( process_attr, &objattr, &attr_len ))) goto done;
699 if ((status = alloc_handle_list( handles_attr, &handles, &handles_size )))
701 free( objattr );
702 goto done;
705 if ((status = alloc_handle_list( jobs_attr, &jobs, &jobs_size )))
707 free( objattr );
708 free( handles );
709 goto done;
712 /* create the socket for the new process */
714 if (socketpair( PF_UNIX, SOCK_STREAM, 0, socketfd ) == -1)
716 status = STATUS_TOO_MANY_OPENED_FILES;
717 free( objattr );
718 free( handles );
719 free( jobs );
720 goto done;
722 #ifdef SO_PASSCRED
723 else
725 int enable = 1;
726 setsockopt( socketfd[0], SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable) );
728 #endif
730 wine_server_send_fd( socketfd[1] );
731 close( socketfd[1] );
733 /* create the process on the server side */
735 SERVER_START_REQ( new_process )
737 req->token = wine_server_obj_handle( token );
738 req->debug = wine_server_obj_handle( debug );
739 req->parent_process = wine_server_obj_handle( parent );
740 req->flags = process_flags;
741 req->socket_fd = socketfd[1];
742 req->access = process_access;
743 req->info_size = startup_info_size;
744 req->handles_size = handles_size;
745 req->jobs_size = jobs_size;
746 wine_server_add_data( req, objattr, attr_len );
747 wine_server_add_data( req, handles, handles_size );
748 wine_server_add_data( req, jobs, jobs_size );
749 wine_server_add_data( req, startup_info, startup_info_size );
750 wine_server_add_data( req, params->Environment, env_size );
751 if (!(status = wine_server_call( req )))
753 process_handle = wine_server_ptr_handle( reply->handle );
754 id.UniqueProcess = ULongToHandle( reply->pid );
756 process_info = wine_server_ptr_handle( reply->info );
758 SERVER_END_REQ;
759 free( objattr );
760 free( handles );
761 free( jobs );
763 if (status)
765 switch (status)
767 case STATUS_INVALID_IMAGE_WIN_64:
768 ERR( "64-bit application %s not supported in 32-bit prefix\n", debugstr_us(&path) );
769 break;
770 case STATUS_INVALID_IMAGE_FORMAT:
771 ERR( "%s not supported on this installation (machine %04x)\n",
772 debugstr_us(&path), pe_info.machine );
773 break;
775 goto done;
778 if ((status = alloc_object_attributes( thread_attr, &objattr, &attr_len ))) goto done;
780 SERVER_START_REQ( new_thread )
782 req->process = wine_server_obj_handle( process_handle );
783 req->access = thread_access;
784 req->suspend = !!(thread_flags & THREAD_CREATE_FLAGS_CREATE_SUSPENDED);
785 req->request_fd = -1;
786 wine_server_add_data( req, objattr, attr_len );
787 if (!(status = wine_server_call( req )))
789 thread_handle = wine_server_ptr_handle( reply->handle );
790 id.UniqueThread = ULongToHandle( reply->tid );
793 SERVER_END_REQ;
794 free( objattr );
795 if (status) goto done;
797 /* create the child process */
799 if ((status = spawn_process( params, socketfd[0], unixdir, winedebug, &pe_info ))) goto done;
801 close( socketfd[0] );
802 socketfd[0] = -1;
804 /* wait for the new process info to be ready */
806 NtWaitForSingleObject( process_info, FALSE, NULL );
807 SERVER_START_REQ( get_new_process_info )
809 req->info = wine_server_obj_handle( process_info );
810 wine_server_call( req );
811 success = reply->success;
812 status = reply->exit_code;
814 SERVER_END_REQ;
816 if (!success)
818 if (!status) status = STATUS_INTERNAL_ERROR;
819 goto done;
822 TRACE( "%s pid %04x tid %04x handles %p/%p\n", debugstr_us(&path),
823 HandleToULong(id.UniqueProcess), HandleToULong(id.UniqueThread),
824 process_handle, thread_handle );
826 /* update output attributes */
828 for (i = 0; i < attr_count; i++)
830 switch (ps_attr->Attributes[i].Attribute)
832 case PS_ATTRIBUTE_CLIENT_ID:
834 SIZE_T size = min( ps_attr->Attributes[i].Size, sizeof(id) );
835 memcpy( ps_attr->Attributes[i].ValuePtr, &id, size );
836 if (ps_attr->Attributes[i].ReturnLength) *ps_attr->Attributes[i].ReturnLength = size;
837 break;
839 case PS_ATTRIBUTE_IMAGE_INFO:
841 SECTION_IMAGE_INFORMATION info;
842 SIZE_T size = min( ps_attr->Attributes[i].Size, sizeof(info) );
843 virtual_fill_image_information( &pe_info, &info );
844 memcpy( ps_attr->Attributes[i].ValuePtr, &info, size );
845 if (ps_attr->Attributes[i].ReturnLength) *ps_attr->Attributes[i].ReturnLength = size;
846 break;
848 case PS_ATTRIBUTE_TEB_ADDRESS:
849 default:
850 if (!(ps_attr->Attributes[i].Attribute & PS_ATTRIBUTE_INPUT))
851 FIXME( "unhandled output attribute %lx\n", ps_attr->Attributes[i].Attribute );
852 break;
855 *process_handle_ptr = process_handle;
856 *thread_handle_ptr = thread_handle;
857 process_handle = thread_handle = 0;
858 status = STATUS_SUCCESS;
860 done:
861 if (file_handle) NtClose( file_handle );
862 if (process_info) NtClose( process_info );
863 if (process_handle) NtClose( process_handle );
864 if (thread_handle) NtClose( thread_handle );
865 if (socketfd[0] != -1) close( socketfd[0] );
866 if (unixdir != -1) close( unixdir );
867 free( startup_info );
868 free( winedebug );
869 free( redir.Buffer );
870 return status;
874 /******************************************************************************
875 * NtTerminateProcess (NTDLL.@)
877 NTSTATUS WINAPI NtTerminateProcess( HANDLE handle, LONG exit_code )
879 NTSTATUS ret;
880 BOOL self;
882 SERVER_START_REQ( terminate_process )
884 req->handle = wine_server_obj_handle( handle );
885 req->exit_code = exit_code;
886 ret = wine_server_call( req );
887 self = reply->self;
889 SERVER_END_REQ;
890 if (self)
892 if (!handle) process_exiting = TRUE;
893 else if (process_exiting) exit_process( exit_code );
894 else abort_process( exit_code );
896 return ret;
900 #if defined(HAVE_MACH_MACH_H)
902 void fill_vm_counters( VM_COUNTERS_EX *pvmi, int unix_pid )
904 #if defined(MACH_TASK_BASIC_INFO)
905 struct mach_task_basic_info info;
906 mach_msg_type_number_t infoCount;
908 if (unix_pid != -1) return; /* FIXME: Retrieve information for other processes. */
910 infoCount = MACH_TASK_BASIC_INFO_COUNT;
911 if(task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, &infoCount) == KERN_SUCCESS)
913 pvmi->VirtualSize = info.resident_size + info.virtual_size;
914 pvmi->PagefileUsage = info.virtual_size;
915 pvmi->WorkingSetSize = info.resident_size;
916 pvmi->PeakWorkingSetSize = info.resident_size_max;
918 #endif
921 #elif defined(linux)
923 void fill_vm_counters( VM_COUNTERS_EX *pvmi, int unix_pid )
925 FILE *f;
926 char line[256], path[26];
927 unsigned long value;
929 if (unix_pid == -1)
930 strcpy( path, "/proc/self/status" );
931 else
932 sprintf( path, "/proc/%u/status", unix_pid);
933 f = fopen( path, "r" );
934 if (!f) return;
936 while (fgets(line, sizeof(line), f))
938 if (sscanf(line, "VmPeak: %lu", &value))
939 pvmi->PeakVirtualSize = (ULONG64)value * 1024;
940 else if (sscanf(line, "VmSize: %lu", &value))
941 pvmi->VirtualSize = (ULONG64)value * 1024;
942 else if (sscanf(line, "VmHWM: %lu", &value))
943 pvmi->PeakWorkingSetSize = (ULONG64)value * 1024;
944 else if (sscanf(line, "VmRSS: %lu", &value))
945 pvmi->WorkingSetSize = (ULONG64)value * 1024;
946 else if (sscanf(line, "RssAnon: %lu", &value))
947 pvmi->PagefileUsage += (ULONG64)value * 1024;
948 else if (sscanf(line, "VmSwap: %lu", &value))
949 pvmi->PagefileUsage += (ULONG64)value * 1024;
951 pvmi->PeakPagefileUsage = pvmi->PagefileUsage;
953 fclose(f);
956 #else
958 void fill_vm_counters( VM_COUNTERS_EX *pvmi, int unix_pid )
960 /* FIXME : real data */
963 #endif
965 #define UNIMPLEMENTED_INFO_CLASS(c) \
966 case c: \
967 FIXME( "(process=%p) Unimplemented information class: " #c "\n", handle); \
968 ret = STATUS_INVALID_INFO_CLASS; \
969 break
971 /**********************************************************************
972 * NtQueryInformationProcess (NTDLL.@)
974 NTSTATUS WINAPI NtQueryInformationProcess( HANDLE handle, PROCESSINFOCLASS class, void *info,
975 ULONG size, ULONG *ret_len )
977 NTSTATUS ret = STATUS_SUCCESS;
978 ULONG len = 0;
980 TRACE( "(%p,0x%08x,%p,0x%08x,%p)\n", handle, class, info, size, ret_len );
982 switch (class)
984 UNIMPLEMENTED_INFO_CLASS(ProcessQuotaLimits);
985 UNIMPLEMENTED_INFO_CLASS(ProcessBasePriority);
986 UNIMPLEMENTED_INFO_CLASS(ProcessRaisePriority);
987 UNIMPLEMENTED_INFO_CLASS(ProcessExceptionPort);
988 UNIMPLEMENTED_INFO_CLASS(ProcessAccessToken);
989 UNIMPLEMENTED_INFO_CLASS(ProcessLdtInformation);
990 UNIMPLEMENTED_INFO_CLASS(ProcessLdtSize);
991 UNIMPLEMENTED_INFO_CLASS(ProcessIoPortHandlers);
992 UNIMPLEMENTED_INFO_CLASS(ProcessPooledUsageAndLimits);
993 UNIMPLEMENTED_INFO_CLASS(ProcessWorkingSetWatch);
994 UNIMPLEMENTED_INFO_CLASS(ProcessUserModeIOPL);
995 UNIMPLEMENTED_INFO_CLASS(ProcessEnableAlignmentFaultFixup);
996 UNIMPLEMENTED_INFO_CLASS(ProcessWx86Information);
997 UNIMPLEMENTED_INFO_CLASS(ProcessPriorityBoost);
998 UNIMPLEMENTED_INFO_CLASS(ProcessDeviceMap);
999 UNIMPLEMENTED_INFO_CLASS(ProcessForegroundInformation);
1000 UNIMPLEMENTED_INFO_CLASS(ProcessLUIDDeviceMapsEnabled);
1001 UNIMPLEMENTED_INFO_CLASS(ProcessBreakOnTermination);
1002 UNIMPLEMENTED_INFO_CLASS(ProcessHandleTracing);
1004 case ProcessBasicInformation:
1006 PROCESS_BASIC_INFORMATION pbi;
1007 const ULONG_PTR affinity_mask = get_system_affinity_mask();
1009 if (size >= sizeof(PROCESS_BASIC_INFORMATION))
1011 if (!info) ret = STATUS_ACCESS_VIOLATION;
1012 else
1014 SERVER_START_REQ(get_process_info)
1016 req->handle = wine_server_obj_handle( handle );
1017 if ((ret = wine_server_call( req )) == STATUS_SUCCESS)
1019 pbi.ExitStatus = reply->exit_code;
1020 pbi.PebBaseAddress = wine_server_get_ptr( reply->peb );
1021 pbi.AffinityMask = reply->affinity & affinity_mask;
1022 pbi.BasePriority = reply->priority;
1023 pbi.UniqueProcessId = reply->pid;
1024 pbi.InheritedFromUniqueProcessId = reply->ppid;
1025 #ifndef _WIN64
1026 if (is_wow64)
1028 if (reply->machine != native_machine)
1029 pbi.PebBaseAddress = (PEB *)((char *)pbi.PebBaseAddress + 0x1000);
1030 else
1031 pbi.PebBaseAddress = NULL;
1033 #endif
1036 SERVER_END_REQ;
1038 memcpy( info, &pbi, sizeof(PROCESS_BASIC_INFORMATION) );
1039 len = sizeof(PROCESS_BASIC_INFORMATION);
1041 if (size > sizeof(PROCESS_BASIC_INFORMATION)) ret = STATUS_INFO_LENGTH_MISMATCH;
1043 else
1045 len = sizeof(PROCESS_BASIC_INFORMATION);
1046 ret = STATUS_INFO_LENGTH_MISMATCH;
1049 break;
1051 case ProcessIoCounters:
1053 IO_COUNTERS pii;
1055 if (size >= sizeof(IO_COUNTERS))
1057 if (!info) ret = STATUS_ACCESS_VIOLATION;
1058 else if (!handle) ret = STATUS_INVALID_HANDLE;
1059 else
1061 /* FIXME : real data */
1062 memset(&pii, 0 , sizeof(IO_COUNTERS));
1063 memcpy(info, &pii, sizeof(IO_COUNTERS));
1064 len = sizeof(IO_COUNTERS);
1066 if (size > sizeof(IO_COUNTERS)) ret = STATUS_INFO_LENGTH_MISMATCH;
1068 else
1070 len = sizeof(IO_COUNTERS);
1071 ret = STATUS_INFO_LENGTH_MISMATCH;
1074 break;
1076 case ProcessVmCounters:
1078 VM_COUNTERS_EX pvmi;
1080 /* older Windows versions don't have the PrivateUsage field */
1081 if (size >= sizeof(VM_COUNTERS))
1083 if (!info) ret = STATUS_ACCESS_VIOLATION;
1084 else
1086 memset(&pvmi, 0, sizeof(pvmi));
1087 if (handle == GetCurrentProcess()) fill_vm_counters( &pvmi, -1 );
1088 else
1090 SERVER_START_REQ(get_process_vm_counters)
1092 req->handle = wine_server_obj_handle( handle );
1093 if (!(ret = wine_server_call( req )))
1095 pvmi.PeakVirtualSize = reply->peak_virtual_size;
1096 pvmi.VirtualSize = reply->virtual_size;
1097 pvmi.PeakWorkingSetSize = reply->peak_working_set_size;
1098 pvmi.WorkingSetSize = reply->working_set_size;
1099 pvmi.PagefileUsage = reply->pagefile_usage;
1100 pvmi.PeakPagefileUsage = reply->peak_pagefile_usage;
1103 SERVER_END_REQ;
1104 if (ret) break;
1106 if (size >= sizeof(VM_COUNTERS_EX))
1107 pvmi.PrivateUsage = pvmi.PagefileUsage;
1108 len = size;
1109 if (len != sizeof(VM_COUNTERS)) len = sizeof(VM_COUNTERS_EX);
1110 memcpy(info, &pvmi, min(size, sizeof(pvmi)));
1112 if (size != sizeof(VM_COUNTERS) && size != sizeof(VM_COUNTERS_EX))
1113 ret = STATUS_INFO_LENGTH_MISMATCH;
1115 else
1117 len = sizeof(pvmi);
1118 ret = STATUS_INFO_LENGTH_MISMATCH;
1121 break;
1123 case ProcessTimes:
1125 KERNEL_USER_TIMES pti = {{{0}}};
1127 if (size >= sizeof(KERNEL_USER_TIMES))
1129 if (!info) ret = STATUS_ACCESS_VIOLATION;
1130 else if (!handle) ret = STATUS_INVALID_HANDLE;
1131 else
1133 long ticks = sysconf(_SC_CLK_TCK);
1134 struct tms tms;
1136 /* FIXME: user/kernel times only work for current process */
1137 if (ticks && times( &tms ) != -1)
1139 pti.UserTime.QuadPart = (ULONGLONG)tms.tms_utime * 10000000 / ticks;
1140 pti.KernelTime.QuadPart = (ULONGLONG)tms.tms_stime * 10000000 / ticks;
1143 SERVER_START_REQ(get_process_info)
1145 req->handle = wine_server_obj_handle( handle );
1146 if ((ret = wine_server_call( req )) == STATUS_SUCCESS)
1148 pti.CreateTime.QuadPart = reply->start_time;
1149 pti.ExitTime.QuadPart = reply->end_time;
1152 SERVER_END_REQ;
1154 memcpy(info, &pti, sizeof(KERNEL_USER_TIMES));
1155 len = sizeof(KERNEL_USER_TIMES);
1157 if (size > sizeof(KERNEL_USER_TIMES)) ret = STATUS_INFO_LENGTH_MISMATCH;
1159 else
1161 len = sizeof(KERNEL_USER_TIMES);
1162 ret = STATUS_INFO_LENGTH_MISMATCH;
1165 break;
1167 case ProcessDebugPort:
1168 len = sizeof(DWORD_PTR);
1169 if (size == len)
1171 if (!info) ret = STATUS_ACCESS_VIOLATION;
1172 else
1174 HANDLE debug;
1176 SERVER_START_REQ(get_process_debug_info)
1178 req->handle = wine_server_obj_handle( handle );
1179 ret = wine_server_call( req );
1180 debug = wine_server_ptr_handle( reply->debug );
1182 SERVER_END_REQ;
1183 if (ret == STATUS_SUCCESS)
1185 *(DWORD_PTR *)info = ~0ul;
1186 NtClose( debug );
1188 else if (ret == STATUS_PORT_NOT_SET)
1190 *(DWORD_PTR *)info = 0;
1191 ret = STATUS_SUCCESS;
1195 else ret = STATUS_INFO_LENGTH_MISMATCH;
1196 break;
1198 case ProcessDebugFlags:
1199 len = sizeof(DWORD);
1200 if (size == len)
1202 if (!info) ret = STATUS_ACCESS_VIOLATION;
1203 else
1205 HANDLE debug;
1207 SERVER_START_REQ(get_process_debug_info)
1209 req->handle = wine_server_obj_handle( handle );
1210 ret = wine_server_call( req );
1211 debug = wine_server_ptr_handle( reply->debug );
1212 *(DWORD *)info = reply->debug_children;
1214 SERVER_END_REQ;
1215 if (ret == STATUS_SUCCESS) NtClose( debug );
1216 else if (ret == STATUS_PORT_NOT_SET) ret = STATUS_SUCCESS;
1219 else ret = STATUS_INFO_LENGTH_MISMATCH;
1220 break;
1222 case ProcessDefaultHardErrorMode:
1223 len = sizeof(process_error_mode);
1224 if (size == len) memcpy(info, &process_error_mode, len);
1225 else ret = STATUS_INFO_LENGTH_MISMATCH;
1226 break;
1228 case ProcessDebugObjectHandle:
1229 len = sizeof(HANDLE);
1230 if (size == len)
1232 if (!info) ret = STATUS_ACCESS_VIOLATION;
1233 else
1235 SERVER_START_REQ(get_process_debug_info)
1237 req->handle = wine_server_obj_handle( handle );
1238 ret = wine_server_call( req );
1239 *(HANDLE *)info = wine_server_ptr_handle( reply->debug );
1241 SERVER_END_REQ;
1244 else ret = STATUS_INFO_LENGTH_MISMATCH;
1245 break;
1247 case ProcessHandleCount:
1248 if (size >= 4)
1250 if (!info) ret = STATUS_ACCESS_VIOLATION;
1251 else if (!handle) ret = STATUS_INVALID_HANDLE;
1252 else
1254 memset(info, 0, 4);
1255 len = 4;
1257 if (size > 4) ret = STATUS_INFO_LENGTH_MISMATCH;
1259 else
1261 len = 4;
1262 ret = STATUS_INFO_LENGTH_MISMATCH;
1264 break;
1266 case ProcessAffinityMask:
1267 len = sizeof(ULONG_PTR);
1268 if (size == len)
1270 const ULONG_PTR system_mask = get_system_affinity_mask();
1272 SERVER_START_REQ(get_process_info)
1274 req->handle = wine_server_obj_handle( handle );
1275 if (!(ret = wine_server_call( req )))
1276 *(ULONG_PTR *)info = reply->affinity & system_mask;
1278 SERVER_END_REQ;
1280 else ret = STATUS_INFO_LENGTH_MISMATCH;
1281 break;
1283 case ProcessSessionInformation:
1284 len = sizeof(DWORD);
1285 if (size == len)
1287 SERVER_START_REQ(get_process_info)
1289 req->handle = wine_server_obj_handle( handle );
1290 if (!(ret = wine_server_call( req )))
1291 *(DWORD *)info = reply->session_id;
1293 SERVER_END_REQ;
1295 else ret = STATUS_INFO_LENGTH_MISMATCH;
1296 break;
1298 case ProcessWow64Information:
1299 len = sizeof(ULONG_PTR);
1300 if (size != len) ret = STATUS_INFO_LENGTH_MISMATCH;
1301 else if (!info) ret = STATUS_ACCESS_VIOLATION;
1302 else if (!handle) ret = STATUS_INVALID_HANDLE;
1303 else if (handle == GetCurrentProcess()) *(ULONG_PTR *)info = !!NtCurrentTeb()->WowTebOffset;
1304 else
1306 ULONG_PTR val = 0;
1308 SERVER_START_REQ( get_process_info )
1310 req->handle = wine_server_obj_handle( handle );
1311 if (!(ret = wine_server_call( req ))) val = (reply->machine != native_machine);
1313 SERVER_END_REQ;
1314 *(ULONG_PTR *)info = val;
1316 break;
1318 case ProcessImageFileName:
1319 /* FIXME: Should return a device path */
1320 case ProcessImageFileNameWin32:
1321 SERVER_START_REQ( get_process_image_name )
1323 UNICODE_STRING *str = info;
1325 req->handle = wine_server_obj_handle( handle );
1326 req->win32 = (class == ProcessImageFileNameWin32);
1327 wine_server_set_reply( req, str ? str + 1 : NULL,
1328 size > sizeof(UNICODE_STRING) ? size - sizeof(UNICODE_STRING) : 0 );
1329 ret = wine_server_call( req );
1330 if (ret == STATUS_BUFFER_TOO_SMALL) ret = STATUS_INFO_LENGTH_MISMATCH;
1331 len = sizeof(UNICODE_STRING) + reply->len;
1332 if (ret == STATUS_SUCCESS)
1334 str->MaximumLength = str->Length = reply->len;
1335 str->Buffer = (PWSTR)(str + 1);
1338 SERVER_END_REQ;
1339 break;
1341 case ProcessExecuteFlags:
1342 len = sizeof(ULONG);
1343 if (size == len) *(ULONG *)info = execute_flags;
1344 else ret = STATUS_INFO_LENGTH_MISMATCH;
1345 break;
1347 case ProcessPriorityClass:
1348 len = sizeof(PROCESS_PRIORITY_CLASS);
1349 if (size == len)
1351 if (!info) ret = STATUS_ACCESS_VIOLATION;
1352 else
1354 PROCESS_PRIORITY_CLASS *priority = info;
1356 SERVER_START_REQ(get_process_info)
1358 req->handle = wine_server_obj_handle( handle );
1359 if ((ret = wine_server_call( req )) == STATUS_SUCCESS)
1361 priority->PriorityClass = reply->priority;
1362 /* FIXME: Not yet supported by the wineserver */
1363 priority->Foreground = FALSE;
1366 SERVER_END_REQ;
1369 else ret = STATUS_INFO_LENGTH_MISMATCH;
1370 break;
1372 case ProcessCookie:
1373 FIXME( "ProcessCookie (%p,%p,0x%08x,%p) stub\n", handle, info, size, ret_len );
1374 if (handle == NtCurrentProcess())
1376 len = sizeof(ULONG);
1377 if (size == len) *(ULONG *)info = 0;
1378 else ret = STATUS_INFO_LENGTH_MISMATCH;
1380 else ret = STATUS_INVALID_PARAMETER;
1381 break;
1383 case ProcessImageInformation:
1384 len = sizeof(SECTION_IMAGE_INFORMATION);
1385 if (size == len)
1387 if (info)
1389 pe_image_info_t pe_info;
1391 SERVER_START_REQ( get_process_info )
1393 req->handle = wine_server_obj_handle( handle );
1394 wine_server_set_reply( req, &pe_info, sizeof(pe_info) );
1395 if ((ret = wine_server_call( req )) == STATUS_SUCCESS)
1396 virtual_fill_image_information( &pe_info, info );
1398 SERVER_END_REQ;
1400 else ret = STATUS_ACCESS_VIOLATION;
1402 else ret = STATUS_INFO_LENGTH_MISMATCH;
1403 break;
1405 default:
1406 FIXME("(%p,info_class=%d,%p,0x%08x,%p) Unknown information class\n",
1407 handle, class, info, size, ret_len );
1408 ret = STATUS_INVALID_INFO_CLASS;
1409 break;
1412 if (ret_len) *ret_len = len;
1413 return ret;
1417 /**********************************************************************
1418 * NtSetInformationProcess (NTDLL.@)
1420 NTSTATUS WINAPI NtSetInformationProcess( HANDLE handle, PROCESSINFOCLASS class, void *info, ULONG size )
1422 NTSTATUS ret = STATUS_SUCCESS;
1424 switch (class)
1426 case ProcessDefaultHardErrorMode:
1427 if (size != sizeof(UINT)) return STATUS_INVALID_PARAMETER;
1428 process_error_mode = *(UINT *)info;
1429 break;
1431 case ProcessAffinityMask:
1433 const ULONG_PTR system_mask = get_system_affinity_mask();
1435 if (size != sizeof(DWORD_PTR)) return STATUS_INVALID_PARAMETER;
1436 if (*(PDWORD_PTR)info & ~system_mask)
1437 return STATUS_INVALID_PARAMETER;
1438 if (!*(PDWORD_PTR)info)
1439 return STATUS_INVALID_PARAMETER;
1440 SERVER_START_REQ( set_process_info )
1442 req->handle = wine_server_obj_handle( handle );
1443 req->affinity = *(PDWORD_PTR)info;
1444 req->mask = SET_PROCESS_INFO_AFFINITY;
1445 ret = wine_server_call( req );
1447 SERVER_END_REQ;
1448 break;
1450 case ProcessPriorityClass:
1451 if (size != sizeof(PROCESS_PRIORITY_CLASS)) return STATUS_INVALID_PARAMETER;
1452 else
1454 PROCESS_PRIORITY_CLASS* ppc = info;
1456 SERVER_START_REQ( set_process_info )
1458 req->handle = wine_server_obj_handle( handle );
1459 /* FIXME Foreground isn't used */
1460 req->priority = ppc->PriorityClass;
1461 req->mask = SET_PROCESS_INFO_PRIORITY;
1462 ret = wine_server_call( req );
1464 SERVER_END_REQ;
1466 break;
1468 case ProcessExecuteFlags:
1469 if (is_win64 || size != sizeof(ULONG)) return STATUS_INVALID_PARAMETER;
1470 if (execute_flags & MEM_EXECUTE_OPTION_PERMANENT) return STATUS_ACCESS_DENIED;
1471 else
1473 BOOL enable;
1474 switch (*(ULONG *)info & (MEM_EXECUTE_OPTION_ENABLE|MEM_EXECUTE_OPTION_DISABLE))
1476 case MEM_EXECUTE_OPTION_ENABLE:
1477 enable = TRUE;
1478 break;
1479 case MEM_EXECUTE_OPTION_DISABLE:
1480 enable = FALSE;
1481 break;
1482 default:
1483 return STATUS_INVALID_PARAMETER;
1485 execute_flags = *(ULONG *)info;
1486 virtual_set_force_exec( enable );
1488 break;
1490 case ProcessInstrumentationCallback:
1492 PROCESS_INSTRUMENTATION_CALLBACK_INFORMATION *instr = info;
1494 FIXME( "ProcessInstrumentationCallback stub.\n" );
1496 if (size < sizeof(*instr)) return STATUS_INFO_LENGTH_MISMATCH;
1497 ret = STATUS_SUCCESS;
1498 break;
1501 case ProcessThreadStackAllocation:
1503 void *addr = NULL;
1504 SIZE_T reserve;
1505 PROCESS_STACK_ALLOCATION_INFORMATION *stack = info;
1506 if (size == sizeof(PROCESS_STACK_ALLOCATION_INFORMATION_EX))
1507 stack = &((PROCESS_STACK_ALLOCATION_INFORMATION_EX *)info)->AllocInfo;
1508 else if (size != sizeof(*stack)) return STATUS_INFO_LENGTH_MISMATCH;
1510 reserve = stack->ReserveSize;
1511 ret = NtAllocateVirtualMemory( GetCurrentProcess(), &addr, stack->ZeroBits, &reserve,
1512 MEM_RESERVE, PAGE_READWRITE );
1513 if (!ret)
1515 #ifdef VALGRIND_STACK_REGISTER
1516 VALGRIND_STACK_REGISTER( addr, (char *)addr + reserve );
1517 #endif
1518 stack->StackBase = addr;
1520 break;
1523 case ProcessWineMakeProcessSystem:
1524 if (size != sizeof(HANDLE *)) return STATUS_INFO_LENGTH_MISMATCH;
1525 SERVER_START_REQ( make_process_system )
1527 req->handle = wine_server_obj_handle( handle );
1528 if (!(ret = wine_server_call( req )))
1529 *(HANDLE *)info = wine_server_ptr_handle( reply->event );
1531 SERVER_END_REQ;
1532 return ret;
1534 default:
1535 FIXME( "(%p,0x%08x,%p,0x%08x) stub\n", handle, class, info, size );
1536 ret = STATUS_NOT_IMPLEMENTED;
1537 break;
1539 return ret;
1543 /**********************************************************************
1544 * NtOpenProcess (NTDLL.@)
1546 NTSTATUS WINAPI NtOpenProcess( HANDLE *handle, ACCESS_MASK access,
1547 const OBJECT_ATTRIBUTES *attr, const CLIENT_ID *id )
1549 NTSTATUS status;
1551 *handle = 0;
1553 SERVER_START_REQ( open_process )
1555 req->pid = HandleToULong( id->UniqueProcess );
1556 req->access = access;
1557 req->attributes = attr ? attr->Attributes : 0;
1558 status = wine_server_call( req );
1559 if (!status) *handle = wine_server_ptr_handle( reply->handle );
1561 SERVER_END_REQ;
1562 return status;
1566 /**********************************************************************
1567 * NtSuspendProcess (NTDLL.@)
1569 NTSTATUS WINAPI NtSuspendProcess( HANDLE handle )
1571 NTSTATUS ret;
1573 SERVER_START_REQ( suspend_process )
1575 req->handle = wine_server_obj_handle( handle );
1576 ret = wine_server_call( req );
1578 SERVER_END_REQ;
1579 return ret;
1583 /**********************************************************************
1584 * NtResumeProcess (NTDLL.@)
1586 NTSTATUS WINAPI NtResumeProcess( HANDLE handle )
1588 NTSTATUS ret;
1590 SERVER_START_REQ( resume_process )
1592 req->handle = wine_server_obj_handle( handle );
1593 ret = wine_server_call( req );
1595 SERVER_END_REQ;
1596 return ret;
1600 /**********************************************************************
1601 * NtDebugActiveProcess (NTDLL.@)
1603 NTSTATUS WINAPI NtDebugActiveProcess( HANDLE process, HANDLE debug )
1605 NTSTATUS ret;
1607 SERVER_START_REQ( debug_process )
1609 req->handle = wine_server_obj_handle( process );
1610 req->debug = wine_server_obj_handle( debug );
1611 req->attach = 1;
1612 ret = wine_server_call( req );
1614 SERVER_END_REQ;
1615 return ret;
1619 /**********************************************************************
1620 * NtRemoveProcessDebug (NTDLL.@)
1622 NTSTATUS WINAPI NtRemoveProcessDebug( HANDLE process, HANDLE debug )
1624 NTSTATUS ret;
1626 SERVER_START_REQ( debug_process )
1628 req->handle = wine_server_obj_handle( process );
1629 req->debug = wine_server_obj_handle( debug );
1630 req->attach = 0;
1631 ret = wine_server_call( req );
1633 SERVER_END_REQ;
1634 return ret;
1638 /**********************************************************************
1639 * NtDebugContinue (NTDLL.@)
1641 NTSTATUS WINAPI NtDebugContinue( HANDLE handle, CLIENT_ID *client, NTSTATUS status )
1643 NTSTATUS ret;
1645 SERVER_START_REQ( continue_debug_event )
1647 req->debug = wine_server_obj_handle( handle );
1648 req->pid = HandleToULong( client->UniqueProcess );
1649 req->tid = HandleToULong( client->UniqueThread );
1650 req->status = status;
1651 ret = wine_server_call( req );
1653 SERVER_END_REQ;
1654 return ret;