-
Notifications
You must be signed in to change notification settings - Fork 124
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(client): prevent out-of-range slice access #1569
Conversation
The Quic Network Simulator `handshakeloss` testcase instructs the `neqo-client` to download from multiple URLs in series. The client takes one URL after the next and tries to request it: ``` rust to_request = &remaining[..1]; remaining = &remaining[1..]; ``` This will panic on the last URL, trying to access the first element in an empty slice. This commit removes the out-of-range access. Instead of using slice operations which hide potential panics, it uses owned collections (`VecDeque` and `Vec`) and their safe methods (e.g. `pop_front`, `drain`).
Codecov ReportAttention:
Additional details and impacted files@@ Coverage Diff @@
## main #1569 +/- ##
=======================================
Coverage 87.60% 87.61%
=======================================
Files 117 117
Lines 38333 38326 -7
=======================================
- Hits 33583 33579 -4
+ Misses 4750 4747 -3 ☔ View full report in Codecov by Sentry. |
neqo-client/src/main.rs
Outdated
to_request = remaining; | ||
remaining = &[][..]; | ||
} | ||
urls.drain(..).collect() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
urls.drain(..).collect() | |
std::mem::take(urls) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh neat!
neqo-client/src/main.rs
Outdated
@@ -832,7 +832,7 @@ fn handle_test( | |||
local_addr: SocketAddr, | |||
remote_addr: SocketAddr, | |||
hostname: &str, | |||
urls: &[Url], | |||
urls: Vec<Url>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would prefer if you changed this to a VecDeque. You can see that this argument is transformed into a VecDeque for processing anyway, so you might as well save a transformation.
(At first, this change looked to be gratuitous. The change works without it. But I think that you are right to change to a pass-by-value in this case as the test functions all basically rely on having ownership of the list of URLs.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I missed this. Thank you.
neqo-client/src/main.rs
Outdated
for url in &args.urls { | ||
let entry = urls_by_origin.entry(url.origin()).or_default(); | ||
entry.push(url.clone()); | ||
entry.push_back(url.clone()); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looking at this, I find this loop annoy, because it could produce what the next loop needs (host, port) -> Url
more directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See a0975fc.
neqo-client/src/main.rs
Outdated
remaining = &remaining[1..]; | ||
if args.resume && first && remaining.is_empty() { | ||
let to_request = if (args.resume && first) || args.download_in_series { | ||
if args.resume && first && urls.len() < 2 { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another annoying thing. This check could be made outside of the loop, in which case you wouldn't need first
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool. Yep. Simplifies things.
@martinthomson thank you for the review. Can you take another look? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very nice. Thanks for indulging me. That new per-origin rollup is much cleaner.
Great. Any time @martinthomson! |
QUIC Interop Runner testcases `resumption` and `0-rtt` expect the client to download the first file, close the connection, and then download the remaining files on a second connection. https://github.com/quic-interop/quic-interop-runner/tree/master#test-cases Thus `neqo-client`, when `args.resume` is `true` must only take a single URL on the **first** loop iteration. On the second iteration it must take all remaining URLs. Regression introduced in mozilla#1569.
QUIC Interop Runner testcases `resumption` and `0-rtt` expect the client to download the first file, close the connection, and then download the remaining files on a second connection. https://github.com/quic-interop/quic-interop-runner/tree/master#test-cases Thus `neqo-client`, when `args.resume` is `true` must only take a single URL on the **first** loop iteration. On the second iteration it must take all remaining URLs. Regression introduced in #1569.
There are two server implementations based on neqo: 1. https://github.com/mozilla/neqo/tree/main/neqo-bin/src/server - http3 and http09 implementation - used for manual testing and QUIC Interop 2. https://searchfox.org/mozilla-central/source/netwerk/test/http3server/src/main.rs - used to test Firefox I assume one was once an exact copy of the other. Both implement their own I/O, event loop, ... Since then, the two implementations diverged significantly. Especially (1) saw a lot of improvements in recent months: - mozilla#1564 - mozilla#1569 - mozilla#1578 - mozilla#1581 - mozilla#1604 - mozilla#1612 - mozilla#1676 - mozilla#1692 - mozilla#1707 - mozilla#1708 - mozilla#1727 - mozilla#1753 - mozilla#1756 - mozilla#1766 - mozilla#1772 - mozilla#1786 - mozilla#1787 - mozilla#1788 - mozilla#1794 - mozilla#1806 - mozilla#1808 - mozilla#1848 - mozilla#1866 At this point, bugs in (2) are hard to fix, see e.g. mozilla#1801. This commit merges (2) into (1), thus removing all duplicate logic and having (2) benefit from all the recent improvements to (1).
There are two server implementations based on neqo: 1. https://github.com/mozilla/neqo/tree/main/neqo-bin/src/server - http3 and http09 implementation - used for manual testing and QUIC Interop 2. https://searchfox.org/mozilla-central/source/netwerk/test/http3server/src/main.rs - used to test Firefox I assume one was once an exact copy of the other. Both implement their own I/O, event loop, ... Since then, the two implementations diverged significantly. Especially (1) saw a lot of improvements in recent months: - mozilla#1564 - mozilla#1569 - mozilla#1578 - mozilla#1581 - mozilla#1604 - mozilla#1612 - mozilla#1676 - mozilla#1692 - mozilla#1707 - mozilla#1708 - mozilla#1727 - mozilla#1753 - mozilla#1756 - mozilla#1766 - mozilla#1772 - mozilla#1786 - mozilla#1787 - mozilla#1788 - mozilla#1794 - mozilla#1806 - mozilla#1808 - mozilla#1848 - mozilla#1866 At this point, bugs in (2) are hard to fix, see e.g. mozilla#1801. This commit merges (2) into (1), thus removing all duplicate logic and having (2) benefit from all the recent improvements to (1).
* refactor(bin): introduce server/http3.rs and server/http09.rs The QUIC Interop Runner requires an http3 and http09 implementation for both client and server. The client code is already structured into an http3 and an http09 implementation since #1727. This commit does the same for the server side, i.e. splits the http3 and http09 implementation into separate Rust modules. * refactor: merge mozilla-central http3 server into neqo-bin There are two server implementations based on neqo: 1. https://github.com/mozilla/neqo/tree/main/neqo-bin/src/server - http3 and http09 implementation - used for manual testing and QUIC Interop 2. https://searchfox.org/mozilla-central/source/netwerk/test/http3server/src/main.rs - used to test Firefox I assume one was once an exact copy of the other. Both implement their own I/O, event loop, ... Since then, the two implementations diverged significantly. Especially (1) saw a lot of improvements in recent months: - #1564 - #1569 - #1578 - #1581 - #1604 - #1612 - #1676 - #1692 - #1707 - #1708 - #1727 - #1753 - #1756 - #1766 - #1772 - #1786 - #1787 - #1788 - #1794 - #1806 - #1808 - #1848 - #1866 At this point, bugs in (2) are hard to fix, see e.g. #1801. This commit merges (2) into (1), thus removing all duplicate logic and having (2) benefit from all the recent improvements to (1). * Move firefox.rs to mozilla-central * Reduce HttpServer trait functions * Extract constructor * Remove unused deps * Remove clap color feature Nice to have. Adds multiple dependencies. Hard to justify for mozilla-central.
The Quic Network Simulator
handshakeloss
testcase instructs theneqo-client
to download from multiple URLs in series. The client takes one URL after the next and tries to request it:This will panic on the last URL, trying to access the first element in the empty slice
remaining
.This commit removes the out-of-range access. Instead of using slice operations which hide potential panics, it uses owned collections (
VecDeque
andVec
) and their safe methods (e.g.pop_front
,drain
).Needed for quic-interop/quic-interop-runner#344.
Related to #1552.