@@ -255,6 +255,7 @@ enum hide_dotfiles_type {
255
255
HIDE_DOTFILES_DOTGITONLY
256
256
};
257
257
258
+ static int core_restrict_inherited_handles = -1 ;
258
259
static enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY ;
259
260
static char * unset_environment_variables ;
260
261
int core_fscache ;
@@ -286,6 +287,15 @@ int mingw_core_config(const char *var, const char *value, void *cb)
286
287
return 0 ;
287
288
}
288
289
290
+ if (!strcmp (var , "core.restrictinheritedhandles" )) {
291
+ if (value && !strcasecmp (value , "auto" ))
292
+ core_restrict_inherited_handles = -1 ;
293
+ else
294
+ core_restrict_inherited_handles =
295
+ git_config_bool (var , value );
296
+ return 0 ;
297
+ }
298
+
289
299
return 0 ;
290
300
}
291
301
@@ -1623,8 +1633,13 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1623
1633
const char * dir ,
1624
1634
int prepend_cmd , int fhin , int fhout , int fherr )
1625
1635
{
1626
- STARTUPINFOW si ;
1636
+ static int restrict_handle_inheritance = -1 ;
1637
+ STARTUPINFOEXW si ;
1627
1638
PROCESS_INFORMATION pi ;
1639
+ LPPROC_THREAD_ATTRIBUTE_LIST attr_list = NULL ;
1640
+ HANDLE stdhandles [3 ];
1641
+ DWORD stdhandles_count = 0 ;
1642
+ SIZE_T size ;
1628
1643
struct strbuf args ;
1629
1644
wchar_t wcmd [MAX_PATH ], wdir [MAX_PATH ], * wargs , * wenvblk = NULL ;
1630
1645
unsigned flags = CREATE_UNICODE_ENVIRONMENT ;
@@ -1634,6 +1649,16 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1634
1649
is_msys2_sh (* argv ) ? quote_arg_msys2 : quote_arg_msvc ;
1635
1650
const char * strace_env ;
1636
1651
1652
+ if (restrict_handle_inheritance < 0 )
1653
+ restrict_handle_inheritance = core_restrict_inherited_handles ;
1654
+ /*
1655
+ * The following code to restrict which handles are inherited seems
1656
+ * to work properly only on Windows 7 and later, so let's disable it
1657
+ * on Windows Vista and 2008.
1658
+ */
1659
+ if (restrict_handle_inheritance < 0 )
1660
+ restrict_handle_inheritance = GetVersion () >> 16 >= 7601 ;
1661
+
1637
1662
do_unset_environment_variables ();
1638
1663
1639
1664
/* Determine whether or not we are associated to a console */
@@ -1661,11 +1686,23 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1661
1686
CloseHandle (cons );
1662
1687
}
1663
1688
memset (& si , 0 , sizeof (si ));
1664
- si .cb = sizeof (si );
1665
- si .dwFlags = STARTF_USESTDHANDLES ;
1666
- si .hStdInput = winansi_get_osfhandle (fhin );
1667
- si .hStdOutput = winansi_get_osfhandle (fhout );
1668
- si .hStdError = winansi_get_osfhandle (fherr );
1689
+ si .StartupInfo .cb = sizeof (si );
1690
+ si .StartupInfo .hStdInput = winansi_get_osfhandle (fhin );
1691
+ si .StartupInfo .hStdOutput = winansi_get_osfhandle (fhout );
1692
+ si .StartupInfo .hStdError = winansi_get_osfhandle (fherr );
1693
+
1694
+ /* The list of handles cannot contain duplicates */
1695
+ if (si .StartupInfo .hStdInput != INVALID_HANDLE_VALUE )
1696
+ stdhandles [stdhandles_count ++ ] = si .StartupInfo .hStdInput ;
1697
+ if (si .StartupInfo .hStdOutput != INVALID_HANDLE_VALUE &&
1698
+ si .StartupInfo .hStdOutput != si .StartupInfo .hStdInput )
1699
+ stdhandles [stdhandles_count ++ ] = si .StartupInfo .hStdOutput ;
1700
+ if (si .StartupInfo .hStdError != INVALID_HANDLE_VALUE &&
1701
+ si .StartupInfo .hStdError != si .StartupInfo .hStdInput &&
1702
+ si .StartupInfo .hStdError != si .StartupInfo .hStdOutput )
1703
+ stdhandles [stdhandles_count ++ ] = si .StartupInfo .hStdError ;
1704
+ if (stdhandles_count )
1705
+ si .StartupInfo .dwFlags |= STARTF_USESTDHANDLES ;
1669
1706
1670
1707
if (* argv && !strcmp (cmd , * argv ))
1671
1708
wcmd [0 ] = L'\0' ;
@@ -1727,16 +1764,97 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1727
1764
wenvblk = make_environment_block (deltaenv );
1728
1765
1729
1766
memset (& pi , 0 , sizeof (pi ));
1730
- ret = CreateProcessW (* wcmd ? wcmd : NULL , wargs , NULL , NULL , TRUE,
1731
- flags , wenvblk , dir ? wdir : NULL , & si , & pi );
1767
+ if (restrict_handle_inheritance && stdhandles_count &&
1768
+ (InitializeProcThreadAttributeList (NULL , 1 , 0 , & size ) ||
1769
+ GetLastError () == ERROR_INSUFFICIENT_BUFFER ) &&
1770
+ (attr_list = (LPPROC_THREAD_ATTRIBUTE_LIST )
1771
+ (HeapAlloc (GetProcessHeap (), 0 , size ))) &&
1772
+ InitializeProcThreadAttributeList (attr_list , 1 , 0 , & size ) &&
1773
+ UpdateProcThreadAttribute (attr_list , 0 ,
1774
+ PROC_THREAD_ATTRIBUTE_HANDLE_LIST ,
1775
+ stdhandles ,
1776
+ stdhandles_count * sizeof (HANDLE ),
1777
+ NULL , NULL )) {
1778
+ si .lpAttributeList = attr_list ;
1779
+ flags |= EXTENDED_STARTUPINFO_PRESENT ;
1780
+ }
1781
+
1782
+ ret = CreateProcessW (* wcmd ? wcmd : NULL , wargs , NULL , NULL ,
1783
+ stdhandles_count ? TRUE : FALSE,
1784
+ flags , wenvblk , dir ? wdir : NULL ,
1785
+ & si .StartupInfo , & pi );
1786
+
1787
+ /*
1788
+ * On Windows 2008 R2, it seems that specifying certain types of handles
1789
+ * (such as FILE_TYPE_CHAR or FILE_TYPE_PIPE) will always produce an
1790
+ * error. Rather than playing finicky and fragile games, let's just try
1791
+ * to detect this situation and simply try again without restricting any
1792
+ * handle inheritance. This is still better than failing to create
1793
+ * processes.
1794
+ */
1795
+ if (!ret && restrict_handle_inheritance && stdhandles_count ) {
1796
+ DWORD err = GetLastError ();
1797
+ struct strbuf buf = STRBUF_INIT ;
1798
+
1799
+ if (err != ERROR_NO_SYSTEM_RESOURCES &&
1800
+ /*
1801
+ * On Windows 7 and earlier, handles on pipes and character
1802
+ * devices are inherited automatically, and cannot be
1803
+ * specified in the thread handle list. Rather than trying
1804
+ * to catch each and every corner case (and running the
1805
+ * chance of *still* forgetting a few), let's just fall
1806
+ * back to creating the process without trying to limit the
1807
+ * handle inheritance.
1808
+ */
1809
+ !(err == ERROR_INVALID_PARAMETER &&
1810
+ GetVersion () >> 16 < 9200 ) &&
1811
+ !getenv ("SUPPRESS_HANDLE_INHERITANCE_WARNING" )) {
1812
+ DWORD fl = 0 ;
1813
+ int i ;
1814
+
1815
+ setenv ("SUPPRESS_HANDLE_INHERITANCE_WARNING" , "1" , 1 );
1816
+
1817
+ for (i = 0 ; i < stdhandles_count ; i ++ ) {
1818
+ HANDLE h = stdhandles [i ];
1819
+ strbuf_addf (& buf , "handle #%d: %p (type %lx, "
1820
+ "handle info (%d) %lx\n" , i , h ,
1821
+ GetFileType (h ),
1822
+ GetHandleInformation (h , & fl ),
1823
+ fl );
1824
+ }
1825
+ strbuf_addstr (& buf , "\nThis is a bug; please report it "
1826
+ "at\nhttps://github.com/git-for-windows/"
1827
+ "git/issues/new\n\n"
1828
+ "To suppress this warning, please set "
1829
+ "the environment variable\n\n"
1830
+ "\tSUPPRESS_HANDLE_INHERITANCE_WARNING=1"
1831
+ "\n" );
1832
+ }
1833
+ restrict_handle_inheritance = 0 ;
1834
+ flags &= ~EXTENDED_STARTUPINFO_PRESENT ;
1835
+ ret = CreateProcessW (* wcmd ? wcmd : NULL , wargs , NULL , NULL ,
1836
+ TRUE, flags , wenvblk , dir ? wdir : NULL ,
1837
+ & si .StartupInfo , & pi );
1838
+ if (ret && buf .len ) {
1839
+ errno = err_win_to_posix (GetLastError ());
1840
+ warning ("failed to restrict file handles (%ld)\n\n%s" ,
1841
+ err , buf .buf );
1842
+ }
1843
+ strbuf_release (& buf );
1844
+ } else if (!ret )
1845
+ errno = err_win_to_posix (GetLastError ());
1846
+
1847
+ if (si .lpAttributeList )
1848
+ DeleteProcThreadAttributeList (si .lpAttributeList );
1849
+ if (attr_list )
1850
+ HeapFree (GetProcessHeap (), 0 , attr_list );
1732
1851
1733
1852
free (wenvblk );
1734
1853
free (wargs );
1735
1854
1736
- if (!ret ) {
1737
- errno = ENOENT ;
1855
+ if (!ret )
1738
1856
return -1 ;
1739
- }
1857
+
1740
1858
CloseHandle (pi .hThread );
1741
1859
1742
1860
/*
0 commit comments