Skip to content

Commit 3d1da7f

Browse files
committed
avoid a race between channel open confirmation and queued data
1 parent 952eb25 commit 3d1da7f

2 files changed

Lines changed: 29 additions & 6 deletions

File tree

russh/src/client/mod.rs

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1252,6 +1252,7 @@ impl Session {
12521252
return Err(crate::Error::InactivityTimeout.into());
12531253
}
12541254
msg = self.receiver.recv(), if can_receive_outbound => {
1255+
self.drain_priority_msgs()?;
12551256
match msg {
12561257
Some(msg) => self.handle_msg(msg)?,
12571258
None => {
@@ -1262,6 +1263,7 @@ impl Session {
12621263

12631264
// eagerly take all outgoing messages so writes are batched
12641265
while !self.kex.active() && !self.common.has_any_pending_data() {
1266+
self.drain_priority_msgs()?;
12651267
match self.receiver.try_recv() {
12661268
Ok(next) => self.handle_msg(next)?,
12671269
Err(_) => break
@@ -1275,21 +1277,18 @@ impl Session {
12751277
}
12761278

12771279
// eagerly take all outgoing messages so writes are batched
1278-
while !self.kex.active() {
1279-
match self.priority_receiver.try_recv() {
1280-
Ok(next) => self.handle_msg(next)?,
1281-
Err(_) => break
1282-
}
1283-
}
1280+
self.drain_priority_msgs()?;
12841281
}
12851282
msg = self.inbound_channel_receiver.recv(), if can_receive_outbound => {
1283+
self.drain_priority_msgs()?;
12861284
match msg {
12871285
Some(msg) => self.handle_msg(msg)?,
12881286
None => (),
12891287
}
12901288

12911289
// eagerly take all outgoing messages so writes are batched
12921290
while !self.kex.active() && !self.common.has_any_pending_data() {
1291+
self.drain_priority_msgs()?;
12931292
match self.inbound_channel_receiver.try_recv() {
12941293
Ok(next) => self.handle_msg(next)?,
12951294
Err(_) => break
@@ -1359,6 +1358,21 @@ impl Session {
13591358
})
13601359
}
13611360

1361+
/// Channel open replies must be dispatched before any channel traffic
1362+
/// queued after them: the bounded receivers may hold data for a channel
1363+
/// whose confirmation is still sitting in the priority queue, and
1364+
/// dispatching that data first would silently drop it (the channel is
1365+
/// only registered when its open reply is processed).
1366+
fn drain_priority_msgs(&mut self) -> Result<(), crate::Error> {
1367+
while !self.kex.active() {
1368+
match self.priority_receiver.try_recv() {
1369+
Ok(msg) => self.handle_msg(msg)?,
1370+
Err(_) => break,
1371+
}
1372+
}
1373+
Ok(())
1374+
}
1375+
13621376
fn handle_msg(&mut self, msg: Msg) -> Result<(), crate::Error> {
13631377
match msg {
13641378
Msg::Authenticate { user, method } => {

russh/src/server/session.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -768,6 +768,15 @@ impl Session {
768768
}
769769
}
770770
msg = self.receiver.recv(), if !self.kex.active() && !self.common.has_any_pending_data() => {
771+
// Channel open replies must be dispatched before any
772+
// channel traffic queued after them: `msg` may be data for
773+
// a channel whose confirmation is still sitting in the
774+
// priority queue, and dispatching that data first would
775+
// silently drop it (the channel is only registered when
776+
// its open reply is processed).
777+
while let Ok(reply) = self.priority_receiver.try_recv() {
778+
self.dispatch_msg(reply)?;
779+
}
771780
match msg {
772781
Some(msg) => self.dispatch_msg(msg)?,
773782
None => {

0 commit comments

Comments
 (0)