@@ -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
@@ -1430,8 +1440,13 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1430
1440
const char * dir ,
1431
1441
int prepend_cmd , int fhin , int fhout , int fherr )
1432
1442
{
1433
- STARTUPINFOW si ;
1443
+ static int restrict_handle_inheritance = -1 ;
1444
+ STARTUPINFOEXW si ;
1434
1445
PROCESS_INFORMATION pi ;
1446
+ LPPROC_THREAD_ATTRIBUTE_LIST attr_list = NULL ;
1447
+ HANDLE stdhandles [3 ];
1448
+ DWORD stdhandles_count = 0 ;
1449
+ SIZE_T size ;
1435
1450
struct strbuf args ;
1436
1451
wchar_t wcmd [MAX_PATH ], wdir [MAX_PATH ], * wargs , * wenvblk = NULL ;
1437
1452
unsigned flags = CREATE_UNICODE_ENVIRONMENT ;
@@ -1441,6 +1456,16 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1441
1456
is_msys2_sh (* argv ) ? quote_arg_msys2 : quote_arg_msvc ;
1442
1457
const char * strace_env ;
1443
1458
1459
+ if (restrict_handle_inheritance < 0 )
1460
+ restrict_handle_inheritance = core_restrict_inherited_handles ;
1461
+ /*
1462
+ * The following code to restrict which handles are inherited seems
1463
+ * to work properly only on Windows 7 and later, so let's disable it
1464
+ * on Windows Vista and 2008.
1465
+ */
1466
+ if (restrict_handle_inheritance < 0 )
1467
+ restrict_handle_inheritance = GetVersion () >> 16 >= 7601 ;
1468
+
1444
1469
do_unset_environment_variables ();
1445
1470
1446
1471
/* Determine whether or not we are associated to a console */
@@ -1468,11 +1493,23 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1468
1493
CloseHandle (cons );
1469
1494
}
1470
1495
memset (& si , 0 , sizeof (si ));
1471
- si .cb = sizeof (si );
1472
- si .dwFlags = STARTF_USESTDHANDLES ;
1473
- si .hStdInput = winansi_get_osfhandle (fhin );
1474
- si .hStdOutput = winansi_get_osfhandle (fhout );
1475
- si .hStdError = winansi_get_osfhandle (fherr );
1496
+ si .StartupInfo .cb = sizeof (si );
1497
+ si .StartupInfo .hStdInput = winansi_get_osfhandle (fhin );
1498
+ si .StartupInfo .hStdOutput = winansi_get_osfhandle (fhout );
1499
+ si .StartupInfo .hStdError = winansi_get_osfhandle (fherr );
1500
+
1501
+ /* The list of handles cannot contain duplicates */
1502
+ if (si .StartupInfo .hStdInput != INVALID_HANDLE_VALUE )
1503
+ stdhandles [stdhandles_count ++ ] = si .StartupInfo .hStdInput ;
1504
+ if (si .StartupInfo .hStdOutput != INVALID_HANDLE_VALUE &&
1505
+ si .StartupInfo .hStdOutput != si .StartupInfo .hStdInput )
1506
+ stdhandles [stdhandles_count ++ ] = si .StartupInfo .hStdOutput ;
1507
+ if (si .StartupInfo .hStdError != INVALID_HANDLE_VALUE &&
1508
+ si .StartupInfo .hStdError != si .StartupInfo .hStdInput &&
1509
+ si .StartupInfo .hStdError != si .StartupInfo .hStdOutput )
1510
+ stdhandles [stdhandles_count ++ ] = si .StartupInfo .hStdError ;
1511
+ if (stdhandles_count )
1512
+ si .StartupInfo .dwFlags |= STARTF_USESTDHANDLES ;
1476
1513
1477
1514
if (* argv && !strcmp (cmd , * argv ))
1478
1515
wcmd [0 ] = L'\0' ;
@@ -1530,16 +1567,97 @@ static pid_t mingw_spawnve_fd(const char *cmd, const char **argv, char **deltaen
1530
1567
wenvblk = make_environment_block (deltaenv );
1531
1568
1532
1569
memset (& pi , 0 , sizeof (pi ));
1533
- ret = CreateProcessW (* wcmd ? wcmd : NULL , wargs , NULL , NULL , TRUE,
1534
- flags , wenvblk , dir ? wdir : NULL , & si , & pi );
1570
+ if (restrict_handle_inheritance && stdhandles_count &&
1571
+ (InitializeProcThreadAttributeList (NULL , 1 , 0 , & size ) ||
1572
+ GetLastError () == ERROR_INSUFFICIENT_BUFFER ) &&
1573
+ (attr_list = (LPPROC_THREAD_ATTRIBUTE_LIST )
1574
+ (HeapAlloc (GetProcessHeap (), 0 , size ))) &&
1575
+ InitializeProcThreadAttributeList (attr_list , 1 , 0 , & size ) &&
1576
+ UpdateProcThreadAttribute (attr_list , 0 ,
1577
+ PROC_THREAD_ATTRIBUTE_HANDLE_LIST ,
1578
+ stdhandles ,
1579
+ stdhandles_count * sizeof (HANDLE ),
1580
+ NULL , NULL )) {
1581
+ si .lpAttributeList = attr_list ;
1582
+ flags |= EXTENDED_STARTUPINFO_PRESENT ;
1583
+ }
1584
+
1585
+ ret = CreateProcessW (* wcmd ? wcmd : NULL , wargs , NULL , NULL ,
1586
+ stdhandles_count ? TRUE : FALSE,
1587
+ flags , wenvblk , dir ? wdir : NULL ,
1588
+ & si .StartupInfo , & pi );
1589
+
1590
+ /*
1591
+ * On Windows 2008 R2, it seems that specifying certain types of handles
1592
+ * (such as FILE_TYPE_CHAR or FILE_TYPE_PIPE) will always produce an
1593
+ * error. Rather than playing finicky and fragile games, let's just try
1594
+ * to detect this situation and simply try again without restricting any
1595
+ * handle inheritance. This is still better than failing to create
1596
+ * processes.
1597
+ */
1598
+ if (!ret && restrict_handle_inheritance && stdhandles_count ) {
1599
+ DWORD err = GetLastError ();
1600
+ struct strbuf buf = STRBUF_INIT ;
1601
+
1602
+ if (err != ERROR_NO_SYSTEM_RESOURCES &&
1603
+ /*
1604
+ * On Windows 7 and earlier, handles on pipes and character
1605
+ * devices are inherited automatically, and cannot be
1606
+ * specified in the thread handle list. Rather than trying
1607
+ * to catch each and every corner case (and running the
1608
+ * chance of *still* forgetting a few), let's just fall
1609
+ * back to creating the process without trying to limit the
1610
+ * handle inheritance.
1611
+ */
1612
+ !(err == ERROR_INVALID_PARAMETER &&
1613
+ GetVersion () >> 16 < 9200 ) &&
1614
+ !getenv ("SUPPRESS_HANDLE_INHERITANCE_WARNING" )) {
1615
+ DWORD fl = 0 ;
1616
+ int i ;
1617
+
1618
+ setenv ("SUPPRESS_HANDLE_INHERITANCE_WARNING" , "1" , 1 );
1619
+
1620
+ for (i = 0 ; i < stdhandles_count ; i ++ ) {
1621
+ HANDLE h = stdhandles [i ];
1622
+ strbuf_addf (& buf , "handle #%d: %p (type %lx, "
1623
+ "handle info (%d) %lx\n" , i , h ,
1624
+ GetFileType (h ),
1625
+ GetHandleInformation (h , & fl ),
1626
+ fl );
1627
+ }
1628
+ strbuf_addstr (& buf , "\nThis is a bug; please report it "
1629
+ "at\nhttps://github.com/git-for-windows/"
1630
+ "git/issues/new\n\n"
1631
+ "To suppress this warning, please set "
1632
+ "the environment variable\n\n"
1633
+ "\tSUPPRESS_HANDLE_INHERITANCE_WARNING=1"
1634
+ "\n" );
1635
+ }
1636
+ restrict_handle_inheritance = 0 ;
1637
+ flags &= ~EXTENDED_STARTUPINFO_PRESENT ;
1638
+ ret = CreateProcessW (* wcmd ? wcmd : NULL , wargs , NULL , NULL ,
1639
+ TRUE, flags , wenvblk , dir ? wdir : NULL ,
1640
+ & si .StartupInfo , & pi );
1641
+ if (ret && buf .len ) {
1642
+ errno = err_win_to_posix (GetLastError ());
1643
+ warning ("failed to restrict file handles (%ld)\n\n%s" ,
1644
+ err , buf .buf );
1645
+ }
1646
+ strbuf_release (& buf );
1647
+ } else if (!ret )
1648
+ errno = err_win_to_posix (GetLastError ());
1649
+
1650
+ if (si .lpAttributeList )
1651
+ DeleteProcThreadAttributeList (si .lpAttributeList );
1652
+ if (attr_list )
1653
+ HeapFree (GetProcessHeap (), 0 , attr_list );
1535
1654
1536
1655
free (wenvblk );
1537
1656
free (wargs );
1538
1657
1539
- if (!ret ) {
1540
- errno = ENOENT ;
1658
+ if (!ret )
1541
1659
return -1 ;
1542
- }
1660
+
1543
1661
CloseHandle (pi .hThread );
1544
1662
1545
1663
/*
0 commit comments