Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2014-08-22 13:21:33 +0400
committerCorinna Vinschen <corinna@vinschen.de>2014-08-22 13:21:33 +0400
commit3f3bd10104550243781f0b4d9248975e35d91ac7 (patch)
treec7ac2839d2c3da2321bd9979a1574667ed39bc26 /winsup/cygwin/spawn.cc
parent33ed7bb5bc2cb41259df064229968933d9c898ca (diff)
* Throughout, use __try/__except/__endtry blocks, rather than myfault
handler. * cygtls.cc (_cygtls::remove): Accommodate the fact that pathbufs has been moved from _local_storage to _cygtls. * cygtls.h (class tls_pathbuf): Add comment to hint to gendef usage of counters. Change type of counters to uint32_t for clarity. Remove _cygtls as friend class. (struct _local_storage): Move pathbufs from here... (struct _cygtls): ...to here, allowing to access it from _sigbe. (class san): Only define on 32 bit. Remove errno, _c_cnt and _w_cnt members. (san::setup): Drop parameter. Don't initialize removed members. (san::leave): Don't set removed members. (class myfault): Only define on 32 bit. (myfault::faulted): Only keep implementation not taking any parameter. Drop argument in call to sebastian.setup. (__try/__leave/__except/__endtry): Implement to support real SEH. For now stick to SJLJ on 32 bit. * dcrt0.cc (dll_crt0_0): Drop 64 bit call to exception::install_myfault_handler. * exception.h (exception_handler): Define with EXCEPTION_DISPOSITION as return type. (PDISPATCHER_CONTEXT): Define as void * on 32 bit. Define as pointer to _DISPATCHER_CONTEXT on 64 bit. (class exception): Define separately for 32 and 64 bit. (exception::myfault): Add handler for myfault SEH handling on 64 bit. (exception::exception): Fix mangled method name to account for change in type of last parameter. (exception::install_myfault_handler): Remove. * exceptions.cc (exception::myfault_handle): Remove. (exception::myfault): New SEH handler for 64 bit. * gendef (_sigbe): Set tls_pathbuf counters to 0 explicitely when returning to the caller. * ntdll.h: Move a comment to a better place. (struct _SCOPE_TABLE): Define on 64 bit. * thread.cc (verifyable_object_isvalid): Remove gcc 4.7 workaround. * tls_pbuf.cc (tls_pbuf): Fix to accommodate new place of pathbufs. (tls_pathbuf::destroy): Change type of loop variables to uint32_t. * tls_pbuf.h (class tmp_pathbuf): Change type of buffer counters to uint32_t. Accommodate new place of pathbufs. * tlsoffsets.h: Regenerate. * tlsoffsets64.h: Regenerate.
Diffstat (limited to 'winsup/cygwin/spawn.cc')
-rw-r--r--winsup/cygwin/spawn.cc991
1 files changed, 497 insertions, 494 deletions
diff --git a/winsup/cygwin/spawn.cc b/winsup/cygwin/spawn.cc
index d1b1fbad6..56f36a3e6 100644
--- a/winsup/cygwin/spawn.cc
+++ b/winsup/cygwin/spawn.cc
@@ -1,7 +1,7 @@
/* spawn.cc
Copyright 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006,
- 2007, 2008, 2009, 2010, 2011, 2012, 2013 Red Hat, Inc.
+ 2007, 2008, 2009, 2010, 2011, 2012, 2013, 2014 Red Hat, Inc.
This file is part of Cygwin.
@@ -330,552 +330,552 @@ child_info_spawn::worker (const char *prog_arg, const char *const *argv,
STARTUPINFOW si = {};
int looped = 0;
- myfault efault;
system_call_handle system_call (mode == _P_SYSTEM);
- if (efault.faulted ())
+
+ __try
{
- if (get_errno () == ENOMEM)
- set_errno (E2BIG);
+ child_info_types chtype;
+ if (mode == _P_OVERLAY)
+ chtype = _CH_EXEC;
else
- set_errno (EFAULT);
- res = -1;
- goto out;
- }
-
- child_info_types chtype;
- if (mode == _P_OVERLAY)
- chtype = _CH_EXEC;
- else
- chtype = _CH_SPAWN;
+ chtype = _CH_SPAWN;
- moreinfo = cygheap_exec_info::alloc ();
+ moreinfo = cygheap_exec_info::alloc ();
- /* CreateProcess takes one long string that is the command line (sigh).
- We need to quote any argument that has whitespace or embedded "'s. */
+ /* CreateProcess takes one long string that is the command line (sigh).
+ We need to quote any argument that has whitespace or embedded "'s. */
- int ac;
- for (ac = 0; argv[ac]; ac++)
- /* nothing */;
+ int ac;
+ for (ac = 0; argv[ac]; ac++)
+ /* nothing */;
- int err;
- const char *ext;
- if ((ext = perhaps_suffix (prog_arg, real_path, err, FE_NADA)) == NULL)
- {
- set_errno (err);
- res = -1;
- goto out;
- }
-
- res = newargv.setup (prog_arg, real_path, ext, ac, argv, p_type_exec);
+ int err;
+ const char *ext;
+ if ((ext = perhaps_suffix (prog_arg, real_path, err, FE_NADA)) == NULL)
+ {
+ set_errno (err);
+ res = -1;
+ __leave;
+ }
- if (res)
- goto out;
+ res = newargv.setup (prog_arg, real_path, ext, ac, argv, p_type_exec);
- if (!real_path.iscygexec () && ::cygheap->cwd.get_error ())
- {
- small_printf ("Error: Current working directory %s.\n"
- "Can't start native Windows application from here.\n\n",
- ::cygheap->cwd.get_error_desc ());
- set_errno (::cygheap->cwd.get_error ());
- res = -1;
- goto out;
- }
+ if (res)
+ __leave;
- if (ac == 3 && argv[1][0] == '/' && tolower (argv[1][1]) == 'c' &&
- (iscmd (argv[0], "command.com") || iscmd (argv[0], "cmd.exe")))
- {
- real_path.check (prog_arg);
- cmd.add ("\"");
- if (!real_path.error)
- cmd.add (real_path.get_win32 ());
- else
- cmd.add (argv[0]);
- cmd.add ("\"");
- cmd.add (" ");
- cmd.add (argv[1]);
- cmd.add (" ");
- cmd.add (argv[2]);
- real_path.set_path (argv[0]);
- null_app_name = true;
- }
- else
- {
- if (real_path.iscygexec ())
- {
- moreinfo->argc = newargv.argc;
- moreinfo->argv = newargv;
- }
- if ((wincmdln || !real_path.iscygexec ())
- && !cmd.fromargv (newargv, real_path.get_win32 (),
- real_path.iscygexec ()))
+ if (!real_path.iscygexec () && ::cygheap->cwd.get_error ())
{
+ small_printf ("Error: Current working directory %s.\n"
+ "Can't start native Windows application from here.\n\n",
+ ::cygheap->cwd.get_error_desc ());
+ set_errno (::cygheap->cwd.get_error ());
res = -1;
- goto out;
+ __leave;
}
-
- if (mode != _P_OVERLAY || !real_path.iscygexec ()
- || !DuplicateHandle (GetCurrentProcess (), myself.shared_handle (),
- GetCurrentProcess (), &moreinfo->myself_pinfo,
- 0, TRUE, DUPLICATE_SAME_ACCESS))
- moreinfo->myself_pinfo = NULL;
+ if (ac == 3 && argv[1][0] == '/' && tolower (argv[1][1]) == 'c' &&
+ (iscmd (argv[0], "command.com") || iscmd (argv[0], "cmd.exe")))
+ {
+ real_path.check (prog_arg);
+ cmd.add ("\"");
+ if (!real_path.error)
+ cmd.add (real_path.get_win32 ());
+ else
+ cmd.add (argv[0]);
+ cmd.add ("\"");
+ cmd.add (" ");
+ cmd.add (argv[1]);
+ cmd.add (" ");
+ cmd.add (argv[2]);
+ real_path.set_path (argv[0]);
+ null_app_name = true;
+ }
else
- VerifyHandle (moreinfo->myself_pinfo);
- }
+ {
+ if (real_path.iscygexec ())
+ {
+ moreinfo->argc = newargv.argc;
+ moreinfo->argv = newargv;
+ }
+ if ((wincmdln || !real_path.iscygexec ())
+ && !cmd.fromargv (newargv, real_path.get_win32 (),
+ real_path.iscygexec ()))
+ {
+ res = -1;
+ __leave;
+ }
- PROCESS_INFORMATION pi;
- pi.hProcess = pi.hThread = NULL;
- pi.dwProcessId = pi.dwThreadId = 0;
- /* Set up needed handles for stdio */
- si.dwFlags = STARTF_USESTDHANDLES;
- si.hStdInput = handle ((in__stdin < 0 ? 0 : in__stdin), false);
- si.hStdOutput = handle ((in__stdout < 0 ? 1 : in__stdout), true);
- si.hStdError = handle (2, true);
+ if (mode != _P_OVERLAY || !real_path.iscygexec ()
+ || !DuplicateHandle (GetCurrentProcess (), myself.shared_handle (),
+ GetCurrentProcess (), &moreinfo->myself_pinfo,
+ 0, TRUE, DUPLICATE_SAME_ACCESS))
+ moreinfo->myself_pinfo = NULL;
+ else
+ VerifyHandle (moreinfo->myself_pinfo);
+ }
- si.cb = sizeof (si);
+ PROCESS_INFORMATION pi;
+ pi.hProcess = pi.hThread = NULL;
+ pi.dwProcessId = pi.dwThreadId = 0;
- c_flags = GetPriorityClass (GetCurrentProcess ());
- sigproc_printf ("priority class %d", c_flags);
+ /* Set up needed handles for stdio */
+ si.dwFlags = STARTF_USESTDHANDLES;
+ si.hStdInput = handle ((in__stdin < 0 ? 0 : in__stdin), false);
+ si.hStdOutput = handle ((in__stdout < 0 ? 1 : in__stdout), true);
+ si.hStdError = handle (2, true);
- c_flags |= CREATE_SEPARATE_WOW_VDM | CREATE_UNICODE_ENVIRONMENT;
+ si.cb = sizeof (si);
- if (wincap.has_program_compatibility_assistant ())
- {
- /* We're adding the CREATE_BREAKAWAY_FROM_JOB flag here to workaround
- issues with the "Program Compatibility Assistant (PCA) Service"
- starting with Windows Vista. For some reason, when starting long
- running sessions from mintty(*), the affected svchost.exe process
- takes more and more memory and at one point takes over the CPU. At
- this point the machine becomes unresponsive. The only way to get
- back to normal is to stop the entire mintty session, or to stop the
- PCA service. However, a process which is controlled by PCA is part
- of a compatibility job, which allows child processes to break away
- from the job. This helps to avoid this issue.
-
- First we call IsProcessInJob. It fetches the information whether or
- not we're part of a job 20 times faster than QueryInformationJobObject.
-
- (*) Note that this is not mintty's fault. It has just been observed
- with mintty in the first place. See the archives for more info:
- http://cygwin.com/ml/cygwin-developers/2012-02/msg00018.html */
-
- JOBOBJECT_BASIC_LIMIT_INFORMATION jobinfo;
- BOOL is_in_job;
-
- if (IsProcessInJob (GetCurrentProcess (), NULL, &is_in_job)
- && is_in_job
- && QueryInformationJobObject (NULL, JobObjectBasicLimitInformation,
- &jobinfo, sizeof jobinfo, NULL)
- && (jobinfo.LimitFlags & (JOB_OBJECT_LIMIT_BREAKAWAY_OK
- | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK)))
- {
- debug_printf ("Add CREATE_BREAKAWAY_FROM_JOB");
- c_flags |= CREATE_BREAKAWAY_FROM_JOB;
- }
- }
+ c_flags = GetPriorityClass (GetCurrentProcess ());
+ sigproc_printf ("priority class %d", c_flags);
- if (mode == _P_DETACH)
- c_flags |= DETACHED_PROCESS;
- else
- fhandler_console::need_invisible ();
+ c_flags |= CREATE_SEPARATE_WOW_VDM | CREATE_UNICODE_ENVIRONMENT;
- if (mode != _P_OVERLAY)
- myself->exec_sendsig = NULL;
- else
- {
- /* Reset sendsig so that any process which wants to send a signal
- to this pid will wait for the new process to become active.
- Save the old value in case the exec fails. */
- if (!myself->exec_sendsig)
+ if (wincap.has_program_compatibility_assistant ())
{
- myself->exec_sendsig = myself->sendsig;
- myself->exec_dwProcessId = myself->dwProcessId;
- myself->sendsig = NULL;
- reset_sendsig = true;
+ /* We're adding the CREATE_BREAKAWAY_FROM_JOB flag here to workaround
+ issues with the "Program Compatibility Assistant (PCA) Service"
+ starting with Windows Vista. For some reason, when starting long
+ running sessions from mintty(*), the affected svchost.exe process
+ takes more and more memory and at one point takes over the CPU. At
+ this point the machine becomes unresponsive. The only way to get
+ back to normal is to stop the entire mintty session, or to stop the
+ PCA service. However, a process which is controlled by PCA is part
+ of a compatibility job, which allows child processes to break away
+ from the job. This helps to avoid this issue.
+
+ First we call IsProcessInJob. It fetches the information whether or
+ not we're part of a job 20 times faster than QueryInformationJobObject.
+
+ (*) Note that this is not mintty's fault. It has just been observed
+ with mintty in the first place. See the archives for more info:
+ http://cygwin.com/ml/cygwin-developers/2012-02/msg00018.html */
+
+ JOBOBJECT_BASIC_LIMIT_INFORMATION jobinfo;
+ BOOL is_in_job;
+
+ if (IsProcessInJob (GetCurrentProcess (), NULL, &is_in_job)
+ && is_in_job
+ && QueryInformationJobObject (NULL, JobObjectBasicLimitInformation,
+ &jobinfo, sizeof jobinfo, NULL)
+ && (jobinfo.LimitFlags & (JOB_OBJECT_LIMIT_BREAKAWAY_OK
+ | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK)))
+ {
+ debug_printf ("Add CREATE_BREAKAWAY_FROM_JOB");
+ c_flags |= CREATE_BREAKAWAY_FROM_JOB;
+ }
}
- }
- if (null_app_name)
- runpath = NULL;
- else
- {
- USHORT len = real_path.get_nt_native_path ()->Length / sizeof (WCHAR);
- if (RtlEqualUnicodePathPrefix (real_path.get_nt_native_path (),
- &ro_u_natp, FALSE))
+ if (mode == _P_DETACH)
+ c_flags |= DETACHED_PROCESS;
+ else
+ fhandler_console::need_invisible ();
+
+ if (mode != _P_OVERLAY)
+ myself->exec_sendsig = NULL;
+ else
{
- runpath = real_path.get_wide_win32_path (runpath);
- /* If the executable path length is < MAX_PATH, make sure the long
- path win32 prefix is removed from the path to make subsequent
- not long path aware native Win32 child processes happy. */
- if (len < MAX_PATH + 4)
+ /* Reset sendsig so that any process which wants to send a signal
+ to this pid will wait for the new process to become active.
+ Save the old value in case the exec fails. */
+ if (!myself->exec_sendsig)
{
- if (runpath[5] == ':')
- runpath += 4;
- else if (len < MAX_PATH + 6)
- *(runpath += 6) = L'\\';
+ myself->exec_sendsig = myself->sendsig;
+ myself->exec_dwProcessId = myself->dwProcessId;
+ myself->sendsig = NULL;
+ reset_sendsig = true;
}
}
- else if (len < NT_MAX_PATH - ro_u_globalroot.Length / sizeof (WCHAR))
- {
- UNICODE_STRING rpath;
- RtlInitEmptyUnicodeString (&rpath, runpath,
- (NT_MAX_PATH - 1) * sizeof (WCHAR));
- RtlCopyUnicodeString (&rpath, &ro_u_globalroot);
- RtlAppendUnicodeStringToString (&rpath,
- real_path.get_nt_native_path ());
- }
+ if (null_app_name)
+ runpath = NULL;
else
{
- set_errno (ENAMETOOLONG);
- res = -1;
- goto out;
- }
- }
-
- cygbench ("spawn-worker");
-
- if (!real_path.iscygexec())
- ::cygheap->fdtab.set_file_pointers_for_exec ();
+ USHORT len = real_path.get_nt_native_path ()->Length / sizeof (WCHAR);
+ if (RtlEqualUnicodePathPrefix (real_path.get_nt_native_path (),
+ &ro_u_natp, FALSE))
+ {
+ runpath = real_path.get_wide_win32_path (runpath);
+ /* If the executable path length is < MAX_PATH, make sure the long
+ path win32 prefix is removed from the path to make subsequent
+ not long path aware native Win32 child processes happy. */
+ if (len < MAX_PATH + 4)
+ {
+ if (runpath[5] == ':')
+ runpath += 4;
+ else if (len < MAX_PATH + 6)
+ *(runpath += 6) = L'\\';
+ }
+ }
+ else if (len < NT_MAX_PATH - ro_u_globalroot.Length / sizeof (WCHAR))
+ {
+ UNICODE_STRING rpath;
- moreinfo->envp = build_env (envp, envblock, moreinfo->envc,
- real_path.iscygexec ());
- if (!moreinfo->envp || !envblock)
- {
- set_errno (E2BIG);
- res = -1;
- goto out;
- }
- set (chtype, real_path.iscygexec ());
- __stdin = in__stdin;
- __stdout = in__stdout;
- record_children ();
-
- si.lpReserved2 = (LPBYTE) this;
- si.cbReserved2 = sizeof (*this);
-
- /* Depends on set call above.
- Some file types might need extra effort in the parent after CreateProcess
- and before copying the datastructures to the child. So we have to start
- the child in suspend state, unfortunately, to avoid a race condition. */
- if (!newargv.win16_exe
- && (!iscygwin () || mode != _P_OVERLAY
- || ::cygheap->fdtab.need_fixup_before ()))
- c_flags |= CREATE_SUSPENDED;
- /* If a native application should be spawned, we test here if the spawning
- process is running in a console and, if so, if it's a foreground or
- background process. If it's a background process, we start the native
- process with the CREATE_NEW_PROCESS_GROUP flag set. This lets the native
- process ignore Ctrl-C by default. If we don't do that, pressing Ctrl-C
- in a console will break native processes running in the background,
- because the Ctrl-C event is sent to all processes in the console, unless
- they ignore it explicitely. CREATE_NEW_PROCESS_GROUP does that for us. */
- if (!iscygwin () && fhandler_console::exists ()
- && fhandler_console::tc_getpgid () != myself->pgid)
- c_flags |= CREATE_NEW_PROCESS_GROUP;
- refresh_cygheap ();
-
- if (mode == _P_DETACH)
- /* all set */;
- else if (mode != _P_OVERLAY || !my_wr_proc_pipe)
- prefork ();
- else
- wr_proc_pipe = my_wr_proc_pipe;
-
- /* Don't allow child to inherit these handles if it's not a Cygwin program.
- wr_proc_pipe will be injected later. parent won't be used by the child
- so there is no reason for the child to have it open as it can confuse
- ps into thinking that children of windows processes are all part of
- the same "execed" process.
- FIXME: Someday, make it so that parent is never created when starting
- non-Cygwin processes. */
- if (!iscygwin ())
- {
- SetHandleInformation (wr_proc_pipe, HANDLE_FLAG_INHERIT, 0);
- SetHandleInformation (parent, HANDLE_FLAG_INHERIT, 0);
- }
- /* FIXME: racy */
- if (mode != _P_OVERLAY)
- SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT, 0);
- parent_winpid = GetCurrentProcessId ();
-
-loop:
- /* When ruid != euid we create the new process under the current original
- account and impersonate in child, this way maintaining the different
- effective vs. real ids.
- FIXME: If ruid != euid and ruid != saved_uid we currently give
- up on ruid. The new process will have ruid == euid. */
- ::cygheap->user.deimpersonate ();
-
- if (!real_path.iscygexec () && mode == _P_OVERLAY)
- myself->process_state |= PID_NOTCYGWIN;
-
- wchar_t wcmd[(size_t) cmd];
- if (!::cygheap->user.issetuid ()
- || (::cygheap->user.saved_uid == ::cygheap->user.real_uid
- && ::cygheap->user.saved_gid == ::cygheap->user.real_gid
- && !::cygheap->user.groups.issetgroups ()
- && !::cygheap->user.setuid_to_restricted))
- {
- rc = CreateProcessW (runpath, /* image name - with full path */
- cmd.wcs (wcmd),/* what was passed to exec */
- &sec_none_nih, /* process security attrs */
- &sec_none_nih, /* thread security attrs */
- TRUE, /* inherit handles from parent */
- c_flags,
- envblock, /* environment */
- NULL,
- &si,
- &pi);
- }
- else
- {
- /* Give access to myself */
- if (mode == _P_OVERLAY)
- myself.set_acl();
-
- WCHAR wstname[1024] = { L'\0' };
- HWINSTA hwst_orig = NULL, hwst = NULL;
- HDESK hdsk_orig = NULL, hdsk = NULL;
- PSECURITY_ATTRIBUTES sa;
- DWORD n;
-
- hwst_orig = GetProcessWindowStation ();
- hdsk_orig = GetThreadDesktop (GetCurrentThreadId ());
- GetUserObjectInformationW (hwst_orig, UOI_NAME, wstname, 1024, &n);
- /* Prior to Vista it was possible to start a service with the
- "Interact with desktop" flag. This started the service in the
- interactive window station of the console. A big security
- risk, but we don't want to disable this behaviour for older
- OSes because it's still heavily used by some users. They have
- been warned. */
- if (!::cygheap->user.setuid_to_restricted
- && wcscasecmp (wstname, L"WinSta0") != 0)
- {
- WCHAR sid[128];
-
- sa = sec_user ((PSECURITY_ATTRIBUTES) alloca (1024),
- ::cygheap->user.sid ());
- /* We're creating a window station per user, not per logon session.
- First of all we might not have a valid logon session for
- the user (logon by create_token), and second, it doesn't
- make sense in terms of security to create a new window
- station for every logon of the same user. It just fills up
- the system with window stations for no good reason. */
- hwst = CreateWindowStationW (::cygheap->user.get_windows_id (sid), 0,
- GENERIC_READ | GENERIC_WRITE, sa);
- if (!hwst)
- system_printf ("CreateWindowStation failed, %E");
- else if (!SetProcessWindowStation (hwst))
- system_printf ("SetProcessWindowStation failed, %E");
- else if (!(hdsk = CreateDesktopW (L"Default", NULL, NULL, 0,
- GENERIC_ALL, sa)))
- system_printf ("CreateDesktop failed, %E");
+ RtlInitEmptyUnicodeString (&rpath, runpath,
+ (NT_MAX_PATH - 1) * sizeof (WCHAR));
+ RtlCopyUnicodeString (&rpath, &ro_u_globalroot);
+ RtlAppendUnicodeStringToString (&rpath,
+ real_path.get_nt_native_path ());
+ }
else
{
- wcpcpy (wcpcpy (wstname, sid), L"\\Default");
- si.lpDesktop = wstname;
- debug_printf ("Desktop: %W", si.lpDesktop);
+ set_errno (ENAMETOOLONG);
+ res = -1;
+ __leave;
}
}
- rc = CreateProcessAsUserW (::cygheap->user.primary_token (),
- runpath, /* image name - with full path */
- cmd.wcs (wcmd),/* what was passed to exec */
- &sec_none_nih, /* process security attrs */
- &sec_none_nih, /* thread security attrs */
- TRUE, /* inherit handles from parent */
- c_flags,
- envblock, /* environment */
- NULL,
- &si,
- &pi);
- if (hwst)
+ cygbench ("spawn-worker");
+
+ if (!real_path.iscygexec())
+ ::cygheap->fdtab.set_file_pointers_for_exec ();
+
+ moreinfo->envp = build_env (envp, envblock, moreinfo->envc,
+ real_path.iscygexec ());
+ if (!moreinfo->envp || !envblock)
+ {
+ set_errno (E2BIG);
+ res = -1;
+ __leave;
+ }
+ set (chtype, real_path.iscygexec ());
+ __stdin = in__stdin;
+ __stdout = in__stdout;
+ record_children ();
+
+ si.lpReserved2 = (LPBYTE) this;
+ si.cbReserved2 = sizeof (*this);
+
+ /* Depends on set call above.
+ Some file types might need extra effort in the parent after CreateProcess
+ and before copying the datastructures to the child. So we have to start
+ the child in suspend state, unfortunately, to avoid a race condition. */
+ if (!newargv.win16_exe
+ && (!iscygwin () || mode != _P_OVERLAY
+ || ::cygheap->fdtab.need_fixup_before ()))
+ c_flags |= CREATE_SUSPENDED;
+ /* If a native application should be spawned, we test here if the spawning
+ process is running in a console and, if so, if it's a foreground or
+ background process. If it's a background process, we start the native
+ process with the CREATE_NEW_PROCESS_GROUP flag set. This lets the native
+ process ignore Ctrl-C by default. If we don't do that, pressing Ctrl-C
+ in a console will break native processes running in the background,
+ because the Ctrl-C event is sent to all processes in the console, unless
+ they ignore it explicitely. CREATE_NEW_PROCESS_GROUP does that for us. */
+ if (!iscygwin () && fhandler_console::exists ()
+ && fhandler_console::tc_getpgid () != myself->pgid)
+ c_flags |= CREATE_NEW_PROCESS_GROUP;
+ refresh_cygheap ();
+
+ if (mode == _P_DETACH)
+ /* all set */;
+ else if (mode != _P_OVERLAY || !my_wr_proc_pipe)
+ prefork ();
+ else
+ wr_proc_pipe = my_wr_proc_pipe;
+
+ /* Don't allow child to inherit these handles if it's not a Cygwin program.
+ wr_proc_pipe will be injected later. parent won't be used by the child
+ so there is no reason for the child to have it open as it can confuse
+ ps into thinking that children of windows processes are all part of
+ the same "execed" process.
+ FIXME: Someday, make it so that parent is never created when starting
+ non-Cygwin processes. */
+ if (!iscygwin ())
{
- SetProcessWindowStation (hwst_orig);
- CloseWindowStation (hwst);
+ SetHandleInformation (wr_proc_pipe, HANDLE_FLAG_INHERIT, 0);
+ SetHandleInformation (parent, HANDLE_FLAG_INHERIT, 0);
}
- if (hdsk)
+ /* FIXME: racy */
+ if (mode != _P_OVERLAY)
+ SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT, 0);
+ parent_winpid = GetCurrentProcessId ();
+
+ loop:
+ /* When ruid != euid we create the new process under the current original
+ account and impersonate in child, this way maintaining the different
+ effective vs. real ids.
+ FIXME: If ruid != euid and ruid != saved_uid we currently give
+ up on ruid. The new process will have ruid == euid. */
+ ::cygheap->user.deimpersonate ();
+
+ if (!real_path.iscygexec () && mode == _P_OVERLAY)
+ myself->process_state |= PID_NOTCYGWIN;
+
+ wchar_t wcmd[(size_t) cmd];
+ if (!::cygheap->user.issetuid ()
+ || (::cygheap->user.saved_uid == ::cygheap->user.real_uid
+ && ::cygheap->user.saved_gid == ::cygheap->user.real_gid
+ && !::cygheap->user.groups.issetgroups ()
+ && !::cygheap->user.setuid_to_restricted))
{
- SetThreadDesktop (hdsk_orig);
- CloseDesktop (hdsk);
+ rc = CreateProcessW (runpath, /* image name - with full path */
+ cmd.wcs (wcmd),/* what was passed to exec */
+ &sec_none_nih, /* process security attrs */
+ &sec_none_nih, /* thread security attrs */
+ TRUE, /* inherit handles from parent */
+ c_flags,
+ envblock, /* environment */
+ NULL,
+ &si,
+ &pi);
}
- }
-
- if (mode != _P_OVERLAY)
- SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT,
- HANDLE_FLAG_INHERIT);
-
- /* Set errno now so that debugging messages from it appear before our
- final debugging message [this is a general rule for debugging
- messages]. */
- if (!rc)
- {
- __seterrno ();
- syscall_printf ("CreateProcess failed, %E");
- /* If this was a failed exec, restore the saved sendsig. */
- if (reset_sendsig)
+ else
{
- myself->sendsig = myself->exec_sendsig;
- myself->exec_sendsig = NULL;
+ /* Give access to myself */
+ if (mode == _P_OVERLAY)
+ myself.set_acl();
+
+ WCHAR wstname[1024] = { L'\0' };
+ HWINSTA hwst_orig = NULL, hwst = NULL;
+ HDESK hdsk_orig = NULL, hdsk = NULL;
+ PSECURITY_ATTRIBUTES sa;
+ DWORD n;
+
+ hwst_orig = GetProcessWindowStation ();
+ hdsk_orig = GetThreadDesktop (GetCurrentThreadId ());
+ GetUserObjectInformationW (hwst_orig, UOI_NAME, wstname, 1024, &n);
+ /* Prior to Vista it was possible to start a service with the
+ "Interact with desktop" flag. This started the service in the
+ interactive window station of the console. A big security
+ risk, but we don't want to disable this behaviour for older
+ OSes because it's still heavily used by some users. They have
+ been warned. */
+ if (!::cygheap->user.setuid_to_restricted
+ && wcscasecmp (wstname, L"WinSta0") != 0)
+ {
+ WCHAR sid[128];
+
+ sa = sec_user ((PSECURITY_ATTRIBUTES) alloca (1024),
+ ::cygheap->user.sid ());
+ /* We're creating a window station per user, not per logon session.
+ First of all we might not have a valid logon session for
+ the user (logon by create_token), and second, it doesn't
+ make sense in terms of security to create a new window
+ station for every logon of the same user. It just fills up
+ the system with window stations for no good reason. */
+ hwst = CreateWindowStationW (::cygheap->user.get_windows_id (sid), 0,
+ GENERIC_READ | GENERIC_WRITE, sa);
+ if (!hwst)
+ system_printf ("CreateWindowStation failed, %E");
+ else if (!SetProcessWindowStation (hwst))
+ system_printf ("SetProcessWindowStation failed, %E");
+ else if (!(hdsk = CreateDesktopW (L"Default", NULL, NULL, 0,
+ GENERIC_ALL, sa)))
+ system_printf ("CreateDesktop failed, %E");
+ else
+ {
+ wcpcpy (wcpcpy (wstname, sid), L"\\Default");
+ si.lpDesktop = wstname;
+ debug_printf ("Desktop: %W", si.lpDesktop);
+ }
+ }
+
+ rc = CreateProcessAsUserW (::cygheap->user.primary_token (),
+ runpath, /* image name - with full path */
+ cmd.wcs (wcmd),/* what was passed to exec */
+ &sec_none_nih, /* process security attrs */
+ &sec_none_nih, /* thread security attrs */
+ TRUE, /* inherit handles from parent */
+ c_flags,
+ envblock, /* environment */
+ NULL,
+ &si,
+ &pi);
+ if (hwst)
+ {
+ SetProcessWindowStation (hwst_orig);
+ CloseWindowStation (hwst);
+ }
+ if (hdsk)
+ {
+ SetThreadDesktop (hdsk_orig);
+ CloseDesktop (hdsk);
+ }
}
- myself->process_state &= ~PID_NOTCYGWIN;
- /* Reset handle inheritance to default when the execution of a non-Cygwin
- process fails. Only need to do this for _P_OVERLAY since the handle will
- be closed otherwise. Don't need to do this for 'parent' since it will
- be closed in every case. See FIXME above. */
- if (!iscygwin () && mode == _P_OVERLAY)
- SetHandleInformation (wr_proc_pipe, HANDLE_FLAG_INHERIT,
- HANDLE_FLAG_INHERIT);
- if (wr_proc_pipe == my_wr_proc_pipe)
- wr_proc_pipe = NULL; /* We still own it: don't nuke in destructor */
- /* Restore impersonation. In case of _P_OVERLAY this isn't
- allowed since it would overwrite child data. */
if (mode != _P_OVERLAY)
- ::cygheap->user.reimpersonate ();
+ SetHandleInformation (my_wr_proc_pipe, HANDLE_FLAG_INHERIT,
+ HANDLE_FLAG_INHERIT);
- res = -1;
- goto out;
- }
+ /* Set errno now so that debugging messages from it appear before our
+ final debugging message [this is a general rule for debugging
+ messages]. */
+ if (!rc)
+ {
+ __seterrno ();
+ syscall_printf ("CreateProcess failed, %E");
+ /* If this was a failed exec, restore the saved sendsig. */
+ if (reset_sendsig)
+ {
+ myself->sendsig = myself->exec_sendsig;
+ myself->exec_sendsig = NULL;
+ }
+ myself->process_state &= ~PID_NOTCYGWIN;
+ /* Reset handle inheritance to default when the execution of a non-Cygwin
+ process fails. Only need to do this for _P_OVERLAY since the handle will
+ be closed otherwise. Don't need to do this for 'parent' since it will
+ be closed in every case. See FIXME above. */
+ if (!iscygwin () && mode == _P_OVERLAY)
+ SetHandleInformation (wr_proc_pipe, HANDLE_FLAG_INHERIT,
+ HANDLE_FLAG_INHERIT);
+ if (wr_proc_pipe == my_wr_proc_pipe)
+ wr_proc_pipe = NULL; /* We still own it: don't nuke in destructor */
+
+ /* Restore impersonation. In case of _P_OVERLAY this isn't
+ allowed since it would overwrite child data. */
+ if (mode != _P_OVERLAY)
+ ::cygheap->user.reimpersonate ();
- /* The CREATE_SUSPENDED case is handled below */
- if (iscygwin () && !(c_flags & CREATE_SUSPENDED))
- strace.write_childpid (pi.dwProcessId);
+ res = -1;
+ __leave;
+ }
- /* Fixup the parent data structures if needed and resume the child's
- main thread. */
- if (::cygheap->fdtab.need_fixup_before ())
- ::cygheap->fdtab.fixup_before_exec (pi.dwProcessId);
+ /* The CREATE_SUSPENDED case is handled below */
+ if (iscygwin () && !(c_flags & CREATE_SUSPENDED))
+ strace.write_childpid (pi.dwProcessId);
- if (mode != _P_OVERLAY)
- cygpid = cygwin_pid (pi.dwProcessId);
- else
- cygpid = myself->pid;
+ /* Fixup the parent data structures if needed and resume the child's
+ main thread. */
+ if (::cygheap->fdtab.need_fixup_before ())
+ ::cygheap->fdtab.fixup_before_exec (pi.dwProcessId);
- /* We print the original program name here so the user can see that too. */
- syscall_printf ("pid %d, prog_arg %s, cmd line %.9500s)",
- rc ? cygpid : (unsigned int) -1, prog_arg, (const char *) cmd);
+ if (mode != _P_OVERLAY)
+ cygpid = cygwin_pid (pi.dwProcessId);
+ else
+ cygpid = myself->pid;
- /* Name the handle similarly to proc_subproc. */
- ProtectHandle1 (pi.hProcess, childhProc);
+ /* We print the original program name here so the user can see that too. */
+ syscall_printf ("pid %d, prog_arg %s, cmd line %.9500s)",
+ rc ? cygpid : (unsigned int) -1, prog_arg, (const char *) cmd);
- if (mode == _P_OVERLAY)
- {
- myself->dwProcessId = pi.dwProcessId;
- strace.execing = 1;
- myself.hProcess = hExeced = pi.hProcess;
- real_path.get_wide_win32_path (myself->progname); // FIXME: race?
- sigproc_printf ("new process name %W", myself->progname);
- if (!iscygwin ())
- close_all_files ();
- }
- else
- {
- myself->set_has_pgid_children ();
- ProtectHandle (pi.hThread);
- pinfo child (cygpid,
- PID_IN_USE | (real_path.iscygexec () ? 0 : PID_NOTCYGWIN));
- if (!child)
+ /* Name the handle similarly to proc_subproc. */
+ ProtectHandle1 (pi.hProcess, childhProc);
+
+ if (mode == _P_OVERLAY)
{
- syscall_printf ("pinfo failed");
- if (get_errno () != ENOMEM)
- set_errno (EAGAIN);
- res = -1;
- goto out;
+ myself->dwProcessId = pi.dwProcessId;
+ strace.execing = 1;
+ myself.hProcess = hExeced = pi.hProcess;
+ real_path.get_wide_win32_path (myself->progname); // FIXME: race?
+ sigproc_printf ("new process name %W", myself->progname);
+ if (!iscygwin ())
+ close_all_files ();
}
- child->dwProcessId = pi.dwProcessId;
- child.hProcess = pi.hProcess;
-
- real_path.get_wide_win32_path (child->progname);
- /* FIXME: This introduces an unreferenced, open handle into the child.
- The purpose is to keep the pid shared memory open so that all of
- the fields filled out by child.remember do not disappear and so there
- is not a brief period during which the pid is not available.
- However, we should try to find another way to do this eventually. */
- DuplicateHandle (GetCurrentProcess (), child.shared_handle (),
- pi.hProcess, NULL, 0, 0, DUPLICATE_SAME_ACCESS);
- child->start_time = time (NULL); /* Register child's starting time. */
- child->nice = myself->nice;
- postfork (child);
- if (!child.remember (mode == _P_DETACH))
+ else
{
- /* FIXME: Child in strange state now */
- CloseHandle (pi.hProcess);
- ForceCloseHandle (pi.hThread);
- res = -1;
- goto out;
+ myself->set_has_pgid_children ();
+ ProtectHandle (pi.hThread);
+ pinfo child (cygpid,
+ PID_IN_USE | (real_path.iscygexec () ? 0 : PID_NOTCYGWIN));
+ if (!child)
+ {
+ syscall_printf ("pinfo failed");
+ if (get_errno () != ENOMEM)
+ set_errno (EAGAIN);
+ res = -1;
+ __leave;
+ }
+ child->dwProcessId = pi.dwProcessId;
+ child.hProcess = pi.hProcess;
+
+ real_path.get_wide_win32_path (child->progname);
+ /* FIXME: This introduces an unreferenced, open handle into the child.
+ The purpose is to keep the pid shared memory open so that all of
+ the fields filled out by child.remember do not disappear and so there
+ is not a brief period during which the pid is not available.
+ However, we should try to find another way to do this eventually. */
+ DuplicateHandle (GetCurrentProcess (), child.shared_handle (),
+ pi.hProcess, NULL, 0, 0, DUPLICATE_SAME_ACCESS);
+ child->start_time = time (NULL); /* Register child's starting time. */
+ child->nice = myself->nice;
+ postfork (child);
+ if (!child.remember (mode == _P_DETACH))
+ {
+ /* FIXME: Child in strange state now */
+ CloseHandle (pi.hProcess);
+ ForceCloseHandle (pi.hThread);
+ res = -1;
+ __leave;
+ }
}
- }
- /* Start the child running */
- if (c_flags & CREATE_SUSPENDED)
- {
- /* Inject a non-inheritable wr_proc_pipe handle into child so that we
- can accurately track when the child exits without keeping this
- process waiting around for it to exit. */
- if (!iscygwin ())
- DuplicateHandle (GetCurrentProcess (), wr_proc_pipe, pi.hProcess, NULL,
- 0, false, DUPLICATE_SAME_ACCESS);
- ResumeThread (pi.hThread);
- if (iscygwin ())
- strace.write_childpid (pi.dwProcessId);
- }
- ForceCloseHandle (pi.hThread);
+ /* Start the child running */
+ if (c_flags & CREATE_SUSPENDED)
+ {
+ /* Inject a non-inheritable wr_proc_pipe handle into child so that we
+ can accurately track when the child exits without keeping this
+ process waiting around for it to exit. */
+ if (!iscygwin ())
+ DuplicateHandle (GetCurrentProcess (), wr_proc_pipe, pi.hProcess, NULL,
+ 0, false, DUPLICATE_SAME_ACCESS);
+ ResumeThread (pi.hThread);
+ if (iscygwin ())
+ strace.write_childpid (pi.dwProcessId);
+ }
+ ForceCloseHandle (pi.hThread);
- sigproc_printf ("spawned windows pid %d", pi.dwProcessId);
+ sigproc_printf ("spawned windows pid %d", pi.dwProcessId);
- bool synced;
- if ((mode == _P_DETACH || mode == _P_NOWAIT) && !iscygwin ())
- synced = false;
- else
- /* Just mark a non-cygwin process as 'synced'. We will still eventually
- wait for it to exit in maybe_set_exit_code_from_windows(). */
- synced = iscygwin () ? sync (pi.dwProcessId, pi.hProcess, INFINITE) : true;
+ bool synced;
+ if ((mode == _P_DETACH || mode == _P_NOWAIT) && !iscygwin ())
+ synced = false;
+ else
+ /* Just mark a non-cygwin process as 'synced'. We will still eventually
+ wait for it to exit in maybe_set_exit_code_from_windows(). */
+ synced = iscygwin () ? sync (pi.dwProcessId, pi.hProcess, INFINITE) : true;
- switch (mode)
- {
- case _P_OVERLAY:
- myself.hProcess = pi.hProcess;
- if (!synced)
+ switch (mode)
{
- if (!proc_retry (pi.hProcess))
+ case _P_OVERLAY:
+ myself.hProcess = pi.hProcess;
+ if (!synced)
+ {
+ if (!proc_retry (pi.hProcess))
+ {
+ looped++;
+ goto loop;
+ }
+ close_all_files (true);
+ }
+ else
{
- looped++;
- goto loop;
+ if (iscygwin ())
+ close_all_files (true);
+ if (!my_wr_proc_pipe
+ && WaitForSingleObject (pi.hProcess, 0) == WAIT_TIMEOUT)
+ wait_for_myself ();
}
- close_all_files (true);
+ myself.exit (EXITCODE_NOSET);
+ break;
+ case _P_WAIT:
+ case _P_SYSTEM:
+ system_call.arm ();
+ if (waitpid (cygpid, &res, 0) != cygpid)
+ res = -1;
+ break;
+ case _P_DETACH:
+ res = 0; /* Lost all memory of this child. */
+ break;
+ case _P_NOWAIT:
+ case _P_NOWAITO:
+ case _P_VFORK:
+ res = cygpid;
+ break;
+ default:
+ break;
}
+ }
+ __except (NO_ERROR)
+ {
+ if (get_errno () == ENOMEM)
+ set_errno (E2BIG);
else
- {
- if (iscygwin ())
- close_all_files (true);
- if (!my_wr_proc_pipe
- && WaitForSingleObject (pi.hProcess, 0) == WAIT_TIMEOUT)
- wait_for_myself ();
- }
- myself.exit (EXITCODE_NOSET);
- break;
- case _P_WAIT:
- case _P_SYSTEM:
- system_call.arm ();
- if (waitpid (cygpid, &res, 0) != cygpid)
- res = -1;
- break;
- case _P_DETACH:
- res = 0; /* Lost all memory of this child. */
- break;
- case _P_NOWAIT:
- case _P_NOWAITO:
- case _P_VFORK:
- res = cygpid;
- break;
- default:
- break;
+ set_errno (EFAULT);
+ res = -1;
}
-
-out:
+ __endtry
this->cleanup ();
if (envblock)
free (envblock);
@@ -1137,28 +1137,31 @@ av::setup (const char *prog_arg, path_conv& real_path, const char *ext,
}
{
- myfault efault;
- if (efault.faulted ())
+ __try
{
- UnmapViewOfFile (buf);
- CloseHandle (hm);
- real_path.set_cygexec (false);
- break;
+ if (buf[0] == 'M' && buf[1] == 'Z')
+ {
+ WORD subsys;
+ unsigned off = (unsigned char) buf[0x18] | (((unsigned char) buf[0x19]) << 8);
+ win16_exe = off < sizeof (IMAGE_DOS_HEADER);
+ if (!win16_exe)
+ real_path.set_cygexec (hook_or_detect_cygwin (buf, NULL,
+ subsys, hm));
+ else
+ real_path.set_cygexec (false);
+ UnmapViewOfFile (buf);
+ CloseHandle (hm);
+ break;
+ }
}
- if (buf[0] == 'M' && buf[1] == 'Z')
+ __except (NO_ERROR)
{
- WORD subsys;
- unsigned off = (unsigned char) buf[0x18] | (((unsigned char) buf[0x19]) << 8);
- win16_exe = off < sizeof (IMAGE_DOS_HEADER);
- if (!win16_exe)
- real_path.set_cygexec (hook_or_detect_cygwin (buf, NULL,
- subsys, hm));
- else
- real_path.set_cygexec (false);
UnmapViewOfFile (buf);
CloseHandle (hm);
+ real_path.set_cygexec (false);
break;
}
+ __endtry
}
CloseHandle (hm);