Skip to content

OpenSSH for Windows hangs while writing to STDERR asynchronously #1427

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
lizhaoliu opened this issue Aug 5, 2019 · 1 comment
Open

OpenSSH for Windows hangs while writing to STDERR asynchronously #1427

lizhaoliu opened this issue Aug 5, 2019 · 1 comment

Comments

@lizhaoliu
Copy link

Troubleshooting steps
https://github.com/PowerShell/Win32-OpenSSH/wiki/Troubleshooting-Steps

Terminal issue? please go through wiki
https://github.com/PowerShell/Win32-OpenSSH/wiki/TTY-PTY-support-in-Windows-OpenSSH

Please answer the following

"OpenSSH for Windows" version
7.9p1, 8.0p1.

Server OperatingSystem
Debian rodete rodete (x86-64).

Client OperatingSystem
Windows 10, Windows Server 2016.

What is failing
Reproduced reliably with OpenSSH 7.9p1, 8.0p1:

  1. We have an SSH client (named "test runner") written in Go running on Linux.
  2. Test runner SSH'es into Windows 10 and Server 2016 machines (OpenSSH server) to run commands which will create another SSH session connecting to other Linux machines. In short, the SSH sessions propagate like this: test runner (Linux) => Win (OpenSSH) => device (Linux).
  3. Test runner gets indefinitely blocked while trying to read from STDERR in the Windows SSH session since there is no output to STDERR.

I collected the call tack of ssh.exe on Windows:

        [External Code]
        ssh.exe!wait_for_multiple_objects_enhanced(unsigned long nCount, void * const * lpHandles, unsigned long dwMilliseconds, int bAlertable) Line 96        C
        ssh.exe!wait_for_any_event(void * * events, int num_events, unsigned long milli_seconds) Line 289       C
        ssh.exe!fileio_write(w32_io * pio, const void * buf, unsigned __int64 max_bytes) Line 749       C
        ssh.exe!w32_write(int fd, const void * buf, unsigned __int64 max) Line 562      C
        ssh.exe!do_log(LogLevel level, const char * fmt, char * args) Line 468  C
        ssh.exe!error(const char * fmt, ...) Line 170   C
        ssh.exe!check_host_key(char * hostname, sockaddr * hostaddr, unsigned short port, sshkey * host_key, int readonly, char * * user_hostfiles, unsigned int num_user_hostfiles, char * * system_hostfiles, unsigned int num_system_hostfiles) Line 1165    C
        ssh.exe!verify_host_key(char * host, sockaddr * hostaddr, sshkey * host_key) Line 1272  C
        ssh.exe!verify_host_key_callback(sshkey * hostkey, ssh * ssh) Line 98   C
        ssh.exe!kex_verify_host_key(ssh * ssh, sshkey * server_host_key) Line 1071      C
        ssh.exe!input_kex_gen_reply(int type, unsigned int seq, ssh * ssh) Line 160     C
        ssh.exe!ssh_dispatch_run(ssh * ssh, int mode, volatile int * done) Line 114     C
        ssh.exe!ssh_kex2(ssh * ssh, char * host, sockaddr * port, unsigned short) Line 224      C
        ssh.exe!ssh_login(ssh * ssh, Sensitive * sensitive, const char *) Line 1320     C
        ssh.exe!main(int ac, char * * av) Line 1499     C
        ssh.exe!wmain(int argc, wchar_t * * wargv) Line 61      C
        [External Code] 

For some reason the asyn write WriteFileEx gets stuck writing to STDERR and the main thread hangs waiting for the write to be completed.

I tried forcing the STDERR write to be sync and the problem goes away, i.e. in w32_write function, insert the following code:

if (fd == STDERR_FILENO) {
	fd_table.w32_ios[fd]->type = NONSOCK_SYNC_FD;
}

Expected output
The SSH sessions complete without hanging.

Actual output
The Windows SSH session hangs while writing to STDERR asynchronously.

@maertendMSFT
Copy link
Collaborator

Can you attempt this manually, if you still see the issue, can you provide your manual repro steps?

manu0401 added a commit to manu0401/openssh-portable that referenced this issue Oct 31, 2024
stdio descriptors (stdin, stdout and stderr) can be operated in various
modes by win32compat code. The behavior is set very early in
fd_table_initialize() by setting pio->type.

In PowerShell/Win32-OpenSSH#1427 it was
chosen to set pio->type to NONSOCK_SYNC_FD to resolve an I/O hang
problem. Unfortunately this introduce problems for other ssh usage.

sshfs-wiun uses ssh and has at leas 6 open issues for the same
problem introduced by this NONSOCK_SYNC_FD change:
https://github.com/winfsp/sshfs-win/issues?q=is%3Aissue+cb+%3A87

The sshfs-win workaround it to use an older ssh.exe from cygwin, which
is bundled with sshfs-win. This program is unable to use ssh-agent,
which is quite frustrating. And if PATH is not set to use it, sshfs-win
cannot work.

This change introduce an OPENSSH_STDIO_MODE environment variable that
can be set to the following values: unknown, sock, nonsock, nonsock_sync.
It cause pio->type to be set to UNKNOWN_FD, SOCK_FD, NONSOCK_FD, and
NONSOCK_SYNC_FD respecitively. The default behavior when the variable
is not set is unchanged (which means NONSOCK_SYNC_FD).

Setting OPENSSH_STDIO_MODE="nonsock" lets sshfs-win work again with
openssh-portable ssh.exe. ssh-agent can be used, and this is good.
tgauth pushed a commit to PowerShell/openssh-portable that referenced this issue Nov 19, 2024
* Add an environement variable to control stdio mode

stdio descriptors (stdin, stdout and stderr) can be operated in various
modes by win32compat code. The behavior is set very early in
fd_table_initialize() by setting pio->type.

In PowerShell/Win32-OpenSSH#1427 it was
chosen to set pio->type to NONSOCK_SYNC_FD to resolve an I/O hang
problem. Unfortunately this introduce problems for other ssh usage.

sshfs-wiun uses ssh and has at leas 6 open issues for the same
problem introduced by this NONSOCK_SYNC_FD change:
https://github.com/winfsp/sshfs-win/issues?q=is%3Aissue+cb+%3A87

The sshfs-win workaround it to use an older ssh.exe from cygwin, which
is bundled with sshfs-win. This program is unable to use ssh-agent,
which is quite frustrating. And if PATH is not set to use it, sshfs-win
cannot work.

This change introduce an OPENSSH_STDIO_MODE environment variable that
can be set to the following values: unknown, sock, nonsock, nonsock_sync.
It cause pio->type to be set to UNKNOWN_FD, SOCK_FD, NONSOCK_FD, and
NONSOCK_SYNC_FD respecitively. The default behavior when the variable
is not set is unchanged (which means NONSOCK_SYNC_FD).

Setting OPENSSH_STDIO_MODE="nonsock" lets sshfs-win work again with
openssh-portable ssh.exe. ssh-agent can be used, and this is good.

* Leave out  UNKNOWN_FD as the possible rtpes for stdio descriptors

An assert(pio->type != UNKNOWN_FD) in fd_table_set() causes that
case to fail early anyway.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants