Bug 3280 - stdout resource unavailable error when used with a pipe
Summary: stdout resource unavailable error when used with a pipe
Status: CLOSED FIXED
Alias: None
Product: Portable OpenSSH
Classification: Unclassified
Component: ssh (show other bugs)
Version: 8.5p1
Hardware: All All
: P1 critical
Assignee: Assigned to nobody
URL:
Keywords:
: 3310 (view as bug list)
Depends on:
Blocks: V_8_7
  Show dependency treegraph
 
Reported: 2021-03-15 20:29 AEDT by sanumesh
Modified: 2022-02-25 13:59 AEDT (History)
3 users (show)

See Also:


Attachments
ssh related patch (1.31 KB, patch)
2021-05-06 05:32 AEST, sanumesh
no flags Details | Diff
clientloop related patch (1.31 KB, patch)
2021-05-06 05:33 AEST, sanumesh
no flags Details | Diff
restore non-blocking status for stdio file descriptors (11.79 KB, patch)
2021-05-14 15:06 AEST, Damien Miller
dtucker: ok+
Details | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description sanumesh 2021-03-15 20:29:44 AEDT
Hello

when a script that has ssh and cat is passed onto a pipe command then there is a error seen as resource unavailable.

Recreation :

# cat tp.sh
#!/usr/bin/ksh93

export LANG=C

{
  ssh localhost hostname
  cat /usr/bin/mksysb
} | sleep 10

execution output :

# ./tp.sh
root@localhost's password:
cat: output error
Resource temporarily unavailable

Possible root cause :

1 ssh calls dup() to copy stdout(fd=1) to fd=5.

2 ssh sets O_NONBLOCK flag to fd=5.

3 ssh calls dup2() to assign /dev/null(fd=7) to fd=1.
then, ssh closes fd=7. so fd=1 -> /dev/null and fd=5 -> ssh's stdout

4- ssh calls unset_nonblock() to try to clear
O_NONBLOCK from fd=1, but it can't because /dev/null has been assigned to fd=1.

ssh doesn't clear O_NONBLOCK from ssh's stdout which
is fd=5 and ssh closes its stdout(fd=5) without clearing
O_NONBLOCK.

5- The subsequent program "cat", fails to write buffers
to its stdout, because cat's stdout is connected to the
same pipe as ssh, which still has O_NONBLOCK.

When executed in debug mode, we get the following error :
debug3: send packet: type 1
debug1: fd 0 clearing O_NONBLOCK
debug3: fd 1 is not O_NONBLOCK      <<<<<<
debug1: fd 2 clearing O_NONBLOCK
Transferred: sent 1940, received 2424 bytes, in 0.0 seconds
Bytes per second: sent 48522.2, received 60627.8
debug1: Exit status 0
cat: output error
Resource temporarily unavailable


Note: This error is not seen in 7.5p1. If the step 3 mentioned above is commented, then no issue is seen.

Please advice on how this can be fixed ?

Thanks
Comment 1 sanumesh 2021-03-24 17:47:35 AEDT
Notes :

- This issue occurs on even Linux, and all other platform as well.

- This issue is not specific to ksh93 alone, it occurs on sh/bash as well

- This issue is not specific to mksysb, failure is seen in cat with any files whose size is over several hundred KB
Comment 2 sanumesh 2021-05-06 05:32:00 AEST
Created attachment 3510 [details]
ssh related patch

maintain a global variable and dup the STDOUT to it, before dup2 of stdout to /dev/null
Comment 3 sanumesh 2021-05-06 05:33:51 AEST
Created attachment 3511 [details]
clientloop related patch

assign back the stored fd to stdout before restoring blocking io
Comment 4 sanumesh 2021-05-10 23:14:50 AEST
Hello

raising the severity to 1 since it is related to user data integrity checks. In some of the scenarios, the output of cat gets truncated with no errors. 
Please have a look at the attached patch and let me know if any further clarifications is required.
Thanks
Comment 5 Damien Miller 2021-05-14 15:06:59 AEST
Created attachment 3519 [details]
restore non-blocking status for stdio file descriptors

I don't think your patches cover all the cases, particularly the session-multiplexing and stdio forwarding ones. AFAIk this one does.
Comment 6 Damien Miller 2021-05-19 11:19:41 AEST
*** Bug 3310 has been marked as a duplicate of this bug. ***
Comment 7 Damien Miller 2021-05-19 11:52:52 AEST
Fix committed as 7be4ac81366
Comment 8 Damien Miller 2022-02-25 13:59:08 AEDT
closing bugs resolved before openssh-8.9