VirtualBox

Changeset 3447 in kBuild


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

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

Location:
trunk/src/kash
Files:
4 edited

Legend:

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

    r3444 r3447  
    10501050# endif /* SH_FORKED_MODE */
    10511051
     1052/** shfile_exec_win helper that make sure there are no _O_APPEND handles. */
     1053static KBOOL shfile_exec_win_no_append(shfdtab *pfdtab, unsigned count)
     1054{
     1055    unsigned i;
     1056    for (i = 0; i < count; i++)
     1057        if (   (pfdtab->tab[i].oflags & _O_APPEND)
     1058            && (pfdtab->tab[i].oflags & (_O_WRONLY | _O_RDWR)))
     1059            return K_FALSE;
     1060    return K_TRUE;
     1061}
     1062
    10521063/**
    10531064 * Helper for sh_execve.
     
    10581069 * it will restore the handle inheritability properties.
    10591070 *
    1060  * @returns Pointer to CRT data if prepare is 1, NULL if prepare is 0.
     1071 * @returns 0 on success, non-zero on failure.
    10611072 * @param   pfdtab  The file descriptor table.
    10621073 * @param   prepare Which call, 1 if before, 0 if after and success, -1 if after on failure.
    1063  * @param   sizep   Where to store the size of the returned data.
    1064  * @param   hndls   Where to store the three standard handles.
    1065  */
    1066 void *shfile_exec_win(shfdtab *pfdtab, int prepare, unsigned short *sizep, intptr_t *hndls)
    1067 {
    1068     void       *pvRet;
    1069     shmtxtmp    tmp;
    1070     unsigned    count;
    1071     unsigned    i;
     1074 * @param   info    The info structure.
     1075 */
     1076int shfile_exec_win(shfdtab *pfdtab, int prepare, shfdexecwin *info)
     1077{
     1078    STARTUPINFOA   *strtinfo = (STARTUPINFOA *)info->strtinfo;
     1079    int             rc = 0;
     1080    shmtxtmp        tmp;
     1081    unsigned        count;
     1082    unsigned        i;
    10721083
    10731084    shmtx_enter(&pfdtab->mtx, &tmp);
     
    10771088           ? pfdtab->size
    10781089           : (0x10000-4) / (1 + sizeof(HANDLE));
    1079     while (count > 3 && pfdtab->tab[count - 1].fd == -1)
     1090    while (   count > 3
     1091           && (   pfdtab->tab[count - 1].fd == -1
     1092               || (pfdtab->tab[count - 1].shflags & SHFILE_FLAGS_CLOSE_ON_EXEC)))
    10801093        count--;
    10811094
    10821095    if (prepare > 0)
    10831096    {
    1084         size_t      cbData = sizeof(int) + count * (1 + sizeof(HANDLE));
    1085         uint8_t    *pbData = sh_malloc(shthread_get_shell(), cbData);
    1086         uint8_t    *paf = pbData + sizeof(int);
    1087         HANDLE     *pah = (HANDLE *)(paf + count);
    1088 
    1089         *(int *)pbData = count;
    1090 
    1091         i = count;
    1092         while (i-- > 0)
    1093         {
    1094             if (    pfdtab->tab[i].fd == i
    1095                 &&  !(pfdtab->tab[i].shflags & SHFILE_FLAGS_CLOSE_ON_EXEC))
     1097        if (count <= 3 && shfile_exec_win_no_append(pfdtab, count))
     1098        {
     1099            info->inherithandles  = 0;
     1100            info->startsuspended  = 1;
     1101            strtinfo->cbReserved2 = 0;
     1102            strtinfo->lpReserved2 = NULL;
     1103        }
     1104        else
     1105        {
     1106            size_t      cbData = sizeof(int) + count * (1 + sizeof(HANDLE));
     1107            uint8_t    *pbData = sh_malloc(shthread_get_shell(), cbData);
     1108            uint8_t    *paf = pbData + sizeof(int);
     1109            HANDLE     *pah = (HANDLE *)(paf + count);
     1110
     1111            info->inherithandles  = 1;
     1112            info->startsuspended  = 0;
     1113            strtinfo->cbReserved2 = (unsigned short)cbData;
     1114            strtinfo->lpReserved2 = pbData;
     1115
     1116            shmtx_leave(&pfdtab->mtx, &tmp); /* should be harmless as this isn't really necessary at all. */
     1117            shmtx_enter(&g_sh_exec_inherit_mtx, &info->tmp);
     1118            shmtx_enter(&pfdtab->mtx, &tmp);
     1119
     1120            *(int *)pbData = count;
     1121
     1122            i = count;
     1123            while (i-- > 0)
    10961124            {
    1097                 HANDLE hFile = shfile_set_inherit_win(&pfdtab->tab[i], 1);
    1098                 TRACE2((NULL, "  #%d: native=%#x oflags=%#x shflags=%#x\n",
    1099                         i, hFile, pfdtab->tab[i].oflags, pfdtab->tab[i].shflags));
    1100                 paf[i] = FOPEN;
    1101                 if (pfdtab->tab[i].oflags & _O_APPEND)
    1102                     paf[i] |= FAPPEND;
    1103                 if (pfdtab->tab[i].oflags & _O_TEXT)
    1104                     paf[i] |= FTEXT;
    1105                 switch (pfdtab->tab[i].shflags & SHFILE_FLAGS_TYPE_MASK)
     1125                if (    pfdtab->tab[i].fd == i
     1126                    &&  !(pfdtab->tab[i].shflags & SHFILE_FLAGS_CLOSE_ON_EXEC))
    11061127                {
    1107                     case SHFILE_FLAGS_TTY:  paf[i] |= FDEV; break;
    1108                     case SHFILE_FLAGS_PIPE: paf[i] |= FPIPE; break;
     1128                    HANDLE hFile = shfile_set_inherit_win(&pfdtab->tab[i], 1);
     1129                    TRACE2((NULL, "  #%d: native=%#x oflags=%#x shflags=%#x\n",
     1130                            i, hFile, pfdtab->tab[i].oflags, pfdtab->tab[i].shflags));
     1131                    paf[i] = FOPEN;
     1132                    if (pfdtab->tab[i].oflags & _O_APPEND)
     1133                        paf[i] |= FAPPEND;
     1134                    if (pfdtab->tab[i].oflags & _O_TEXT)
     1135                        paf[i] |= FTEXT;
     1136                    switch (pfdtab->tab[i].shflags & SHFILE_FLAGS_TYPE_MASK)
     1137                    {
     1138                        case SHFILE_FLAGS_TTY:  paf[i] |= FDEV; break;
     1139                        case SHFILE_FLAGS_PIPE: paf[i] |= FPIPE; break;
     1140                    }
     1141                    pah[i] = hFile;
    11091142                }
    1110                 pah[i] = hFile;
     1143                else
     1144                {
     1145                    paf[i] = 0;
     1146                    pah[i] = INVALID_HANDLE_VALUE;
     1147                }
     1148            }
     1149        }
     1150
     1151        for (i = 0; i < 3; i++)
     1152        {
     1153            if (    i < count
     1154                &&  pfdtab->tab[i].fd == i)
     1155            {
     1156                info->replacehandles[i] = 1;
     1157                info->handles[i] = pfdtab->tab[i].native;
    11111158            }
    11121159            else
    11131160            {
    1114                 paf[i] = 0;
    1115                 pah[i] = INVALID_HANDLE_VALUE;
     1161                info->replacehandles[i] = 0;
     1162                info->handles[i] = (intptr_t)INVALID_HANDLE_VALUE;
    11161163            }
    1117         }
    1118 
    1119         for (i = 0; i < 3; i++)
    1120         {
    1121             if (    i < count
    1122                 &&  pfdtab->tab[i].fd == i)
    1123                 hndls[i] = pfdtab->tab[i].native;
    1124             else
    1125                 hndls[i] = (intptr_t)INVALID_HANDLE_VALUE;
    11261164            TRACE2((NULL, "shfile_exec_win: i=%d count=%d fd=%d native=%d hndls[%d]=\n",
    1127                     i, count, pfdtab->tab[i].fd, pfdtab->tab[i].native, i, hndls[i]));
    1128         }
    1129 
    1130         *sizep = (unsigned short)cbData;
    1131         pvRet = pbData;
     1165                    i, count, pfdtab->tab[i].fd, pfdtab->tab[i].native, i, info->handles[i]));
     1166        }
    11321167    }
    11331168    else
    11341169    {
    11351170        shfile *file = pfdtab->tab;
    1136         assert(!hndls);
    1137         assert(!sizep);
     1171
     1172        sh_free(NULL, strtinfo->lpReserved2);
     1173        strtinfo->lpReserved2 = NULL;
     1174
    11381175        i = count;
    11391176        if (prepare == 0)
     
    11511188                }
    11521189            }
    1153         else
     1190        else if (info->inherithandles)
    11541191            for (i = 0; i < count; i++, file++)
    11551192                if (    file->fd == i
    11561193                    &&  !(file->shflags & SHFILE_FLAGS_CLOSE_ON_EXEC))
    11571194                    shfile_set_inherit_win(file, 0);
    1158         pvRet = NULL;
     1195
     1196        if (info->inherithandles)
     1197            shmtx_leave(&g_sh_exec_inherit_mtx, &info->tmp);
    11591198    }
    11601199
    11611200    shmtx_leave(&pfdtab->mtx, &tmp);
    1162     return pvRet;
     1201    return rc;
    11631202}
    11641203
  • trunk/src/kash/shfile.h

    r3444 r3447  
    134134void shfile_uninit(shfdtab *);
    135135void shfile_fork_win(shfdtab *pfdtab, int set, intptr_t *hndls);
    136 void *shfile_exec_win(shfdtab *pfdtab, int prepare, unsigned short *sizep, intptr_t *hndls);
     136typedef struct shfdexecwin
     137{
     138    int inherithandles;
     139    int startsuspended;
     140    shmtxtmp tmp;
     141    int replacehandles[3];
     142    intptr_t handles[3];
     143    void *strtinfo;
     144} shfdexecwin;
     145int shfile_exec_win(shfdtab *pfdtab, int prepare, shfdexecwin *info);
    137146int shfile_exec_unix(shfdtab *pfdtab);
    138147
  • 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;
  • trunk/src/kash/shinstance.h

    r3439 r3447  
    5959# define strncasecmp strnicmp
    6060#endif
     61
     62extern shmtx g_sh_exec_inherit_mtx;
    6163
    6264/**
Note: See TracChangeset for help on using the changeset viewer.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette