Subject: | Race condition in SSHv2 |
Date: | Thu, 30 Jul 2009 21:02:03 -0400 |
To: | bug-Net-SSH-Perl [...] rt.cpan.org |
From: | Kevin Miller <kevinm [...] abtech.org> |
This was tested against Net-SSH-Perl-1.33, running under perl 5.8.8 on
Linux-2.6c2.5-i686-64int.
We have identified a race condition having to do with SSHv2
connections/channels created using the SSH2 'open2' method. The
sequence of events that triggers the race condition is:
1. Client sends a message (using the open2 write handle) to the
server that indicates it wishes to terminate the connection
(application layer)
2. Server (application) acknowledges with a reply message, then
closes the channel
3. Client (Net::SSH::Perl) processes the channel close message and
marks the channel istate = CHAN_INPUT_CLOSED
4. Client (our application) parses the reply message and sends a
final "\n" message to the server
5. SSH was opened using Net::SSH::Perl::SSH2::open2, so the "\n" is
written via Net::SSH::Perl::Handle::SSH2
6. The Handle writes to the channel using send_data
7. send_data queues the data to the channel's input buffer
8. The channel's istate is 8 (CHAN_INPUT_CLOSED), so this buffer is
never processed. However, we never exit the loop in
Net::SSH::Perl::Channel::drain_outgoing, which has as the exit
condition the input length being 0
It appears also that a similar race condition can occur if the order
of events (from above) is: 1, 2, 4, 5, 6, 7, 3, 8. In this case, the
channel is considered OPEN when the write occurs, but is subsequently
set to CLOSED (in Net::SSH::Perl::Channel::rcvd_oclose) before the
data can be processed for transmission.
We have attempted to fix both race conditions by:
* In Net::SSH::Perl::Handle::SSH2::WRITE, observe the istate of
the channel and return undef if the istate is not CHAN_INPUT_OPEN
* In Net::SSH::Perl::Channel::shutdown_read, flush the input
buffer ($c->{input}->empty)
Thanks,
-Kevin