Security adivsory for the Rust standard library, 2018-09-21

2283 views
Skip to first unread message

Alex Crichton

unread,
Sep 21, 2018, 2:19:07 PM9/21/18
to rustlang-securi...@googlegroups.com
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA512

# Security adivsory for the Rust standard library - 2018-09-21

The Rust team was recently notified of a security vulnerability affecting
the `str::repeat` function in the standard library. If your code does not
use this function, it is not affected.

We are applying for a CVE for this vulnerability, but since there is no
embargo, we have not filed for one yet. Once a CVE is assigned, we'll make a
second post to make mention of the CVE number.

## Overview

This vulnerability is an instance of CWE-680: Integer Overflow to Buffer
Overflow[1].

The `str::repeat` function in the standard library allows repeating a
string a fixed number of times, returning an owned version of the final
string. The capacity of the final string is calculated by multiplying
the length of the string being repeated by the number of copies. This
calculation can overflow, and this case was not properly checked for.

The rest of the implementation of `str::repeat` contains unsafe code
that relies on a preallocated vector having the capacity calculated
earlier. On integer overflow the capacity will be less than required,
and which then writes outside of the allocated buffer, leading to
buffer overflow.

## Affected Versions

While the `str::repeat` function has been in Rust since 1.16.0, this
vulnerability was introduced into the standard library in pull
request #48657 [2]. The pull request was merged on March 6, 2018 and
was first part of the 1.26.0 stable released on May 10, 2018.

As such, this vulnerability affects:

* Every nightly we've produced since March 6, 2018
* Every beta produced since March 6, 2018
* These specific Rust releases:
* 1.29.0
* 1.28.0
* 1.27.2
* 1.27.1
* 1.27.0
* 1.26.2
* 1.26.1
* 1.26.0

## Mitigations

This bug can be mitigated manually by auditing for calls to `str::repeat`
and testing if the resulting vector's capacity will overflow. If it does,
then the program should panic.

For Rust 1.29, we'll be releasing a 1.29.1 on 2018-09-25 with the fix,
which consists of checking for overflow and deterministically panicking
if it happens. Nightlies and betas produced after 2019-09-21 will also
contain a fix for this issue.

We will not be releasing our own fixes for previous versions of Rust.
The patch to fix 1.29 should roughly applicable to older versions, although
the implementation has seen a few refactorings since it was introduced.
The patch for 1.29 is included at the end of this email. If you
need assistance patching an older version of Rust on your own, please reach
out to our security mailing list, secu...@rust-lang.org, and we'll be happy
to help.

The current beta and nightly channels will be updated with a fix for this
issue as well.

## Timeline of events

* Sun, Sep 16, 2018 at 20:24 PM - Bug reported to secu...@rust-lang.org
* Mon, Sep 17, 2018 at 14:19 PM - Steve responds, confirming the bug
* Tue, Sep 18, 2018 - Steve works up an initial patch
* Wed, Sep 19, 2018 - Core team confirms 1.29.1 release date
* Thu, Sep 20, 2018 - PRs posted to GitHub for
stable[3]/beta[4]/master[5] branches
* Fri, Sep 21, 2018 - Security list informed of this issue
* (planned) Tue, Sep 25, 2018 - Rust 1.29.1 is released with a fix for
this issue

## Acknowledgements

Thanks to Scott McMurray, who found this bug and reported it to us in
accordance with our security policy https://www.rust-lang.org/security.html.

## Links

1: https://cwe.mitre.org/data/definitions/680.html
2: https://github.com/rust-lang/rust/pull/48657
3. https://github.com/rust-lang/rust/pull/54397
4. https://github.com/rust-lang/rust/pull/54398
5. https://github.com/rust-lang/rust/pull/54399

## Patch for 1.29.0

diff --git a/src/liballoc/slice.rs b/src/liballoc/slice.rs
index c27c596e79..e64ddd0e64 100644
- - --- a/src/liballoc/slice.rs
+++ b/src/liballoc/slice.rs
@@ -417,7 +417,7 @@ impl<T> [T] {
// and `rem` is the remaining part of `n`.

// Using `Vec` to access `set_len()`.
- - let mut buf = Vec::with_capacity(self.len() * n);
+ let mut buf =
Vec::with_capacity(self.len().checked_mul(n).expect("capacity
overflow"));

// `2^expn` repetition is done by doubling `buf` `expn`-times.
buf.extend(self);
-----BEGIN PGP SIGNATURE-----

iQIzBAEBCgAdFiEEV2nIi/XdPRSiNKes77mGCudSDawFAlulNREACgkQ77mGCudS
DawxvhAAjTnVCi6iv+TWvutJVKUopuDO9lqKQHuSU4C9BPQCLEUlYkVv6QFb7PlD
z1XtZ82AhH7DKCBg+O2Z/8TTCsVxSkCiQbFa6/KqtGO6wtchnCt5UprsIL+hY+zX
6YPC8KQOGaIxvhb/v2RjPK0PJiBpVvINdnHjRabieeJfwvT9HL8+ogbPS3Mhu9oI
q81ddFdFtGpDfJ7JzZ+yyiOM+RGdiUgGeeCGywUPK3fjvoVGauACqr/y+kNyRcPF
pcrC4pE0IV0huHXSGKEEx6II6lhAwRcCrj5xS7cYSE3hMBffS9DJum2zMKfzHDtX
p2gW926FFV5D1i74KTIDklPggNliPenJKxRDQzSlq45BKGuWDUtpTg9PBRSw+e9L
X4TJ9Lp3FvZoJyRHz3QuKstbXzD/KrQaqir5rZwlegylFRuKsuxKlvw/XlDPlJtr
+RF29lSc7JQ/hnn1azkA67KovObRA4OPciaob7W2Vw4+0qX2B9BWz8LRXXN0CHGx
ShXwmOOKAZqPrnbcLDvRrLAwJhCTRp7rL1Y4NM7W8rSIzM5td/cOgpZrVr3cFxbR
Qmqm15nY/2cXPQo/lj4Wed1OvUTUDWo0DRzZHWae/4gRVDRofWrleEV43f4MzQBw
1QiJZcZKndH242pKXezcqLlgh56v/WQOSLvFdM1UCs+zltFebpo=
=i0IP
-----END PGP SIGNATURE-----

Steve Klabnik

unread,
Oct 9, 2018, 12:01:52 PM10/9/18
to rustlang-security-announcements
Reply all
Reply to author
Forward
0 new messages