Ignore:
Timestamp:
Sep 11, 2020, 3:22:14 PM (5 years ago)
Author:
bird
Message:

kash: Avoid handle inheritance on windows when possible, allowing concurrent CreateProcess calls.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kash/shinstance.c

    r3446 r3447  
    5050#if K_OS == K_OS_WINDOWS
    5151# include <Windows.h>
     52# include "nt/nt_child_inject_standard_handles.h"
    5253# ifdef SH_FORKED_MODE
    5354extern pid_t shfork_do(shinstance *psh); /* shforkA-win.asm */
     
    7071#ifndef SH_FORKED_MODE
    7172/** Mutex serializing exec/spawn to prevent unwanted file inherting. */
    72 static shmtx        g_sh_exec_mtx;
     73shmtx               g_sh_exec_inherit_mtx;
    7374#endif
    7475/** The mutex protecting the the globals and some shell instance members (sigs). */
     
    8283/** The number of shells. */
    8384static int volatile g_num_shells;
     85/* Statistics: Number of subshells spawned. */
     86static KU64             g_stat_subshells = 0;
     87/* Statistics: Number of program exec'ed. */
     88static KU64 volatile    g_stat_execs = 0;
     89#if K_OS == K_OS_WINDOWS
     90/* Statistics: Number of serialized exec calls. */
     91static KU64 volatile    g_stat_execs_serialized = 0;
     92#endif
    8493/** Per signal state for determining a common denominator.
    8594 * @remarks defaults and unmasked actions aren't counted. */
     
    172181    if (psh->rootshell)
    173182        g_sh_root = psh;
     183    else
     184        g_stat_subshells++;
    174185
    175186    psh->next = NULL;
     
    637648    shmtx_init(&g_sh_mtx);
    638649#ifndef SH_FORKED_MODE
    639     shmtx_init(&g_sh_exec_mtx);
     650    shmtx_init(&g_sh_exec_inherit_mtx);
    640651#endif
    641652
     
    16601671    int rc;
    16611672
     1673    g_stat_execs++;
     1674
    16621675#ifdef DEBUG
    16631676    /* log it all */
     
    16981711         * This ain't quite straight forward on Windows...
    16991712         */
    1700 #ifndef SH_FORKED_MODE
    1701         shmtxtmp tmp;
    1702 #endif
    17031713        PROCESS_INFORMATION ProcInfo;
    17041714        STARTUPINFO StrtInfo;
    1705         intptr_t hndls[3];
     1715        shfdexecwin fdinfo;
    17061716        char *cwd = shfile_getcwd(&psh->fdtab, NULL, 0);
    17071717        char *cmdline;
     
    18121822
    18131823        /* File handles. */
    1814 #ifndef SH_FORKED_MODE
    1815         shmtx_enter(&g_sh_exec_mtx, &tmp);
    1816 #endif
    1817         StrtInfo.dwFlags   |= STARTF_USESTDHANDLES;
    1818         StrtInfo.lpReserved2 = shfile_exec_win(&psh->fdtab, 1 /* prepare */, &StrtInfo.cbReserved2, hndls);
    1819         StrtInfo.hStdInput  = (HANDLE)hndls[0];
    1820         StrtInfo.hStdOutput = (HANDLE)hndls[1];
    1821         StrtInfo.hStdError  = (HANDLE)hndls[2];
     1824        fdinfo.strtinfo = &StrtInfo;
     1825        shfile_exec_win(&psh->fdtab, 1 /* prepare */, &fdinfo);
     1826        TRACE2((psh, "sh_execve: inherithandles=%d replacehandles={%d,%d,%d} handles={%p,%p,%p} suspended=%d Reserved2=%p LB %#x\n",
     1827                fdinfo.inherithandles, fdinfo.replacehandles[0], fdinfo.replacehandles[1], fdinfo.replacehandles[2],
     1828                fdinfo.handles[0], fdinfo.handles[1], fdinfo.handles[3], fdinfo.startsuspended,
     1829                StrtInfo.lpReserved2, StrtInfo.cbReserved2));
     1830        if (!fdinfo.inherithandles)
     1831        {
     1832            StrtInfo.dwFlags |= STARTF_USESTDHANDLES;
     1833            StrtInfo.hStdInput  = INVALID_HANDLE_VALUE;
     1834            StrtInfo.hStdOutput = INVALID_HANDLE_VALUE;
     1835            StrtInfo.hStdError  = INVALID_HANDLE_VALUE;
     1836        }
     1837        else
     1838        {
     1839            StrtInfo.dwFlags |= STARTF_USESTDHANDLES;
     1840            StrtInfo.hStdInput  = (HANDLE)fdinfo.handles[0];
     1841            StrtInfo.hStdOutput = (HANDLE)fdinfo.handles[1];
     1842            StrtInfo.hStdError  = (HANDLE)fdinfo.handles[2];
     1843            g_stat_execs_serialized++;
     1844        }
    18221845
    18231846        /* Get going... */
    1824         rc = CreateProcess(exe,
    1825                            cmdline,
    1826                            NULL,         /* pProcessAttributes */
    1827                            NULL,         /* pThreadAttributes */
    1828                            TRUE,         /* bInheritHandles */
    1829                            0,            /* dwCreationFlags */
    1830                            envblock,
    1831                            cwd,
    1832                            &StrtInfo,
    1833                            &ProcInfo);
    1834 
    1835         shfile_exec_win(&psh->fdtab, rc ? 0 /* done */ : -1 /* done but failed */, NULL, NULL);
    1836 #ifndef SH_FORKED_MODE
    1837         shmtx_leave(&g_sh_exec_mtx, &tmp);
    1838 #endif
     1847        rc = CreateProcessA(exe,
     1848                            cmdline,
     1849                            NULL,         /* pProcessAttributes */
     1850                            NULL,         /* pThreadAttributes */
     1851                            fdinfo.inherithandles,
     1852                            fdinfo.startsuspended ? CREATE_SUSPENDED : 0,
     1853                            envblock,
     1854                            cwd,
     1855                            &StrtInfo,
     1856                            &ProcInfo);
    18391857        if (rc)
    18401858        {
     
    18421860            DWORD dwExitCode;
    18431861
     1862            if (fdinfo.startsuspended)
     1863            {
     1864                char errmsg[512];
     1865                rc = nt_child_inject_standard_handles(ProcInfo.hProcess, fdinfo.replacehandles, (HANDLE*)&fdinfo.handles[0],
     1866                                                      errmsg, sizeof(errmsg));
     1867                if (!rc)
     1868                {
     1869                    rc = ResumeThread(ProcInfo.hThread);
     1870                    if (!rc)
     1871                        TRACE2((psh, "sh_execve: ResumeThread failed: %u -> errno=ENXIO\n", GetLastError()));
     1872                }
     1873                else
     1874                {
     1875                    TRACE2((psh, "sh_execve: nt_child_inject_standard_handles failed: %d -> errno=ENXIO; %s\n", rc, errmsg));
     1876                    rc = FALSE;
     1877                }
     1878                errno = ENXIO;
     1879            }
     1880
     1881            shfile_exec_win(&psh->fdtab, rc ? 0 /* done */ : -1 /* done but failed */, &fdinfo);
     1882
    18441883            CloseHandle(ProcInfo.hThread);
    1845             dwErr = WaitForSingleObject(ProcInfo.hProcess, INFINITE);
    1846             assert(dwErr == WAIT_OBJECT_0);
    1847 
    1848             if (GetExitCodeProcess(ProcInfo.hProcess, &dwExitCode))
     1884            ProcInfo.hThread = INVALID_HANDLE_VALUE;
     1885            if (rc)
    18491886            {
    1850                 CloseHandle(ProcInfo.hProcess);
    1851                 sh__exit(psh, dwExitCode);
     1887                /*
     1888                 * Wait for it and forward the exit code.
     1889                 */
     1890                dwErr = WaitForSingleObject(ProcInfo.hProcess, INFINITE);
     1891                assert(dwErr == WAIT_OBJECT_0);
     1892
     1893                if (GetExitCodeProcess(ProcInfo.hProcess, &dwExitCode))
     1894                {
     1895#ifndef SH_FORKED_MODE
     1896                    /** @todo signal the end of this subshell now, we can do the cleaning up
     1897                     *        after the parent shell has resumed. */
     1898#endif
     1899                    CloseHandle(ProcInfo.hProcess);
     1900                    ProcInfo.hProcess = INVALID_HANDLE_VALUE;
     1901                    sh__exit(psh, dwExitCode);
     1902                }
     1903
     1904                /* this shouldn't happen... */
     1905                TRACE2((psh, "sh_execve: GetExitCodeProcess failed: %u\n", GetLastError()));
     1906                assert(0);
     1907                errno = EINVAL;
    18521908            }
    1853             TRACE2((psh, "sh_execve: GetExitCodeProcess failed: %u\n", GetLastError()));
    1854             assert(0);
     1909            TerminateProcess(ProcInfo.hProcess, 0x40000015);
    18551910            CloseHandle(ProcInfo.hProcess);
    1856             errno = EINVAL;
    18571911        }
    18581912        else
    18591913        {
    18601914            DWORD dwErr = GetLastError();
     1915
     1916            shfile_exec_win(&psh->fdtab, -1 /* done but failed */, &fdinfo);
     1917
    18611918            switch (dwErr)
    18621919            {
     
    18651922                case ERROR_BAD_EXE_FORMAT:          errno = ENOEXEC; break;
    18661923                case ERROR_INVALID_EXE_SIGNATURE:   errno = ENOEXEC; break;
    1867                 default:
    1868                     errno = EINVAL;
    1869                     break;
     1924                default:                            errno = EINVAL; break;
    18701925            }
    18711926            TRACE2((psh, "sh_execve: dwErr=%d -> errno=%d\n", dwErr, errno));
    18721927        }
    1873 
    18741928    }
    18751929    rc = -1;
Note: See TracChangeset for help on using the changeset viewer.