Compare commits

...

10 Commits

Author SHA1 Message Date
Brian Inglis 6604db8b80 fhandler/proc.cc: use wincap.has_user_shstk
In test for AMD/Intel Control flow Enforcement Technology user mode
shadow stack support replace Windows version tests with test of wincap
member addition has_user_shstk with Windows version dependent value

Fixes: 41fdb869f9 ("fhandler/proc.cc(format_proc_cpuinfo): Add Linux 6.3 cpuinfo")
Signed-off-by: Brian Inglis <Brian.Inglis@Shaw.ca>
2023-06-20 10:06:56 +02:00
Brian Inglis 1c4a00962f wincap.cc: set wincap member has_user_shstk true for 2004+
Signed-off-by: Brian Inglis <Brian.Inglis@Shaw.ca>
2023-06-20 10:06:56 +02:00
Brian Inglis 293785382c wincap.h: add wincap member has_user_shstk
Indicate support of user mode hardware-enforced shadow stack

Signed-off-by: Brian Inglis <Brian.Inglis@Shaw.ca>
2023-06-20 10:06:56 +02:00
Philippe Cerfon 0480315010 Cygwin: use new XATTR_{NAME,SIZE}_MAX instead of MAX_EA_{NAME,VALUE}_LEN
Signed-off-by: Philippe Cerfon <philcerf@gmail.com>
2023-06-16 21:44:41 +02:00
Philippe Cerfon 538b29a8da Cygwin: export XATTR_{NAME,SIZE,LIST}_MAX
These are used for example by CPython.

Signed-off-by: Philippe Cerfon <philcerf@gmail.com>
Signed-off-by: Corinna Vinschen <corinna@vinschen.de>
2023-06-16 21:44:41 +02:00
Johannes Schindelin 80ff7bc26c Do not rely on `getenv ("HOME")`'s path conversion
In the very early code path where `dll_crt0_1 ()` calls
`user_shared->initialize ()`, the Cygwin runtime calls `internal_pwsid ()`
to initialize the user name in preparation for reading the `fstab` file.

In case `db_home: env` is defined in `/etc/nsswitch.conf`, we need to
look at the environment variable `HOME` and use it, if set.

When all of this happens, though, the `pinfo_init ()` function has had no
chance to run yet (and therefore, `environ_init ()`). At this stage,
therefore, `getenv ()`'s `findenv_func ()` call still finds `getearly ()`
and we get the _verbatim_ value of `HOME`. That is, the Windows form.
But we need the "POSIX" form.

To add insult to injury, later calls to `getpwuid (getuid ())` will
receive a cached version of the home directory via
`cygheap->pg.pwd_cache.win.find_user ()` thanks to the first
`internal_pwsid ()` call caching the result via
`add_user_from_cygserver ()`, read: we will never receive the converted
`HOME` but always the Windows variant.

So, contrary to the assumptions made in 27376c60a9 (Allow deriving the
current user's home directory via the HOME variable, 2023-03-28), we
cannot assume that `getenv ("HOME")` returned a "POSIX" path.

This is a real problem. Even setting aside that common callers of
`getpwuid ()` (such as OpenSSH) are unable to handle Windows paths in the
`pw_dir` attribute, the Windows path never makes it back to the caller
unscathed. The value returned from `fetch_home_env ()` is not actually
used as-is. Instead, the `fetch_account_from_windows ()` method uses it
to write a pseudo `/etc/passwd`-formatted line that is _then_ parsed via
the `pwdgrp::parse_passwd ()` method which sees no problem with
misinterpreting the colon after the drive letter as a field separator of
that `/etc/passwd`-formatted line, and instead of a Windows path, we now
have a mere drive letter.

Let's detect when the `HOME` value is still in Windows format in
`fetch_home_env ()`, and convert it in that case.

For good measure, interpret this "Windows format" not only to include
absolute paths with drive prefixes, but also UNC paths.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2023-06-06 15:18:53 +02:00
Johannes Schindelin e9dd5d8f25 uinfo: special-case IIS APPPOOL accounts
The account under which Azure Web Apps run is an IIS APPOOL account that
is generated on the fly.

These are special because the virtual machines on which thes Apps run
are not domain-joined, yet the accounts are domain accounts.

To support the use case where such a Web App needs to call `ssh` (e.g.
to deploy from a Git repository that is accessible only via SSH), we do
need OpenSSH's `getpwuid (getuid ())` invocation to work.

But currently it does not. Concretely, `getuid ()` returns -1 for these
accounts, and OpenSSH fails to find the correct home directory
(_especially_ when that home directory was overridden via a `db_home:
env` line in `/etc/nsswitch.conf`).

This can be verified e.g. in a Kudu console (for details about Kudu
consoles, see https://github.com/projectkudu/kudu/wiki/Kudu-console):
the domain is `IIS APPPOOL`, the account name is the name of the Azure
Web App, the SID starts with 'S-1-5-82-`, and
`pwdgrp::fetch_account_from_windows()` runs into the code path where
"[...] the domain returned by LookupAccountSid is not our machine name,
and if our machine is no domain member, we lose.  We have nobody to ask
for the POSIX offset."

Since these IIS APPPOOL accounts are relatively similar to AzureAD
accounts in this scenario, let's imitate the latter to support also the
former.

Reported-by: David Ebbo <david.ebbo@gmail.com>
Helped-by: Corinna Vinschen <corinna@vinschen.de>
Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
2023-06-06 15:18:53 +02:00
Takashi Yano a903878948 Cygwin: pty: Additional fix for transferring input at exit.
The commit 9fc746d17d does not fix transferring input at exit
appropriately. If the more than one non-cygwin apps are executed
simultaneously and one of them is terminated, the pty master failed
to send input to the other non-cygwin apps. This patch fixes that.

Fixes: 9fc746d17d ("Cygwin: pty: Fix transferring type-ahead input between input pipes.")
Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
2023-06-02 10:19:18 +09:00
Takashi Yano 9fc746d17d Cygwin: pty: Fix transferring type-ahead input between input pipes.
After the commit e5fcc5837c, transferring type-ahead input between
the pipe for cygwin app and the pipe for non-cygwin app will not be
done appropriately when the stdin of the non-cygwin app is not pty.
Due to this issue, sometimes the keyboard input might be lost which
should be sent to cygwin app. This patch fixes the issue.

Fixes: e5fcc5837c ("Cygwin: pty: Fix reading CONIN$ when stdin is not a pty.")
Signed-off-by: Takashi Yano <takashi.yano@nifty.ne.jp>
2023-06-01 20:00:45 +09:00
Chris Packham 28489b0702 config/mt-d30v: Append flags
Append to CFLAGS_FOR_TARGET/CXXFLAGS_FOR_TARGET rather than replacing
them.

Signed-off-by: Chris Packham <judge.packham@gmail.com>
2023-05-30 13:55:09 -04:00
8 changed files with 151 additions and 43 deletions

View File

@ -1,4 +1,4 @@
# Build libraries optimizing for space, not speed.
# Turn off warnings about symbols named the same as registers
CFLAGS_FOR_TARGET = -g -Os -Wa,-C
CXXFLAGS_FOR_TARGET = -g -Os -Wa,-C
CFLAGS_FOR_TARGET += -g -Os -Wa,-C
CXXFLAGS_FOR_TARGET += -g -Os -Wa,-C

View File

@ -1486,12 +1486,12 @@ format_proc_cpuinfo (void *, char *&destbuf)
/* ftcprint (features1, 6, "split_lock_detect");*//* MSR_TEST_CTRL split lock */
/* cpuid 0x00000007 ecx & Windows [20]20H1/[20]2004+ */
if (maxf >= 0x00000007 && wincap.osname () >= "10.0"
&& wincap.build_number () >= 19041)
/* Windows [20]20H1/[20]2004/19041 user shadow stack */
if (maxf >= 0x00000007 && wincap.has_user_shstk ())
{
/* cpuid 0x00000007 ecx CET shadow stack */
cpuid (&unused, &unused, &features1, &unused, 0x00000007, 0);
ftcprint (features1, 7, "user_shstk"); /* "user shadow stack" */
ftcprint (features1, 7, "user_shstk"); /* user shadow stack */
}
/* cpuid 0x00000007:1 eax */

View File

@ -1297,17 +1297,7 @@ fhandler_pty_slave::mask_switch_to_nat_pipe (bool mask, bool xfer)
else if (InterlockedDecrement (&num_reader) == 0)
CloseHandle (slave_reading);
/* This is needed when cygwin-app is started from non-cygwin app if
pseudo console is disabled. */
bool need_xfer = get_ttyp ()->nat_fg (get_ttyp ()->getpgid ())
&& get_ttyp ()->switch_to_nat_pipe && !get_ttyp ()->pcon_activated;
/* In GDB, transfer input based on setpgid() does not work because
GDB may not set terminal process group properly. Therefore,
transfer input here if isHybrid is set. */
bool need_gdb_xfer =
isHybrid && GetStdHandle (STD_INPUT_HANDLE) == get_handle ();
if (!!masked != mask && xfer && (need_gdb_xfer || need_xfer))
if (!!masked != mask && xfer && get_ttyp ()->switch_to_nat_pipe)
{
if (mask && get_ttyp ()->pty_input_state_eq (tty::to_nat))
{
@ -2238,11 +2228,7 @@ fhandler_pty_master::write (const void *ptr, size_t len)
if (!get_ttyp ()->pcon_start)
{ /* Pseudo console initialization has been done in above code. */
pinfo pp (get_ttyp ()->pcon_start_pid);
bool pcon_fg = (pp && get_ttyp ()->getpgid () == pp->pgid);
/* GDB may set WINPID rather than cygwin PID to process group
when the debugged process is a non-cygwin process.*/
pcon_fg |= !pinfo (get_ttyp ()->getpgid ());
if (get_ttyp ()->switch_to_nat_pipe && pcon_fg
if (get_ttyp ()->switch_to_nat_pipe
&& get_ttyp ()->pty_input_state_eq (tty::to_cyg))
{
/* This accept_input() call is needed in order to transfer input
@ -4089,7 +4075,14 @@ fhandler_pty_slave::cleanup_for_non_cygwin_app (handle_set_t *p, tty *ttyp,
DWORD force_switch_to)
{
ttyp->wait_fwd ();
if (ttyp->getpgid () == myself->pgid && stdin_is_ptys
DWORD current_pid = myself->exec_dwProcessId ?: myself->dwProcessId;
DWORD switch_to = force_switch_to;
WaitForSingleObject (p->pipe_sw_mutex, INFINITE);
if (!switch_to)
switch_to = get_console_process_id (current_pid, false, true, true);
if (!switch_to)
switch_to = get_console_process_id (current_pid, false, true, false);
if ((!switch_to && (ttyp->pcon_activated || stdin_is_ptys))
&& ttyp->pty_input_state_eq (tty::to_nat))
{
WaitForSingleObject (p->input_mutex, mutex_timeout);
@ -4099,7 +4092,6 @@ fhandler_pty_slave::cleanup_for_non_cygwin_app (handle_set_t *p, tty *ttyp,
release_attach_mutex ();
ReleaseMutex (p->input_mutex);
}
WaitForSingleObject (p->pipe_sw_mutex, INFINITE);
if (ttyp->pcon_activated)
close_pseudoconsole (ttyp, force_switch_to);
else

View File

@ -56,4 +56,11 @@ details. */
#define __PATH_MAX 4096
#define __PIPE_BUF 4096
/* XATTR_NAME_MAX is the maximum XATTR name length excluding the null
* terminator. Since only XATTRs in the `user' namespace are allowed and the
* `user.' prefix is not stored, the maximum is increased by 5. */
#define XATTR_NAME_MAX 260
#define XATTR_SIZE_MAX 65536
#define XATTR_LIST_MAX 65536
#endif /* _CYGWIN_LIMITS_H__ */

View File

@ -32,6 +32,7 @@ struct wincaps
unsigned has_linux_tcp_keepalive_sockopts : 1;
unsigned has_tcp_maxrtms : 1;
unsigned has_con_broken_tabs : 1;
unsigned has_user_shstk : 1;
};
};
@ -84,6 +85,7 @@ public:
bool IMPLEMENT (has_linux_tcp_keepalive_sockopts)
bool IMPLEMENT (has_tcp_maxrtms)
bool IMPLEMENT (has_con_broken_tabs)
bool IMPLEMENT (has_user_shstk)
void disable_case_sensitive_dirs ()
{

View File

@ -17,9 +17,11 @@ details. */
#include "tls_pbuf.h"
#include <stdlib.h>
#include <attr/xattr.h>
#include <cygwin/limits.h>
#define MAX_EA_NAME_LEN 256
#define MAX_EA_VALUE_LEN 65536
/* On storage the `user.` prefix is not included but the terminating null byte
is needed.*/
#define _XATTR_NAME_MAX_ONDISK_ (XATTR_NAME_MAX - strlen("user.") + 1)
/* At least one maximum sized entry fits.
CV 2014-04-04: NtQueryEaFile function chokes on buffers bigger than 64K
@ -27,13 +29,13 @@ details. */
on a remote share, at least on Windows 7 and later.
In theory the buffer should have a size of
sizeof (FILE_FULL_EA_INFORMATION) + MAX_EA_NAME_LEN
+ MAX_EA_VALUE_LEN
sizeof (FILE_FULL_EA_INFORMATION) + _XATTR_NAME_MAX_ONDISK_
+ XATTR_SIZE_MAX
(65804 bytes), but we're opting for simplicity here, and
a 64K buffer has the advantage that we can use a tmp_pathbuf
buffer, rather than having to alloca 64K from stack. */
#define EA_BUFSIZ MAX_EA_VALUE_LEN
#define EA_BUFSIZ XATTR_SIZE_MAX
#define NEXT_FEA(p) ((PFILE_FULL_EA_INFORMATION) (p->NextEntryOffset \
? (char *) p + p->NextEntryOffset : NULL))
@ -55,7 +57,7 @@ read_ea (HANDLE hdl, path_conv &pc, const char *name, char *value, size_t size)
returns the last EA entry of the file infinitely. Even utilizing the
optional EaIndex only helps marginally. If you use that, the last
EA in the file is returned twice. */
char lastname[MAX_EA_NAME_LEN];
char lastname[_XATTR_NAME_MAX_ONDISK_];
__try
{
@ -95,7 +97,7 @@ read_ea (HANDLE hdl, path_conv &pc, const char *name, char *value, size_t size)
__leave;
}
if ((nlen = strlen (name)) >= MAX_EA_NAME_LEN)
if ((nlen = strlen (name)) >= _XATTR_NAME_MAX_ONDISK_)
{
set_errno (EINVAL);
__leave;
@ -197,7 +199,7 @@ read_ea (HANDLE hdl, path_conv &pc, const char *name, char *value, size_t size)
/* For compatibility with Linux, we always prepend "user." to
the attribute name, so effectively we only support user
attributes from a application point of view. */
char tmpbuf[MAX_EA_NAME_LEN * 2];
char tmpbuf[_XATTR_NAME_MAX_ONDISK_ * 2];
char *tp = stpcpy (tmpbuf, "user.");
stpcpy (tp, fea->EaName);
/* NTFS stores all EA names in uppercase unfortunately. To
@ -297,7 +299,7 @@ write_ea (HANDLE hdl, path_conv &pc, const char *name, const char *value,
/* Skip "user." prefix. */
name += 5;
if ((nlen = strlen (name)) >= MAX_EA_NAME_LEN)
if ((nlen = strlen (name)) >= _XATTR_NAME_MAX_ONDISK_)
{
set_errno (EINVAL);
__leave;

View File

@ -929,7 +929,13 @@ fetch_home_env (void)
/* If `HOME` is set, prefer it */
const char *home = getenv ("HOME");
if (home)
return strdup (home);
{
/* In the very early code path of `user_info::initialize ()`, the value
of the environment variable `HOME` is still in its Windows form. */
if (isdrive (home) || home[0] == '\\')
return (char *) cygwin_create_path (CCP_WIN_A_TO_POSIX, home);
return strdup (home);
}
/* If `HOME` is unset, fall back to `HOMEDRIVE``HOMEPATH`
(without a directory separator, as `HOMEPATH` starts with one). */
@ -1485,9 +1491,9 @@ get_logon_sid ()
}
}
/* Fetch special AzureAD group, which is part of the token group list but
*not* recognized by LookupAccountSid (ERROR_NONE_MAPPED). */
static cygsid azure_grp_sid ("");
/* Fetch special AzureAD and IIS APPPOOL groups, which are part of the token
group list but *not* recognized by LookupAccountSid (ERROR_NONE_MAPPED). */
static cygsid azure_grp_sid (""), iis_apppool_grp_sid ("");
static void
get_azure_grp_sid ()
@ -1515,6 +1521,36 @@ get_azure_grp_sid ()
}
}
static void
get_iis_apppool_grp_sid ()
{
if (PSID (iis_apppool_grp_sid) == NO_SID)
{
NTSTATUS status;
ULONG size;
tmp_pathbuf tp;
PTOKEN_GROUPS groups = (PTOKEN_GROUPS) tp.w_get ();
status = NtQueryInformationToken (hProcToken, TokenGroups, groups,
2 * NT_MAX_PATH, &size);
if (!NT_SUCCESS (status))
debug_printf ("NtQueryInformationToken (TokenGroups) %y", status);
else
{
for (DWORD pg = 0; pg < groups->GroupCount; ++pg)
{
PSID sid = groups->Groups[pg].Sid;
if (sid_id_auth (sid) == 5 &&
sid_sub_auth (sid, 0) == SECURITY_APPPOOL_ID_BASE_RID)
{
iis_apppool_grp_sid = sid;
break;
}
}
}
}
}
void *
pwdgrp::add_account_post_fetch (char *line, bool lock)
{
@ -1796,6 +1832,16 @@ pwdgrp::construct_sid_from_name (cygsid &sid, wchar_t *name, wchar_t *sep)
}
return false;
}
if (sep && wcscmp (name, L"IIS APPPOOL\\Group") == 0)
{
get_iis_apppool_grp_sid ();
if (PSID (logon_sid) != NO_SID)
{
sid = iis_apppool_grp_sid;
return true;
}
return false;
}
if (!sep && wcscmp (name, L"CurrentSession") == 0)
{
get_logon_sid ();
@ -2018,8 +2064,11 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap)
/* Last but not least, some validity checks on the name style. */
if (!fq_name)
{
/* AzureAD user must be prepended by "domain" name. */
if (sid_id_auth (sid) == 12)
/* AzureAD and IIS APPPOOL users must be prepended by "domain"
name. */
if (sid_id_auth (sid) == 12 ||
(sid_id_auth (sid) == 5 &&
sid_sub_auth (sid, 0) == SECURITY_APPPOOL_ID_BASE_RID))
return NULL;
/* name_only account is either builtin or primary domain, or
account domain on non-domain machines. */
@ -2045,8 +2094,10 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap)
}
else
{
/* AzureAD accounts should be fully qualifed either. */
if (sid_id_auth (sid) == 12)
/* AzureAD and IIS APPPOOL accounts should be fully qualifed either. */
if (sid_id_auth (sid) == 12 ||
(sid_id_auth (sid) == 5 &&
sid_sub_auth (sid, 0) == SECURITY_APPPOOL_ID_BASE_RID))
break;
/* Otherwise, no fully_qualified for builtin accounts, except for
NT SERVICE, for which we require the prefix. Note that there's
@ -2125,6 +2176,19 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap)
sid = csid = azure_grp_sid;
break;
}
else if (arg.id == 0x1002)
{
/* IIS APPPOOL S-1-5-82-* user */
csid = cygheap->user.saved_sid ();
}
else if (arg.id == 0x1003)
{
/* Special IIS APPPOOL group SID */
get_iis_apppool_grp_sid ();
/* LookupAccountSidW will fail. */
sid = csid = iis_apppool_grp_sid;
break;
}
else if (arg.id == 0xfffe)
{
/* Special case "nobody" for reproducible construction of a
@ -2253,7 +2317,9 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap)
Those we let pass, but no others. */
bool its_ok = false;
if (sid_id_auth (sid) == 12)
if (sid_id_auth (sid) == 12 ||
(sid_id_auth (sid) == 5 &&
sid_sub_auth (sid, 0) == SECURITY_APPPOOL_ID_BASE_RID))
its_ok = true;
else /* Microsoft Account */
{
@ -2342,7 +2408,7 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap)
posix_offset = fetch_posix_offset (td, &loc_ldap);
}
}
/* AzureAD S-1-12-1-W-X-Y-Z user */
/* AzureAD S-1-12-1-W-X-Y-Z and IIS APPOOL S-1-5-82-* user */
else if (sid_id_auth (sid) == 12)
{
uid = gid = 0x1000;
@ -2355,6 +2421,21 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap)
name, fully_qualified_name);
break;
}
/* IIS APPOOL S-1-5-82-* user */
else if (sid_id_auth (sid) == 5 &&
sid_sub_auth (sid, 0) == SECURITY_APPPOOL_ID_BASE_RID)
{
uid = 0x1002;
gid = 0x1003;
fully_qualified_name = true;
home = cygheap->pg.get_home ((PUSER_INFO_3) NULL, sid, dom, name,
fully_qualified_name);
shell = cygheap->pg.get_shell ((PUSER_INFO_3) NULL, sid, dom,
name, fully_qualified_name);
gecos = cygheap->pg.get_gecos ((PUSER_INFO_3) NULL, sid, dom,
name, fully_qualified_name);
break;
}
/* If the domain returned by LookupAccountSid is not our machine
name, and if our machine is no domain member, we lose. We have
nobody to ask for the POSIX offset. */
@ -2614,6 +2695,20 @@ pwdgrp::fetch_account_from_windows (fetch_user_arg_t &arg, cyg_ldap *pldap)
fully_qualified_name = true;
acc_type = SidTypeUnknown;
}
else if (sid_id_auth (sid) == 5 &&
sid_sub_auth (sid, 0) == SECURITY_APPPOOL_ID_BASE_RID)
{
/* Special IIS APPPOOL group SID which can't be resolved by
LookupAccountSid (ERROR_NONE_MAPPED). This is only allowed
as group entry, not as passwd entry. */
if (is_passwd ())
return NULL;
uid = gid = 0x1003;
wcpcpy (dom, L"IIS APPPOOL");
wcpcpy (name = namebuf, L"Group");
fully_qualified_name = true;
acc_type = SidTypeUnknown;
}
else if (sid_id_auth (sid) == 5 /* SECURITY_NT_AUTHORITY */
&& sid_sub_auth (sid, 0) == SECURITY_LOGON_IDS_RID)
{

View File

@ -31,6 +31,7 @@ static const wincaps wincap_8_1 = {
has_linux_tcp_keepalive_sockopts:false,
has_tcp_maxrtms:false,
has_con_broken_tabs:false,
has_user_shstk:false,
},
};
@ -52,6 +53,7 @@ static const wincaps wincap_10_1507 = {
has_linux_tcp_keepalive_sockopts:false,
has_tcp_maxrtms:false,
has_con_broken_tabs:false,
has_user_shstk:false,
},
};
@ -73,6 +75,7 @@ static const wincaps wincap_10_1607 = {
has_linux_tcp_keepalive_sockopts:false,
has_tcp_maxrtms:true,
has_con_broken_tabs:false,
has_user_shstk:false,
},
};
@ -94,6 +97,7 @@ static const wincaps wincap_10_1703 = {
has_linux_tcp_keepalive_sockopts:false,
has_tcp_maxrtms:true,
has_con_broken_tabs:true,
has_user_shstk:false,
},
};
@ -115,6 +119,7 @@ static const wincaps wincap_10_1709 = {
has_linux_tcp_keepalive_sockopts:true,
has_tcp_maxrtms:true,
has_con_broken_tabs:true,
has_user_shstk:false,
},
};
@ -136,6 +141,7 @@ static const wincaps wincap_10_1803 = {
has_linux_tcp_keepalive_sockopts:true,
has_tcp_maxrtms:true,
has_con_broken_tabs:true,
has_user_shstk:false,
},
};
@ -157,6 +163,7 @@ static const wincaps wincap_10_1809 = {
has_linux_tcp_keepalive_sockopts:true,
has_tcp_maxrtms:true,
has_con_broken_tabs:true,
has_user_shstk:false,
},
};
@ -178,6 +185,7 @@ static const wincaps wincap_10_1903 = {
has_linux_tcp_keepalive_sockopts:true,
has_tcp_maxrtms:true,
has_con_broken_tabs:true,
has_user_shstk:false,
},
};
@ -199,6 +207,7 @@ static const wincaps wincap_10_2004 = {
has_linux_tcp_keepalive_sockopts:true,
has_tcp_maxrtms:true,
has_con_broken_tabs:true,
has_user_shstk:true,
},
};
@ -220,6 +229,7 @@ static const wincaps wincap_11 = {
has_linux_tcp_keepalive_sockopts:true,
has_tcp_maxrtms:true,
has_con_broken_tabs:false,
has_user_shstk:true,
},
};