Skip to content

Commit 6b87603

Browse files
authored
fix(transport): don't consider remote stream illegal (#2358)
#2269 made a "stream control or data frame for a stream that is ours to initiate but we haven't yet" illegal. ``` rust let existed = !stream_id.is_remote_initiated(self.role) && self.local_stream_limits[stream_id.stream_type()].used() > stream_id.index(); ``` Problem is, when `is_remote_initiated` is `true`, then `existed` is `false`, which leads to a false positive for remote initiated streams.
1 parent b550010 commit 6b87603

File tree

2 files changed

+60
-14
lines changed

2 files changed

+60
-14
lines changed

neqo-transport/src/connection/tests/stream.rs

Lines changed: 50 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -539,23 +539,23 @@ fn do_not_accept_data_after_stop_sending() {
539539
);
540540
}
541541

542+
struct Writer(Vec<u64>);
543+
544+
impl crate::connection::test_internal::FrameWriter for Writer {
545+
fn write_frames(&mut self, builder: &mut PacketBuilder) {
546+
builder.write_varint_frame(&self.0);
547+
}
548+
}
549+
542550
#[test]
543551
/// Server sends a number of stream-related frames for a client-initiated stream that is not yet
544552
/// created. This should cause the client to close the connection.
545553
fn illegal_stream_related_frames() {
546-
struct IllegalWriter(Vec<u64>);
547-
548-
impl crate::connection::test_internal::FrameWriter for IllegalWriter {
549-
fn write_frames(&mut self, builder: &mut PacketBuilder) {
550-
builder.write_varint_frame(&self.0);
551-
}
552-
}
553-
554554
fn test_with_illegal_frame(frame: &[u64]) {
555555
let mut client = default_client();
556556
let mut server = default_server();
557557
connect(&mut client, &mut server);
558-
let dgram = send_with_extra(&mut server, IllegalWriter(frame.to_vec()), now());
558+
let dgram = send_with_extra(&mut server, Writer(frame.to_vec()), now());
559559
client.process_input(dgram, now());
560560
assert!(client.state().closed());
561561
}
@@ -576,6 +576,47 @@ fn illegal_stream_related_frames() {
576576
}
577577
}
578578

579+
#[test]
580+
/// Regression <https://github.com/mozilla/neqo/pull/2358>.
581+
fn legal_out_of_order_frame_on_remote_initiated_closed_stream() {
582+
const REQUEST: &[u8] = b"ping";
583+
let mut client = default_client();
584+
let mut server = default_server();
585+
connect(&mut client, &mut server);
586+
587+
// Client sends request and closes stream.
588+
let stream_id = client.stream_create(StreamType::BiDi).unwrap();
589+
_ = client.stream_send(stream_id, REQUEST).unwrap();
590+
client.stream_close_send(stream_id).unwrap();
591+
let dgram = client.process_output(now()).dgram();
592+
593+
// Server reads request and closes stream.
594+
server.process_input(dgram.unwrap(), now());
595+
let mut buf = [0; REQUEST.len()];
596+
server.stream_recv(stream_id, &mut buf).unwrap();
597+
server.stream_close_send(stream_id).unwrap();
598+
let dgram = server.process_output(now()).dgram();
599+
client.process_input(dgram.unwrap(), now());
600+
601+
// Client ACKs server's close stream, thus server forgetting about stream.
602+
let dgram = send_something(&mut client, now());
603+
let dgram = server.process(Some(dgram), now()).dgram();
604+
client.process_input(dgram.unwrap(), now());
605+
606+
// Deliver an out-of-order `FRAME_TYPE_MAX_STREAM_DATA` on forgotten stream.
607+
let dgram = send_with_extra(
608+
&mut client,
609+
Writer(vec![FRAME_TYPE_MAX_STREAM_DATA, stream_id.as_u64(), 0, 0]),
610+
now(),
611+
);
612+
server.process_input(dgram, now());
613+
614+
assert!(
615+
!server.state().closed(),
616+
"expect server to ignore out-of-order frame on forgotten stream"
617+
);
618+
}
619+
579620
#[test]
580621
// Server sends stop_sending, the client simultaneous sends reset.
581622
fn simultaneous_stop_sending_and_reset() {

neqo-transport/src/streams.rs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -411,13 +411,18 @@ impl Streams {
411411
stream_id: StreamId,
412412
) -> Res<(Option<&mut SendStream>, Option<&mut RecvStream>)> {
413413
self.ensure_created_if_remote(stream_id)?;
414-
// Has this local stream existed in the past, i.e., is its index lower than the number of
415-
// used streams?
416-
let existed = !stream_id.is_remote_initiated(self.role)
417-
&& self.local_stream_limits[stream_id.stream_type()].used() > stream_id.index();
418414
let ss = self.send.get_mut(stream_id).ok();
419415
let rs = self.recv.get_mut(stream_id).ok();
420-
if ss.is_none() && rs.is_none() && !existed {
416+
// If it is:
417+
// - neither a known send nor receive stream,
418+
// - and it must be locally initiated,
419+
// - and its index is larger than the local used stream limit,
420+
// then it is an illegal stream.
421+
if ss.is_none()
422+
&& rs.is_none()
423+
&& !stream_id.is_remote_initiated(self.role)
424+
&& self.local_stream_limits[stream_id.stream_type()].used() <= stream_id.index()
425+
{
421426
return Err(Error::StreamStateError);
422427
}
423428
Ok((ss, rs))

0 commit comments

Comments
 (0)