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

Failing to drop HeaderMap::Drain causes double-free #354

Closed
Qwaz opened this issue Nov 16, 2019 · 2 comments · Fixed by #357
Closed

Failing to drop HeaderMap::Drain causes double-free #354

Qwaz opened this issue Nov 16, 2019 · 2 comments · Fixed by #357

Comments

@Qwaz
Copy link

Qwaz commented Nov 16, 2019

http/src/header/map.rs

Lines 2115 to 2122 in 9c05e39

unsafe {
let entry = &(*self.map).entries[idx];
// Read the header name
key = ptr::read(&entry.key as *const _);
value = ptr::read(&entry.value as *const _);
next = entry.links.map(|l| l.next);
};

http/src/header/map.rs

Lines 2140 to 2148 in 9c05e39

impl<'a, T> Drop for Drain<'a, T> {
fn drop(&mut self) {
unsafe {
let map = &mut *self.map;
debug_assert!(map.extra_values.is_empty());
map.entries.set_len(0);
}
}
}

Failing to drop a value is considered safe in Rust, and unsafe code should not rely on this behavior.

It is reasonable for safe code to assume that destructor leaks do not happen, as any program that leaks destructors is probably wrong. However unsafe code cannot rely on destructors to be run in order to be safe.

HeaderMap::Drain uses ptr::read to move out entries from the map when it iterates, and calls map.entries.set_len(0) to clear the map at once when it is dropped. If Drain's drop is not called, double-free happens when HeaderMap is dropped. Also, if Drain is dropped without iterating to the end, it leaks memory.

Demonstration

@Shnatsel
Copy link

Double free is an exploitable security vulnerability. After releasing a fixed version please file a security advisory and, if possible, yank the affected versions from crates.io.

@hawkw
Copy link
Contributor

hawkw commented Nov 19, 2019

I started attempting to fix this using a similar approach as Vec::drain, setting the length of self.entries to 0 when creating the Drain iterator, and then setting the length back if the Drain iterator is dropped before draining all elements. This way, mem::forgetting the iterator would only amplify a leak, rather than calling a double-free.

However, this isn't trivially possible here: the ValueDrain iterator calls HeaderMap::remove_extra_values, which relies on indexing the entries vector. If we've already set it's length to 0, the bounds checks there will fail. So, either that method needs to be refactored to not rely on indexing, or we need a different solution here (possibly involving ManuallyDrop?). I'll keep working on it.

Qwaz added a commit to Qwaz/advisory-db that referenced this issue Jan 9, 2020
Qwaz added a commit to Qwaz/advisory-db that referenced this issue Jan 9, 2020
tarcieri added a commit to rustsec/advisory-db that referenced this issue Jan 9, 2020
roy-work added a commit to roy-work/advisory-db that referenced this issue Jan 9, 2020
…0.1.20

I believe these two vulnerabilities were patched at 0.1.20.

For RUSTSEC-2019-0033:

The advisory links to the bug: hyperium/http#352
In that bug, the fixing PR was hyperium/http#360
That PR merged the commit 81ceb61 to fix the bug; that commit, according to
GitHub, was first picked up by tag v0.1.20 ([commit][1]).

[1]: hyperium/http@81ceb61

For RUSTSEC-2019-0034:

This advisory is two separate GitHub issues against `HeaderMap::drain`,
http rustsec#354 and http rustsec#355.

For the first: the issue: hyperium/http#354
In that bug, the fixing PR was hyperium/http#357
That PR merged the commit 82d53db to fix the bug; that commit, according to
GitHub, was first picked up by tag v0.1.20 ([commit][2]).

[2]: hyperium/http@82d53db

For the second: the issue: hyperium/http#355
In that bug, the fixing PR was hyperium/http#362
That PR merged the commit 8ffe094 to fix the bug; that commit, according to
GitHub, was first picked up by tag v0.1.20 ([commit][3]).

[3]: hyperium/http@8ffe094
dfinity-bot added a commit to dfinity/sdk that referenced this issue Mar 5, 2020
Commits: [rustsec/advisory-db@891a872b...19196c29](rustsec/advisory-db@891a872...19196c2)

* [`6da6344b`](rustsec/advisory-db@6da6344) Add advisory for deprecated/unmaintained quickersort
* [`36b8de69`](rustsec/advisory-db@36b8de6) hyperium/http/issues/352
* [`ba2df66b`](rustsec/advisory-db@ba2df66) hyperium/http/issues/354,355
* [`0e59ecb7`](rustsec/advisory-db@0e59ecb) Assign RUSTSEC-2019-0033 to http
* [`526892a1`](rustsec/advisory-db@526892a) Assign RUSTSEC-2019-0034 to http
* [`200651cf`](rustsec/advisory-db@200651c) Correct affected version range on RUSTSEC-2019-003[34] to patched at 0.1.20
* [`57f553ee`](rustsec/advisory-db@57f553e) Add advisory for prost stack overflow
* [`7a0d254b`](rustsec/advisory-db@7a0d254) fixup! Add advisory for prost stack overflow
* [`a5b6099b`](rustsec/advisory-db@a5b6099) Assign RUSTSEC-2020-0002 to prost
* [`8b072513`](rustsec/advisory-db@8b07251) Fix typo
* [`e30a06a6`](rustsec/advisory-db@e30a06a) RUSTSEC-2016-0005: add note about rust-crypto vs RustCrypto
* [`17e82e13`](rustsec/advisory-db@17e82e1) Assign RUSTSEC-2018-0016 to quickersort
* [`b300fa84`](rustsec/advisory-db@b300fa8) Add unmaintained crate informational advisory: rust_sodium
* [`f8ff9cfc`](rustsec/advisory-db@f8ff9cf) Add lucet-runtime-internals sigstack allocation vuln advisory
* [`3f1f71de`](rustsec/advisory-db@3f1f71d) Update crates/lucet-runtime-internals/RUSTSEC-0000-0000.toml
* [`0271003e`](rustsec/advisory-db@0271003) Update crates/lucet-runtime-internals/RUSTSEC-0000-0000.toml
* [`2b82281e`](rustsec/advisory-db@2b82281) Assign RUSTSEC-2020-0003 (informational) to rust_sodium
* [`d8e872fd`](rustsec/advisory-db@d8e872f) Assign RUSTSEC-2020-0004 to lucet-runtime-internals
* [`df7657d3`](rustsec/advisory-db@df7657d) Fix broken/malformatted outbound links
* [`64c17acf`](rustsec/advisory-db@64c17ac) Migrate all advisories to V2 format (closes rustsec/advisory-db#228)
* [`38626513`](rustsec/advisory-db@3862651) .github: cache installation of rustsec-admin
* [`ce781096`](rustsec/advisory-db@ce78109) .github: fix rustsec-admin install caching
* [`f0ee46e9`](rustsec/advisory-db@f0ee46e) Migrate `rust/` advisories to V2 format
mergify bot added a commit to dfinity/sdk that referenced this issue Mar 9, 2020
Commits: [rustsec/advisory-db@891a872b...19196c29](rustsec/advisory-db@891a872...19196c2)

* [`6da6344b`](rustsec/advisory-db@6da6344) Add advisory for deprecated/unmaintained quickersort
* [`36b8de69`](rustsec/advisory-db@36b8de6) hyperium/http/issues/352
* [`ba2df66b`](rustsec/advisory-db@ba2df66) hyperium/http/issues/354,355
* [`0e59ecb7`](rustsec/advisory-db@0e59ecb) Assign RUSTSEC-2019-0033 to http
* [`526892a1`](rustsec/advisory-db@526892a) Assign RUSTSEC-2019-0034 to http
* [`200651cf`](rustsec/advisory-db@200651c) Correct affected version range on RUSTSEC-2019-003[34] to patched at 0.1.20
* [`57f553ee`](rustsec/advisory-db@57f553e) Add advisory for prost stack overflow
* [`7a0d254b`](rustsec/advisory-db@7a0d254) fixup! Add advisory for prost stack overflow
* [`a5b6099b`](rustsec/advisory-db@a5b6099) Assign RUSTSEC-2020-0002 to prost
* [`8b072513`](rustsec/advisory-db@8b07251) Fix typo
* [`e30a06a6`](rustsec/advisory-db@e30a06a) RUSTSEC-2016-0005: add note about rust-crypto vs RustCrypto
* [`17e82e13`](rustsec/advisory-db@17e82e1) Assign RUSTSEC-2018-0016 to quickersort
* [`b300fa84`](rustsec/advisory-db@b300fa8) Add unmaintained crate informational advisory: rust_sodium
* [`f8ff9cfc`](rustsec/advisory-db@f8ff9cf) Add lucet-runtime-internals sigstack allocation vuln advisory
* [`3f1f71de`](rustsec/advisory-db@3f1f71d) Update crates/lucet-runtime-internals/RUSTSEC-0000-0000.toml
* [`0271003e`](rustsec/advisory-db@0271003) Update crates/lucet-runtime-internals/RUSTSEC-0000-0000.toml
* [`2b82281e`](rustsec/advisory-db@2b82281) Assign RUSTSEC-2020-0003 (informational) to rust_sodium
* [`d8e872fd`](rustsec/advisory-db@d8e872f) Assign RUSTSEC-2020-0004 to lucet-runtime-internals
* [`df7657d3`](rustsec/advisory-db@df7657d) Fix broken/malformatted outbound links
* [`64c17acf`](rustsec/advisory-db@64c17ac) Migrate all advisories to V2 format (closes rustsec/advisory-db#228)
* [`38626513`](rustsec/advisory-db@3862651) .github: cache installation of rustsec-admin
* [`ce781096`](rustsec/advisory-db@ce78109) .github: fix rustsec-admin install caching
* [`f0ee46e9`](rustsec/advisory-db@f0ee46e) Migrate `rust/` advisories to V2 format

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
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 a pull request may close this issue.

3 participants