|
| 1 | +[advisory] |
| 2 | +id = "CVE-2018-1000622" |
| 3 | +package = "rustdoc" |
| 4 | +date = "2018-07-05" |
| 5 | +title = "Uncontrolled search path element vulnerability in rustdoc plugins" |
| 6 | +description = """ |
| 7 | +Rustdoc, if not passed the `--plugin-path` argument, defaults to |
| 8 | +`/tmp/rustdoc/plugins`. `/tmp` is world-writable on many systems, and so an |
| 9 | +attacker could craft a malicious plugin, place it in that directory, and the |
| 10 | +victim would end up executing their code. This only occurs when the |
| 11 | +`--plugin` argument is also passed. If you're not using that argument, then |
| 12 | +the loading, and therefore the bug, will not happen. |
| 13 | +
|
| 14 | +Because this feature is very difficult to use, and has been deprecated for |
| 15 | +almost a year[2] with no comments on its usage, we don't expect this to |
| 16 | +affect many users. For more details, read on. |
| 17 | +
|
| 18 | +## Background |
| 19 | +
|
| 20 | +Rustdoc has a "plugins" feature that lets you extend rustdoc. To write a |
| 21 | +plugin, you create a library with a specific exposed symbol. You instruct |
| 22 | +rustdoc to use this plugin, and it will load it, and execute the function as |
| 23 | +a callback to modify rustdoc's AST. |
| 24 | +
|
| 25 | +This feature is quite hard to use, because the function needs to take as |
| 26 | +input and return as output Rustdoc's AST type. The Rust project does not ship |
| 27 | +a copy of `librustdoc` to end users, and so they would have to synthesize |
| 28 | +this type on their own. Furthermore, Rust's ABI is unstable, and so |
| 29 | +dynamically loading a plugin is only guaranteed to work if the plugin is |
| 30 | +compiled with the same compiler revision as the rustdoc that you're using. |
| 31 | +Beyond that, the feature and how to use it are completely undocumented. |
| 32 | +
|
| 33 | +Given all of this, we're not aware of any usage of plugins in the wild, |
| 34 | +though the functionality still exists in the codebase. |
| 35 | +
|
| 36 | +## Description of the attack |
| 37 | +
|
| 38 | +If you pass the `--plugins` parameter, let's say with "foo", and *do not* |
| 39 | +pass the `--plugin-path` parameter, rustdoc will look for the "foo" plugin |
| 40 | +in /tmp/rustdoc/plugins. Given that /tmp is world-writable on many systems, |
| 41 | +an attacker with access to your machine could place a maliciously crafted |
| 42 | +plugin into /tmp/rustdoc/plugins, and rustdoc would then load the plugin, |
| 43 | +and execute the attacker's callback, running arbitrary Rust code as your |
| 44 | +user instead of theirs. |
| 45 | +
|
| 46 | +## Affected Versions |
| 47 | +
|
| 48 | +This functionality was introduced into rustdoc on December 31, 2013, in commit |
| 49 | +14f59e890207f3b7a70bcfffaea7ad8865604111 [3]. That change was to rename |
| 50 | +/tmp/rustdoc_ng/plugins to /tmp/rustdoc/plugins; The addition of this |
| 51 | +search path generally came with the first commit to this iteration of rustdoc, |
| 52 | +on September 22, 2013, in commit 7b24efd6f333620ed2559d70b32da8f6f9957385 [4]. |
| 53 | +
|
| 54 | +## Mitigations |
| 55 | +
|
| 56 | +To prevent this bug from happening on any version of Rust, you can always |
| 57 | +pass the `--plugin-path` flag to control the path. This only applies if |
| 58 | +you use the `--plugin` flag in the first place. |
| 59 | +
|
| 60 | +For Rust 1.27, we'll be releasing a 1.27.1 on Tuesday with the fix, which |
| 61 | +consists of requiring `--plugin-path` to be passed whenever `--plugin` |
| 62 | +is passed. |
| 63 | +
|
| 64 | +We will not be releasing our own fixes for previous versions of Rust, given |
| 65 | +the low severity and impact of this bug. The patch to fix 1.27 should be |
| 66 | +trivially applicable to previous versions, as this code has not changed in |
| 67 | +a very long time. The patch is included at the end of this email. If you |
| 68 | +need assistance patching an older version of Rust on your own, please reach |
| 69 | +out to Steve Klabnik, st...@steveklabnik.com, and he'll be happy to help. |
| 70 | +
|
| 71 | +On beta and nightly we will be removing plugins entirely. |
| 72 | +
|
| 73 | +## Timeline of events |
| 74 | +
|
| 75 | +* Tue, Jul 3, 2018 at 11:57 PM UTC - Bug reported to security@rust-lang.org |
| 76 | +* Tue, Jul 3, 2018 at 12:13 PM UTC - Steve responds, confirming the bug |
| 77 | +* Weds, Jul 4, 2018 - Steve works up an initial patch |
| 78 | +* Thu, Jul 5, 2018 at 6:00 PM UTC - Rust team decides to not embargo this bug |
| 79 | +* Fri, Jul 6, 2018 at 12:38 AM - Final patch created after feedback from Red Hat |
| 80 | +
|
| 81 | +## Acknowledgements |
| 82 | +
|
| 83 | +Thanks to Red Hat Product Security, which found this bug. And specifically to |
| 84 | +Josh Stone, who took their findings and reported it to us in accordance with |
| 85 | +our security policy https://www.rust-lang.org/security.html, as well as providing |
| 86 | +feedback on the patch itself. You can find their bug at [5]. |
| 87 | +
|
| 88 | +[1]: https://cwe.mitre.org/data/definitions/427.html |
| 89 | +[2]: https://github.com/rust-lang/rust/issues/44136 |
| 90 | +[3]: https://github.com/rust-lang/rust/commit/14f59e890207f3b7a70bcfffaea7ad8865604111 |
| 91 | +[4]: https://github.com/rust-lang/rust/commit/7b24efd6f333620ed2559d70b32da8f6f9957385 |
| 92 | +[5]: https://bugzilla.redhat.com/show_bug.cgi?id=1597063 |
| 93 | +""" |
| 94 | +patched_versions = ["> 1.27.0"] |
| 95 | +url = "https://groups.google.com/forum/#!topic/rustlang-security-announcements/4ybxYLTtXuM" |
| 96 | +cvss = "CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H" |
0 commit comments