@@ -225,6 +225,7 @@ enum hide_dotfiles_type {
225
225
HIDE_DOTFILES_DOTGITONLY
226
226
};
227
227
228
+ static int core_restrict_inherited_handles = -1 ;
228
229
static enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY ;
229
230
static char * unset_environment_variables ;
230
231
@@ -244,6 +245,15 @@ int mingw_core_config(const char *var, const char *value, void *cb)
244
245
return 0 ;
245
246
}
246
247
248
+ if (!strcmp (var , "core.restrictinheritedhandles" )) {
249
+ if (value && !strcasecmp (value , "auto" ))
250
+ core_restrict_inherited_handles = -1 ;
251
+ else
252
+ core_restrict_inherited_handles =
253
+ git_config_bool (var , value );
254
+ return 0 ;
255
+ }
256
+
247
257
return 0 ;
248
258
}
249
259
@@ -1468,8 +1478,13 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1468
1478
const char * dir ,
1469
1479
int prepend_cmd , int fhin , int fhout , int fherr )
1470
1480
{
1471
- STARTUPINFOW si ;
1481
+ static int restrict_handle_inheritance = -1 ;
1482
+ STARTUPINFOEXW si ;
1472
1483
PROCESS_INFORMATION pi ;
1484
+ LPPROC_THREAD_ATTRIBUTE_LIST attr_list = NULL ;
1485
+ HANDLE stdhandles [3 ];
1486
+ DWORD stdhandles_count = 0 ;
1487
+ SIZE_T size ;
1473
1488
struct strbuf args ;
1474
1489
wchar_t wcmd [MAX_PATH ], wdir [MAX_PATH ], * wargs , * wenvblk = NULL ;
1475
1490
unsigned flags = CREATE_UNICODE_ENVIRONMENT ;
@@ -1480,6 +1495,16 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1480
1495
quote_arg_msys2 : quote_arg_msvc ;
1481
1496
const char * strace_env ;
1482
1497
1498
+ if (restrict_handle_inheritance < 0 )
1499
+ restrict_handle_inheritance = core_restrict_inherited_handles ;
1500
+ /*
1501
+ * The following code to restrict which handles are inherited seems
1502
+ * to work properly only on Windows 7 and later, so let's disable it
1503
+ * on Windows Vista and 2008.
1504
+ */
1505
+ if (restrict_handle_inheritance < 0 )
1506
+ restrict_handle_inheritance = GetVersion () >> 16 >= 7601 ;
1507
+
1483
1508
do_unset_environment_variables ();
1484
1509
1485
1510
/* Determine whether or not we are associated to a console */
@@ -1507,11 +1532,23 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1507
1532
CloseHandle (cons );
1508
1533
}
1509
1534
memset (& si , 0 , sizeof (si ));
1510
- si .cb = sizeof (si );
1511
- si .dwFlags = STARTF_USESTDHANDLES ;
1512
- si .hStdInput = winansi_get_osfhandle (fhin );
1513
- si .hStdOutput = winansi_get_osfhandle (fhout );
1514
- si .hStdError = winansi_get_osfhandle (fherr );
1535
+ si .StartupInfo .cb = sizeof (si );
1536
+ si .StartupInfo .hStdInput = winansi_get_osfhandle (fhin );
1537
+ si .StartupInfo .hStdOutput = winansi_get_osfhandle (fhout );
1538
+ si .StartupInfo .hStdError = winansi_get_osfhandle (fherr );
1539
+
1540
+ /* The list of handles cannot contain duplicates */
1541
+ if (si .StartupInfo .hStdInput != INVALID_HANDLE_VALUE )
1542
+ stdhandles [stdhandles_count ++ ] = si .StartupInfo .hStdInput ;
1543
+ if (si .StartupInfo .hStdOutput != INVALID_HANDLE_VALUE &&
1544
+ si .StartupInfo .hStdOutput != si .StartupInfo .hStdInput )
1545
+ stdhandles [stdhandles_count ++ ] = si .StartupInfo .hStdOutput ;
1546
+ if (si .StartupInfo .hStdError != INVALID_HANDLE_VALUE &&
1547
+ si .StartupInfo .hStdError != si .StartupInfo .hStdInput &&
1548
+ si .StartupInfo .hStdError != si .StartupInfo .hStdOutput )
1549
+ stdhandles [stdhandles_count ++ ] = si .StartupInfo .hStdError ;
1550
+ if (stdhandles_count )
1551
+ si .StartupInfo .dwFlags |= STARTF_USESTDHANDLES ;
1515
1552
1516
1553
if (* argv && !strcmp (cmd , * argv ))
1517
1554
wcmd [0 ] = L'\0' ;
@@ -1569,16 +1606,97 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1569
1606
wenvblk = make_environment_block (deltaenv );
1570
1607
1571
1608
memset (& pi , 0 , sizeof (pi ));
1572
- ret = CreateProcessW (* wcmd ? wcmd : NULL , wargs , NULL , NULL , TRUE,
1573
- flags , wenvblk , dir ? wdir : NULL , & si , & pi );
1609
+ if (restrict_handle_inheritance && stdhandles_count &&
1610
+ (InitializeProcThreadAttributeList (NULL , 1 , 0 , & size ) ||
1611
+ GetLastError () == ERROR_INSUFFICIENT_BUFFER ) &&
1612
+ (attr_list = (LPPROC_THREAD_ATTRIBUTE_LIST )
1613
+ (HeapAlloc (GetProcessHeap (), 0 , size ))) &&
1614
+ InitializeProcThreadAttributeList (attr_list , 1 , 0 , & size ) &&
1615
+ UpdateProcThreadAttribute (attr_list , 0 ,
1616
+ PROC_THREAD_ATTRIBUTE_HANDLE_LIST ,
1617
+ stdhandles ,
1618
+ stdhandles_count * sizeof (HANDLE ),
1619
+ NULL , NULL )) {
1620
+ si .lpAttributeList = attr_list ;
1621
+ flags |= EXTENDED_STARTUPINFO_PRESENT ;
1622
+ }
1623
+
1624
+ ret = CreateProcessW (* wcmd ? wcmd : NULL , wargs , NULL , NULL ,
1625
+ stdhandles_count ? TRUE : FALSE,
1626
+ flags , wenvblk , dir ? wdir : NULL ,
1627
+ & si .StartupInfo , & pi );
1628
+
1629
+ /*
1630
+ * On Windows 2008 R2, it seems that specifying certain types of handles
1631
+ * (such as FILE_TYPE_CHAR or FILE_TYPE_PIPE) will always produce an
1632
+ * error. Rather than playing finicky and fragile games, let's just try
1633
+ * to detect this situation and simply try again without restricting any
1634
+ * handle inheritance. This is still better than failing to create
1635
+ * processes.
1636
+ */
1637
+ if (!ret && restrict_handle_inheritance && stdhandles_count ) {
1638
+ DWORD err = GetLastError ();
1639
+ struct strbuf buf = STRBUF_INIT ;
1640
+
1641
+ if (err != ERROR_NO_SYSTEM_RESOURCES &&
1642
+ /*
1643
+ * On Windows 7 and earlier, handles on pipes and character
1644
+ * devices are inherited automatically, and cannot be
1645
+ * specified in the thread handle list. Rather than trying
1646
+ * to catch each and every corner case (and running the
1647
+ * chance of *still* forgetting a few), let's just fall
1648
+ * back to creating the process without trying to limit the
1649
+ * handle inheritance.
1650
+ */
1651
+ !(err == ERROR_INVALID_PARAMETER &&
1652
+ GetVersion () >> 16 < 9200 ) &&
1653
+ !getenv ("SUPPRESS_HANDLE_INHERITANCE_WARNING" )) {
1654
+ DWORD fl = 0 ;
1655
+ int i ;
1656
+
1657
+ setenv ("SUPPRESS_HANDLE_INHERITANCE_WARNING" , "1" , 1 );
1658
+
1659
+ for (i = 0 ; i < stdhandles_count ; i ++ ) {
1660
+ HANDLE h = stdhandles [i ];
1661
+ strbuf_addf (& buf , "handle #%d: %p (type %lx, "
1662
+ "handle info (%d) %lx\n" , i , h ,
1663
+ GetFileType (h ),
1664
+ GetHandleInformation (h , & fl ),
1665
+ fl );
1666
+ }
1667
+ strbuf_addstr (& buf , "\nThis is a bug; please report it "
1668
+ "at\nhttps://github.com/git-for-windows/"
1669
+ "git/issues/new\n\n"
1670
+ "To suppress this warning, please set "
1671
+ "the environment variable\n\n"
1672
+ "\tSUPPRESS_HANDLE_INHERITANCE_WARNING=1"
1673
+ "\n" );
1674
+ }
1675
+ restrict_handle_inheritance = 0 ;
1676
+ flags &= ~EXTENDED_STARTUPINFO_PRESENT ;
1677
+ ret = CreateProcessW (* wcmd ? wcmd : NULL , wargs , NULL , NULL ,
1678
+ TRUE, flags , wenvblk , dir ? wdir : NULL ,
1679
+ & si .StartupInfo , & pi );
1680
+ if (ret && buf .len ) {
1681
+ errno = err_win_to_posix (GetLastError ());
1682
+ warning ("failed to restrict file handles (%ld)\n\n%s" ,
1683
+ err , buf .buf );
1684
+ }
1685
+ strbuf_release (& buf );
1686
+ } else if (!ret )
1687
+ errno = err_win_to_posix (GetLastError ());
1688
+
1689
+ if (si .lpAttributeList )
1690
+ DeleteProcThreadAttributeList (si .lpAttributeList );
1691
+ if (attr_list )
1692
+ HeapFree (GetProcessHeap (), 0 , attr_list );
1574
1693
1575
1694
free (wenvblk );
1576
1695
free (wargs );
1577
1696
1578
- if (!ret ) {
1579
- errno = ENOENT ;
1697
+ if (!ret )
1580
1698
return -1 ;
1581
- }
1699
+
1582
1700
CloseHandle (pi .hThread );
1583
1701
1584
1702
/*
0 commit comments