@@ -114,6 +114,7 @@ int err_win_to_posix(DWORD winerr)
114
114
case ERROR_SHARING_BUFFER_EXCEEDED : error = ENFILE ; break ;
115
115
case ERROR_SHARING_VIOLATION : error = EACCES ; break ;
116
116
case ERROR_STACK_OVERFLOW : error = ENOMEM ; break ;
117
+ case ERROR_SUCCESS : BUG ("err_win_to_posix() called without an error!" );
117
118
case ERROR_SWAPERROR : error = ENOENT ; break ;
118
119
case ERROR_TOO_MANY_MODULES : error = EMFILE ; break ;
119
120
case ERROR_TOO_MANY_OPEN_FILES : error = EMFILE ; break ;
@@ -212,6 +213,7 @@ enum hide_dotfiles_type {
212
213
HIDE_DOTFILES_DOTGITONLY
213
214
};
214
215
216
+ static int core_restrict_inherited_handles = -1 ;
215
217
static enum hide_dotfiles_type hide_dotfiles = HIDE_DOTFILES_DOTGITONLY ;
216
218
static char * unset_environment_variables ;
217
219
@@ -231,6 +233,15 @@ int mingw_core_config(const char *var, const char *value, void *cb)
231
233
return 0 ;
232
234
}
233
235
236
+ if (!strcmp (var , "core.restrictinheritedhandles" )) {
237
+ if (value && !strcasecmp (value , "auto" ))
238
+ core_restrict_inherited_handles = -1 ;
239
+ else
240
+ core_restrict_inherited_handles =
241
+ git_config_bool (var , value );
242
+ return 0 ;
243
+ }
244
+
234
245
return 0 ;
235
246
}
236
247
@@ -1436,8 +1447,13 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1436
1447
const char * dir ,
1437
1448
int prepend_cmd , int fhin , int fhout , int fherr )
1438
1449
{
1439
- STARTUPINFOW si ;
1450
+ static int restrict_handle_inheritance = -1 ;
1451
+ STARTUPINFOEXW si ;
1440
1452
PROCESS_INFORMATION pi ;
1453
+ LPPROC_THREAD_ATTRIBUTE_LIST attr_list = NULL ;
1454
+ HANDLE stdhandles [3 ];
1455
+ DWORD stdhandles_count = 0 ;
1456
+ SIZE_T size ;
1441
1457
struct strbuf args ;
1442
1458
wchar_t wcmd [MAX_PATH ], wdir [MAX_PATH ], * wargs , * wenvblk = NULL ;
1443
1459
unsigned flags = CREATE_UNICODE_ENVIRONMENT ;
@@ -1447,6 +1463,19 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1447
1463
is_msys2_sh (cmd ? cmd : * argv ) ?
1448
1464
quote_arg_msys2 : quote_arg_msvc ;
1449
1465
1466
+ /* Make sure to override previous errors, if any */
1467
+ errno = 0 ;
1468
+
1469
+ if (restrict_handle_inheritance < 0 )
1470
+ restrict_handle_inheritance = core_restrict_inherited_handles ;
1471
+ /*
1472
+ * The following code to restrict which handles are inherited seems
1473
+ * to work properly only on Windows 7 and later, so let's disable it
1474
+ * on Windows Vista and 2008.
1475
+ */
1476
+ if (restrict_handle_inheritance < 0 )
1477
+ restrict_handle_inheritance = GetVersion () >> 16 >= 7601 ;
1478
+
1450
1479
do_unset_environment_variables ();
1451
1480
1452
1481
/* Determine whether or not we are associated to a console */
@@ -1474,11 +1503,23 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1474
1503
CloseHandle (cons );
1475
1504
}
1476
1505
memset (& si , 0 , sizeof (si ));
1477
- si .cb = sizeof (si );
1478
- si .dwFlags = STARTF_USESTDHANDLES ;
1479
- si .hStdInput = winansi_get_osfhandle (fhin );
1480
- si .hStdOutput = winansi_get_osfhandle (fhout );
1481
- si .hStdError = winansi_get_osfhandle (fherr );
1506
+ si .StartupInfo .cb = sizeof (si );
1507
+ si .StartupInfo .hStdInput = winansi_get_osfhandle (fhin );
1508
+ si .StartupInfo .hStdOutput = winansi_get_osfhandle (fhout );
1509
+ si .StartupInfo .hStdError = winansi_get_osfhandle (fherr );
1510
+
1511
+ /* The list of handles cannot contain duplicates */
1512
+ if (si .StartupInfo .hStdInput != INVALID_HANDLE_VALUE )
1513
+ stdhandles [stdhandles_count ++ ] = si .StartupInfo .hStdInput ;
1514
+ if (si .StartupInfo .hStdOutput != INVALID_HANDLE_VALUE &&
1515
+ si .StartupInfo .hStdOutput != si .StartupInfo .hStdInput )
1516
+ stdhandles [stdhandles_count ++ ] = si .StartupInfo .hStdOutput ;
1517
+ if (si .StartupInfo .hStdError != INVALID_HANDLE_VALUE &&
1518
+ si .StartupInfo .hStdError != si .StartupInfo .hStdInput &&
1519
+ si .StartupInfo .hStdError != si .StartupInfo .hStdOutput )
1520
+ stdhandles [stdhandles_count ++ ] = si .StartupInfo .hStdError ;
1521
+ if (stdhandles_count )
1522
+ si .StartupInfo .dwFlags |= STARTF_USESTDHANDLES ;
1482
1523
1483
1524
if (* argv && !strcmp (cmd , * argv ))
1484
1525
wcmd [0 ] = L'\0' ;
@@ -1511,16 +1552,98 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1511
1552
wenvblk = make_environment_block (deltaenv );
1512
1553
1513
1554
memset (& pi , 0 , sizeof (pi ));
1514
- ret = CreateProcessW (* wcmd ? wcmd : NULL , wargs , NULL , NULL , TRUE,
1515
- flags , wenvblk , dir ? wdir : NULL , & si , & pi );
1555
+ if (restrict_handle_inheritance && stdhandles_count &&
1556
+ (InitializeProcThreadAttributeList (NULL , 1 , 0 , & size ) ||
1557
+ GetLastError () == ERROR_INSUFFICIENT_BUFFER ) &&
1558
+ (attr_list = (LPPROC_THREAD_ATTRIBUTE_LIST )
1559
+ (HeapAlloc (GetProcessHeap (), 0 , size ))) &&
1560
+ InitializeProcThreadAttributeList (attr_list , 1 , 0 , & size ) &&
1561
+ UpdateProcThreadAttribute (attr_list , 0 ,
1562
+ PROC_THREAD_ATTRIBUTE_HANDLE_LIST ,
1563
+ stdhandles ,
1564
+ stdhandles_count * sizeof (HANDLE ),
1565
+ NULL , NULL )) {
1566
+ si .lpAttributeList = attr_list ;
1567
+ flags |= EXTENDED_STARTUPINFO_PRESENT ;
1568
+ }
1569
+
1570
+ ret = CreateProcessW (* wcmd ? wcmd : NULL , wargs , NULL , NULL ,
1571
+ stdhandles_count ? TRUE : FALSE,
1572
+ flags , wenvblk , dir ? wdir : NULL ,
1573
+ & si .StartupInfo , & pi );
1574
+
1575
+ /*
1576
+ * On Windows 2008 R2, it seems that specifying certain types of handles
1577
+ * (such as FILE_TYPE_CHAR or FILE_TYPE_PIPE) will always produce an
1578
+ * error. Rather than playing finicky and fragile games, let's just try
1579
+ * to detect this situation and simply try again without restricting any
1580
+ * handle inheritance. This is still better than failing to create
1581
+ * processes.
1582
+ */
1583
+ if (!ret && restrict_handle_inheritance && stdhandles_count ) {
1584
+ DWORD err = GetLastError ();
1585
+ struct strbuf buf = STRBUF_INIT ;
1586
+
1587
+ if (err != ERROR_NO_SYSTEM_RESOURCES &&
1588
+ /*
1589
+ * On Windows 7 and earlier, handles on pipes and character
1590
+ * devices are inherited automatically, and cannot be
1591
+ * specified in the thread handle list. Rather than trying
1592
+ * to catch each and every corner case (and running the
1593
+ * chance of *still* forgetting a few), let's just fall
1594
+ * back to creating the process without trying to limit the
1595
+ * handle inheritance.
1596
+ */
1597
+ !(err == ERROR_INVALID_PARAMETER &&
1598
+ GetVersion () >> 16 < 9200 ) &&
1599
+ !getenv ("SUPPRESS_HANDLE_INHERITANCE_WARNING" )) {
1600
+ DWORD fl = 0 ;
1601
+ int i ;
1602
+
1603
+ setenv ("SUPPRESS_HANDLE_INHERITANCE_WARNING" , "1" , 1 );
1604
+
1605
+ for (i = 0 ; i < stdhandles_count ; i ++ ) {
1606
+ HANDLE h = stdhandles [i ];
1607
+ strbuf_addf (& buf , "handle #%d: %p (type %lx, "
1608
+ "handle info (%d) %lx\n" , i , h ,
1609
+ GetFileType (h ),
1610
+ GetHandleInformation (h , & fl ),
1611
+ fl );
1612
+ }
1613
+ strbuf_addstr (& buf , "\nThis is a bug; please report it "
1614
+ "at\nhttps://github.com/git-for-windows/"
1615
+ "git/issues/new\n\n"
1616
+ "To suppress this warning, please set "
1617
+ "the environment variable\n\n"
1618
+ "\tSUPPRESS_HANDLE_INHERITANCE_WARNING=1"
1619
+ "\n" );
1620
+ }
1621
+ restrict_handle_inheritance = 0 ;
1622
+ flags &= ~EXTENDED_STARTUPINFO_PRESENT ;
1623
+ ret = CreateProcessW (* wcmd ? wcmd : NULL , wargs , NULL , NULL ,
1624
+ TRUE, flags , wenvblk , dir ? wdir : NULL ,
1625
+ & si .StartupInfo , & pi );
1626
+ if (!ret )
1627
+ errno = err_win_to_posix (GetLastError ());
1628
+ if (ret && buf .len ) {
1629
+ warning ("failed to restrict file handles (%ld)\n\n%s" ,
1630
+ err , buf .buf );
1631
+ }
1632
+ strbuf_release (& buf );
1633
+ } else if (!ret )
1634
+ errno = err_win_to_posix (GetLastError ());
1635
+
1636
+ if (si .lpAttributeList )
1637
+ DeleteProcThreadAttributeList (si .lpAttributeList );
1638
+ if (attr_list )
1639
+ HeapFree (GetProcessHeap (), 0 , attr_list );
1516
1640
1517
1641
free (wenvblk );
1518
1642
free (wargs );
1519
1643
1520
- if (!ret ) {
1521
- errno = ENOENT ;
1644
+ if (!ret )
1522
1645
return -1 ;
1523
- }
1646
+
1524
1647
CloseHandle (pi .hThread );
1525
1648
1526
1649
/*
0 commit comments