Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Abort on RX of illegal stream control/data frame #2269

Merged
merged 22 commits into from
Dec 16, 2024

Conversation

larseggert
Copy link
Collaborator

@larseggert larseggert commented Dec 4, 2024

Abort the connection if we receive a stream control or data frame for a stream that is ours to initiate but we haven't yet. Don't abort if it is such a frame that arrives very late for a stream that we did use.

Fixes #1457

Abort the connection if we receive a stream control or data frame
for a stream that is ours to initiate but we haven't yet.

Fixes mozilla#1457
Copy link

codecov bot commented Dec 4, 2024

Codecov Report

Attention: Patch coverage is 91.66667% with 1 line in your changes missing coverage. Please review.

Project coverage is 93.29%. Comparing base (3001a3a) to head (42f91a6).
Report is 2 commits behind head on main.

Files with missing lines Patch % Lines
neqo-transport/src/streams.rs 88.88% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2269      +/-   ##
==========================================
+ Coverage   93.26%   93.29%   +0.03%     
==========================================
  Files         113      113              
  Lines       36736    36743       +7     
  Branches    36736    36743       +7     
==========================================
+ Hits        34260    34278      +18     
+ Misses       1685     1682       -3     
+ Partials      791      783       -8     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

Copy link

github-actions bot commented Dec 4, 2024

Failed Interop Tests

QUIC Interop Runner, client vs. server, differences relative to 3001a3a.

neqo-latest as client

neqo-latest as server

All results

Succeeded Interop Tests

QUIC Interop Runner, client vs. server

neqo-latest as client

neqo-latest as server

Unsupported Interop Tests

QUIC Interop Runner, client vs. server

neqo-latest as client

neqo-latest as server

Copy link

github-actions bot commented Dec 4, 2024

Benchmark results

Performance differences relative to 3001a3a.

decode 4096 bytes, mask ff: No change in performance detected.
       time:   [11.863 µs 11.907 µs 11.955 µs]
       change: [-0.8015% -0.2596% +0.1811%] (p = 0.33 > 0.05)

Found 16 outliers among 100 measurements (16.00%)
8 (8.00%) low mild
8 (8.00%) high severe

decode 1048576 bytes, mask ff: No change in performance detected.
       time:   [3.0999 ms 3.1146 ms 3.1344 ms]
       change: [-0.7800% -0.1106% +0.6190%] (p = 0.77 > 0.05)

Found 10 outliers among 100 measurements (10.00%)
10 (10.00%) high severe

decode 4096 bytes, mask 7f: No change in performance detected.
       time:   [19.793 µs 19.850 µs 19.914 µs]
       change: [-0.4499% +0.1803% +0.9863%] (p = 0.70 > 0.05)

Found 19 outliers among 100 measurements (19.00%)
2 (2.00%) low severe
2 (2.00%) low mild
1 (1.00%) high mild
14 (14.00%) high severe

decode 1048576 bytes, mask 7f: No change in performance detected.
       time:   [5.1674 ms 5.1800 ms 5.1931 ms]
       change: [-0.3159% +0.0386% +0.3831%] (p = 0.82 > 0.05)

Found 15 outliers among 100 measurements (15.00%)
15 (15.00%) high severe

decode 4096 bytes, mask 3f: No change in performance detected.
       time:   [6.8938 µs 6.9176 µs 6.9487 µs]
       change: [-0.0720% +0.2477% +0.6357%] (p = 0.19 > 0.05)

Found 21 outliers among 100 measurements (21.00%)
4 (4.00%) low severe
8 (8.00%) low mild
4 (4.00%) high mild
5 (5.00%) high severe

decode 1048576 bytes, mask 3f: Change within noise threshold.
       time:   [1.7581 ms 1.7596 ms 1.7624 ms]
       change: [-1.1084% -0.6414% -0.1788%] (p = 0.00 < 0.05)

Found 2 outliers among 100 measurements (2.00%)
1 (1.00%) high mild
1 (1.00%) high severe

coalesce_acked_from_zero 1+1 entries: Change within noise threshold.
       time:   [98.320 ns 98.625 ns 98.943 ns]
       change: [-1.2795% -0.7355% -0.1716%] (p = 0.01 < 0.05)

Found 13 outliers among 100 measurements (13.00%)
9 (9.00%) high mild
4 (4.00%) high severe

coalesce_acked_from_zero 3+1 entries: No change in performance detected.
       time:   [116.62 ns 116.99 ns 117.41 ns]
       change: [-1.7072% -0.8205% +0.0533%] (p = 0.06 > 0.05)

Found 15 outliers among 100 measurements (15.00%)
1 (1.00%) low severe
2 (2.00%) low mild
1 (1.00%) high mild
11 (11.00%) high severe

coalesce_acked_from_zero 10+1 entries: No change in performance detected.
       time:   [116.39 ns 116.90 ns 117.50 ns]
       change: [-0.7090% +0.0542% +1.2521%] (p = 0.93 > 0.05)

Found 17 outliers among 100 measurements (17.00%)
6 (6.00%) low severe
3 (3.00%) low mild
8 (8.00%) high severe

coalesce_acked_from_zero 1000+1 entries: No change in performance detected.
       time:   [97.397 ns 97.522 ns 97.659 ns]
       change: [-0.9579% -0.1305% +0.6837%] (p = 0.77 > 0.05)

Found 9 outliers among 100 measurements (9.00%)
4 (4.00%) high mild
5 (5.00%) high severe

RxStreamOrderer::inbound_frame(): Change within noise threshold.
       time:   [111.42 ms 111.55 ms 111.77 ms]
       change: [+0.2168% +0.3507% +0.5489%] (p = 0.00 < 0.05)

Found 17 outliers among 100 measurements (17.00%)
10 (10.00%) low mild
6 (6.00%) high mild
1 (1.00%) high severe

SentPackets::take_ranges: No change in performance detected.
       time:   [5.5491 µs 5.7333 µs 5.9269 µs]
       change: [-3.3931% -0.2058% +2.8206%] (p = 0.90 > 0.05)

Found 9 outliers among 100 measurements (9.00%)
9 (9.00%) high mild

transfer/pacing-false/varying-seeds: Change within noise threshold.
       time:   [30.456 ms 31.010 ms 31.545 ms]
       change: [+2.6499% +4.9762% +7.5992%] (p = 0.00 < 0.05)

Found 4 outliers among 100 measurements (4.00%)
4 (4.00%) low mild

transfer/pacing-true/varying-seeds: Change within noise threshold.
       time:   [32.468 ms 33.013 ms 33.548 ms]
       change: [+1.2374% +3.7078% +6.1906%] (p = 0.00 < 0.05)
transfer/pacing-false/same-seed: Change within noise threshold.
       time:   [25.707 ms 26.318 ms 26.919 ms]
       change: [-0.0276% +3.4210% +6.6871%] (p = 0.04 < 0.05)

Found 2 outliers among 100 measurements (2.00%)
2 (2.00%) low mild

transfer/pacing-true/same-seed: Change within noise threshold.
       time:   [29.266 ms 30.100 ms 30.918 ms]
       change: [+0.1254% +4.4562% +8.6628%] (p = 0.04 < 0.05)
1-conn/1-100mb-resp/mtu-1504 (aka. Download)/client: 💚 Performance has improved.
       time:   [868.52 ms 877.55 ms 886.72 ms]
       thrpt:  [112.77 MiB/s 113.95 MiB/s 115.14 MiB/s]
change:
       time:   [-4.3887% -2.9423% -1.5277%] (p = 0.00 < 0.05)
       thrpt:  [+1.5514% +3.0315% +4.5902%]
1-conn/10_000-parallel-1b-resp/mtu-1504 (aka. RPS)/client: No change in performance detected.
       time:   [313.60 ms 316.84 ms 320.06 ms]
       thrpt:  [31.244 Kelem/s 31.562 Kelem/s 31.888 Kelem/s]
change:
       time:   [-1.3608% +0.1134% +1.5447%] (p = 0.88 > 0.05)
       thrpt:  [-1.5212% -0.1132% +1.3796%]
1-conn/1-1b-resp/mtu-1504 (aka. HPS)/client: Change within noise threshold.
       time:   [33.388 ms 33.557 ms 33.736 ms]
       thrpt:  [29.642  elem/s 29.800  elem/s 29.951  elem/s]
change:
       time:   [-1.7381% -0.9060% -0.1014%] (p = 0.04 < 0.05)
       thrpt:  [+0.1015% +0.9143% +1.7688%]

Found 3 outliers among 100 measurements (3.00%)
2 (2.00%) high mild
1 (1.00%) high severe

1-conn/1-100mb-resp/mtu-1504 (aka. Upload)/client: 💚 Performance has improved.
       time:   [1.6976 s 1.7150 s 1.7326 s]
       thrpt:  [57.718 MiB/s 58.310 MiB/s 58.908 MiB/s]
change:
       time:   [-3.9737% -2.5333% -1.0640%] (p = 0.00 < 0.05)
       thrpt:  [+1.0754% +2.5992% +4.1381%]

Client/server transfer results

Transfer of 33554432 bytes over loopback.

Client Server CC Pacing MTU Mean [ms] Min [ms] Max [ms]
gquiche gquiche 1504 511.8 ± 22.4 494.6 568.4
neqo gquiche reno on 1504 762.7 ± 24.4 745.4 826.6
neqo gquiche reno 1504 747.8 ± 17.1 729.4 781.7
neqo gquiche cubic on 1504 739.3 ± 15.3 722.3 769.9
neqo gquiche cubic 1504 770.4 ± 20.9 744.4 812.6
msquic msquic 1504 122.2 ± 48.7 91.6 253.8
neqo msquic reno on 1504 218.4 ± 12.7 202.9 241.9
neqo msquic reno 1504 218.0 ± 12.5 201.0 236.4
neqo msquic cubic on 1504 216.6 ± 12.0 199.1 234.5
neqo msquic cubic 1504 215.7 ± 12.9 197.6 237.0
gquiche neqo reno on 1504 673.9 ± 85.6 550.9 794.2
gquiche neqo reno 1504 694.9 ± 90.6 567.3 833.0
gquiche neqo cubic on 1504 694.2 ± 87.8 565.6 837.5
gquiche neqo cubic 1504 696.1 ± 90.3 546.3 820.0
msquic neqo reno on 1504 471.7 ± 6.7 461.6 479.9
msquic neqo reno 1504 469.5 ± 5.0 459.0 475.4
msquic neqo cubic on 1504 500.7 ± 13.2 485.3 525.3
msquic neqo cubic 1504 469.9 ± 12.8 455.6 487.4
neqo neqo reno on 1504 484.0 ± 35.6 443.2 555.3
neqo neqo reno 1504 484.7 ± 41.2 437.6 559.9
neqo neqo cubic on 1504 561.6 ± 9.7 544.8 571.4
neqo neqo cubic 1504 521.8 ± 26.7 469.0 547.4

⬇️ Download logs

neqo-transport/src/connection/tests/stream.rs Outdated Show resolved Hide resolved
neqo-transport/src/streams.rs Outdated Show resolved Hide resolved
neqo-transport/src/streams.rs Outdated Show resolved Hide resolved
neqo-transport/src/connection/tests/stream.rs Outdated Show resolved Hide resolved
Co-authored-by: Max Inden <[email protected]>
Signed-off-by: Lars Eggert <[email protected]>
Copy link
Member

@martinthomson martinthomson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looking at this more, I'm really not sure that this is safe.

There are cases where the frame is outright illegal. But the code you routinely use here looks like this:

if let (_, Some(rs)) = self.obtain_stream(...)? {
  // happy path
} else {
  return Err(Error::WHATEVER);
}

The problem is that valid frames can arrive late. As @mxinden points out, this results in the stream being removed. The return value would then be (None, None), which will hit the error case. We'll kill connections that are completely valid in that case.

I think that you want a different test for whether the frame is valid than what you have described here. My expectation is that obtain_stream() will be able to catch some cases (where flow control doesn't allow the stream to be created), but not others (like whether you want the receive stream where there shouldn't be one).

A more targeted function (or pair of functions) might do better because it could know that you want send or receive and abort if that part of the stream cannot exist.

That you have not hit this case suggests to me that we need a test that uses and retires streams fully, while sending a bunch of frames that are valid, but very late.

@larseggert
Copy link
Collaborator Author

@mxinden @martinthomson agree. Have been trying to craft a test that hits those error cases, but no luck so far.

@larseggert
Copy link
Collaborator Author

There now is a double_stream_related_frame test that at least hits the case of interest for stream reset. I need to make it hit the case for some of the other frames of interest.

@larseggert
Copy link
Collaborator Author

OK, I think I have tests now that hits the new code paths for all frame types.

Copy link
Collaborator

@mxinden mxinden left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Smaller comments. Overall this looks good to me. Thanks for the test!

neqo-transport/src/streams.rs Outdated Show resolved Hide resolved
neqo-transport/src/connection/tests/stream.rs Outdated Show resolved Hide resolved
neqo-transport/src/connection/tests/stream.rs Outdated Show resolved Hide resolved
neqo-transport/src/connection/tests/stream.rs Outdated Show resolved Hide resolved
neqo-transport/src/connection/tests/stream.rs Outdated Show resolved Hide resolved
neqo-transport/src/connection/tests/stream.rs Outdated Show resolved Hide resolved
neqo-transport/src/connection/tests/stream.rs Outdated Show resolved Hide resolved
neqo-transport/src/connection/tests/stream.rs Outdated Show resolved Hide resolved
Copy link
Member

@martinthomson martinthomson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The checks are solid. I'm not sure about the test.

neqo-transport/src/stream_id.rs Outdated Show resolved Hide resolved
Co-authored-by: Max Inden <[email protected]>
Signed-off-by: Lars Eggert <[email protected]>
@larseggert larseggert enabled auto-merge December 16, 2024 06:37
@larseggert larseggert disabled auto-merge December 16, 2024 15:33
@larseggert larseggert merged commit ad8f390 into mozilla:main Dec 16, 2024
62 of 63 checks passed
@larseggert larseggert deleted the fix-1457 branch December 18, 2024 16:02
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Reject RESET_STREAM and STREAM_DATA_BLOCKED on non-existent streams
3 participants