[Bug 2135] New: Solaris: race condition in channel forwarding when connect() returns EINPROGRESS
bugzilla-daemon at mindrot.org
bugzilla-daemon at mindrot.org
Wed Jul 31 23:12:21 EST 2013
https://bugzilla.mindrot.org/show_bug.cgi?id=2135
Bug ID: 2135
Summary: Solaris: race condition in channel forwarding when
connect() returns EINPROGRESS
Product: Portable OpenSSH
Version: 6.0p1
Hardware: All
OS: Solaris
Status: NEW
Severity: normal
Priority: P5
Component: sshd
Assignee: unassigned-bugs at mindrot.org
Reporter: ivo.raisr at oracle.com
Created attachment 2322
--> https://bugzilla.mindrot.org/attachment.cgi?id=2322&action=edit
the patch for portable
Consider the following scenario with channel forwarding:
- sshd runs on the server machine
- on the client machine, local port forwarding is setup via the
following:
ssh -nfN -o GatewayPorts=yes -L 3333:<REMOTE HOST>:5555 -p 2222 <server
machine>
- <REMOTE HOST> is a faraway machine which takes several tens or
hundreds of milliseconds to respond
(slow line, geographical distance)
- nothing is accepting connections at <REMOTE HOST>:5555
Under normal circumstances, when <REMOTE HOST> is the same machine as
<server machine>
or is near enough, connect() call in channels.c:connect_next() returns
with
non-blocking socket which has already finalized connection attempt
(errno ECONNREFUSED or ETIMEDOUT, for example).
When connection attempt to <REMOTE HOST> takes a while,
connect() call returns with errno EINPROGRESS. In this case, outcome
of the connection attempt is not yet known. When TCP stack finaly
decides
then connection attempt has failed, it places the error into pending
socket error,
where it is later pulled up by select()/poll().
However OpenSSH does a bunch of other stuff between connect() and
select().
In particular, it calls channels.c:channel_register_fds.
And the Portable OpenSSH (not "pure" OpenSSH) invokes isatty() here.
On Solaris, isatty() invokes underlaying ioctl() which
gets and clears the pending socket error.
Therefore on Solaris, there is a race condition when the following
happens:
- OpenSSH invokes connect() which returns EINPROGRESS
- connection attempt outcome is known after a while and is placed into
pending socket error
by the TCP stack
- OpenSSH invokes isatty() which gets and clears this pending socket
error
- OpenSSH invokes select() which blocks indefinitely because the
pending socket error has been already cleared
Had the connection attempt taken a little bit longer and its outcome
had been known
when OpenSSH was already performing select(), it would behave
correctly.
However in this case, this particular timing is important.
=========================
I realized that isatty() call has been put there into Portable OpenSSH
to initialize wfd_isatty attribute
of Channel structure. However this attribute is currently used only for
AIX. So I would
say it is safe to declare and initialize it for AIX only as well.
With the attached patch, the problem is fixed.
The patch is against OpenSSH 6.0p1 but newer releases are affected as
well.
--
You are receiving this mail because:
You are watching the assignee of the bug.
More information about the openssh-bugs
mailing list