├── .github └── ISSUE_TEMPLATE │ └── general-issue.md ├── LICENSE-APACHE ├── LICENSE-MIT ├── README.md ├── docs └── handling-reports.md ├── patches ├── CVE-2019-16760 │ ├── README.md │ ├── rust-1.19.0.patch │ ├── rust-1.19.0.patch.asc │ ├── rust-1.2x.0.patch │ └── rust-1.2x.0.patch.asc ├── CVE-2022-21658 │ ├── 0001-Fix-CVE-2022-21658-for-Windows.patch │ ├── 0001-Fix-CVE-2022-21658-for-Windows.patch.asc │ ├── 0002-Fix-CVE-2022-21658-for-UNIX-like.patch │ ├── 0002-Fix-CVE-2022-21658-for-UNIX-like.patch.asc │ ├── 0003-Fix-CVE-2022-21658-for-WASI.patch │ ├── 0003-Fix-CVE-2022-21658-for-WASI.patch.asc │ ├── 0004-Update-std-fs-remove_dir_all-documentation.patch │ ├── 0004-Update-std-fs-remove_dir_all-documentation.patch.asc │ ├── 0005-Fix-compilation-for-a-few-tier-2-targets.patch │ ├── 0005-Fix-compilation-for-a-few-tier-2-targets.patch.asc │ └── README.md ├── CVE-2022-36113 │ ├── 0001-CVE-2022-36113-avoid-unpacking-.cargo-ok-from-the-cr.patch │ ├── 0001-CVE-2022-36113-avoid-unpacking-.cargo-ok-from-the-cr.patch.asc │ ├── 0002-CVE-2022-36113-add-tests.patch │ ├── 0002-CVE-2022-36113-add-tests.patch.asc │ └── README.md ├── CVE-2022-36114 │ ├── 0001-CVE-2022-36114-limit-the-maximum-unpacked-size-of-a-.patch │ ├── 0001-CVE-2022-36114-limit-the-maximum-unpacked-size-of-a-.patch.asc │ ├── 0002-CVE-2022-36114-add-tests.patch │ ├── 0002-CVE-2022-36114-add-tests.patch.asc │ └── README.md ├── CVE-2022-46176 │ ├── 0001-add-crate-dependencies.patch │ ├── 0001-add-crate-dependencies.patch.asc │ ├── 0002-add-required-APIs-to-libgit2-sys.patch │ ├── 0002-add-required-APIs-to-libgit2-sys.patch.asc │ ├── 0003-add-required-APIs-to-git2.patch │ ├── 0003-add-required-APIs-to-git2.patch.asc │ ├── 0004-CVE-2022-46176-verify-ssh-host-keys-in-cargo.patch │ ├── 0004-CVE-2022-46176-verify-ssh-host-keys-in-cargo.patch.asc │ ├── 0005-hook-up-vendored-dependencies-with-the-build-system.patch │ ├── 0005-hook-up-vendored-dependencies-with-the-build-system.patch.asc │ ├── 0006-suppress-error-in-newer-Rust-compilers.patch │ ├── 0006-suppress-error-in-newer-Rust-compilers.patch.asc │ └── README.md └── CVE-2023-38497 │ ├── 0001-test-verify-permissions-bits-are-preserved-when-unpa.patch │ ├── 0001-test-verify-permissions-bits-are-preserved-when-unpa.patch.asc │ ├── 0002-fix-respect-umask-when-unpacking-.crate-files.patch │ ├── 0002-fix-respect-umask-when-unpacking-.crate-files.patch.asc │ ├── 0003-fix-clear-cache-for-old-.cargo-ok-format.patch │ ├── 0003-fix-clear-cache-for-old-.cargo-ok-format.patch.asc │ └── README.md └── with-rust-security-key.sh /.github/ISSUE_TEMPLATE/general-issue.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: General issue 3 | about: An issue not covered by any other issue template. 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | 17 | -------------------------------------------------------------------------------- /LICENSE-APACHE: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "[]" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright [yyyy] [name of copyright owner] 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /LICENSE-MIT: -------------------------------------------------------------------------------- 1 | Permission is hereby granted, free of charge, to any 2 | person obtaining a copy of this software and associated 3 | documentation files (the "Software"), to deal in the 4 | Software without restriction, including without 5 | limitation the rights to use, copy, modify, merge, 6 | publish, distribute, sublicense, and/or sell copies of 7 | the Software, and to permit persons to whom the Software 8 | is furnished to do so, subject to the following 9 | conditions: 10 | 11 | The above copyright notice and this permission notice 12 | shall be included in all copies or substantial portions 13 | of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF 16 | ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED 17 | TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A 18 | PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 19 | SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY 20 | CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 21 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR 22 | IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 23 | DEALINGS IN THE SOFTWARE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Rust's Security Response WG 2 | 3 | This repository is intended to document the procedures of Rust's Security 4 | Response WG. 5 | 6 | If you're looking for the Rust language security policy, [go here][policy]. If 7 | you're looking to report a vulnerability, do not open an issue in this 8 | repository, instead follow Rust's [security policy][policy]. 9 | 10 | [policy]: https://www.rust-lang.org/policies/security 11 | 12 | ## Documentation 13 | 14 | * [Handling a security report](docs/handling-reports.md) 15 | -------------------------------------------------------------------------------- /docs/handling-reports.md: -------------------------------------------------------------------------------- 1 | # Process of handling a security report 2 | 3 | > **Note**: this is a work-in-progress document, more coming soon! 4 | 5 | 1. First, you'll receive an email to `security@rust-lang.org`. Some spam comes 6 | to this email address sometimes, it can be disregarded. 7 | 2. Messages may be encrypted with our GPG key. The private key is stored in 8 | Rust's 1password instance. You can request access to the key or you can wait 9 | for another member to decrypt and share the information amongst the WG. 10 | 3. The report should be determined if it's credible or not. Either way, a 11 | response should be sent the the reporter relatively soon (we try to be 12 | ASAP-ish). It's fine to say we continue to investigate. 13 | 4. Now comes the fun part, discussing the vulnerability! (assuming it needs more 14 | investigation and hasn't been ruled out). 15 | 16 | The preferred venue for discussing the vulnerability and plan a fix is a Zulip 17 | stream (on [the rust-lang instance](https://rust-lang.zulipchat.com)) dedicated 18 | to the vulnerability. A dedicated stream allows us to grant access to the 19 | reporter or other team members without letting them access other discussions. 20 | 21 | The stream should be named `wg-security-response/`, it 22 | should be private and it should allow new members to read past messages. Keep 23 | in mind that, while organization admins can't read the chat contents even if 24 | they have full access to the Zulip instance, they can read the stream name: 25 | avoid putting hints of what's going on in the name or the description. 26 | 27 | Over the next few days you'll develop a response to the security issue on 28 | Zulip, and it's recommended to do this in collaboration with the original 29 | reporter as well. They like to be kept in the loop and can often help out in 30 | validating fixes and such! 31 | 32 | Eventually you'll have a desired response and a date will be set for the 33 | announcement. We do not have a procedure for creating a *release* prior to the 34 | announcement at this time. Past procedure has been to make point releases and 35 | patches available soon after an announcement. Depending on the severity of the 36 | report we may need to figure out how to do private releases ahead of time. 37 | 38 | If we consider the vulnerability's severity to be medium or higher we need to 39 | post it to distros@lists.openwall.com **3 days** before the public 40 | announcement. [Read the instructions on how to do that carefully][distros], as 41 | they're pretty strict on what they want. 42 | 43 | When publishing an announcement, this should include: 44 | 45 | * Send mail to the google group mailing list. This should be the first thing 46 | done. Documentation on how to do so is available later in this document. 47 | 48 | * Make a post to the blog. Use the same content, but add a disclaimer that it's 49 | not official and point to the google group mail. 50 | 51 | * Make a post to users.rust-lang.org containing the same contents as the blog. 52 | 53 | * Publish the GitHub Advisory, also with a disclaimer that points to the blog. 54 | 55 | * Send an email to oss-security@lists.openwall.com with a brief excerpt of the 56 | advisory and the link to the google group mail. [Instructions on how to send 57 | an email to oss-security@][oss-security] 58 | 59 | [distros]: https://oss-security.openwall.org/wiki/mailing-lists/distros#list-policy-and-instructions-for-reporters 60 | [oss-security]: https://oss-security.openwall.org/wiki/mailing-lists/oss-security 61 | 62 | ## Disclosing a vulnerability on the rustlang-security-announcements Google Group 63 | 64 | This procedure was tested on a Linux system. 65 | 66 | 1. Import the security public key in your local GPG keychain, to be able to 67 | later ensure the signature is valid: 68 | 69 | ``` 70 | curl https://www.rust-lang.org/static/keys/rust-security-team-key.gpg.ascii | gpg --import 71 | ``` 72 | 73 | 2. Copy the announcement in a local text file named `announcement.txt`. Add the 74 | following sentence at the start of the report: 75 | 76 | > Note: if you're reading this advisory on the Google Groups web interface 77 | > please note that the GPG signature doesn't match, due to the processing 78 | > Google Groups does to the message. You can find a signed copy of this 79 | > advisory attached. 80 | 81 | 3. Sign the message with the security team's key. The command should be 82 | executed inside this repository. You need to provide your 1password 83 | credentials when prompted. 84 | 85 | ``` 86 | ./with-rust-security-key.sh gpg --local-user 0xEFB9860AE7520DAC --clear-sign ${file} 87 | ``` 88 | 89 | 4. Verify the signature is correct: 90 | 91 | ``` 92 | gpg --verify ${file}.asc 93 | ``` 94 | 95 | 5. Send a mail to rustlang-security-announcements@googlegroups.com from your 96 | personal email address with the content of `announcement.txt.asc` as the 97 | message body. Also attach `announcement.txt.asc` to the same mail. 98 | 99 | ## Signing patch files 100 | 101 | Patch files stored in this repository should be signed with the security key. 102 | To do so you'll need to run this command inside the repository (you'll need to 103 | provide your 1Password credentials when prompted): 104 | 105 | ``` 106 | ./with-rust-security-key.sh gpg --local-user 0xEFB9860AE7520DAC --sign --armor --detach ${file} 107 | ``` 108 | -------------------------------------------------------------------------------- /patches/CVE-2019-16760/README.md: -------------------------------------------------------------------------------- 1 | # Patches for CVE-2019-16760 2 | 3 | This directory contains the patches for [CVE-2019-16760][cve] ([read the 4 | security advisory][advisory]). The following patches are available: 5 | 6 | * [`rust-1.19.0.patch`][patch-1.19]: patch for Rust 1.19.0 ([signature][patch-1.19-asc]) 7 | * [`rust-1.2x.0.patch`][patch-1.2x]: patch for Rust 1.20.0 to Rust 1.25.0 ([signature][patch-1.2x-asc]) 8 | 9 | The patches are meant to be applied on top of a source tarball of Rust, 10 | and they contain both the fix to the vulnerability and a test to ensure 11 | they work. Running Cargo's test suite should also execute the new test. 12 | 13 | The patches are released under both the [MIT license][mit] and the [Apache 2.0 14 | license][apache], and signatures from the [Rust Security Response WG's GPG 15 | key][key] are provided. 16 | 17 | [cve]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-16760 18 | [advisory]: https://groups.google.com/forum/#!topic/rustlang-security-announcements/rVQ5e3TDnpQ 19 | [patch-1.19]: https://github.com/rust-lang/wg-security-response/blob/master/patches/CVE-2019-16760/rust-1.19.0.patch 20 | [patch-1.19-asc]: https://github.com/rust-lang/wg-security-response/blob/master/patches/CVE-2019-16760/rust-1.19.0.patch.asc 21 | [patch-1.2x]: https://github.com/rust-lang/wg-security-response/blob/master/patches/CVE-2019-16760/rust-1.2x.0.patch 22 | [patch-1.2x-asc]: https://github.com/rust-lang/wg-security-response/blob/master/patches/CVE-2019-16760/rust-1.2x.0.patch.asc 23 | [mit]: https://github.com/rust-lang/wg-security-response/blob/master/LICENSE-MIT 24 | [apache]: https://github.com/rust-lang/wg-security-response/blob/master/LICENSE-APACHE 25 | [key]: https://www.rust-lang.org/static/keys/rust-security-team.gpg.ascii 26 | -------------------------------------------------------------------------------- /patches/CVE-2019-16760/rust-1.19.0.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/tools/cargo/src/cargo/util/toml.rs b/src/tools/cargo/src/cargo/util/toml.rs 2 | --- a/src/tools/cargo/src/cargo/util/toml.rs 3 | +++ b/src/tools/cargo/src/cargo/util/toml.rs 4 | @@ -169,7 +169,15 @@ impl<'de> de::Deserialize<'de> for TomlDependency { 5 | where V: de::MapAccess<'de> 6 | { 7 | let mvd = de::value::MapAccessDeserializer::new(map); 8 | - DetailedTomlDependency::deserialize(mvd).map(TomlDependency::Detailed) 9 | + let dep = DetailedTomlDependency::deserialize(mvd).map(TomlDependency::Detailed); 10 | + if let Ok(&TomlDependency::Detailed(ref dep)) = dep.as_ref() { 11 | + if dep.package.is_some() { 12 | + return Err(::custom( 13 | + "the package subkey is not allowed due to CVE-2019-16760" 14 | + )); 15 | + } 16 | + } 17 | + dep 18 | } 19 | } 20 | 21 | @@ -187,6 +195,7 @@ pub struct DetailedTomlDependency { 22 | git: Option, 23 | branch: Option, 24 | tag: Option, 25 | + package: Option, 26 | rev: Option, 27 | features: Option>, 28 | optional: Option, 29 | diff --git a/src/tools/cargo/tests/cve_2019_16760.rs b/src/tools/cargo/tests/cve_2019_16760.rs 30 | new file mode 100644 31 | --- /dev/null 32 | +++ b/src/tools/cargo/tests/cve_2019_16760.rs 33 | @@ -0,0 +1,28 @@ 34 | +extern crate cargotest; 35 | +extern crate hamcrest; 36 | + 37 | +use cargotest::support::{project, execs}; 38 | +use hamcrest::assert_that; 39 | + 40 | +#[test] 41 | +fn test_cve_2019_16760() { 42 | + let pb = project("foo") 43 | + .file("Cargo.toml", r#" 44 | + [package] 45 | + name = "foo" 46 | + version = "0.0.0" 47 | + authors = [] 48 | + 49 | + [dependencies] 50 | + lazy_static1 = { version = "1", package = "lazy_static" } 51 | + "#) 52 | + .file("src/lib.rs", ""); 53 | + let p = pb.build(); 54 | + 55 | + assert_that(p.cargo("check"), execs().with_status(101).with_stderr("\ 56 | +error: failed to parse manifest at `[..]` 57 | + 58 | +Caused by: 59 | + the package subkey is not allowed due to CVE-2019-16760 for key `dependencies.lazy_static1` 60 | +")); 61 | +} 62 | 63 | -------------------------------------------------------------------------------- /patches/CVE-2019-16760/rust-1.19.0.patch.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQIzBAABCgAdFiEEV2nIi/XdPRSiNKes77mGCudSDawFAl2SDVUACgkQ77mGCudS 4 | DawFtw/+Izd+WevY6f+vZSYEvgxVlJ/3Ebdv14NQReiLgTBk+zAc0eTQLPHEj92+ 5 | lIiheh4IBA5xbzg6x4vXLsfk3KjKh8FeKq/Am5i9ZqHG0QTFxsJeyAUBCnnuf2v+ 6 | zZ95O37/cGC92/MA3RGO8SJ3Fdr21G3Fp6aKhhB2gCt1wI/yxNmf9WZm/RQ4C5ir 7 | ORKKqJ9wlEB4VwekHjZ53khtBRKRgImJzPLdBnKhImMmaBkZWJssZ/Dtgub9lB91 8 | dh3gx+WCqihuJZ0+gmkIHkyeWRfS75lT4PLWB0ppNVlvN8Twlaq52wb0++K/KcnH 9 | IH5brdr2RR3m84lddkzKS7s+AMUXR3I4iHUP+QQYjcTSyV+q4kodf3MGQdG8YA8C 10 | E+eodS6XoY+7cfLP8XYvzIz1w7aXJwkbkvy9bLdqLQ8uXldR0rhD/mnEANjP4XDG 11 | ymBnzY+bBbtkTQxyVuIdcAh6VXDjHm5YnUi8uoy9DjwZMF9C+uSJyQxzx4rMt7Eo 12 | bRWu+VdJrXcs5dQVwnjAMCZf+Tzmx/Z8/8eOVkqM30nJfn+m26DZCPOzRiDmswiC 13 | G/HU6u4ji5wCQ77hq5tCOeUVROkTH5IGC99XkFCGYzfePIyucj941q0OajWF213V 14 | NsG7vpzYG0eET4YtHG9gTcRk54zYmMBODyhJcrSD3xs3rBC8E+k= 15 | =vOYF 16 | -----END PGP SIGNATURE----- 17 | -------------------------------------------------------------------------------- /patches/CVE-2019-16760/rust-1.2x.0.patch: -------------------------------------------------------------------------------- 1 | diff --git a/src/tools/cargo/src/cargo/util/toml/mod.rs b/src/tools/cargo/src/cargo/util/toml/mod.rs 2 | --- a/src/tools/cargo/src/cargo/util/toml/mod.rs 3 | +++ b/src/tools/cargo/src/cargo/util/toml/mod.rs 4 | @@ -169,7 +169,15 @@ impl<'de> de::Deserialize<'de> for TomlDependency { 5 | where V: de::MapAccess<'de> 6 | { 7 | let mvd = de::value::MapAccessDeserializer::new(map); 8 | - DetailedTomlDependency::deserialize(mvd).map(TomlDependency::Detailed) 9 | + let dep = DetailedTomlDependency::deserialize(mvd).map(TomlDependency::Detailed); 10 | + if let Ok(&TomlDependency::Detailed(ref dep)) = dep.as_ref() { 11 | + if dep.package.is_some() { 12 | + return Err(::custom( 13 | + "the package subkey is not allowed due to CVE-2019-16760" 14 | + )); 15 | + } 16 | + } 17 | + dep 18 | } 19 | } 20 | 21 | @@ -187,6 +195,7 @@ pub struct DetailedTomlDependency { 22 | git: Option, 23 | branch: Option, 24 | tag: Option, 25 | + package: Option, 26 | rev: Option, 27 | features: Option>, 28 | optional: Option, 29 | diff --git a/src/tools/cargo/tests/cve_2019_16760.rs b/src/tools/cargo/tests/cve_2019_16760.rs 30 | new file mode 100644 31 | --- /dev/null 32 | +++ b/src/tools/cargo/tests/cve_2019_16760.rs 33 | @@ -0,0 +1,28 @@ 34 | +extern crate cargotest; 35 | +extern crate hamcrest; 36 | + 37 | +use cargotest::support::{project, execs}; 38 | +use hamcrest::assert_that; 39 | + 40 | +#[test] 41 | +fn test_cve_2019_16760() { 42 | + let pb = project("foo") 43 | + .file("Cargo.toml", r#" 44 | + [package] 45 | + name = "foo" 46 | + version = "0.0.0" 47 | + authors = [] 48 | + 49 | + [dependencies] 50 | + lazy_static1 = { version = "1", package = "lazy_static" } 51 | + "#) 52 | + .file("src/lib.rs", ""); 53 | + let p = pb.build(); 54 | + 55 | + assert_that(p.cargo("check"), execs().with_status(101).with_stderr("\ 56 | +error: failed to parse manifest at `[..]` 57 | + 58 | +Caused by: 59 | + the package subkey is not allowed due to CVE-2019-16760 for key `dependencies.lazy_static1` 60 | +")); 61 | +} 62 | 63 | -------------------------------------------------------------------------------- /patches/CVE-2019-16760/rust-1.2x.0.patch.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQIzBAABCgAdFiEEV2nIi/XdPRSiNKes77mGCudSDawFAl2SDasACgkQ77mGCudS 4 | DayqgA/9GVC+nbI7WmB3u2gUYi7WpUP8TgBqXM5HCD3+LiaV2jehIGxgWqGChokh 5 | bvVB4SqiCHGISa9W6juWmbt5/5iImupJnxYB0ax+14hFFk1oR535JqznwkYDStkw 6 | GZdMpGpmbQQraidis//nIYieQNduKMPBMbM5VUWABdcUyq2I0X5PfyrLDOcOQaUW 7 | zCCW0LH2+NKvvhHVoYMnrUuIajPwYF4tLFdLh0IcqeoP/N8YygTN6Pf9yBAJhWNi 8 | ty0TJFmbgAmK1sUgEJnKCk4U78zY63z4p9Op9rc8zk0F6PnQSDXe5gnFvIvCGlxA 9 | 90/EU3C1jEVP9Kpxn/gW8xjbugX3pd+/K9lQ55JKJItbqkvXgHHHMAT52ryIVlC8 10 | LLiOLiQ+bhIFJrz198hK/rKV8Sv7UdVG0kBykvmK6i4Mcbc+/B+HX7SNhn+oP32+ 11 | UbbttReq0ebnWAhSFnMICIVixNFNvz5T2OiWXxyP2BN4JGfDvUGn/cnVMxGNYV++ 12 | i5wWUU1aWoTkLOEQfc7SKitacAuj9DmpVDHeNLNV2oMbnVFDbnFtFkwv12Zczlkc 13 | fiHG1P3AYa0Vv2FrbWtEGVjdI+XXjDYgyGGTbir4nFof6oKeVx4RnaFHT2tvw8BX 14 | kjvUKgdAc57e8ATSaWuegVZqDhL6kJvL59WmYOBhIHHgLh1bZxg= 15 | =86AM 16 | -----END PGP SIGNATURE----- 17 | -------------------------------------------------------------------------------- /patches/CVE-2022-21658/0001-Fix-CVE-2022-21658-for-Windows.patch: -------------------------------------------------------------------------------- 1 | From d28c910f218167b2a77bd4bc4bf665bc3dcd0bc0 Mon Sep 17 00:00:00 2001 2 | From: Chris Denton 3 | Date: Thu, 6 Jan 2022 02:47:36 +0000 4 | Subject: [PATCH 1/4] Fix CVE-2022-21658 for Windows 5 | 6 | --- 7 | library/std/src/sys/windows/c.rs | 124 +++++++++++- 8 | library/std/src/sys/windows/fs.rs | 322 ++++++++++++++++++++++++++++-- 9 | 2 files changed, 419 insertions(+), 27 deletions(-) 10 | 11 | diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs 12 | index 50c4547de85..1ef6addc11b 100644 13 | --- a/library/std/src/sys/windows/c.rs 14 | +++ b/library/std/src/sys/windows/c.rs 15 | @@ -4,6 +4,7 @@ 16 | #![cfg_attr(test, allow(dead_code))] 17 | #![unstable(issue = "none", feature = "windows_c")] 18 | 19 | +use crate::mem; 20 | use crate::os::raw::NonZero_c_ulong; 21 | use crate::os::raw::{c_char, c_int, c_long, c_longlong, c_uint, c_ulong, c_ushort}; 22 | use crate::ptr; 23 | @@ -36,6 +37,7 @@ 24 | pub type SIZE_T = usize; 25 | pub type WORD = u16; 26 | pub type CHAR = c_char; 27 | +pub type CCHAR = c_char; 28 | pub type ULONG_PTR = usize; 29 | pub type ULONG = c_ulong; 30 | pub type NTSTATUS = LONG; 31 | @@ -86,16 +88,21 @@ 32 | pub const FILE_SHARE_READ: DWORD = 0x1; 33 | pub const FILE_SHARE_WRITE: DWORD = 0x2; 34 | 35 | +pub const FILE_OPEN_REPARSE_POINT: ULONG = 0x200000; 36 | +pub const OBJ_DONT_REPARSE: ULONG = 0x1000; 37 | + 38 | pub const CREATE_ALWAYS: DWORD = 2; 39 | pub const CREATE_NEW: DWORD = 1; 40 | pub const OPEN_ALWAYS: DWORD = 4; 41 | pub const OPEN_EXISTING: DWORD = 3; 42 | pub const TRUNCATE_EXISTING: DWORD = 5; 43 | 44 | +pub const FILE_LIST_DIRECTORY: DWORD = 0x1; 45 | pub const FILE_WRITE_DATA: DWORD = 0x00000002; 46 | pub const FILE_APPEND_DATA: DWORD = 0x00000004; 47 | pub const FILE_WRITE_EA: DWORD = 0x00000010; 48 | pub const FILE_WRITE_ATTRIBUTES: DWORD = 0x00000100; 49 | +pub const DELETE: DWORD = 0x10000; 50 | pub const READ_CONTROL: DWORD = 0x00020000; 51 | pub const SYNCHRONIZE: DWORD = 0x00100000; 52 | pub const GENERIC_READ: DWORD = 0x80000000; 53 | @@ -261,9 +268,61 @@ pub struct ipv6_mreq { 54 | pub const STACK_SIZE_PARAM_IS_A_RESERVATION: DWORD = 0x00010000; 55 | 56 | pub const STATUS_SUCCESS: NTSTATUS = 0x00000000; 57 | +pub const STATUS_DELETE_PENDING: NTSTATUS = 0xc0000056_u32 as _; 58 | +pub const STATUS_INVALID_PARAMETER: NTSTATUS = 0xc000000d_u32 as _; 59 | + 60 | +// Equivalent to the `NT_SUCCESS` C preprocessor macro. 61 | +// See: https://docs.microsoft.com/en-us/windows-hardware/drivers/kernel/using-ntstatus-values 62 | +pub fn nt_success(status: NTSTATUS) -> bool { 63 | + status >= 0 64 | +} 65 | 66 | pub const BCRYPT_USE_SYSTEM_PREFERRED_RNG: DWORD = 0x00000002; 67 | 68 | +#[repr(C)] 69 | +pub struct UNICODE_STRING { 70 | + pub Length: u16, 71 | + pub MaximumLength: u16, 72 | + pub Buffer: *mut u16, 73 | +} 74 | +impl UNICODE_STRING { 75 | + pub fn from_ref(slice: &[u16]) -> Self { 76 | + let len = slice.len() * mem::size_of::(); 77 | + Self { Length: len as _, MaximumLength: len as _, Buffer: slice.as_ptr() as _ } 78 | + } 79 | +} 80 | +#[repr(C)] 81 | +pub struct OBJECT_ATTRIBUTES { 82 | + pub Length: ULONG, 83 | + pub RootDirectory: HANDLE, 84 | + pub ObjectName: *const UNICODE_STRING, 85 | + pub Attributes: ULONG, 86 | + pub SecurityDescriptor: *mut c_void, 87 | + pub SecurityQualityOfService: *mut c_void, 88 | +} 89 | +impl Default for OBJECT_ATTRIBUTES { 90 | + fn default() -> Self { 91 | + Self { 92 | + Length: mem::size_of::() as _, 93 | + RootDirectory: ptr::null_mut(), 94 | + ObjectName: ptr::null_mut(), 95 | + Attributes: 0, 96 | + SecurityDescriptor: ptr::null_mut(), 97 | + SecurityQualityOfService: ptr::null_mut(), 98 | + } 99 | + } 100 | +} 101 | +#[repr(C)] 102 | +pub struct IO_STATUS_BLOCK { 103 | + pub Pointer: *mut c_void, 104 | + pub Information: usize, 105 | +} 106 | +impl Default for IO_STATUS_BLOCK { 107 | + fn default() -> Self { 108 | + Self { Pointer: ptr::null_mut(), Information: 0 } 109 | + } 110 | +} 111 | + 112 | #[repr(C)] 113 | #[cfg(not(target_pointer_width = "64"))] 114 | pub struct WSADATA { 115 | @@ -353,9 +412,43 @@ pub enum FILE_INFO_BY_HANDLE_CLASS { 116 | FileIdInfo = 18, // 0x12 117 | FileIdExtdDirectoryInfo = 19, // 0x13 118 | FileIdExtdDirectoryRestartInfo = 20, // 0x14 119 | + FileDispositionInfoEx = 21, // 0x15, Windows 10 version 1607 120 | MaximumFileInfoByHandlesClass, 121 | } 122 | 123 | +#[repr(C)] 124 | +pub struct FILE_DISPOSITION_INFO { 125 | + pub DeleteFile: BOOLEAN, 126 | +} 127 | + 128 | +pub const FILE_DISPOSITION_DELETE: DWORD = 0x1; 129 | +pub const FILE_DISPOSITION_POSIX_SEMANTICS: DWORD = 0x2; 130 | +pub const FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE: DWORD = 0x10; 131 | + 132 | +#[repr(C)] 133 | +pub struct FILE_DISPOSITION_INFO_EX { 134 | + pub Flags: DWORD, 135 | +} 136 | + 137 | +#[repr(C)] 138 | +#[derive(Default)] 139 | +pub struct FILE_ID_BOTH_DIR_INFO { 140 | + pub NextEntryOffset: DWORD, 141 | + pub FileIndex: DWORD, 142 | + pub CreationTime: LARGE_INTEGER, 143 | + pub LastAccessTime: LARGE_INTEGER, 144 | + pub LastWriteTime: LARGE_INTEGER, 145 | + pub ChangeTime: LARGE_INTEGER, 146 | + pub EndOfFile: LARGE_INTEGER, 147 | + pub AllocationSize: LARGE_INTEGER, 148 | + pub FileAttributes: DWORD, 149 | + pub FileNameLength: DWORD, 150 | + pub EaSize: DWORD, 151 | + pub ShortNameLength: CCHAR, 152 | + pub ShortName: [WCHAR; 12], 153 | + pub FileId: LARGE_INTEGER, 154 | + pub FileName: [WCHAR; 1], 155 | +} 156 | #[repr(C)] 157 | pub struct FILE_BASIC_INFO { 158 | pub CreationTime: LARGE_INTEGER, 159 | @@ -750,16 +843,6 @@ pub struct FILE_STANDARD_INFO { 160 | pub DeletePending: BOOLEAN, 161 | pub Directory: BOOLEAN, 162 | } 163 | - 164 | - #[link(name = "kernel32")] 165 | - extern "system" { 166 | - pub fn GetFileInformationByHandleEx( 167 | - hFile: HANDLE, 168 | - fileInfoClass: FILE_INFO_BY_HANDLE_CLASS, 169 | - lpFileInformation: LPVOID, 170 | - dwBufferSize: DWORD, 171 | - ) -> BOOL; 172 | - } 173 | } 174 | } 175 | 176 | @@ -949,6 +1032,12 @@ pub fn GetFinalPathNameByHandleW( 177 | cchFilePath: DWORD, 178 | dwFlags: DWORD, 179 | ) -> DWORD; 180 | + pub fn GetFileInformationByHandleEx( 181 | + hFile: HANDLE, 182 | + fileInfoClass: FILE_INFO_BY_HANDLE_CLASS, 183 | + lpFileInformation: LPVOID, 184 | + dwBufferSize: DWORD, 185 | + ) -> BOOL; 186 | pub fn SetFileInformationByHandle( 187 | hFile: HANDLE, 188 | FileInformationClass: FILE_INFO_BY_HANDLE_CLASS, 189 | @@ -1133,6 +1222,21 @@ pub fn WakeByAddressSingle(Address: LPVOID) -> () { 190 | 191 | compat_fn! { 192 | "ntdll": 193 | + pub fn NtOpenFile( 194 | + FileHandle: *mut HANDLE, 195 | + DesiredAccess: ACCESS_MASK, 196 | + ObjectAttributes: *const OBJECT_ATTRIBUTES, 197 | + IoStatusBlock: *mut IO_STATUS_BLOCK, 198 | + ShareAccess: ULONG, 199 | + OpenOptions: ULONG 200 | + ) -> NTSTATUS { 201 | + panic!("`NtOpenFile` not available"); 202 | + } 203 | + pub fn RtlNtStatusToDosError( 204 | + Status: NTSTATUS 205 | + ) -> ULONG { 206 | + panic!("`RtlNtStatusToDosError` not available"); 207 | + } 208 | pub fn NtCreateKeyedEvent( 209 | KeyedEventHandle: LPHANDLE, 210 | DesiredAccess: ACCESS_MASK, 211 | diff --git a/library/std/src/sys/windows/fs.rs b/library/std/src/sys/windows/fs.rs 212 | index 9859000c8d4..5894c680349 100644 213 | --- a/library/std/src/sys/windows/fs.rs 214 | +++ b/library/std/src/sys/windows/fs.rs 215 | @@ -543,6 +543,218 @@ pub fn set_permissions(&self, perm: FilePermissions) -> io::Result<()> { 216 | })?; 217 | Ok(()) 218 | } 219 | + /// Get only basic file information such as attributes and file times. 220 | + fn basic_info(&self) -> io::Result { 221 | + unsafe { 222 | + let mut info: c::FILE_BASIC_INFO = mem::zeroed(); 223 | + let size = mem::size_of_val(&info); 224 | + cvt(c::GetFileInformationByHandleEx( 225 | + self.handle.as_raw_handle(), 226 | + c::FileBasicInfo, 227 | + &mut info as *mut _ as *mut libc::c_void, 228 | + size as c::DWORD, 229 | + ))?; 230 | + Ok(info) 231 | + } 232 | + } 233 | + /// Delete using POSIX semantics. 234 | + /// 235 | + /// Files will be deleted as soon as the handle is closed. This is supported 236 | + /// for Windows 10 1607 (aka RS1) and later. However some filesystem 237 | + /// drivers will not support it even then, e.g. FAT32. 238 | + /// 239 | + /// If the operation is not supported for this filesystem or OS version 240 | + /// then errors will be `ERROR_NOT_SUPPORTED` or `ERROR_INVALID_PARAMETER`. 241 | + fn posix_delete(&self) -> io::Result<()> { 242 | + let mut info = c::FILE_DISPOSITION_INFO_EX { 243 | + Flags: c::FILE_DISPOSITION_DELETE 244 | + | c::FILE_DISPOSITION_POSIX_SEMANTICS 245 | + | c::FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE, 246 | + }; 247 | + let size = mem::size_of_val(&info); 248 | + cvt(unsafe { 249 | + c::SetFileInformationByHandle( 250 | + self.handle.as_raw_handle(), 251 | + c::FileDispositionInfoEx, 252 | + &mut info as *mut _ as *mut _, 253 | + size as c::DWORD, 254 | + ) 255 | + })?; 256 | + Ok(()) 257 | + } 258 | + 259 | + /// Delete a file using win32 semantics. The file won't actually be deleted 260 | + /// until all file handles are closed. However, marking a file for deletion 261 | + /// will prevent anyone from opening a new handle to the file. 262 | + fn win32_delete(&self) -> io::Result<()> { 263 | + let mut info = c::FILE_DISPOSITION_INFO { DeleteFile: c::TRUE as _ }; 264 | + let size = mem::size_of_val(&info); 265 | + cvt(unsafe { 266 | + c::SetFileInformationByHandle( 267 | + self.handle.as_raw_handle(), 268 | + c::FileDispositionInfo, 269 | + &mut info as *mut _ as *mut _, 270 | + size as c::DWORD, 271 | + ) 272 | + })?; 273 | + Ok(()) 274 | + } 275 | + 276 | + /// Fill the given buffer with as many directory entries as will fit. 277 | + /// This will remember its position and continue from the last call unless 278 | + /// `restart` is set to `true`. 279 | + /// 280 | + /// The returned bool indicates if there are more entries or not. 281 | + /// It is an error if `self` is not a directory. 282 | + /// 283 | + /// # Symlinks and other reparse points 284 | + /// 285 | + /// On Windows a file is either a directory or a non-directory. 286 | + /// A symlink directory is simply an empty directory with some "reparse" metadata attached. 287 | + /// So if you open a link (not its target) and iterate the directory, 288 | + /// you will always iterate an empty directory regardless of the target. 289 | + fn fill_dir_buff(&self, buffer: &mut DirBuff, restart: bool) -> io::Result { 290 | + let class = 291 | + if restart { c::FileIdBothDirectoryRestartInfo } else { c::FileIdBothDirectoryInfo }; 292 | + 293 | + unsafe { 294 | + let result = cvt(c::GetFileInformationByHandleEx( 295 | + self.handle.as_raw_handle(), 296 | + class, 297 | + buffer.as_mut_ptr().cast(), 298 | + buffer.capacity() as _, 299 | + )); 300 | + match result { 301 | + Ok(_) => Ok(true), 302 | + Err(e) if e.raw_os_error() == Some(c::ERROR_NO_MORE_FILES as _) => Ok(false), 303 | + Err(e) => Err(e), 304 | + } 305 | + } 306 | + } 307 | +} 308 | + 309 | +/// A buffer for holding directory entries. 310 | +struct DirBuff { 311 | + buffer: Vec, 312 | +} 313 | +impl DirBuff { 314 | + fn new() -> Self { 315 | + const BUFFER_SIZE: usize = 1024; 316 | + Self { buffer: vec![0_u8; BUFFER_SIZE] } 317 | + } 318 | + fn capacity(&self) -> usize { 319 | + self.buffer.len() 320 | + } 321 | + fn as_mut_ptr(&mut self) -> *mut u8 { 322 | + self.buffer.as_mut_ptr().cast() 323 | + } 324 | + /// Returns a `DirBuffIter`. 325 | + fn iter(&self) -> DirBuffIter<'_> { 326 | + DirBuffIter::new(self) 327 | + } 328 | +} 329 | +impl AsRef<[u8]> for DirBuff { 330 | + fn as_ref(&self) -> &[u8] { 331 | + &self.buffer 332 | + } 333 | +} 334 | + 335 | +/// An iterator over entries stored in a `DirBuff`. 336 | +/// 337 | +/// Currently only returns file names (UTF-16 encoded). 338 | +struct DirBuffIter<'a> { 339 | + buffer: Option<&'a [u8]>, 340 | + cursor: usize, 341 | +} 342 | +impl<'a> DirBuffIter<'a> { 343 | + fn new(buffer: &'a DirBuff) -> Self { 344 | + Self { buffer: Some(buffer.as_ref()), cursor: 0 } 345 | + } 346 | +} 347 | +impl<'a> Iterator for DirBuffIter<'a> { 348 | + type Item = &'a [u16]; 349 | + fn next(&mut self) -> Option { 350 | + use crate::mem::size_of; 351 | + let buffer = &self.buffer?[self.cursor..]; 352 | + 353 | + // Get the name and next entry from the buffer. 354 | + // SAFETY: The buffer contains a `FILE_ID_BOTH_DIR_INFO` struct but the 355 | + // last field (the file name) is unsized. So an offset has to be 356 | + // used to get the file name slice. 357 | + let (name, next_entry) = unsafe { 358 | + let info = buffer.as_ptr().cast::(); 359 | + let next_entry = (*info).NextEntryOffset as usize; 360 | + let name = crate::slice::from_raw_parts( 361 | + (*info).FileName.as_ptr().cast::(), 362 | + (*info).FileNameLength as usize / size_of::(), 363 | + ); 364 | + (name, next_entry) 365 | + }; 366 | + 367 | + if next_entry == 0 { 368 | + self.buffer = None 369 | + } else { 370 | + self.cursor += next_entry 371 | + } 372 | + 373 | + // Skip `.` and `..` pseudo entries. 374 | + const DOT: u16 = b'.' as u16; 375 | + match name { 376 | + [DOT] | [DOT, DOT] => self.next(), 377 | + _ => Some(name), 378 | + } 379 | + } 380 | +} 381 | + 382 | +/// Open a link relative to the parent directory, ensure no symlinks are followed. 383 | +fn open_link_no_reparse(parent: &File, name: &[u16], access: u32) -> io::Result { 384 | + // This is implemented using the lower level `NtOpenFile` function as 385 | + // unfortunately opening a file relative to a parent is not supported by 386 | + // win32 functions. It is however a fundamental feature of the NT kernel. 387 | + // 388 | + // See https://docs.microsoft.com/en-us/windows/win32/api/winternl/nf-winternl-ntopenfile 389 | + unsafe { 390 | + let mut handle = ptr::null_mut(); 391 | + let mut io_status = c::IO_STATUS_BLOCK::default(); 392 | + let name_str = c::UNICODE_STRING::from_ref(name); 393 | + use crate::sync::atomic::{AtomicU32, Ordering}; 394 | + // The `OBJ_DONT_REPARSE` attribute ensures that we haven't been 395 | + // tricked into following a symlink. However, it may not be available in 396 | + // earlier versions of Windows. 397 | + static ATTRIBUTES: AtomicU32 = AtomicU32::new(c::OBJ_DONT_REPARSE); 398 | + let object = c::OBJECT_ATTRIBUTES { 399 | + ObjectName: &name_str, 400 | + RootDirectory: parent.as_raw_handle(), 401 | + Attributes: ATTRIBUTES.load(Ordering::Relaxed), 402 | + ..c::OBJECT_ATTRIBUTES::default() 403 | + }; 404 | + let status = c::NtOpenFile( 405 | + &mut handle, 406 | + access, 407 | + &object, 408 | + &mut io_status, 409 | + c::FILE_SHARE_DELETE | c::FILE_SHARE_READ | c::FILE_SHARE_WRITE, 410 | + // If `name` is a symlink then open the link rather than the target. 411 | + c::FILE_OPEN_REPARSE_POINT, 412 | + ); 413 | + // Convert an NTSTATUS to the more familiar Win32 error codes (aka "DosError") 414 | + if c::nt_success(status) { 415 | + Ok(File::from_raw_handle(handle)) 416 | + } else if status == c::STATUS_DELETE_PENDING { 417 | + // We make a special exception for `STATUS_DELETE_PENDING` because 418 | + // otherwise this will be mapped to `ERROR_ACCESS_DENIED` which is 419 | + // very unhelpful. 420 | + Err(io::Error::from_raw_os_error(c::ERROR_DELETE_PENDING as _)) 421 | + } else if status == c::STATUS_INVALID_PARAMETER 422 | + && ATTRIBUTES.load(Ordering::Relaxed) == c::OBJ_DONT_REPARSE 423 | + { 424 | + // Try without `OBJ_DONT_REPARSE`. See above. 425 | + ATTRIBUTES.store(0, Ordering::Relaxed); 426 | + open_link_no_reparse(parent, name, access) 427 | + } else { 428 | + Err(io::Error::from_raw_os_error(c::RtlNtStatusToDosError(status) as _)) 429 | + } 430 | + } 431 | } 432 | 433 | impl AsInner for File { 434 | @@ -752,30 +964,106 @@ pub fn rmdir(p: &Path) -> io::Result<()> { 435 | Ok(()) 436 | } 437 | 438 | +/// Open a file or directory without following symlinks. 439 | +fn open_link(path: &Path, access_mode: u32) -> io::Result { 440 | + let mut opts = OpenOptions::new(); 441 | + opts.access_mode(access_mode); 442 | + // `FILE_FLAG_BACKUP_SEMANTICS` allows opening directories. 443 | + // `FILE_FLAG_OPEN_REPARSE_POINT` opens a link instead of its target. 444 | + opts.custom_flags(c::FILE_FLAG_BACKUP_SEMANTICS | c::FILE_FLAG_OPEN_REPARSE_POINT); 445 | + File::open(path, &opts) 446 | +} 447 | + 448 | pub fn remove_dir_all(path: &Path) -> io::Result<()> { 449 | - let filetype = lstat(path)?.file_type(); 450 | - if filetype.is_symlink() { 451 | - // On Windows symlinks to files and directories are removed differently. 452 | - // rmdir only deletes dir symlinks and junctions, not file symlinks. 453 | - rmdir(path) 454 | + let file = open_link(path, c::DELETE | c::FILE_LIST_DIRECTORY)?; 455 | + 456 | + // Test if the file is not a directory or a symlink to a directory. 457 | + if (file.basic_info()?.FileAttributes & c::FILE_ATTRIBUTE_DIRECTORY) == 0 { 458 | + return Err(io::Error::from_raw_os_error(c::ERROR_DIRECTORY as _)); 459 | + } 460 | + let mut delete: fn(&File) -> io::Result<()> = File::posix_delete; 461 | + let result = match delete(&file) { 462 | + Err(e) if e.kind() == io::ErrorKind::DirectoryNotEmpty => { 463 | + match remove_dir_all_recursive(&file, delete) { 464 | + // Return unexpected errors. 465 | + Err(e) if e.kind() != io::ErrorKind::DirectoryNotEmpty => return Err(e), 466 | + result => result, 467 | + } 468 | + } 469 | + // If POSIX delete is not supported for this filesystem then fallback to win32 delete. 470 | + Err(e) 471 | + if e.raw_os_error() == Some(c::ERROR_NOT_SUPPORTED as i32) 472 | + || e.raw_os_error() == Some(c::ERROR_INVALID_PARAMETER as i32) => 473 | + { 474 | + delete = File::win32_delete; 475 | + Err(e) 476 | + } 477 | + result => result, 478 | + }; 479 | + if result.is_ok() { 480 | + Ok(()) 481 | } else { 482 | - remove_dir_all_recursive(path) 483 | + // This is a fallback to make sure the directory is actually deleted. 484 | + // Otherwise this function is prone to failing with `DirectoryNotEmpty` 485 | + // due to possible delays between marking a file for deletion and the 486 | + // file actually being deleted from the filesystem. 487 | + // 488 | + // So we retry a few times before giving up. 489 | + for _ in 0..5 { 490 | + match remove_dir_all_recursive(&file, delete) { 491 | + Err(e) if e.kind() == io::ErrorKind::DirectoryNotEmpty => {} 492 | + result => return result, 493 | + } 494 | + } 495 | + // Try one last time. 496 | + delete(&file) 497 | } 498 | } 499 | 500 | -fn remove_dir_all_recursive(path: &Path) -> io::Result<()> { 501 | - for child in readdir(path)? { 502 | - let child = child?; 503 | - let child_type = child.file_type()?; 504 | - if child_type.is_dir() { 505 | - remove_dir_all_recursive(&child.path())?; 506 | - } else if child_type.is_symlink_dir() { 507 | - rmdir(&child.path())?; 508 | - } else { 509 | - unlink(&child.path())?; 510 | +fn remove_dir_all_recursive(f: &File, delete: fn(&File) -> io::Result<()>) -> io::Result<()> { 511 | + let mut buffer = DirBuff::new(); 512 | + let mut restart = true; 513 | + // Fill the buffer and iterate the entries. 514 | + while f.fill_dir_buff(&mut buffer, restart)? { 515 | + for name in buffer.iter() { 516 | + // Open the file without following symlinks and try deleting it. 517 | + // We try opening will all needed permissions and if that is denied 518 | + // fallback to opening without `FILE_LIST_DIRECTORY` permission. 519 | + // Note `SYNCHRONIZE` permission is needed for synchronous access. 520 | + let mut result = 521 | + open_link_no_reparse(&f, name, c::SYNCHRONIZE | c::DELETE | c::FILE_LIST_DIRECTORY); 522 | + if matches!(&result, Err(e) if e.kind() == io::ErrorKind::PermissionDenied) { 523 | + result = open_link_no_reparse(&f, name, c::SYNCHRONIZE | c::DELETE); 524 | + } 525 | + match result { 526 | + Ok(file) => match delete(&file) { 527 | + Err(e) if e.kind() == io::ErrorKind::DirectoryNotEmpty => { 528 | + // Iterate the directory's files. 529 | + // Ignore `DirectoryNotEmpty` errors here. They will be 530 | + // caught when `remove_dir_all` tries to delete the top 531 | + // level directory. It can then decide if to retry or not. 532 | + match remove_dir_all_recursive(&file, delete) { 533 | + Err(e) if e.kind() == io::ErrorKind::DirectoryNotEmpty => {} 534 | + result => result?, 535 | + } 536 | + } 537 | + result => result?, 538 | + }, 539 | + // Ignore error if a delete is already in progress or the file 540 | + // has already been deleted. It also ignores sharing violations 541 | + // (where a file is locked by another process) as these are 542 | + // usually temporary. 543 | + Err(e) 544 | + if e.raw_os_error() == Some(c::ERROR_DELETE_PENDING as _) 545 | + || e.kind() == io::ErrorKind::NotFound 546 | + || e.raw_os_error() == Some(c::ERROR_SHARING_VIOLATION as _) => {} 547 | + Err(e) => return Err(e), 548 | + } 549 | } 550 | + // Continue reading directory entries without restarting from the beginning, 551 | + restart = false; 552 | } 553 | - rmdir(path) 554 | + delete(&f) 555 | } 556 | 557 | pub fn readlink(path: &Path) -> io::Result { 558 | -- 559 | 2.32.0 560 | 561 | -------------------------------------------------------------------------------- /patches/CVE-2022-21658/0001-Fix-CVE-2022-21658-for-Windows.patch.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP MESSAGE----- 2 | 3 | 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 145 | NRZL7VqjzqkaZrWeD+zQSG+lhK+xpQkkbpeyilOcHW76dUeQWr2yAoGCfqNDVzQD 146 | E7BwX1jnQKK2odDxrmV128BgKojd3uA2HPTJanwCGy/F8BnUW6yEHiOpQnaikM2l 147 | Ur/xnInL91yW2vPzL7jx8jPaJ1/19GOz1949+Uf3P/mBO1NPNK+6/7nPkb+W3r8n 148 | 9bxr/CdTn7n6B1fazm++7mVfLZxd7L356uL8gw9dcZd9xwH7cfIHr/iF+rXVTzz1 149 | nS+/9fuvmfyZzpWj131x/g8P3HCxn9m6/f0fev2j5ufvfbz+T9e/+MM3XPORlzx4 150 | XeGGqU8UX/JoRnrs839/NDv1wMaT8g9fdEz5wlsP3PfOy5q33PcNJbvnAXkr1fq9 151 | M9XfOdz9nHrPG09+86HXpz/1WPvQvqvOrKh3XfHkR9//Vfc9L/7WI9f869g377n2 152 | 76bufvPRj13z8ec/mfnsp64cf+57vzr5jvUfla//8KPP+9K37/veX77we1++6vw/ 153 | vmY5/6k7Uw++/U8efkvxupGLF/548bFXVL5w4prrn3/6Lnermv6XQ/fl9fved9/X 154 | lSsq333ZVR/8pa4x98jHnp79rezfjP3ne38w+unx1KWXjt7wo2k688OXPL307SvX 155 | Hn7NXx2rPrzaKZsfWfhO9uq7n1i7Of+qz7/h0ivrr/7ZD/3uX7z6kX8wjLe+6ZHb 156 | 771/6h2VB59+9KGfe/wT1737t/fcc/kbKLlr/+9fOPPAwQXy2lfqVx/56cX8tXff 157 | 8YGv77n8317wxe9/4YnbH3zTx//sLQ9cu+/KX2588p8f+vChP33RGx5/197vH3vd 158 | y0d/8XLpBU9NHSGP3vXCd//5qdHz+frTd9/z6PTse5+78J7nPdR+455fedsD73v0 159 | wF2/9vD119Zu/eyvfuOv/708cvrsV95+z3Pe9uT7v+n8+pc+eF/R+eiTdy099dSb 160 | 9flXPPxd7Ykr7v3Kt7546Ycfkz5XeOTuO5/f/uQ7//bdr2z8xzs+81Nvko7/5Oue 161 | /vRj/wU= 162 | =TP+m 163 | -----END PGP MESSAGE----- 164 | -------------------------------------------------------------------------------- /patches/CVE-2022-21658/0002-Fix-CVE-2022-21658-for-UNIX-like.patch: -------------------------------------------------------------------------------- 1 | From a03c7b755b54e09a3e274974a63c8d0ac32254d7 Mon Sep 17 00:00:00 2001 2 | From: Hans Kratz 3 | Date: Mon, 17 Jan 2022 09:45:46 +0100 4 | Subject: [PATCH 2/4] Fix CVE-2022-21658 for UNIX-like 5 | 6 | --- 7 | library/std/src/fs/tests.rs | 70 ++++++++ 8 | library/std/src/sys/unix/fs.rs | 279 +++++++++++++++++++++++++++++-- 9 | library/std/src/sys/unix/weak.rs | 5 +- 10 | 3 files changed, 342 insertions(+), 12 deletions(-) 11 | 12 | diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs 13 | index 9a8f1e44f1f..4d1959258be 100644 14 | --- a/library/std/src/fs/tests.rs 15 | +++ b/library/std/src/fs/tests.rs 16 | @@ -4,8 +4,10 @@ 17 | use crate::io::{ErrorKind, SeekFrom}; 18 | use crate::path::Path; 19 | use crate::str; 20 | +use crate::sync::Arc; 21 | use crate::sys_common::io::test::{tmpdir, TempDir}; 22 | use crate::thread; 23 | +use crate::time::{Duration, Instant}; 24 | 25 | use rand::{rngs::StdRng, RngCore, SeedableRng}; 26 | 27 | @@ -602,6 +604,21 @@ fn recursive_rmdir_of_symlink() { 28 | assert!(canary.exists()); 29 | } 30 | 31 | +#[test] 32 | +fn recursive_rmdir_of_file_fails() { 33 | + // test we do not delete a directly specified file. 34 | + let tmpdir = tmpdir(); 35 | + let canary = tmpdir.join("do_not_delete"); 36 | + check!(check!(File::create(&canary)).write(b"foo")); 37 | + let result = fs::remove_dir_all(&canary); 38 | + #[cfg(unix)] 39 | + error!(result, "Not a directory"); 40 | + #[cfg(windows)] 41 | + error!(result, 267); // ERROR_DIRECTORY - The directory name is invalid. 42 | + assert!(result.is_err()); 43 | + assert!(canary.exists()); 44 | +} 45 | + 46 | #[test] 47 | // only Windows makes a distinction between file and directory symlinks. 48 | #[cfg(windows)] 49 | @@ -621,6 +638,59 @@ fn recursive_rmdir_of_file_symlink() { 50 | } 51 | } 52 | 53 | +#[test] 54 | +#[ignore] // takes too much time 55 | +fn recursive_rmdir_toctou() { 56 | + // Test for time-of-check to time-of-use issues. 57 | + // 58 | + // Scenario: 59 | + // The attacker wants to get directory contents deleted, to which he does not have access. 60 | + // He has a way to get a privileged Rust binary call `std::fs::remove_dir_all()` on a 61 | + // directory he controls, e.g. in his home directory. 62 | + // 63 | + // The POC sets up the `attack_dest/attack_file` which the attacker wants to have deleted. 64 | + // The attacker repeatedly creates a directory and replaces it with a symlink from 65 | + // `victim_del` to `attack_dest` while the victim code calls `std::fs::remove_dir_all()` 66 | + // on `victim_del`. After a few seconds the attack has succeeded and 67 | + // `attack_dest/attack_file` is deleted. 68 | + let tmpdir = tmpdir(); 69 | + let victim_del_path = tmpdir.join("victim_del"); 70 | + let victim_del_path_clone = victim_del_path.clone(); 71 | + 72 | + // setup dest 73 | + let attack_dest_dir = tmpdir.join("attack_dest"); 74 | + let attack_dest_dir = attack_dest_dir.as_path(); 75 | + fs::create_dir(attack_dest_dir).unwrap(); 76 | + let attack_dest_file = tmpdir.join("attack_dest/attack_file"); 77 | + File::create(&attack_dest_file).unwrap(); 78 | + 79 | + let drop_canary_arc = Arc::new(()); 80 | + let drop_canary_weak = Arc::downgrade(&drop_canary_arc); 81 | + 82 | + eprintln!("x: {:?}", &victim_del_path); 83 | + 84 | + // victim just continuously removes `victim_del` 85 | + thread::spawn(move || { 86 | + while drop_canary_weak.upgrade().is_some() { 87 | + let _ = fs::remove_dir_all(&victim_del_path_clone); 88 | + } 89 | + }); 90 | + 91 | + // attacker (could of course be in a separate process) 92 | + let start_time = Instant::now(); 93 | + while Instant::now().duration_since(start_time) < Duration::from_secs(1000) { 94 | + if !attack_dest_file.exists() { 95 | + panic!( 96 | + "Victim deleted symlinked file outside of victim_del. Attack succeeded in {:?}.", 97 | + Instant::now().duration_since(start_time) 98 | + ); 99 | + } 100 | + let _ = fs::create_dir(&victim_del_path); 101 | + let _ = fs::remove_dir(&victim_del_path); 102 | + let _ = symlink_dir(attack_dest_dir, &victim_del_path); 103 | + } 104 | +} 105 | + 106 | #[test] 107 | fn unicode_path_is_dir() { 108 | assert!(Path::new(".").is_dir()); 109 | diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs 110 | index a4fff9b2e64..a150d1a9aac 100644 111 | --- a/library/std/src/sys/unix/fs.rs 112 | +++ b/library/std/src/sys/unix/fs.rs 113 | @@ -64,7 +64,7 @@ 114 | dirent64, fstat64, ftruncate64, lseek64, lstat64, off64_t, open64, readdir64_r, stat64, 115 | }; 116 | 117 | -pub use crate::sys_common::fs::{remove_dir_all, try_exists}; 118 | +pub use crate::sys_common::fs::try_exists; 119 | 120 | pub struct File(FileDesc); 121 | 122 | @@ -228,7 +228,7 @@ pub struct DirEntry { 123 | target_os = "fuchsia", 124 | target_os = "redox" 125 | ))] 126 | - name: Box<[u8]>, 127 | + name: CString, 128 | } 129 | 130 | #[derive(Clone, Debug)] 131 | @@ -455,8 +455,6 @@ impl Iterator for ReadDir { 132 | target_os = "illumos" 133 | ))] 134 | fn next(&mut self) -> Option> { 135 | - use crate::slice; 136 | - 137 | unsafe { 138 | loop { 139 | // Although readdir_r(3) would be a correct function to use here because 140 | @@ -474,14 +472,10 @@ fn next(&mut self) -> Option> { 141 | }; 142 | } 143 | 144 | - let name = (*entry_ptr).d_name.as_ptr(); 145 | - let namelen = libc::strlen(name) as usize; 146 | - 147 | let ret = DirEntry { 148 | entry: *entry_ptr, 149 | - name: slice::from_raw_parts(name as *const u8, namelen as usize) 150 | - .to_owned() 151 | - .into_boxed_slice(), 152 | + // d_name is guaranteed to be null-terminated. 153 | + name: CStr::from_ptr((*entry_ptr).d_name.as_ptr()).to_owned(), 154 | dir: Arc::clone(&self.inner), 155 | }; 156 | if ret.name_bytes() != b"." && ret.name_bytes() != b".." { 157 | @@ -664,7 +658,26 @@ fn name_bytes(&self) -> &[u8] { 158 | target_os = "redox" 159 | ))] 160 | fn name_bytes(&self) -> &[u8] { 161 | - &*self.name 162 | + self.name.as_bytes() 163 | + } 164 | + 165 | + #[cfg(not(any( 166 | + target_os = "solaris", 167 | + target_os = "illumos", 168 | + target_os = "fuchsia", 169 | + target_os = "redox" 170 | + )))] 171 | + fn name_cstr(&self) -> &CStr { 172 | + unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) } 173 | + } 174 | + #[cfg(any( 175 | + target_os = "solaris", 176 | + target_os = "illumos", 177 | + target_os = "fuchsia", 178 | + target_os = "redox" 179 | + ))] 180 | + fn name_cstr(&self) -> &CStr { 181 | + &self.name 182 | } 183 | 184 | pub fn file_name_os_str(&self) -> &OsStr { 185 | @@ -1439,3 +1452,247 @@ pub fn chroot(dir: &Path) -> io::Result<()> { 186 | cvt(unsafe { libc::chroot(dir.as_ptr()) })?; 187 | Ok(()) 188 | } 189 | + 190 | +pub use remove_dir_impl::remove_dir_all; 191 | + 192 | +// Fallback for REDOX 193 | +#[cfg(target_os = "redox")] 194 | +mod remove_dir_impl { 195 | + pub use crate::sys_common::fs::remove_dir_all; 196 | +} 197 | + 198 | +// Dynamically choose implementation Macos x86-64: modern for 10.10+, fallback for older versions 199 | +#[cfg(all(target_os = "macos", target_arch = "x86_64"))] 200 | +mod remove_dir_impl { 201 | + use super::{cstr, lstat, Dir, InnerReadDir, ReadDir}; 202 | + use crate::ffi::CStr; 203 | + use crate::io; 204 | + use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd}; 205 | + use crate::os::unix::prelude::{OwnedFd, RawFd}; 206 | + use crate::path::{Path, PathBuf}; 207 | + use crate::sync::Arc; 208 | + use crate::sys::weak::weak; 209 | + use crate::sys::{cvt, cvt_r}; 210 | + use libc::{c_char, c_int, DIR}; 211 | + 212 | + pub fn openat_nofollow_dironly(parent_fd: Option, p: &CStr) -> io::Result { 213 | + weak!(fn openat(c_int, *const c_char, c_int) -> c_int); 214 | + let fd = cvt_r(|| unsafe { 215 | + openat.get().unwrap()( 216 | + parent_fd.unwrap_or(libc::AT_FDCWD), 217 | + p.as_ptr(), 218 | + libc::O_CLOEXEC | libc::O_RDONLY | libc::O_NOFOLLOW | libc::O_DIRECTORY, 219 | + ) 220 | + })?; 221 | + Ok(unsafe { OwnedFd::from_raw_fd(fd) }) 222 | + } 223 | + 224 | + fn fdreaddir(dir_fd: OwnedFd) -> io::Result<(ReadDir, RawFd)> { 225 | + weak!(fn fdopendir(c_int) -> *mut DIR, "fdopendir$INODE64"); 226 | + let ptr = unsafe { fdopendir.get().unwrap()(dir_fd.as_raw_fd()) }; 227 | + if ptr.is_null() { 228 | + return Err(io::Error::last_os_error()); 229 | + } 230 | + let dirp = Dir(ptr); 231 | + // file descriptor is automatically closed by libc::closedir() now, so give up ownership 232 | + let new_parent_fd = dir_fd.into_raw_fd(); 233 | + // a valid root is not needed because we do not call any functions involving the full path 234 | + // of the DirEntrys. 235 | + let dummy_root = PathBuf::new(); 236 | + Ok(( 237 | + ReadDir { 238 | + inner: Arc::new(InnerReadDir { dirp, root: dummy_root }), 239 | + end_of_stream: false, 240 | + }, 241 | + new_parent_fd, 242 | + )) 243 | + } 244 | + 245 | + fn remove_dir_all_recursive(parent_fd: Option, p: &Path) -> io::Result<()> { 246 | + weak!(fn unlinkat(c_int, *const c_char, c_int) -> c_int); 247 | + 248 | + let pcstr = cstr(p)?; 249 | + 250 | + // entry is expected to be a directory, open as such 251 | + let fd = openat_nofollow_dironly(parent_fd, &pcstr)?; 252 | + 253 | + // open the directory passing ownership of the fd 254 | + let (dir, fd) = fdreaddir(fd)?; 255 | + for child in dir { 256 | + let child = child?; 257 | + match child.entry.d_type { 258 | + libc::DT_DIR => { 259 | + remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?; 260 | + } 261 | + libc::DT_UNKNOWN => { 262 | + match cvt(unsafe { unlinkat.get().unwrap()(fd, child.name_cstr().as_ptr(), 0) }) 263 | + { 264 | + // type unknown - try to unlink 265 | + Err(err) if err.raw_os_error() == Some(libc::EPERM) => { 266 | + // if the file is a directory unlink fails with EPERM 267 | + remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?; 268 | + } 269 | + result => { 270 | + result?; 271 | + } 272 | + } 273 | + } 274 | + _ => { 275 | + // not a directory -> unlink 276 | + cvt(unsafe { unlinkat.get().unwrap()(fd, child.name_cstr().as_ptr(), 0) })?; 277 | + } 278 | + } 279 | + } 280 | + 281 | + // unlink the directory after removing its contents 282 | + cvt(unsafe { 283 | + unlinkat.get().unwrap()( 284 | + parent_fd.unwrap_or(libc::AT_FDCWD), 285 | + pcstr.as_ptr(), 286 | + libc::AT_REMOVEDIR, 287 | + ) 288 | + })?; 289 | + Ok(()) 290 | + } 291 | + 292 | + fn remove_dir_all_modern(p: &Path) -> io::Result<()> { 293 | + // We cannot just call remove_dir_all_recursive() here because that would not delete a passed 294 | + // symlink. No need to worry about races, because remove_dir_all_recursive() does not recurse 295 | + // into symlinks. 296 | + let attr = lstat(p)?; 297 | + if attr.file_type().is_symlink() { 298 | + crate::fs::remove_file(p) 299 | + } else { 300 | + remove_dir_all_recursive(None, p) 301 | + } 302 | + } 303 | + 304 | + pub fn remove_dir_all(p: &Path) -> io::Result<()> { 305 | + weak!(fn openat(c_int, *const c_char, c_int) -> c_int); 306 | + if openat.get().is_some() { 307 | + // openat() is available with macOS 10.10+, just like unlinkat() and fdopendir() 308 | + remove_dir_all_modern(p) 309 | + } else { 310 | + // fall back to classic implementation 311 | + crate::sys_common::fs::remove_dir_all(p) 312 | + } 313 | + } 314 | +} 315 | + 316 | +// Modern implementation using openat(), unlinkat() and fdopendir() 317 | +#[cfg(not(any(all(target_os = "macos", target_arch = "x86_64"), target_os = "redox")))] 318 | +mod remove_dir_impl { 319 | + use super::{cstr, lstat, Dir, InnerReadDir, ReadDir}; 320 | + use crate::ffi::CStr; 321 | + use crate::io; 322 | + use crate::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd}; 323 | + use crate::os::unix::prelude::{OwnedFd, RawFd}; 324 | + use crate::path::{Path, PathBuf}; 325 | + use crate::sync::Arc; 326 | + use crate::sys::{cvt, cvt_r}; 327 | + use libc::{fdopendir, openat, unlinkat}; 328 | + 329 | + pub fn openat_nofollow_dironly(parent_fd: Option, p: &CStr) -> io::Result { 330 | + let fd = cvt_r(|| unsafe { 331 | + openat( 332 | + parent_fd.unwrap_or(libc::AT_FDCWD), 333 | + p.as_ptr(), 334 | + libc::O_CLOEXEC | libc::O_RDONLY | libc::O_NOFOLLOW | libc::O_DIRECTORY, 335 | + ) 336 | + })?; 337 | + Ok(unsafe { OwnedFd::from_raw_fd(fd) }) 338 | + } 339 | + 340 | + fn fdreaddir(dir_fd: OwnedFd) -> io::Result<(ReadDir, RawFd)> { 341 | + let ptr = unsafe { fdopendir(dir_fd.as_raw_fd()) }; 342 | + if ptr.is_null() { 343 | + return Err(io::Error::last_os_error()); 344 | + } 345 | + let dirp = Dir(ptr); 346 | + // file descriptor is automatically closed by libc::closedir() now, so give up ownership 347 | + let new_parent_fd = dir_fd.into_raw_fd(); 348 | + // a valid root is not needed because we do not call any functions involving the full path 349 | + // of the DirEntrys. 350 | + let dummy_root = PathBuf::new(); 351 | + Ok(( 352 | + ReadDir { 353 | + inner: Arc::new(InnerReadDir { dirp, root: dummy_root }), 354 | + #[cfg(not(any( 355 | + target_os = "solaris", 356 | + target_os = "illumos", 357 | + target_os = "fuchsia", 358 | + target_os = "redox", 359 | + )))] 360 | + end_of_stream: false, 361 | + }, 362 | + new_parent_fd, 363 | + )) 364 | + } 365 | + 366 | + fn remove_dir_all_recursive(parent_fd: Option, p: &Path) -> io::Result<()> { 367 | + let pcstr = cstr(p)?; 368 | + 369 | + // entry is expected to be a directory, open as such 370 | + let fd = openat_nofollow_dironly(parent_fd, &pcstr)?; 371 | + 372 | + // open the directory passing ownership of the fd 373 | + let (dir, fd) = fdreaddir(fd)?; 374 | + for child in dir { 375 | + let child = child?; 376 | + let child_is_dir = if cfg!(any( 377 | + target_os = "solaris", 378 | + target_os = "illumos", 379 | + target_os = "haiku", 380 | + target_os = "vxworks" 381 | + )) { 382 | + // no d_type in dirent 383 | + None 384 | + } else { 385 | + match child.entry.d_type { 386 | + libc::DT_UNKNOWN => None, 387 | + libc::DT_DIR => Some(true), 388 | + _ => Some(false), 389 | + } 390 | + }; 391 | + match child_is_dir { 392 | + Some(true) => { 393 | + remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?; 394 | + } 395 | + Some(false) => { 396 | + cvt(unsafe { unlinkat(fd, child.name_cstr().as_ptr(), 0) })?; 397 | + } 398 | + None => match cvt(unsafe { unlinkat(fd, child.name_cstr().as_ptr(), 0) }) { 399 | + // type unknown - try to unlink 400 | + Err(err) 401 | + if err.raw_os_error() == Some(libc::EISDIR) 402 | + || err.raw_os_error() == Some(libc::EPERM) => 403 | + { 404 | + // if the file is a directory unlink fails with EISDIR on Linux and EPERM everyhwere else 405 | + remove_dir_all_recursive(Some(fd), Path::new(&child.file_name()))?; 406 | + } 407 | + result => { 408 | + result?; 409 | + } 410 | + }, 411 | + } 412 | + } 413 | + 414 | + // unlink the directory after removing its contents 415 | + cvt(unsafe { 416 | + unlinkat(parent_fd.unwrap_or(libc::AT_FDCWD), pcstr.as_ptr(), libc::AT_REMOVEDIR) 417 | + })?; 418 | + Ok(()) 419 | + } 420 | + 421 | + pub fn remove_dir_all(p: &Path) -> io::Result<()> { 422 | + // We cannot just call remove_dir_all_recursive() here because that would not delete a passed 423 | + // symlink. No need to worry about races, because remove_dir_all_recursive() does not recurse 424 | + // into symlinks. 425 | + let attr = lstat(p)?; 426 | + if attr.file_type().is_symlink() { 427 | + crate::fs::remove_file(p) 428 | + } else { 429 | + remove_dir_all_recursive(None, p) 430 | + } 431 | + } 432 | +} 433 | diff --git a/library/std/src/sys/unix/weak.rs b/library/std/src/sys/unix/weak.rs 434 | index ba432ec5494..83ff78fa7a2 100644 435 | --- a/library/std/src/sys/unix/weak.rs 436 | +++ b/library/std/src/sys/unix/weak.rs 437 | @@ -28,9 +28,12 @@ 438 | 439 | pub(crate) macro weak { 440 | (fn $name:ident($($t:ty),*) -> $ret:ty) => ( 441 | + weak!(fn $name($($t),*) -> $ret, stringify!($name)); 442 | + ), 443 | + (fn $name:ident($($t:ty),*) -> $ret:ty, $sym:expr) => ( 444 | #[allow(non_upper_case_globals)] 445 | static $name: crate::sys::weak::Weak $ret> = 446 | - crate::sys::weak::Weak::new(concat!(stringify!($name), '\0')); 447 | + crate::sys::weak::Weak::new(concat!($sym, '\0')); 448 | ) 449 | } 450 | 451 | -- 452 | 2.32.0 453 | 454 | -------------------------------------------------------------------------------- /patches/CVE-2022-21658/0002-Fix-CVE-2022-21658-for-UNIX-like.patch.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP MESSAGE----- 2 | 3 | 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 93 | U1/yl9QPbdOlXFUftHMPNK7RGY3h/zetQmE1NU+08RfT5zu+xt4v1Ow52dXjzwe7 94 | q7ecUDRVJZnMvAZS9AJiTMls9Fq20muZcq/VsHqxn9GLrbusaZHSilMSmq7QJVKS 95 | Cv15Kg8URgrZ7HC/qg4Nq9KQlCd9udxgoZDIZDKr2C/R09Ozmj23biWZ/HB6hPTA 96 | Z1+ebN2aIAnEr8DUmcKWn2mwBiSojekA+5Ab0NcUNQWOlrBB2GAX7UYqvZEBewPU 97 | sfgTHUogf/NamGwpWxRcAQWmbcJB19RGl8CmeKVuM59Y3b5psgEQUoR823RZ8Oy8 98 | flbCBBrqKV10ajVqirJkUXG+YpQgjkNt4s1ENGqyu1uoV4RiFIsH4HOz63joko09 99 | wuRYEo58i1xbyGgiE4PSCDHuzMHByZLdJbSoIk0uvjp3caj4Xy0t1Ia/nC1LJQDA 100 | BIBEEvlsfz6bSyRu/lD/qWtOSay54BNdpx7QvnfLmy+NfvwPC/c9+PpDNyZemVn3 101 | 4Ic/JL0qjKxJnHFWc+SBB89a84T52HnrNl6041tP/M6eV5/97q1/9L2jl0+e9vKR 102 | 4mWpd8+vJN9Yf8HhHQ9MPfHAdYVvjf/whnO/8c79M1deMDY/ef4Z377w6Rc+NfCV 103 | XYu3/OzoxbN/fNXRHzx3SGmc/bPqhf/8mfue/+JHnrr905/9g8nJs780f9+Xbxmr 104 | H33s2GVzL12++5JnT3/x62unjt6964bbtZnLnS98fun5c47Miu+c8bHzBh99etfu 105 | yR8/I6XvufrZ9/I/uijx/Re/+Uj3PRde9vR/vPmZdz++60vvba5/9OWv1ree+V// 106 | +vTBR381qf3kp5+Vjoyf8UnzmZGrfnLhOY+fv2bt2HW/+Vt3zp37yavv2vP7z31u 107 | dPcd2rpjmnrsjgeunXro8ezXb65vv135+WnPnH7dKbObP33by6Xry8eq9//3z4c+ 108 | /7U33rn1P9e/demui/5k9r23Hj62/8V/H5hNX63NfaV65v53/+nI4OCd239w1tny 109 | 4zvWzp3+j8PP7//cczf97UNvP7nhr7tTv/uXpzlvnPfURV9+/C3x/sePPJG45dzx 110 | u2ZuMs5ZOzH7wz9/8+Hrlf6777hnx3O/l//YX1z16JlnvrLrH/Y8dtubD21+4W9+ 111 | dPSp184+uO/hV66/6PUbH7zkscE9v/Haa+89cuw755+SeuHXvnvGsV/pFtbuO3Dk 112 | x3//0oU37Drz6kT1r56aXP6z779evXvs289PHLy59PZdj9FPfPPJD//bNx4mx+bu 113 | ffvwjp/+9rabvnYOvfgjX610dd+2996XHjl1+qOZXz+65r2b/+XJv7v3O+tuveq6 114 | DZN3PtP1Pw== 115 | =1cNT 116 | -----END PGP MESSAGE----- 117 | -------------------------------------------------------------------------------- /patches/CVE-2022-21658/0003-Fix-CVE-2022-21658-for-WASI.patch: -------------------------------------------------------------------------------- 1 | From 018592e08474ee48098a6882df83b1eca48066e6 Mon Sep 17 00:00:00 2001 2 | From: Alex Crichton 3 | Date: Tue, 4 Jan 2022 08:44:15 -0800 4 | Subject: [PATCH 3/4] Fix CVE-2022-21658 for WASI 5 | 6 | --- 7 | library/std/src/sys/wasi/fs.rs | 71 ++++++++++++++++++++++++++++++---- 8 | 1 file changed, 63 insertions(+), 8 deletions(-) 9 | 10 | diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs 11 | index 984dda8dc0b..00b9ab3b864 100644 12 | --- a/library/std/src/sys/wasi/fs.rs 13 | +++ b/library/std/src/sys/wasi/fs.rs 14 | @@ -16,7 +16,7 @@ 15 | use crate::sys::unsupported; 16 | use crate::sys_common::{AsInner, FromInner, IntoInner}; 17 | 18 | -pub use crate::sys_common::fs::{remove_dir_all, try_exists}; 19 | +pub use crate::sys_common::fs::try_exists; 20 | 21 | pub struct File { 22 | fd: WasiFd, 23 | @@ -130,6 +130,18 @@ pub fn bits(&self) -> wasi::Filetype { 24 | } 25 | } 26 | 27 | +impl ReadDir { 28 | + fn new(dir: File, root: PathBuf) -> ReadDir { 29 | + ReadDir { 30 | + cookie: Some(0), 31 | + buf: vec![0; 128], 32 | + offset: 0, 33 | + cap: 0, 34 | + inner: Arc::new(ReadDirInner { dir, root }), 35 | + } 36 | + } 37 | +} 38 | + 39 | impl fmt::Debug for ReadDir { 40 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 41 | f.debug_struct("ReadDir").finish_non_exhaustive() 42 | @@ -512,13 +524,7 @@ pub fn readdir(p: &Path) -> io::Result { 43 | opts.directory(true); 44 | opts.read(true); 45 | let dir = File::open(p, &opts)?; 46 | - Ok(ReadDir { 47 | - cookie: Some(0), 48 | - buf: vec![0; 128], 49 | - offset: 0, 50 | - cap: 0, 51 | - inner: Arc::new(ReadDirInner { dir, root: p.to_path_buf() }), 52 | - }) 53 | + Ok(ReadDir::new(dir, p.to_path_buf())) 54 | } 55 | 56 | pub fn unlink(p: &Path) -> io::Result<()> { 57 | @@ -712,3 +718,52 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { 58 | 59 | io::copy(&mut reader, &mut writer) 60 | } 61 | + 62 | +pub fn remove_dir_all(path: &Path) -> io::Result<()> { 63 | + let (parent, path) = open_parent(path)?; 64 | + remove_dir_all_recursive(&parent, &path) 65 | +} 66 | + 67 | +fn remove_dir_all_recursive(parent: &WasiFd, path: &Path) -> io::Result<()> { 68 | + // Open up a file descriptor for the directory itself. Note that we don't 69 | + // follow symlinks here and we specifically open directories. 70 | + // 71 | + // At the root invocation of this function this will correctly handle 72 | + // symlinks passed to the top-level `remove_dir_all`. At the recursive 73 | + // level this will double-check that after the `readdir` call deduced this 74 | + // was a directory it's still a directory by the time we open it up. 75 | + // 76 | + // If the opened file was actually a symlink then the symlink is deleted, 77 | + // not the directory recursively. 78 | + let mut opts = OpenOptions::new(); 79 | + opts.lookup_flags(0); 80 | + opts.directory(true); 81 | + opts.read(true); 82 | + let fd = open_at(parent, path, &opts)?; 83 | + if fd.file_attr()?.file_type().is_symlink() { 84 | + return parent.unlink_file(osstr2str(path.as_ref())?); 85 | + } 86 | + 87 | + // this "root" is only used by `DirEntry::path` which we don't use below so 88 | + // it's ok for this to be a bogus value 89 | + let dummy_root = PathBuf::new(); 90 | + 91 | + // Iterate over all the entries in this directory, and travel recursively if 92 | + // necessary 93 | + for entry in ReadDir::new(fd, dummy_root) { 94 | + let entry = entry?; 95 | + let path = crate::str::from_utf8(&entry.name).map_err(|_| { 96 | + io::Error::new_const(io::ErrorKind::Uncategorized, &"invalid utf-8 file name found") 97 | + })?; 98 | + 99 | + if entry.file_type()?.is_dir() { 100 | + remove_dir_all_recursive(&entry.inner.dir.fd, path.as_ref())?; 101 | + } else { 102 | + entry.inner.dir.fd.unlink_file(path)?; 103 | + } 104 | + } 105 | + 106 | + // Once all this directory's contents are deleted it should be safe to 107 | + // delete the directory tiself. 108 | + parent.remove_directory(osstr2str(path.as_ref())?) 109 | +} 110 | -- 111 | 2.32.0 112 | 113 | -------------------------------------------------------------------------------- /patches/CVE-2022-21658/0003-Fix-CVE-2022-21658-for-WASI.patch.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP MESSAGE----- 2 | 3 | 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 54 | =b4sL 55 | -----END PGP MESSAGE----- 56 | -------------------------------------------------------------------------------- /patches/CVE-2022-21658/0004-Update-std-fs-remove_dir_all-documentation.patch: -------------------------------------------------------------------------------- 1 | From f14f6baaf11b29d86489993a791c368e997911f1 Mon Sep 17 00:00:00 2001 2 | From: Pietro Albini 3 | Date: Wed, 19 Jan 2022 13:14:24 +0100 4 | Subject: [PATCH 4/4] Update std::fs::remove_dir_all documentation 5 | 6 | --- 7 | library/std/src/fs.rs | 12 ++++++++---- 8 | 1 file changed, 8 insertions(+), 4 deletions(-) 9 | 10 | diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs 11 | index a14f1e2ecb2..f7f7a9ba4e4 100644 12 | --- a/library/std/src/fs.rs 13 | +++ b/library/std/src/fs.rs 14 | @@ -2045,13 +2045,17 @@ pub fn remove_dir>(path: P) -> io::Result<()> { 15 | /// 16 | /// # Platform-specific behavior 17 | /// 18 | -/// This function currently corresponds to `opendir`, `lstat`, `rm` and `rmdir` functions on Unix 19 | -/// and the `FindFirstFile`, `GetFileAttributesEx`, `DeleteFile`, and `RemoveDirectory` functions 20 | -/// on Windows. 21 | -/// Note that, this [may change in the future][changes]. 22 | +/// This function currently corresponds to `openat`, `fdopendir`, `unlinkat` and `lstat` functions 23 | +/// on Unix (except for macOS before version 10.10 and REDOX) and the `CreateFileW`, 24 | +/// `GetFileInformationByHandleEx`, `SetFileInformationByHandle`, and `NtOpenFile` functions on 25 | +/// Windows. Note that, this [may change in the future][changes]. 26 | /// 27 | /// [changes]: io#platform-specific-behavior 28 | /// 29 | +/// On macOS before version 10.10 and REDOX this function is not protected against time-of-check to 30 | +/// time-of-use (TOCTOU) race conditions, and should not be used in security-sensitive code on 31 | +/// those platforms. All other platforms are protected. 32 | +/// 33 | /// # Errors 34 | /// 35 | /// See [`fs::remove_file`] and [`fs::remove_dir`]. 36 | -- 37 | 2.32.0 38 | 39 | -------------------------------------------------------------------------------- /patches/CVE-2022-21658/0004-Update-std-fs-remove_dir_all-documentation.patch.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP MESSAGE----- 2 | 3 | owGdVQlsFGUU3gJCnXBKhZYjvHK23c7uznZpu5OytrS0UOnhtk0Lbe3OzvzDjt2d 4 | 2czMlq4UTYpWEEQuQzUISogHAiFWDFch0ihFSEBQkCqGu0VOQ4oFjfGfnW4PA4m6 5 | 2UzevHn/9977vjdv1gwbaCAi7u5rINqdw3ZE7By8yT3TYrHYyBI/x6iIVFSO5BVS 6 | Rj6pBlVxglzFeL0kJ7EBHxJVRhUk0eRnVNbDdMRVZcuSD3jKxie7GYanKLfVzqUm 7 | 21LtdnsSk2Kn2KTkVGS3Y4viKciTRChCfqBSwGKhQ3+wWiwUocHQUCggVZYgw+sW 8 | RAHS/KFbExO6TeeRLEsBhVSCiop8iomVfA4iCxdMQyniEoGyQy4jYjirFagkmrLR 9 | VhsYLZTFQhQF3C8hVqWhvDCjOHMu2My2StC7BdwtTfMKTffvF/r1SxAkSRLgFdwy 10 | IwfN+IxZkVkzr5hkBeqAsoKx+0eGAingBS8CTJG4SKstFQRRQbIGpcQZ4xPBBhzy 11 | Iv2ejCcITuB5IMlFggqM+fFp3I/3E4LIoVpgsAQUsiLWbTWZ+BQ+hbG7GRuyAe4/ 12 | 2WbT6n8SMoHLfiJ6ejqQVottZiKVBEbdSAHs9AfcwIvQS1paIQ0ZihPxaYWM6nE4 13 | 4vCIeLCk8UA6QJBo2omUgFdNi4t3wBICzGZz6AJToNDLqLwk+0jFj1iBF1hwIw9T 14 | I0iyHkZqYcUeQQE+ILIaZ8AGZBlr4w0CK2FL8Usip4AqgUvyIxFX40oEl1fB4mmG 15 | 7HMBI3KaoT3qgVEAQ5WIQq2eQgtRPQhc2ZjSbEFW1GwsogaQg0JmhqrKgjugImVO 16 | rebO0iRE3UGhBM4QHVmCjKdNkoN9UukpcL5SDC4tVky6I1/CI6h6GDURX3GH5T4m 17 | 2D02eGRC5fABNSCjynLdq1SaCON/JUSngef6kBMQvYJYjR/ohetc9SnX2F2uRg/E 18 | oVoW+VXAKoGPYQuKsELYRlCDZEVLT1lMlCWE5JyTVVAW38tlpowYnaNSV6KOGqZz 19 | nqipHnq/Zgfn4hNepPNa9MTnYZ7z1QLcSoj5fmrqCcIU/z92e0ezx0njAZ7i/+eY 20 | kv3HNJS6QPxXBOnl9KiHbVFSwS/jelkVccAsYvDCUEEVfIiUeJL1ILYay6knCXsD 21 | CoK44oLM4oKSeJAZFi8cLLsQIkMnSvFIAS8XAncjwPGc1reC8LgIapBUkKjg8Brt 22 | IId6+FM9EkYO94t5zMD7UMJsyb1OYHB3PQXrMxl+oefgRY1XRy+RRQhBuavPktW2 23 | o6syVGI/vzacWAK8qwirKclqshDEigFJgwwRhGHimNhBpULrys4Ls6K22j7eEf5+ 24 | PTVA+wwZiKdHhj1/dYw07Kv/Ym3FvJjok4fI4RenrWltHuG/NST/Mvf+e6uOT/Kc 25 | 3bNxA512rvVRsIlqQoenpS/clv6c3Jb26FJqY/JnbZvu10Z81dzgbDRXt+2OThhx 26 | beFvMbYp7nEnfzg74d6OWod4eynd9MbylIFXJ8+eUncimV881bB4W2Sn9wR1lrf8 27 | tKc09/wzjWceZK6Vjj3cG+U8v32b8cKPda8eGzd7JN9aldd6egznq38zsN+UdHPz 28 | 5l86z1xaYXq36p0b9irTgdLxo3NfVLNLJnMLKlujEq8OHrXLsX1QJZzjiTtTvxl3 29 | q+W1lPYYad/6tCXfxU4zvk62DQlGVLRtIXZ1ZNiGvs0MPbqludWVfHFFZN2tddvL 30 | DDUPFqxIkP4IzoqLLEvtmrp+Zc63o3OuDfp9Fb/v1AsxjVe/n5sxdv6wGycK91fJ 31 | 136urrxWyczYm7+GO1Ve3Fz7aXp7y9lH+yfNWn57zzjjleczN27trHl94t2Zd+7V 32 | 5xzhxn+4OmZd/roWw3q26/oHr1y8LHQdOHjl1zFltzvfuhV33NkxdNSmKxU76dQK 33 | T1vdqEmRR4I51+WOP1m1acR8U9akpV/fvCwdvjsn+vbSivGFyqEJ8dcNp4ePOLM8 34 | 4f70zxOYgYl5sU0PX15WnXN0g8sR++wna2c0SMvKDA1rsvKGXWLVsV3xY7aU5e1u 35 | n2VdHf2RN6p+wpnc6fO/3GppOLjhUMvCvwE= 36 | =U0QX 37 | -----END PGP MESSAGE----- 38 | -------------------------------------------------------------------------------- /patches/CVE-2022-21658/0005-Fix-compilation-for-a-few-tier-2-targets.patch: -------------------------------------------------------------------------------- 1 | From 36289ea9f6193da52ba1ef9864c7ed4b779aadc1 Mon Sep 17 00:00:00 2001 2 | From: Hans Kratz 3 | Date: Thu, 20 Jan 2022 12:43:54 +0100 4 | Subject: [PATCH] Fix compilation for a few tier 2 targets 5 | 6 | --- 7 | library/std/src/sys/unix/fs.rs | 13 +++++-------- 8 | 1 file changed, 5 insertions(+), 8 deletions(-) 9 | 10 | diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs 11 | index ca7f132a8b3..111639d92b7 100644 12 | --- a/library/std/src/sys/unix/fs.rs 13 | +++ b/library/std/src/sys/unix/fs.rs 14 | @@ -670,12 +670,7 @@ fn name_bytes(&self) -> &[u8] { 15 | fn name_cstr(&self) -> &CStr { 16 | unsafe { CStr::from_ptr(self.entry.d_name.as_ptr()) } 17 | } 18 | - #[cfg(any( 19 | - target_os = "solaris", 20 | - target_os = "illumos", 21 | - target_os = "fuchsia", 22 | - target_os = "redox" 23 | - ))] 24 | + #[cfg(any(target_os = "solaris", target_os = "illumos", target_os = "fuchsia"))] 25 | fn name_cstr(&self) -> &CStr { 26 | &self.name 27 | } 28 | @@ -1633,7 +1628,8 @@ fn fdreaddir(dir_fd: OwnedFd) -> io::Result<(ReadDir, RawFd)> { 29 | target_os = "solaris", 30 | target_os = "illumos", 31 | target_os = "haiku", 32 | - target_os = "vxworks" 33 | + target_os = "vxworks", 34 | + target_os = "fuchsia" 35 | ))] 36 | fn is_dir(_ent: &DirEntry) -> Option { 37 | None 38 | @@ -1643,7 +1639,8 @@ fn is_dir(_ent: &DirEntry) -> Option { 39 | target_os = "solaris", 40 | target_os = "illumos", 41 | target_os = "haiku", 42 | - target_os = "vxworks" 43 | + target_os = "vxworks", 44 | + target_os = "fuchsia" 45 | )))] 46 | fn is_dir(ent: &DirEntry) -> Option { 47 | match ent.entry.d_type { 48 | -- 49 | 2.32.0 50 | 51 | -------------------------------------------------------------------------------- /patches/CVE-2022-21658/0005-Fix-compilation-for-a-few-tier-2-targets.patch.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP MESSAGE----- 2 | 3 | owHVVXtQFHUcB1LTNTLCR0rqT0Tmrru9u917H0gWhqYIdDCSg3D89nYX1rvbvXb3 4 | 5JDURAdTTE3RcEbyMb4SUUcnRTNFGR/TQ4XS8VFSMiiojQrqjBbWLgeGEzdM/dd3 5 | due3v/18H7/P5/daGf5CCBJ691AJctMeviu0ql81odfpdEY0ifGjTs7jZdxQZDgW 6 | pTkehShNFaAiQ/EojoqQz6NEQeOFojMftiwam8RzHqA34RYrBa20CbPqSWjECYhR 7 | tNViMjjNFGkgzGYrhKQTA9M4FqRTXoCZgU5n63gArtNhiJzGBiZDVgBTeSjOAfH5 8 | 0vcE6PXSnI/XSGNKQCZCkbKBjHyfWooBUyArNTgOMNxm0NuMBqDSYTodku4jZlFO 9 | 0Qay0t7KSJycDSROoBsnIHECEEicgMwJ4KCTE4KgKIoAN0PwkC/UCiKpFXinVigU 10 | tD6W8WtpQcML4EOA6YFKNrTTEIABmnFTQBKEzaNINTAChhUoXq4mKFRKNbAAknJT 11 | gT6qRBCSoWmAonmMCKC2l4JELw4Iw5KUxBCaaUyPQwuh12gwDDPpraQVJ8xA0sRk 12 | MMjceq2FSKx6rzdhAkBNZp0aw4FKbs1A+kOzgIUeykEUipSgiBUoN60EaAKIzfJZ 13 | skERAmTrcnIKIt/dJzFd5Lt8ZPOxAqQpUARkwGajpbXh8EohcoSGYkW+UEM65Ewa 14 | KHQASiWYGwifi6ByMzbLSecpIFuoCPRlC0yzgxPAeBAtcG7IM0K0OgjOuN0+Dxcc 15 | p33OfIGBQXGeIjl/dABUKrMR1fOj6nksQYbQc2U5679StQPSyK5dUskzKS0UvTSF 16 | KkzawmpL51TSJE9BkmR4hfQ6aNIGUgtYikwiOzIznM1mpwSfW4xX2CW/iQyvBnZY 17 | IMEJ3QsGEbxn/G/Be8bzIePyBZV7tr+A411CdEDnoLA6CN6laaB2d2UZwSHL4JBW 18 | nQ3ESkzfkZdfhwypXnlDxxMc536OdgrHUp3SGjql1VufSfsfEv5/dfynkP+Ctke+ 19 | YoAU8GzLi4Ve6VSQjjKA4Bo9rtEhyJIwfZ+QUCRk5NAxfTKZM6UPfx4/eLNh+66u 20 | u61vmHxJhSADXun6c/3NQX/O/GyfZ7X68rijWa+mXaiYODDiZHl6bPiMxZaiCvs1 21 | tGp73mP/6Or42UW7j10kt6Q1LChOTpsfUWxZ5Wu+slObU596YF2l6b4z0p6SeX5p 22 | TqK/uPbX1aMpz1a3jzky7TYYVq5an3FkSVSs4Zuw6fo76hsHcht3bHW4r5DDdi84 23 | OLKqdcdHdx71HzPl+sP2mOEw7itNVNw28Y+rG0J3367rc3r4vaSSCE+Z8UFT64Zf 24 | Lt2sWxY6v3To1QfTaoT5xxtXLapxtVJ3U+rbs+0V48Q3BjX+tiI3uvY1r6vNsvbH 25 | MrbyxPnM7+Lj0KNERdi83E1L1xjiFpancKSr5sm5y+SemvqIuDPIgKbT9T81W+pf 26 | oirhe/ll1mjy2xWPtSWnmo+cqc2LyWm5tedg3fd7Xe3HNff7bshKeL3/2/1mNJeJ 27 | e1vXlrsmGccqG6ZHJq9R8Ydj29oHEpGbnQ/52rP7RglFTdvCsqd8zb3oa1k3/RFR 28 | 54z64N3sBuPJ9QXFUzdumof5H5/Ar/7gKr1XGuPY3zRiQesnmxMrLyg+/7RhsXWZ 29 | 9+mSL/qNfv/3c7tWWuI/npk8+8aFk3bn4ouH9rTgVScgkfNkYdLtw+3rmLhJczBj 30 | 3Nqo9EG6NtXyl0d9mbtzFrv0VGNCW3JJ5HKFZfjT/QP6DzlWW73oUmri2X3MkL4D 31 | h1VnbIx5ei1EteVWVPiozJYRg/8C 32 | =qqXx 33 | -----END PGP MESSAGE----- 34 | -------------------------------------------------------------------------------- /patches/CVE-2022-21658/README.md: -------------------------------------------------------------------------------- 1 | # Patches for CVE-2022-21658 2 | 3 | This directory contains the patches for [CVE-2022-21658][cve], to be applied on 4 | top of a Rust 1.58.0 source tarball. 5 | 6 | The patches are released under both the [MIT license][mit] and the [Apache 2.0 7 | license][apache], and signatures from the [Rust Security Response WG's GPG 8 | key][key] are provided. 9 | 10 | [cve]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-21658 11 | [mit]: https://github.com/rust-lang/wg-security-response/blob/master/LICENSE-MIT 12 | [apache]: https://github.com/rust-lang/wg-security-response/blob/master/LICENSE-APACHE 13 | [key]: https://www.rust-lang.org/static/keys/rust-security-team.gpg.ascii 14 | -------------------------------------------------------------------------------- /patches/CVE-2022-36113/0001-CVE-2022-36113-avoid-unpacking-.cargo-ok-from-the-cr.patch: -------------------------------------------------------------------------------- 1 | From c4de262f1f6e813e06981c3d635c009d4f5d7082 Mon Sep 17 00:00:00 2001 2 | From: Josh Triplett 3 | Date: Thu, 18 Aug 2022 17:17:19 +0200 4 | Subject: [PATCH 1/2] CVE-2022-36113: avoid unpacking .cargo-ok from the crate 5 | 6 | --- 7 | src/tools/cargo/src/cargo/sources/registry/mod.rs | 15 ++++++++++----- 8 | 1 file changed, 10 insertions(+), 5 deletions(-) 9 | 10 | diff --git a/src/tools/cargo/src/cargo/sources/registry/mod.rs b/src/tools/cargo/src/cargo/sources/registry/mod.rs 11 | index 413734e10..b28bc4942 100644 12 | --- a/src/tools/cargo/src/cargo/sources/registry/mod.rs 13 | +++ b/src/tools/cargo/src/cargo/sources/registry/mod.rs 14 | @@ -639,6 +639,13 @@ impl<'cfg> RegistrySource<'cfg> { 15 | prefix 16 | ) 17 | } 18 | + // Prevent unpacking the lockfile from the crate itself. 19 | + if entry_path 20 | + .file_name() 21 | + .map_or(false, |p| p == PACKAGE_SOURCE_LOCK) 22 | + { 23 | + continue; 24 | + } 25 | // Unpacking failed 26 | let mut result = entry.unpack_in(parent).map_err(anyhow::Error::from); 27 | if cfg!(windows) && restricted_names::is_windows_reserved_path(&entry_path) { 28 | @@ -654,16 +661,14 @@ impl<'cfg> RegistrySource<'cfg> { 29 | .with_context(|| format!("failed to unpack entry at `{}`", entry_path.display()))?; 30 | } 31 | 32 | - // The lock file is created after unpacking so we overwrite a lock file 33 | - // which may have been extracted from the package. 34 | + // Now that we've finished unpacking, create and write to the lock file to indicate that 35 | + // unpacking was successful. 36 | let mut ok = OpenOptions::new() 37 | - .create(true) 38 | + .create_new(true) 39 | .read(true) 40 | .write(true) 41 | .open(&path) 42 | .with_context(|| format!("failed to open `{}`", path.display()))?; 43 | - 44 | - // Write to the lock file to indicate that unpacking was successful. 45 | write!(ok, "ok")?; 46 | 47 | Ok(unpack_dir.to_path_buf()) 48 | -- 49 | 2.34.1 50 | 51 | -------------------------------------------------------------------------------- /patches/CVE-2022-36113/0001-CVE-2022-36113-avoid-unpacking-.cargo-ok-from-the-cr.patch.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQIzBAABCgAdFiEEV2nIi/XdPRSiNKes77mGCudSDawFAmMhnlYACgkQ77mGCudS 4 | DayUMg//c6nVZ7bzKTzian/LQrM1L1v+vSzl1jw8Pv2b6so5BkvAkhPedKO0Miby 5 | LyVSBytiYANDl+ZCcQ67ONG9t/7ezOzcD6bqG1G/C4KXg5uRaTrJaDmw/5hgGwWG 6 | Zo73UB1lnpjPLLhv2Wo6VV5EC6dCHyO5W1YdjpD7qh3slWFg4Yc9h7/eUewAnzA1 7 | Xj8lNFNCdF8J900oc88oE6f+nODALcMzBPRpqMOweyk5WJzwwnphaaKEBZo0XDKe 8 | PA8S4ZN2McfTtHn3OiAge0n1Aw02Xna2I/J5ulM08igF2+lR3xukX5I8akd1u1bg 9 | K6im9WexISg8ZjpqemW9hstINIcI3aKLlQiIJBrR1C2WeM7Viob6qy3cdCaeSt3R 10 | xT/d2mJV4yuc6Xyw05IjI7bxXg48Tl+tv/ZkebIYrZHioHJDtZW5TwPjt3tLN7Qp 11 | zGxc5BtBPQTaiiuqJNzeP5XVUef59AaHI6LouUa5Jy+bozJ/ZGqu/pU/MPAySGFk 12 | l9mcaCGtV786XEXEsyjrD+/pdVCqtmjBWSMU7r18KUuFsPTylZuhQB5yldC2e0ql 13 | vVYLfobmIGYHvhdfOAS5SaUsucwX8/YizATPzHyNjcIcemGsW4aKThMV/BM9wZWE 14 | 866YggbSFfolUFsQOs5ktiaMk/eY69Qer8bmAYGhYZpjE9I+JQU= 15 | =vA2x 16 | -----END PGP SIGNATURE----- 17 | -------------------------------------------------------------------------------- /patches/CVE-2022-36113/0002-CVE-2022-36113-add-tests.patch: -------------------------------------------------------------------------------- 1 | From 550346bbf2d66eda9164cab65d3c30f3422a0527 Mon Sep 17 00:00:00 2001 2 | From: Weihang Lo 3 | Date: Fri, 26 Aug 2022 01:12:25 +0100 4 | Subject: [PATCH 2/2] CVE-2022-36113: add tests 5 | 6 | --- 7 | src/tools/cargo/crates/cargo-test-support/src/registry.rs | 40 ++++++++++++++++++---- 8 | src/tools/cargo/tests/testsuite/registry.rs | 41 +++++++++++++++++++++++ 9 | 2 files changed, 74 insertions(+), 7 deletions(-) 10 | 11 | diff --git a/src/tools/cargo/crates/cargo-test-support/src/registry.rs b/src/tools/cargo/crates/cargo-test-support/src/registry.rs 12 | index 5a0a4c582..667e3edd7 100644 13 | --- a/src/tools/cargo/crates/cargo-test-support/src/registry.rs 14 | +++ b/src/tools/cargo/crates/cargo-test-support/src/registry.rs 15 | @@ -403,10 +403,17 @@ pub struct Dependency { 16 | optional: bool, 17 | } 18 | 19 | +/// Entry with data that corresponds to [`tar::EntryType`]. 20 | +#[non_exhaustive] 21 | +enum EntryData { 22 | + Regular(String), 23 | + Symlink(PathBuf), 24 | +} 25 | + 26 | /// A file to be created in a package. 27 | struct PackageFile { 28 | path: String, 29 | - contents: String, 30 | + contents: EntryData, 31 | /// The Unix mode for the file. Note that when extracted on Windows, this 32 | /// is mostly ignored since it doesn't have the same style of permissions. 33 | mode: u32, 34 | @@ -780,13 +787,24 @@ impl Package { 35 | pub fn file_with_mode(&mut self, path: &str, mode: u32, contents: &str) -> &mut Package { 36 | self.files.push(PackageFile { 37 | path: path.to_string(), 38 | - contents: contents.to_string(), 39 | + contents: EntryData::Regular(contents.into()), 40 | mode, 41 | extra: false, 42 | }); 43 | self 44 | } 45 | 46 | + /// Adds a symlink to a path to the package. 47 | + pub fn symlink(&mut self, dst: &str, src: &str) -> &mut Package { 48 | + self.files.push(PackageFile { 49 | + path: dst.to_string(), 50 | + contents: EntryData::Symlink(src.into()), 51 | + mode: DEFAULT_MODE, 52 | + extra: false, 53 | + }); 54 | + self 55 | + } 56 | + 57 | /// Adds an "extra" file that is not rooted within the package. 58 | /// 59 | /// Normal files are automatically placed within a directory named 60 | @@ -795,7 +813,7 @@ impl Package { 61 | pub fn extra_file(&mut self, path: &str, contents: &str) -> &mut Package { 62 | self.files.push(PackageFile { 63 | path: path.to_string(), 64 | - contents: contents.to_string(), 65 | + contents: EntryData::Regular(contents.to_string()), 66 | mode: DEFAULT_MODE, 67 | extra: true, 68 | }); 69 | @@ -1033,7 +1051,7 @@ impl Package { 70 | self.append_manifest(&mut a); 71 | } 72 | if self.files.is_empty() { 73 | - self.append(&mut a, "src/lib.rs", DEFAULT_MODE, ""); 74 | + self.append(&mut a, "src/lib.rs", DEFAULT_MODE, &EntryData::Regular("".into())); 75 | } else { 76 | for PackageFile { 77 | path, 78 | @@ -1107,10 +1125,10 @@ impl Package { 79 | manifest.push_str("[lib]\nproc-macro = true\n"); 80 | } 81 | 82 | - self.append(ar, "Cargo.toml", DEFAULT_MODE, &manifest); 83 | + self.append(ar, "Cargo.toml", DEFAULT_MODE, &EntryData::Regular(manifest.into())); 84 | } 85 | 86 | - fn append(&self, ar: &mut Builder, file: &str, mode: u32, contents: &str) { 87 | + fn append(&self, ar: &mut Builder, file: &str, mode: u32, contents: &EntryData) { 88 | self.append_raw( 89 | ar, 90 | &format!("{}-{}/{}", self.name, self.vers, file), 91 | @@ -1119,8 +1137,16 @@ impl Package { 92 | ); 93 | } 94 | 95 | - fn append_raw(&self, ar: &mut Builder, path: &str, mode: u32, contents: &str) { 96 | + fn append_raw(&self, ar: &mut Builder, path: &str, mode: u32, contents: &EntryData) { 97 | let mut header = Header::new_ustar(); 98 | + let contents = match contents { 99 | + EntryData::Regular(contents) => contents.as_str(), 100 | + EntryData::Symlink(src) => { 101 | + header.set_entry_type(tar::EntryType::Symlink); 102 | + t!(header.set_link_name(src)); 103 | + "" // Symlink has no contents. 104 | + } 105 | + }; 106 | header.set_size(contents.len() as u64); 107 | t!(header.set_path(path)); 108 | header.set_mode(mode); 109 | diff --git a/src/tools/cargo/tests/testsuite/registry.rs b/src/tools/cargo/tests/testsuite/registry.rs 110 | index 3e9ea5428..ee6f5af0c 100644 111 | --- a/src/tools/cargo/tests/testsuite/registry.rs 112 | +++ b/src/tools/cargo/tests/testsuite/registry.rs 113 | @@ -2582,6 +2582,47 @@ fn package_lock_inside_package_is_overwritten() { 114 | assert_eq!(ok.metadata().unwrap().len(), 2); 115 | } 116 | 117 | +#[cargo_test] 118 | +fn package_lock_as_a_symlink_inside_package_is_overwritten() { 119 | + let registry = registry::init(); 120 | + let p = project() 121 | + .file( 122 | + "Cargo.toml", 123 | + r#" 124 | + [project] 125 | + name = "foo" 126 | + version = "0.0.1" 127 | + authors = [] 128 | + 129 | + [dependencies] 130 | + bar = ">= 0.0.0" 131 | + "#, 132 | + ) 133 | + .file("src/main.rs", "fn main() {}") 134 | + .build(); 135 | + 136 | + Package::new("bar", "0.0.1") 137 | + .file("src/lib.rs", "pub fn f() {}") 138 | + .symlink(".cargo-ok", "src/lib.rs") 139 | + .publish(); 140 | + 141 | + p.cargo("build").run(); 142 | + 143 | + let id = SourceId::for_registry(registry.index_url()).unwrap(); 144 | + let hash = cargo::util::hex::short_hash(&id); 145 | + let pkg_root = cargo_home() 146 | + .join("registry") 147 | + .join("src") 148 | + .join(format!("-{}", hash)) 149 | + .join("bar-0.0.1"); 150 | + let ok = pkg_root.join(".cargo-ok"); 151 | + let librs = pkg_root.join("src/lib.rs"); 152 | + 153 | + // Is correctly overwritten and doesn't affect the file linked to 154 | + assert_eq!(ok.metadata().unwrap().len(), 2); 155 | + assert_eq!(fs::read_to_string(librs).unwrap(), "pub fn f() {}"); 156 | +} 157 | + 158 | #[cargo_test] 159 | fn ignores_unknown_index_version_http() { 160 | let _server = setup_http(); 161 | -- 162 | 2.34.1 163 | 164 | -------------------------------------------------------------------------------- /patches/CVE-2022-36113/0002-CVE-2022-36113-add-tests.patch.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQIzBAABCgAdFiEEV2nIi/XdPRSiNKes77mGCudSDawFAmMhnnwACgkQ77mGCudS 4 | DaxEnw//cE71nlPFdfCU+pTca1uQQnXgsE41AXBLNFAjizqo694I0TG3HTnkqVvT 5 | o02JmrnZFYYpNE4kAHCvYeMrnPu8UFH5EZpLe+Tukjt4un9bbIW59ys0Q8HJXSjD 6 | /yG9eIE3Pehbe1aa0fR7Iq6NGbndfF/FP7elozKc/MBBMzBKoIlBB2mO6SJblb1X 7 | 71C4KwiEO9lHWaeGgK1tQs+cpS43/68/EgHbdpQ+wMeKwTb95a+O/653+IshuPie 8 | 9n/1jSTMYU3xmGcXlPgXiEXgYjOmtZzKlhK97BFT5GhyWnzvJagre4RxIndxBbMe 9 | fk//wOmOKxpNOUll+cL9L5uhEDla7btrOBQ+/bZ1tHnR7tC617E1Ika9A9awatvM 10 | cTvLHOYcBNUT8nOv702UXfi8kp/CNEM0H8qGAdvwavqkUTmiwtQxLn3meIvny3HW 11 | IuBsuL+qnGgYbD9rpNWf2BmeCW7jxqBNT7/j0ROiU6D6SdtzvqHoCUm+Ib/tAOp2 12 | km3nIi/NLeHGyw0L4sAR90S+aCCRGxEfTdbl3nzUIEgyErryodo+3V+NAK0FOOwk 13 | Rj32OJyHfOFKr8kbs9AzR1HTtagDs0K/BP7Yp1s2qeujx7iiytMJNREN0kdevbFz 14 | Y1Ti2D6bLummlV/lQp7TwjDMxsG+pTBafZSOYZ16bcGrvB57yO4= 15 | =wqXE 16 | -----END PGP SIGNATURE----- 17 | -------------------------------------------------------------------------------- /patches/CVE-2022-36113/README.md: -------------------------------------------------------------------------------- 1 | # Patches for CVE-2022-36113 2 | 3 | This directory contains the patches for [CVE-2022-36113][cve], to be applied on 4 | top of a Rust 1.63.0 source tarball. 5 | 6 | The patches are released under both the [MIT license][mit] and the [Apache 2.0 7 | license][apache], and signatures from the [Rust Security Response WG's GPG 8 | key][key] are provided. 9 | 10 | [cve]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-36113 11 | [mit]: https://github.com/rust-lang/wg-security-response/blob/master/LICENSE-MIT 12 | [apache]: https://github.com/rust-lang/wg-security-response/blob/master/LICENSE-APACHE 13 | [key]: https://www.rust-lang.org/static/keys/rust-security-team.gpg.ascii 14 | -------------------------------------------------------------------------------- /patches/CVE-2022-36114/0001-CVE-2022-36114-limit-the-maximum-unpacked-size-of-a-.patch: -------------------------------------------------------------------------------- 1 | From 886efa25746cc4bf397442adebd43d2159bd09d2 Mon Sep 17 00:00:00 2001 2 | From: Josh Triplett 3 | Date: Thu, 18 Aug 2022 17:45:45 +0200 4 | Subject: [PATCH 1/2] CVE-2022-36114: limit the maximum unpacked size of a 5 | crate to 512MB 6 | 7 | This gives users of custom registries the same protections, using the 8 | same size limit that crates.io uses. 9 | 10 | `LimitErrorReader` code copied from crates.io. 11 | --- 12 | src/tools/cargo/src/cargo/sources/registry/mod.rs | 6 +++++- 13 | src/tools/cargo/src/cargo/util/io.rs | 26 ++++++++++++++++++++++++++ 14 | src/tools/cargo/src/cargo/util/mod.rs | 2 ++ 15 | 3 files changed, 33 insertions(+), 1 deletion(-) 16 | create mode 100644 src/cargo/util/io.rs 17 | 18 | diff --git a/src/tools/cargo/src/cargo/sources/registry/mod.rs b/src/tools/cargo/src/cargo/sources/registry/mod.rs 19 | index b28bc4942..b1e246968 100644 20 | --- a/src/tools/cargo/src/cargo/sources/registry/mod.rs 21 | +++ b/src/tools/cargo/src/cargo/sources/registry/mod.rs 22 | @@ -182,7 +182,9 @@ use crate::util::hex; 23 | use crate::util::interning::InternedString; 24 | use crate::util::into_url::IntoUrl; 25 | use crate::util::network::PollExt; 26 | -use crate::util::{restricted_names, CargoResult, Config, Filesystem, OptVersionReq}; 27 | +use crate::util::{ 28 | + restricted_names, CargoResult, Config, Filesystem, LimitErrorReader, OptVersionReq, 29 | +}; 30 | 31 | const PACKAGE_SOURCE_LOCK: &str = ".cargo-ok"; 32 | pub const CRATES_IO_INDEX: &str = "https://github.com/rust-lang/crates.io-index"; 33 | @@ -194,6 +196,7 @@ const VERSION_TEMPLATE: &str = "{version}"; 34 | const PREFIX_TEMPLATE: &str = "{prefix}"; 35 | const LOWER_PREFIX_TEMPLATE: &str = "{lowerprefix}"; 36 | const CHECKSUM_TEMPLATE: &str = "{sha256-checksum}"; 37 | +const MAX_UNPACK_SIZE: u64 = 512 * 1024 * 1024; 38 | 39 | /// A "source" for a local (see `local::LocalRegistry`) or remote (see 40 | /// `remote::RemoteRegistry`) registry. 41 | @@ -615,6 +618,7 @@ impl<'cfg> RegistrySource<'cfg> { 42 | } 43 | } 44 | let gz = GzDecoder::new(tarball); 45 | + let gz = LimitErrorReader::new(gz, MAX_UNPACK_SIZE); 46 | let mut tar = Archive::new(gz); 47 | let prefix = unpack_dir.file_name().unwrap(); 48 | let parent = unpack_dir.parent().unwrap(); 49 | diff --git a/src/tools/cargo/src/cargo/util/io.rs b/src/tools/cargo/src/cargo/util/io.rs 50 | new file mode 100644 51 | index 000000000..cc617954e 52 | --- /dev/null 53 | +++ b/src/tools/cargo/src/cargo/util/io.rs 54 | @@ -0,0 +1,26 @@ 55 | +use std::io::{self, Read, Take}; 56 | + 57 | +#[derive(Debug)] 58 | +pub struct LimitErrorReader { 59 | + inner: Take, 60 | +} 61 | + 62 | +impl LimitErrorReader { 63 | + pub fn new(r: R, limit: u64) -> LimitErrorReader { 64 | + LimitErrorReader { 65 | + inner: r.take(limit), 66 | + } 67 | + } 68 | +} 69 | + 70 | +impl Read for LimitErrorReader { 71 | + fn read(&mut self, buf: &mut [u8]) -> io::Result { 72 | + match self.inner.read(buf) { 73 | + Ok(0) if self.inner.limit() == 0 => Err(io::Error::new( 74 | + io::ErrorKind::Other, 75 | + "maximum limit reached when reading", 76 | + )), 77 | + e => e, 78 | + } 79 | + } 80 | +} 81 | diff --git a/src/tools/cargo/src/cargo/util/mod.rs b/src/tools/cargo/src/cargo/util/mod.rs 82 | index 4b8604f92..dd695fbff 100644 83 | --- a/src/tools/cargo/src/cargo/util/mod.rs 84 | +++ b/src/tools/cargo/src/cargo/util/mod.rs 85 | @@ -14,6 +14,7 @@ pub use self::hasher::StableHasher; 86 | pub use self::hex::{hash_u64, short_hash, to_hex}; 87 | pub use self::into_url::IntoUrl; 88 | pub use self::into_url_with_base::IntoUrlWithBase; 89 | +pub(crate) use self::io::LimitErrorReader; 90 | pub use self::lev_distance::{closest, closest_msg, lev_distance}; 91 | pub use self::lockserver::{LockServer, LockServerClient, LockServerStarted}; 92 | pub use self::progress::{Progress, ProgressStyle}; 93 | @@ -44,6 +45,7 @@ pub mod important_paths; 94 | pub mod interning; 95 | pub mod into_url; 96 | mod into_url_with_base; 97 | +mod io; 98 | pub mod job; 99 | pub mod lev_distance; 100 | mod lockserver; 101 | -- 102 | 2.34.1 103 | 104 | -------------------------------------------------------------------------------- /patches/CVE-2022-36114/0001-CVE-2022-36114-limit-the-maximum-unpacked-size-of-a-.patch.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQIzBAABCgAdFiEEV2nIi/XdPRSiNKes77mGCudSDawFAmMhnu0ACgkQ77mGCudS 4 | DazTTBAAqUCTlWELw3ftXyg+F9BG4eAoBXktnyoI4a7SPKZ6xShkRDT8vrLINHcR 5 | U2r1UpCvmYZEWhJC9IeTDRoW7AVCHjctH9F3tetJSb3q9hoIXE/FF0egVwpZDd4+ 6 | wW/R+VtbVQYAqUNq0mT0Hl1ACGLuKKVhx5JCFRf0BsH2C5AMoNrBxLHXwgk0BkpE 7 | ueFKGX+8O76mVI6gVtpW4/0OOuLSJiuu9qj1GmtTlD4SHFnHOnU+ilpufHi0uCNA 8 | Tbe6+nHFORASf9B3Mx7pINVwyhDrMV4kx6cfGaiKGnEwH2HzSxJPKoQDzHHvvQkd 9 | 7/9Aq9x5gmkqEGrTI83ynUwz+kVyEdNyacbf72YkF3s9VRWALGs4nmbG/MfkfRwd 10 | 6OF0kI5J19usAtGZFY3dLtuDOK7koryJTZzX8Qhlk6Y1S/CCOZGBFJs8qUpyBBrd 11 | tX0MeuDf+ihcOnIn60q6A3EcEBaxQPW+zSgIajc2/AJS29EzjvKz7UF1ncyt60Ce 12 | B7A6MwtRbRsdm2gqRcK0JvDSOSU4u1Q/3LRg1ZyNOUsTV0hMtFMJigOVFdkadte7 13 | 4LygiK4YDF0g61j6WjMR7WNqBpMXAs2s4LHm/Jze+yXlljAJ7b5V6RTYdDb19Eqs 14 | okwf32khTjYxoyfs70uNyKpZDAj7/DlvWv7BwTmJptE8AC/I3yw= 15 | =L8s6 16 | -----END PGP SIGNATURE----- 17 | -------------------------------------------------------------------------------- /patches/CVE-2022-36114/0002-CVE-2022-36114-add-tests.patch: -------------------------------------------------------------------------------- 1 | From be8c68ce8dcb8373835422ee2a8ee147de4f563e Mon Sep 17 00:00:00 2001 2 | From: Weihang Lo 3 | Date: Sun, 21 Aug 2022 11:21:41 +0100 4 | Subject: [PATCH 2/2] CVE-2022-36114: add tests 5 | 6 | --- 7 | src/tools/cargo/src/cargo/sources/registry/mod.rs | 16 +++++++++++- 8 | src/tools/cargo/src/cargo/util/io.rs | 25 ++++++++++++++++++ 9 | src/tools/cargo/tests/testsuite/registry.rs | 42 +++++++++++++++++++++++++++++++ 10 | 3 files changed, 82 insertions(+), 1 deletion(-) 11 | 12 | diff --git a/src/tools/cargo/src/cargo/sources/registry/mod.rs b/src/tools/cargo/src/cargo/sources/registry/mod.rs 13 | index b1e246968..51065e69c 100644 14 | --- a/src/tools/cargo/src/cargo/sources/registry/mod.rs 15 | +++ b/src/tools/cargo/src/cargo/sources/registry/mod.rs 16 | @@ -618,7 +618,7 @@ impl<'cfg> RegistrySource<'cfg> { 17 | } 18 | } 19 | let gz = GzDecoder::new(tarball); 20 | - let gz = LimitErrorReader::new(gz, MAX_UNPACK_SIZE); 21 | + let gz = LimitErrorReader::new(gz, max_unpack_size()); 22 | let mut tar = Archive::new(gz); 23 | let prefix = unpack_dir.file_name().unwrap(); 24 | let parent = unpack_dir.parent().unwrap(); 25 | @@ -840,6 +840,20 @@ impl<'cfg> Source for RegistrySource<'cfg> { 26 | } 27 | } 28 | 29 | +/// For integration test only. 30 | +#[inline] 31 | +fn max_unpack_size() -> u64 { 32 | + const VAR: &str = "__CARGO_TEST_MAX_UNPACK_SIZE"; 33 | + if cfg!(debug_assertions) && std::env::var(VAR).is_ok() { 34 | + std::env::var(VAR) 35 | + .unwrap() 36 | + .parse() 37 | + .expect("a max unpack size in bytes") 38 | + } else { 39 | + MAX_UNPACK_SIZE 40 | + } 41 | +} 42 | + 43 | fn make_dep_prefix(name: &str) -> String { 44 | match name.len() { 45 | 1 => String::from("1"), 46 | diff --git a/src/tools/cargo/src/cargo/util/io.rs b/src/tools/cargo/src/cargo/util/io.rs 47 | index cc617954e..60f3ffe05 100644 48 | --- a/src/tools/cargo/src/cargo/util/io.rs 49 | +++ b/src/tools/cargo/src/cargo/util/io.rs 50 | @@ -24,3 +24,28 @@ impl Read for LimitErrorReader { 51 | } 52 | } 53 | } 54 | + 55 | +#[cfg(test)] 56 | +mod tests { 57 | + use super::LimitErrorReader; 58 | + 59 | + use std::io::Read; 60 | + 61 | + #[test] 62 | + fn under_the_limit() { 63 | + let buf = &[1; 7][..]; 64 | + let mut r = LimitErrorReader::new(buf, 8); 65 | + let mut out = Vec::new(); 66 | + assert!(matches!(r.read_to_end(&mut out), Ok(7))); 67 | + assert_eq!(buf, out.as_slice()); 68 | + } 69 | + 70 | + #[test] 71 | + #[should_panic = "maximum limit reached when reading"] 72 | + fn over_the_limit() { 73 | + let buf = &[1; 8][..]; 74 | + let mut r = LimitErrorReader::new(buf, 8); 75 | + let mut out = Vec::new(); 76 | + r.read_to_end(&mut out).unwrap(); 77 | + } 78 | +} 79 | diff --git a/src/tools/cargo/tests/testsuite/registry.rs b/src/tools/cargo/tests/testsuite/registry.rs 80 | index ee6f5af0c..94068ae73 100644 81 | --- a/src/tools/cargo/tests/testsuite/registry.rs 82 | +++ b/src/tools/cargo/tests/testsuite/registry.rs 83 | @@ -2696,3 +2696,45 @@ fn http_requires_trailing_slash() { 84 | .with_stderr("[ERROR] registry url must end in a slash `/`: sparse+https://index.crates.io") 85 | .run() 86 | } 87 | + 88 | +#[cargo_test] 89 | +fn reach_max_unpack_size() { 90 | + let p = project() 91 | + .file( 92 | + "Cargo.toml", 93 | + r#" 94 | + [project] 95 | + name = "foo" 96 | + version = "0.0.1" 97 | + 98 | + [dependencies] 99 | + bar = ">= 0.0.0" 100 | + "#, 101 | + ) 102 | + .file("src/main.rs", "fn main() {}") 103 | + .build(); 104 | + 105 | + Package::new("bar", "0.0.1").publish(); 106 | + 107 | + p.cargo("build") 108 | + .env("__CARGO_TEST_MAX_UNPACK_SIZE", "8") // hit 8 bytes limit and boom! 109 | + .with_status(101) 110 | + .with_stderr( 111 | + "\ 112 | +[UPDATING] `dummy-registry` index 113 | +[DOWNLOADING] crates ... 114 | +[DOWNLOADED] bar v0.0.1 (registry `dummy-registry`) 115 | +[ERROR] failed to download replaced source registry `crates-io` 116 | + 117 | +Caused by: 118 | + failed to unpack package `bar v0.0.1 (registry `dummy-registry`)` 119 | + 120 | +Caused by: 121 | + failed to iterate over archive 122 | + 123 | +Caused by: 124 | + maximum limit reached when reading 125 | +", 126 | + ) 127 | + .run(); 128 | +} 129 | -- 130 | 2.34.1 131 | 132 | -------------------------------------------------------------------------------- /patches/CVE-2022-36114/0002-CVE-2022-36114-add-tests.patch.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQIzBAABCgAdFiEEV2nIi/XdPRSiNKes77mGCudSDawFAmMhnvsACgkQ77mGCudS 4 | DayHkQ/8DcKiJ3tXNPk2A8IIqvdxEbHIJkd10J0TNNwij2+2Twi9CWtJ1eKCydmL 5 | 2f5Riki/4+VBM2Wio3mBqbzoJT474GMypfU4feptA5VR/qyUohBalDVoRww1C6I0 6 | 31i2eZZRCjhFYNTkmPcTUapW8TwzBYDF9k3zzw56gVw1ery6vFCQCuovvHquryUa 7 | 0JPgQqCWL6otVPL6BpD6OfIShoObZOm3Df263h/h+76cLvodGOw/a+PXdvsbi78g 8 | HeEf8GVmu7nU8dneMnGwZkN1hNxK5LSgNWQHY1bfDTSq039UU8Aq2opDoXwWXdzG 9 | Zo1oVj71PIlMUGawYAQykfHpmWva6kspigsHnDwknUthdQ5ZJgU86HwmE6GMiE+F 10 | GeZAlPFxooyxU85tC46eM/IWxof1pv69C5eupIcW1AMcgJCNzKCpFFEOwOnLmBcT 11 | /MRZObOSeGlj4rkH2jkoSaIpQoqbsEw01fcKDJGdX9IdrGXhpSaqmc3XipZm9kR1 12 | vETvl4coDB96UJBpoI9UH/238MyOvEAt1d1PdjQ0GiPEx1USSpp4X234AVyzv6yj 13 | Q1FN1lbTfWu1q9ROK3yEoxaRphuuA/JhwXuqqzGbj1ljMeGDeA0F9wRDdSvUYFUf 14 | xUJ/DOxDKedkkwhbHvxIz6BGe3wRB7rWTyxu+M376ZDHTjH1Z8g= 15 | =Ag0n 16 | -----END PGP SIGNATURE----- 17 | -------------------------------------------------------------------------------- /patches/CVE-2022-36114/README.md: -------------------------------------------------------------------------------- 1 | # Patches for CVE-2022-36114 2 | 3 | This directory contains the patches for [CVE-2022-36114][cve], to be applied on 4 | top of a Rust 1.63.0 source tarball. 5 | 6 | The patches are released under both the [MIT license][mit] and the [Apache 2.0 7 | license][apache], and signatures from the [Rust Security Response WG's GPG 8 | key][key] are provided. 9 | 10 | [cve]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-36114 11 | [mit]: https://github.com/rust-lang/wg-security-response/blob/master/LICENSE-MIT 12 | [apache]: https://github.com/rust-lang/wg-security-response/blob/master/LICENSE-APACHE 13 | [key]: https://www.rust-lang.org/static/keys/rust-security-team.gpg.ascii 14 | -------------------------------------------------------------------------------- /patches/CVE-2022-46176/0001-add-crate-dependencies.patch.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQIzBAABCgAdFiEEV2nIi/XdPRSiNKes77mGCudSDawFAmO9PYgACgkQ77mGCudS 4 | Day8Zw/+O1x55umvztufbd+ecAMlY313j9NQSNm7GtYjg0vvuO4FEje7H10VCjn9 5 | r5ZLzqBj7hYuDr3+x4mBs+AOAkeC5hv80/5+mz3SqlKRRoO+OZq+NmzI1vTEtoUv 6 | Cak7JAmI7EoGdtO+VAAhcLv/gqpAhLgUjzPwxPtOS50TYNBjFGCUVj50HPCaTvZ+ 7 | BDNYUA/rpOzati5w6XIPwurldfkvFBwK/ZrpFpLfcVJEa9XaQINGM0Zrvkq8HTB/ 8 | STW5rvtTzAqYq0pc/tyfCcSzYLIHJHwi9qnP/83SHekBrHiYuoz5O49bnxPLXLRw 9 | D/ZEOL5zpjIqIJ+L3KTuBR6p826at5XcVDS1vPPV+3cFP3Rm2Pv1kFTEmLQVvCUu 10 | sGusts1FUy68w4sUuGxICqVnGHkyceAQ5OC/rv8IFRFp2acp3BkaCPQ1i1QIkc+s 11 | 8VTT8/WbdLgghbA1ypB/ynoCdI+i1AkjNYYGb3jzcdyUEG+cWIlsVh83vuEsVsXC 12 | orqRPJk7XNEGNElodLLt45Ty++VbQesNWe02eMWDgKalnrOSyYDJGGEfGjDqIemG 13 | Pujo5KVdpe2HT1+0XFEOfYPiaiT97vZqOxgEEhC3RtwShQzum8x+xc5YAIfJXDV6 14 | KrelelfdMy0HeOtvXPC9OVZgAml+AhuFrS8X7LyJgKQjPg3if/M= 15 | =uUaF 16 | -----END PGP SIGNATURE----- 17 | -------------------------------------------------------------------------------- /patches/CVE-2022-46176/0002-add-required-APIs-to-libgit2-sys.patch: -------------------------------------------------------------------------------- 1 | From f385f25fabb3a1f5f3fa644c95dadefd29bd3a1a Mon Sep 17 00:00:00 2001 2 | From: Eric Huss 3 | Date: Sun, 8 Jan 2023 18:42:44 +0100 4 | Subject: [PATCH 2/6] add required APIs to libgit2-sys 5 | 6 | --- 7 | cve-2022-46176-deps/libgit2-sys-0.14.0+1.5.0/lib.rs | 4 ++++ 8 | 1 file changed, 4 insertions(+) 9 | 10 | diff --git a/cve-2022-46176-deps/libgit2-sys-0.14.0+1.5.0/lib.rs b/cve-2022-46176-deps/libgit2-sys-0.14.0+1.5.0/lib.rs 11 | index a113a2952..51e8d7968 100644 12 | --- a/cve-2022-46176-deps/libgit2-sys-0.14.0+1.5.0/lib.rs 13 | +++ b/cve-2022-46176-deps/libgit2-sys-0.14.0+1.5.0/lib.rs 14 | @@ -489,6 +489,10 @@ git_enum! { 15 | GIT_CERT_SSH_RAW_TYPE_UNKNOWN = 0, 16 | GIT_CERT_SSH_RAW_TYPE_RSA = 1, 17 | GIT_CERT_SSH_RAW_TYPE_DSS = 2, 18 | + GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_256 = 3, 19 | + GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_384 = 4, 20 | + GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_521 = 5, 21 | + GIT_CERT_SSH_RAW_TYPE_KEY_ED25519 = 6, 22 | } 23 | } 24 | 25 | -- 26 | 2.34.1 27 | 28 | -------------------------------------------------------------------------------- /patches/CVE-2022-46176/0002-add-required-APIs-to-libgit2-sys.patch.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQIzBAABCgAdFiEEV2nIi/XdPRSiNKes77mGCudSDawFAmO9Pf8ACgkQ77mGCudS 4 | DawVHRAAi4gO9k5QEvcs8DYm6ObQ51e6o8Qi5vqojUQoGDee4boELVvHouxdrC5g 5 | T0pWOr6Z4u017WXEzsNh41RDcAYAZjuB7y9D8mjCTDcxLl8Orsmreqy7BDuzGGHG 6 | VX54Y2B0vbRayiabOBsavZkzOZM50ak+00Tk247CTpICxQkZc9tyOIzK8IQZAfW/ 7 | aMqv19hqgKj0ISVe3/bqvt3LN8tD5Tt4tZGv5ZzwQE69XdEBqSuFs0q81vhY1jqO 8 | 5xJV3Edd6ZKrd7U9z/RKBlhtA7PRDcRTS+LCMSYdxZgEEd7vpeqWohw++I/pN+XU 9 | Dy+NFC+cKiyIbwHsOHLEE3HSsgMGHdPQy147NJhZlaJXDCqz3j4BM6hVrrUYnE78 10 | fQD2wvtXbxFP6nSE/I1nCbMMXFcNiFtb+UEuPloEZGkeC5gcFleEBF292zy7SuvI 11 | pzKtBO48J205BZQIEDU1DIxGKVq4/SNdxOS0JRI3wXvGmPLJnhZ4bqwr2SPOMTCx 12 | DyJVE+g4/OJXGEONEnJc141Fb8dAiCOgjBP74/z1JktClSOZT1aRE9FB+Ug241Ov 13 | B/w6vbXohq0OkF20BlO3Bk3kJ0Z9I0aDJX69I3abQzN3JTmonc8onhiAZDH+OgaY 14 | jULolb6/gpF6zokBMfpufsBFFLJa/F9AaRvSXICQKiuBdWb6KZY= 15 | =X5in 16 | -----END PGP SIGNATURE----- 17 | -------------------------------------------------------------------------------- /patches/CVE-2022-46176/0003-add-required-APIs-to-git2.patch: -------------------------------------------------------------------------------- 1 | From f06f1b991c1bb33ad81ad75096183b78a2ed6289 Mon Sep 17 00:00:00 2001 2 | From: Eric Huss 3 | Date: Sun, 8 Jan 2023 18:44:28 +0100 4 | Subject: [PATCH 3/6] add required APIs to git2 5 | 6 | --- 7 | cve-2022-46176-deps/git2-0.15.0/src/cert.rs | 81 +++++++++++++++++++ 8 | cve-2022-46176-deps/git2-0.15.0/src/lib.rs | 2 +- 9 | .../git2-0.15.0/src/remote_callbacks.rs | 35 ++++++-- 10 | 3 files changed, 110 insertions(+), 8 deletions(-) 11 | 12 | diff --git a/cve-2022-46176-deps/git2-0.15.0/src/cert.rs b/cve-2022-46176-deps/git2-0.15.0/src/cert.rs 13 | index d62b8304c..b232cc3ce 100644 14 | --- a/cve-2022-46176-deps/git2-0.15.0/src/cert.rs 15 | +++ b/cve-2022-46176-deps/git2-0.15.0/src/cert.rs 16 | @@ -27,6 +27,54 @@ pub struct CertX509<'a> { 17 | _marker: marker::PhantomData<&'a raw::git_cert>, 18 | } 19 | 20 | +/// The SSH host key type. 21 | +#[derive(Copy, Clone, Debug)] 22 | +#[non_exhaustive] 23 | +pub enum SshHostKeyType { 24 | + /// Unknown key type 25 | + Unknown = raw::GIT_CERT_SSH_RAW_TYPE_UNKNOWN as isize, 26 | + /// RSA key type 27 | + Rsa = raw::GIT_CERT_SSH_RAW_TYPE_RSA as isize, 28 | + /// DSS key type 29 | + Dss = raw::GIT_CERT_SSH_RAW_TYPE_DSS as isize, 30 | + /// ECDSA 256 key type 31 | + Ecdsa256 = raw::GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_256 as isize, 32 | + /// ECDSA 384 key type 33 | + Ecdsa384 = raw::GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_384 as isize, 34 | + /// ECDSA 521 key type 35 | + Ecdsa521 = raw::GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_521 as isize, 36 | + /// ED25519 key type 37 | + Ed255219 = raw::GIT_CERT_SSH_RAW_TYPE_KEY_ED25519 as isize, 38 | +} 39 | + 40 | +impl SshHostKeyType { 41 | + /// The name of the key type as encoded in the known_hosts file. 42 | + pub fn name(&self) -> &'static str { 43 | + match self { 44 | + SshHostKeyType::Unknown => "unknown", 45 | + SshHostKeyType::Rsa => "ssh-rsa", 46 | + SshHostKeyType::Dss => "ssh-dss", 47 | + SshHostKeyType::Ecdsa256 => "ecdsa-sha2-nistp256", 48 | + SshHostKeyType::Ecdsa384 => "ecdsa-sha2-nistp384", 49 | + SshHostKeyType::Ecdsa521 => "ecdsa-sha2-nistp521", 50 | + SshHostKeyType::Ed255219 => "ssh-ed25519", 51 | + } 52 | + } 53 | + 54 | + /// A short name of the key type, the colloquial form used as a human-readable description. 55 | + pub fn short_name(&self) -> &'static str { 56 | + match self { 57 | + SshHostKeyType::Unknown => "Unknown", 58 | + SshHostKeyType::Rsa => "RSA", 59 | + SshHostKeyType::Dss => "DSA", 60 | + SshHostKeyType::Ecdsa256 => "ECDSA", 61 | + SshHostKeyType::Ecdsa384 => "ECDSA", 62 | + SshHostKeyType::Ecdsa521 => "ECDSA", 63 | + SshHostKeyType::Ed255219 => "ED25519", 64 | + } 65 | + } 66 | +} 67 | + 68 | impl<'a> Cert<'a> { 69 | /// Attempt to view this certificate as an SSH hostkey. 70 | /// 71 | @@ -87,6 +135,39 @@ impl<'a> CertHostkey<'a> { 72 | } 73 | } 74 | } 75 | + 76 | + /// Returns the raw host key. 77 | + pub fn hostkey(&self) -> Option<&[u8]> { 78 | + unsafe { 79 | + if (*self.raw).kind & raw::GIT_CERT_SSH_RAW == 0 { 80 | + return None; 81 | + } 82 | + Some(slice::from_raw_parts( 83 | + (*self.raw).hostkey as *const u8, 84 | + (*self.raw).hostkey_len as usize, 85 | + )) 86 | + } 87 | + } 88 | + 89 | + /// Returns the type of the host key. 90 | + pub fn hostkey_type(&self) -> Option { 91 | + unsafe { 92 | + if (*self.raw).kind & raw::GIT_CERT_SSH_RAW == 0 { 93 | + return None; 94 | + } 95 | + let t = match (*self.raw).raw_type { 96 | + raw::GIT_CERT_SSH_RAW_TYPE_UNKNOWN => SshHostKeyType::Unknown, 97 | + raw::GIT_CERT_SSH_RAW_TYPE_RSA => SshHostKeyType::Rsa, 98 | + raw::GIT_CERT_SSH_RAW_TYPE_DSS => SshHostKeyType::Dss, 99 | + raw::GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_256 => SshHostKeyType::Ecdsa256, 100 | + raw::GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_384 => SshHostKeyType::Ecdsa384, 101 | + raw::GIT_CERT_SSH_RAW_TYPE_KEY_ECDSA_521 => SshHostKeyType::Ecdsa521, 102 | + raw::GIT_CERT_SSH_RAW_TYPE_KEY_ED25519 => SshHostKeyType::Ed255219, 103 | + t => panic!("unexpected host key type {:?}", t), 104 | + }; 105 | + Some(t) 106 | + } 107 | + } 108 | } 109 | 110 | impl<'a> CertX509<'a> { 111 | diff --git a/cve-2022-46176-deps/git2-0.15.0/src/lib.rs b/cve-2022-46176-deps/git2-0.15.0/src/lib.rs 112 | index c297ffe44..34287154e 100644 113 | --- a/cve-2022-46176-deps/git2-0.15.0/src/lib.rs 114 | +++ b/cve-2022-46176-deps/git2-0.15.0/src/lib.rs 115 | @@ -123,7 +123,7 @@ pub use crate::refspec::Refspec; 116 | pub use crate::remote::{ 117 | FetchOptions, PushOptions, Refspecs, Remote, RemoteConnection, RemoteHead, RemoteRedirect, 118 | }; 119 | -pub use crate::remote_callbacks::{Credentials, RemoteCallbacks}; 120 | +pub use crate::remote_callbacks::{CertificateCheckStatus, Credentials, RemoteCallbacks}; 121 | pub use crate::remote_callbacks::{TransportMessage, UpdateTips}; 122 | pub use crate::repo::{Repository, RepositoryInitOptions}; 123 | pub use crate::revert::RevertOptions; 124 | diff --git a/cve-2022-46176-deps/git2-0.15.0/src/remote_callbacks.rs b/cve-2022-46176-deps/git2-0.15.0/src/remote_callbacks.rs 125 | index bcc73e85e..fe1802273 100644 126 | --- a/cve-2022-46176-deps/git2-0.15.0/src/remote_callbacks.rs 127 | +++ b/cve-2022-46176-deps/git2-0.15.0/src/remote_callbacks.rs 128 | @@ -51,7 +51,18 @@ pub type UpdateTips<'a> = dyn FnMut(&str, Oid, Oid) -> bool + 'a; 129 | /// 130 | /// The second argument is the hostname for the connection is passed as the last 131 | /// argument. 132 | -pub type CertificateCheck<'a> = dyn FnMut(&Cert<'_>, &str) -> bool + 'a; 133 | +pub type CertificateCheck<'a> = 134 | + dyn FnMut(&Cert<'_>, &str) -> Result + 'a; 135 | + 136 | +/// The return value for the [`CertificateCheck`] callback. 137 | +pub enum CertificateCheckStatus { 138 | + /// Indicates that the certificate should be accepted. 139 | + CertificateOk, 140 | + /// Indicates that the certificate callback is neither accepting nor 141 | + /// rejecting the certificate. The result of the certificate checks 142 | + /// built-in to libgit2 will be used instead. 143 | + CertificatePassthrough, 144 | +} 145 | 146 | /// Callback for each updated reference on push. 147 | /// 148 | @@ -162,7 +173,7 @@ impl<'a> RemoteCallbacks<'a> { 149 | /// connection to proceed. 150 | pub fn certificate_check(&mut self, cb: F) -> &mut RemoteCallbacks<'a> 151 | where 152 | - F: FnMut(&Cert<'_>, &str) -> bool + 'a, 153 | + F: FnMut(&Cert<'_>, &str) -> Result + 'a, 154 | { 155 | self.certificate_check = Some(Box::new(cb) as Box>); 156 | self 157 | @@ -371,16 +382,26 @@ extern "C" fn certificate_check_cb( 158 | let payload = &mut *(data as *mut RemoteCallbacks<'_>); 159 | let callback = match payload.certificate_check { 160 | Some(ref mut c) => c, 161 | - None => return true, 162 | + None => return Ok(CertificateCheckStatus::CertificatePassthrough), 163 | }; 164 | let cert = Binding::from_raw(cert); 165 | let hostname = str::from_utf8(CStr::from_ptr(hostname).to_bytes()).unwrap(); 166 | callback(&cert, hostname) 167 | }); 168 | - if ok == Some(true) { 169 | - 0 170 | - } else { 171 | - -1 172 | + match ok { 173 | + Some(Ok(CertificateCheckStatus::CertificateOk)) => 0, 174 | + Some(Ok(CertificateCheckStatus::CertificatePassthrough)) => raw::GIT_PASSTHROUGH as c_int, 175 | + Some(Err(e)) => { 176 | + let s = CString::new(e.message()).unwrap(); 177 | + unsafe { 178 | + raw::git_error_set_str(e.class() as c_int, s.as_ptr()); 179 | + } 180 | + e.raw_code() as c_int 181 | + } 182 | + None => { 183 | + // Panic. The *should* get resumed by some future call to check(). 184 | + -1 185 | + } 186 | } 187 | } 188 | 189 | -- 190 | 2.34.1 191 | 192 | -------------------------------------------------------------------------------- /patches/CVE-2022-46176/0003-add-required-APIs-to-git2.patch.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQIzBAABCgAdFiEEV2nIi/XdPRSiNKes77mGCudSDawFAmO9PggACgkQ77mGCudS 4 | Daw80A//QbenGXmlnZM1djpT06341KRwJqFAIWq236Mdd6JDgJAMvhQxks4gti3t 5 | ubLoKDHOvb149nwdLAic+XMc0bKULN39klqzNZLsw0q8UFVhj1ck0KoM1T9aPWCm 6 | GgUtL+edWxh+zslBW6k/kAO+QjJRy3rMsJz5DqohwUHuahQ0RC4NLUYJNO8tu2ll 7 | dWV8YyXGriXE6ec/GtpZTBB33eCWycO1pQb0zymwMXnfuN5FBDke9i1x2Hl8UBkw 8 | 3GlmlT9aXsLWtSDwNjiiFsZoM8/EHv04NNv3fDz7ZNhWI3ZotqJfe3wK3i8HsFas 9 | y2p/9Mkh83g+H9WPSBRP/sImky2/ZYUOoyPjvciibP0w1SybVfiGKWyEjb2Pjam/ 10 | hxSLlySy4ecHcB/YBd6xrFV0L4nRij5PjlHJwgno/1FeA5GDS3pN2RVEE6XUZP0S 11 | +ktR8ts2OrzQrm/rM2AqkFuD1u6tFQPrX9JztmuafpZE5CJWe/wQ6OE6bvyfx2Kp 12 | C8wm/Yz2CyaYQOt2wyF08OIjpBXFKsAMDWYqS3mFHkz4xn50k4rSq/rrzpWpz05F 13 | 5ENdEEtisqM+PYyT73uP0gEd95xSVZQ6C5Q9Z2cN5sKBCzYAG1frj6Zbm70k8kWs 14 | CWt6waSIN+fh+MajwPZO8ijtGud7D9QUytGKujLY6QOWFEp6cbI= 15 | =gSkF 16 | -----END PGP SIGNATURE----- 17 | -------------------------------------------------------------------------------- /patches/CVE-2022-46176/0004-CVE-2022-46176-verify-ssh-host-keys-in-cargo.patch.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQIzBAABCgAdFiEEV2nIi/XdPRSiNKes77mGCudSDawFAmO9Pg4ACgkQ77mGCudS 4 | DaxGDg/9FTRA4yoIMpy4mXviDOxOzVVk9G9w5YjIzFvRhikKmojaOrOmtqiQFPJO 5 | PkB+MKXpkeyjIun7dEB1HbT5N07Iob7eEQ0XePCAAS9u+l6bDzudMnKzCzUnneaw 6 | FyMZ3HcrTSuhAVLtayxsd27/j501BbTi2+KLMPYlWxhnUL15o8AMSXiLS4gfEZm2 7 | rcf3qhz+szGfs9QJnxJTP+9aLiOavhg1BHIO4He6w/EeYVeolojdxSEVYVkNQS5T 8 | a0t5UTVUMZyvlGDY/+4tkYm8LXTZrz5EqEntO/8VSWIS+qNgUVZNAwEwToJ5KYxl 9 | 6MVi8hqYK1fCN4rqLMGM40+fTguaAy4eSp3e/w/IAxA4alRk1kfNGb195uRuKxpK 10 | Gi4P+Pf+wWMXTdXJJ+PKomhVKgd+ZhYPxDHfhGYn6BS3p1t637F36KYVna/vU45Z 11 | QglsO4dtAk7egrlFv03D0+6Dq3p1gaIJJwCyu+lX2gMEDFhvWxIq4MDGz6XW41MV 12 | OyC4YXm0LT9c7n/Pe6Sio7GN6NbC86gxyNkbrrM2Iho6PVu9f8en5uBSBuyG45LS 13 | pZDuACBpfbm7p0AyIreAmkYNzOqMpu8m2YFMpd4rPjVyBQv3l/+aJWYaQdpFoB3A 14 | tOTi3esK2KlrvWsAsIVPyo54AVTLi6sMbE/DV6CG11mT92Xv4B0= 15 | =9MrZ 16 | -----END PGP SIGNATURE----- 17 | -------------------------------------------------------------------------------- /patches/CVE-2022-46176/0005-hook-up-vendored-dependencies-with-the-build-system.patch: -------------------------------------------------------------------------------- 1 | From a6c87d2cdc63430143e13d09970d29e2e7f1ae9e Mon Sep 17 00:00:00 2001 2 | From: Pietro Albini 3 | Date: Sun, 8 Jan 2023 19:11:03 +0100 4 | Subject: [PATCH 5/6] hook up vendored dependencies with the build system 5 | 6 | --- 7 | Cargo.lock | 36 ++++++++++++++------ 8 | Cargo.toml | 8 +++++ 9 | cve-2022-46176-deps/base64-0.13.1/Cargo.toml | 16 --------- 10 | cve-2022-46176-deps/hmac-0.12.1/Cargo.toml | 23 ------------- 11 | cve-2022-46176-deps/sha-1-0.10.1/Cargo.toml | 14 +------- 12 | 5 files changed, 34 insertions(+), 63 deletions(-) 13 | 14 | diff --git a/Cargo.lock b/Cargo.lock 15 | index dab693419..19acbfbba 100644 16 | --- a/Cargo.lock 17 | +++ b/Cargo.lock 18 | @@ -194,6 +194,10 @@ dependencies = [ 19 | "rustc-demangle", 20 | ] 21 | 22 | +[[package]] 23 | +name = "base64" 24 | +version = "0.13.1" 25 | + 26 | [[package]] 27 | name = "bitflags" 28 | version = "1.3.2" 29 | @@ -292,6 +296,7 @@ version = "0.67.0" 30 | dependencies = [ 31 | "anyhow", 32 | "atty", 33 | + "base64", 34 | "bytesize", 35 | "cargo-platform 0.1.2", 36 | "cargo-test-macro", 37 | @@ -309,6 +314,7 @@ dependencies = [ 38 | "git2-curl", 39 | "glob", 40 | "hex 0.4.2", 41 | + "hmac", 42 | "home", 43 | "humantime 2.0.1", 44 | "ignore", 45 | @@ -336,6 +342,7 @@ dependencies = [ 46 | "serde-value", 47 | "serde_ignored", 48 | "serde_json", 49 | + "sha-1", 50 | "shell-escape", 51 | "snapbox", 52 | "strip-ansi-escapes", 53 | @@ -1004,11 +1011,12 @@ dependencies = [ 54 | 55 | [[package]] 56 | name = "crypto-common" 57 | -version = "0.1.2" 58 | +version = "0.1.3" 59 | source = "registry+https://github.com/rust-lang/crates.io-index" 60 | -checksum = "a4600d695eb3f6ce1cd44e6e291adceb2cc3ab12f20a33777ecd0bf6eba34e06" 61 | +checksum = "57952ca27b5e3606ff4dd79b0020231aaf9d6aa76dc05fd30137538c50bd3ce8" 62 | dependencies = [ 63 | "generic-array", 64 | + "typenum", 65 | ] 66 | 67 | [[package]] 68 | @@ -1095,12 +1103,11 @@ checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198" 69 | 70 | [[package]] 71 | name = "digest" 72 | -version = "0.10.2" 73 | -source = "registry+https://github.com/rust-lang/crates.io-index" 74 | -checksum = "8cb780dce4f9a8f5c087362b3a4595936b2019e7c8b30f2c3e9a7e94e6ae9837" 75 | +version = "0.10.6" 76 | dependencies = [ 77 | "block-buffer", 78 | "crypto-common", 79 | + "subtle", 80 | ] 81 | 82 | [[package]] 83 | @@ -1559,8 +1566,6 @@ dependencies = [ 84 | [[package]] 85 | name = "git2" 86 | version = "0.15.0" 87 | -source = "registry+https://github.com/rust-lang/crates.io-index" 88 | -checksum = "2994bee4a3a6a51eb90c218523be382fd7ea09b16380b9312e9dbe955ff7c7d1" 89 | dependencies = [ 90 | "bitflags", 91 | "libc", 92 | @@ -1676,6 +1681,13 @@ version = "0.4.2" 93 | source = "registry+https://github.com/rust-lang/crates.io-index" 94 | checksum = "644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35" 95 | 96 | +[[package]] 97 | +name = "hmac" 98 | +version = "0.12.1" 99 | +dependencies = [ 100 | + "digest", 101 | +] 102 | + 103 | [[package]] 104 | name = "home" 105 | version = "0.5.3" 106 | @@ -1964,8 +1976,6 @@ dependencies = [ 107 | [[package]] 108 | name = "libgit2-sys" 109 | version = "0.14.0+1.5.0" 110 | -source = "registry+https://github.com/rust-lang/crates.io-index" 111 | -checksum = "47a00859c70c8a4f7218e6d1cc32875c4b55f6799445b842b0d8ed5e4c3d959b" 112 | dependencies = [ 113 | "cc", 114 | "libc", 115 | @@ -4745,6 +4755,10 @@ version = "0.10.0" 116 | source = "registry+https://github.com/rust-lang/crates.io-index" 117 | checksum = "73473c0e59e6d5812c5dfe2a064a6444949f089e20eec9a2e5506596494e4623" 118 | 119 | +[[package]] 120 | +name = "subtle" 121 | +version = "2.4.1" 122 | + 123 | [[package]] 124 | name = "syn" 125 | version = "1.0.102" 126 | @@ -5106,9 +5120,9 @@ dependencies = [ 127 | 128 | [[package]] 129 | name = "typenum" 130 | -version = "1.12.0" 131 | +version = "1.15.0" 132 | source = "registry+https://github.com/rust-lang/crates.io-index" 133 | -checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" 134 | +checksum = "dcf81ac59edc17cc8697ff311e8f5ef2d99fcbd9817b34cec66f90b6c3dfd987" 135 | 136 | [[package]] 137 | name = "ucd-parse" 138 | diff --git a/Cargo.toml b/Cargo.toml 139 | index e49fe5e2f..f6dbab771 100644 140 | --- a/Cargo.toml 141 | +++ b/Cargo.toml 142 | @@ -109,5 +109,13 @@ rustc-std-workspace-core = { path = 'library/rustc-std-workspace-core' } 143 | rustc-std-workspace-alloc = { path = 'library/rustc-std-workspace-alloc' } 144 | rustc-std-workspace-std = { path = 'library/rustc-std-workspace-std' } 145 | 146 | +# CVE-2022-46176 patched crates. 147 | +git2 = { path = "cve-2022-46176-deps/git2-0.15.0" } 148 | +libgit2-sys = { path = "cve-2022-46176-deps/libgit2-sys-0.14.0+1.5.0" } 149 | +subtle = { path = "cve-2022-46176-deps/subtle-2.4.1" } 150 | +base64 = { path = "cve-2022-46176-deps/base64-0.13.1" } 151 | +hmac = { path = "cve-2022-46176-deps/hmac-0.12.1" } 152 | +digest = { path = "cve-2022-46176-deps/digest-0.10.6" } 153 | + 154 | [patch."https://github.com/rust-lang/rust-clippy"] 155 | clippy_lints = { path = "src/tools/clippy/clippy_lints" } 156 | diff --git a/cve-2022-46176-deps/base64-0.13.1/Cargo.toml b/cve-2022-46176-deps/base64-0.13.1/Cargo.toml 157 | index 64179e1aa..ee616084c 100644 158 | --- a/cve-2022-46176-deps/base64-0.13.1/Cargo.toml 159 | +++ b/cve-2022-46176-deps/base64-0.13.1/Cargo.toml 160 | @@ -31,22 +31,6 @@ categories = ["encoding"] 161 | license = "MIT/Apache-2.0" 162 | repository = "https://github.com/marshallpierce/rust-base64" 163 | 164 | -[profile.bench] 165 | -debug = true 166 | - 167 | -[[bench]] 168 | -name = "benchmarks" 169 | -harness = false 170 | - 171 | -[dev-dependencies.criterion] 172 | -version = "=0.3.2" 173 | - 174 | -[dev-dependencies.rand] 175 | -version = "0.6.1" 176 | - 177 | -[dev-dependencies.structopt] 178 | -version = "0.3" 179 | - 180 | [features] 181 | alloc = [] 182 | default = ["std"] 183 | diff --git a/cve-2022-46176-deps/hmac-0.12.1/Cargo.toml b/cve-2022-46176-deps/hmac-0.12.1/Cargo.toml 184 | index ca1c001a3..b8f71503a 100644 185 | --- a/cve-2022-46176-deps/hmac-0.12.1/Cargo.toml 186 | +++ b/cve-2022-46176-deps/hmac-0.12.1/Cargo.toml 187 | @@ -27,29 +27,6 @@ rustdoc-args = ["--cfg", "docsrs"] 188 | [dependencies.digest] 189 | version = "0.10.3" 190 | features = ["mac"] 191 | -[dev-dependencies.digest] 192 | -version = "0.10" 193 | -features = ["dev"] 194 | - 195 | -[dev-dependencies.hex-literal] 196 | -version = "0.2.2" 197 | - 198 | -[dev-dependencies.md-5] 199 | -version = "0.10" 200 | -default-features = false 201 | - 202 | -[dev-dependencies.sha-1] 203 | -version = "0.10" 204 | -default-features = false 205 | - 206 | -[dev-dependencies.sha2] 207 | -version = "0.10" 208 | -default-features = false 209 | - 210 | -[dev-dependencies.streebog] 211 | -version = "0.10" 212 | -default-features = false 213 | - 214 | [features] 215 | reset = [] 216 | std = ["digest/std"] 217 | diff --git a/cve-2022-46176-deps/sha-1-0.10.1/Cargo.toml b/cve-2022-46176-deps/sha-1-0.10.1/Cargo.toml 218 | index 27698d988..1fbe23473 100644 219 | --- a/cve-2022-46176-deps/sha-1-0.10.1/Cargo.toml 220 | +++ b/cve-2022-46176-deps/sha-1-0.10.1/Cargo.toml 221 | @@ -44,17 +44,9 @@ name = "sha1" 222 | version = "1.0" 223 | 224 | [dependencies.digest] 225 | -version = "0.10.4" 226 | - 227 | -[dev-dependencies.digest] 228 | -version = "0.10.4" 229 | -features = ["dev"] 230 | - 231 | -[dev-dependencies.hex-literal] 232 | -version = "0.2.2" 233 | +version = "0.10" 234 | 235 | [features] 236 | -asm = ["sha1-asm"] 237 | compress = [] 238 | default = ["std"] 239 | force-soft = [] 240 | @@ -63,7 +55,3 @@ std = ["digest/std"] 241 | 242 | [target."cfg(any(target_arch = \"aarch64\", target_arch = \"x86\", target_arch = \"x86_64\"))".dependencies.cpufeatures] 243 | version = "0.2" 244 | - 245 | -[target."cfg(any(target_arch = \"aarch64\", target_arch = \"x86\", target_arch = \"x86_64\"))".dependencies.sha1-asm] 246 | -version = "0.5" 247 | -optional = true 248 | -- 249 | 2.34.1 250 | 251 | -------------------------------------------------------------------------------- /patches/CVE-2022-46176/0005-hook-up-vendored-dependencies-with-the-build-system.patch.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQIzBAABCgAdFiEEV2nIi/XdPRSiNKes77mGCudSDawFAmO9PhQACgkQ77mGCudS 4 | DaxnTQ//fePV3j22w9F/StIZlCsVhxcZiNtVMfXVe97x3LvS3dIwGrV+jkpxM3of 5 | clB/HJ1x72GeP/9c9Od/4agdPeqWqDkXqNeiUs7t70AkhN6NqyQ4KB7McNF+X37t 6 | EJ5VIrEffFWXFC+E97FGa7laBTVHDhG0XyOk3bZWkjMQT47xPzytV6jvqEdgCukM 7 | SSQFt4Ho2tC3a58IwZ5r1xdWWLkG/aQAVrRqujFQH2CUIHuFFeEQB5DHUY+QtHqW 8 | vrHsBf3mXqXIyeRMEePqM9GZR8NLnyY0KZ8V89y/E+SJi9CH9zxnrQUQ0nLJ7coE 9 | vue53MxIwIZO0QgrFm7RvdlqrtlMqs42cjdL/1VcCK1z1yjMTErt5h9h7DL5oQrS 10 | KrWBC6gDrR5cMnKUwpvDtebYc/5gCAWRkbcAEX3YPfQoyVTVJvhY9NoHGHcsz+QG 11 | zLNdrF613qHYB8vjARdL3iKpBaFVsW61asxos/8jFFHX98uJwpKsv1qO9PbPYTyC 12 | Tf1sa4d/pnwnm/iHNzxpwvuXuWZFPeZAYbFTzduYk7O1yI9Wqif/SgFi+NwH8kgt 13 | 8p7bOsGFfz2gB9B7ZHUNIEjRh1Fy4YJPEU4geh/eNTPkuHCUBiVOSMDAsmDbIp2X 14 | TB4rkh09b/dbQyAoDySLOnljYbkvGM6trn14GFjzt2QriQHuEqQ= 15 | =OtEj 16 | -----END PGP SIGNATURE----- 17 | -------------------------------------------------------------------------------- /patches/CVE-2022-46176/0006-suppress-error-in-newer-Rust-compilers.patch: -------------------------------------------------------------------------------- 1 | From 68a757805c40b138da00b0dcc574c6cc6e90072e Mon Sep 17 00:00:00 2001 2 | From: Pietro Albini 3 | Date: Sun, 8 Jan 2023 19:11:19 +0100 4 | Subject: [PATCH 6/6] suppress error in newer Rust compilers 5 | 6 | --- 7 | cve-2022-46176-deps/base64-0.13.1/src/lib.rs | 2 ++ 8 | cve-2022-46176-deps/digest-0.10.6/src/lib.rs | 2 ++ 9 | 2 files changed, 4 insertions(+) 10 | 11 | diff --git a/cve-2022-46176-deps/base64-0.13.1/src/lib.rs b/cve-2022-46176-deps/base64-0.13.1/src/lib.rs 12 | index 6bded1606..78ff12567 100644 13 | --- a/cve-2022-46176-deps/base64-0.13.1/src/lib.rs 14 | +++ b/cve-2022-46176-deps/base64-0.13.1/src/lib.rs 15 | @@ -57,6 +57,8 @@ 16 | //! 17 | //! The `_slice` flavors of encode or decode will panic if the provided output slice is too small, 18 | 19 | +#![allow(unexpected_cfgs)] 20 | + 21 | #![cfg_attr(feature = "cargo-clippy", allow(clippy::cast_lossless))] 22 | #![deny( 23 | missing_docs, 24 | diff --git a/cve-2022-46176-deps/digest-0.10.6/src/lib.rs b/cve-2022-46176-deps/digest-0.10.6/src/lib.rs 25 | index fc82e2e3a..334734447 100644 26 | --- a/cve-2022-46176-deps/digest-0.10.6/src/lib.rs 27 | +++ b/cve-2022-46176-deps/digest-0.10.6/src/lib.rs 28 | @@ -22,6 +22,8 @@ 29 | //! feature-gated behind `std` feature, which is usually enabled by default 30 | //! by hash implementation crates. 31 | 32 | +#![allow(unexpected_cfgs)] 33 | + 34 | #![no_std] 35 | #![cfg_attr(docsrs, feature(doc_cfg))] 36 | #![forbid(unsafe_code)] 37 | -- 38 | 2.34.1 39 | 40 | -------------------------------------------------------------------------------- /patches/CVE-2022-46176/0006-suppress-error-in-newer-Rust-compilers.patch.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQIzBAABCgAdFiEEV2nIi/XdPRSiNKes77mGCudSDawFAmO9PhoACgkQ77mGCudS 4 | Dayx4hAAr6f3Jt7kCI41MVyn9FtCVWL8v+mB8V6y3axUksObk3WkLxQyjhC9JyWg 5 | q+RieigNX6ur7e2aJy9lh8uK1XcfE2I2CjCFkkLZFtI37a7Jxs5u6QNEULsX4SPQ 6 | jIuHhLfyzZzAX6xxxia3Ld6vDX51pydoKtlbG4lCI84Ime+yFrPOwVHigG+4Cnod 7 | Eo5i4Znkr4xF4iteNAfODVoWIpzHv1aTDHey3v8eP5bRHMGrS6u1ODF6cPx6tPBM 8 | clNb/2UrO2+8oojrPVqGuEOz+4oq504GJzlpSo2lIFOWKbiCkOW+W6UvdpAfrQ6b 9 | 5kk+ZBzbYFliuNLg8hLBQHQSkm3SxLPeN78vX+LE4IaR3gH4m+Wj6U4v048xLOvg 10 | qe3jTUmAV+OL8ya+3IwDIfQDYnN33UI6TofigRBZaincWpy+an3G6dKzv4XwycgN 11 | yvzXM3IJtJzom73hLzg+l1UZmm1J7dVokWPhN/X2SKQMOL2xE1EaCwWTq33ql52C 12 | fJo+XLruxuPZ/H/ZBp9M0/Ilq/8q6/v0bAqdYDBf8yTdKSD3/OB9Uyhj72bSWOSu 13 | xF9zIH5/XbKPkIIiTwgse/M483HvONxRtMqkZ+UgTlA0MH4tjdF8L99c5ZYBeUiK 14 | SI+8ozDK/BZADLOpB92v6x/ZeYjPOdMhKN+nu8jsNu3Hdd2bw2A= 15 | =pkrl 16 | -----END PGP SIGNATURE----- 17 | -------------------------------------------------------------------------------- /patches/CVE-2022-46176/README.md: -------------------------------------------------------------------------------- 1 | # Patches for CVE-2022-46176 2 | 3 | This directory contains the patches for [CVE-2022-46176][cve], to be applied on 4 | top of a Rust 1.66.0 source tarball. 5 | 6 | All the patches except for patch 0001 are released under both the [MIT 7 | license][mit] and the [Apache 2.0 license][apache]. Patch 0001 contains the 8 | source code of third party crates, each released under that crate's license. 9 | Check the contents of patch 0001 for a list of all licenses. 10 | 11 | Signatures from the [Rust Security Response WG's GPG key][key] are provided. 12 | 13 | [cve]: https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2022-46176 14 | [mit]: https://github.com/rust-lang/wg-security-response/blob/master/LICENSE-MIT 15 | [apache]: https://github.com/rust-lang/wg-security-response/blob/master/LICENSE-APACHE 16 | [key]: https://www.rust-lang.org/static/keys/rust-security-team.gpg.ascii 17 | -------------------------------------------------------------------------------- /patches/CVE-2023-38497/0001-test-verify-permissions-bits-are-preserved-when-unpa.patch: -------------------------------------------------------------------------------- 1 | From 33a2cef92cb05674cbc376d68fab7f902c5d9358 Mon Sep 17 00:00:00 2001 2 | From: Weihang Lo 3 | Date: Fri, 7 Jul 2023 14:44:11 +0100 4 | Subject: [PATCH 1/3] test: verify permissions bits are preserved when 5 | unpacking 6 | 7 | This is not secure and will be fixed in the next commit. 8 | --- 9 | src/tools/cargo/tests/testsuite/registry.rs | 55 +++++++++++++++++++++ 10 | 1 file changed, 55 insertions(+) 11 | 12 | diff --git a/src/tools/cargo/tests/testsuite/registry.rs b/src/tools/cargo/tests/testsuite/registry.rs 13 | index f39644965..42107a5e4 100644 14 | --- a/src/tools/cargo/tests/testsuite/registry.rs 15 | +++ b/src/tools/cargo/tests/testsuite/registry.rs 16 | @@ -3403,3 +3403,58 @@ Caused by: 17 | Please slow down 18 | ").run(); 19 | } 20 | + 21 | +#[cfg(unix)] 22 | +#[cargo_test] 23 | +fn set_mask_during_unpacking() { 24 | + use std::os::unix::fs::MetadataExt; 25 | + 26 | + Package::new("bar", "1.0.0") 27 | + .file_with_mode("example.sh", 0o777, "#!/bin/sh") 28 | + .file_with_mode("src/lib.rs", 0o666, "") 29 | + .publish(); 30 | + 31 | + let p = project() 32 | + .file( 33 | + "Cargo.toml", 34 | + r#" 35 | + [package] 36 | + name = "foo" 37 | + version = "0.1.0" 38 | + 39 | + [dependencies] 40 | + bar = "1.0" 41 | + "#, 42 | + ) 43 | + .file("src/lib.rs", "") 44 | + .build(); 45 | + 46 | + p.cargo("fetch") 47 | + .with_stderr( 48 | + "\ 49 | +[UPDATING] `dummy-registry` index 50 | +[DOWNLOADING] crates ... 51 | +[DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) 52 | +", 53 | + ) 54 | + .run(); 55 | + let src_file_path = |path: &str| { 56 | + glob::glob( 57 | + paths::home() 58 | + .join(".cargo/registry/src/*/bar-1.0.0/") 59 | + .join(path) 60 | + .to_str() 61 | + .unwrap(), 62 | + ) 63 | + .unwrap() 64 | + .next() 65 | + .unwrap() 66 | + .unwrap() 67 | + }; 68 | + 69 | + // Assuming umask is `0o022`. 70 | + let metadata = fs::metadata(src_file_path("src/lib.rs")).unwrap(); 71 | + assert_eq!(metadata.mode() & 0o777, 0o666); 72 | + let metadata = fs::metadata(src_file_path("example.sh")).unwrap(); 73 | + assert_eq!(metadata.mode() & 0o777, 0o777); 74 | +} 75 | -- 76 | 2.34.1 77 | 78 | -------------------------------------------------------------------------------- /patches/CVE-2023-38497/0001-test-verify-permissions-bits-are-preserved-when-unpa.patch.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQIzBAABCgAdFiEEV2nIi/XdPRSiNKes77mGCudSDawFAmTLWcsACgkQ77mGCudS 4 | Day0Ug/9E+T+VFFqGhyPjGZ7gL1NyAWUi67yqdTES1xIOFN9aaw6CEvRJiYVWv6M 5 | po9vMafnm7tDLufym/2DxNIMF7f69FGsFEIbFbp0yG9AX4NBFrAl8iPTTi7OcrB3 6 | OUmrnQixSZEbDiA3fCeHQql4fOV7b0ZepKCnSaSjMGsNnehwVJWOlwygv1WY03Je 7 | FUzEgT6n7c3DgHTNRGqkia8HJFncHudgOzII9GUn7CPL1X/7xgDy7r8hRGP9Vu0q 8 | FAR/4wHyQEFxbE35wgtOn1EiHIzJ4zeTVzpjB9fxtdmiNYIMTnba84HK2KTpYaoc 9 | aGqMMkK/fbqY7swJHktREdviOFqPr40ZDSXxjSzFbNufmEysSixfCR86HHHB3+wm 10 | ODem0y/swk2itX1ZG/l3RjvT1kKSRpfYmi08S26ohJJWNfd6/5cJ/lm9BYHIv8mK 11 | SxgleiGpImco8F1IqdbBgH5ATitHHECnN1bYiL4n2lHSfA1QuR94Ec1kLCkTR1ns 12 | ZkBRopU2teoB/vAphA8GL0RoxBHGHSvUxTnotV7nztTzdvUnEa7prmcB2qKdyyv6 13 | s6b6rETSSccRHWvhQQ+9A+07X567YCnpQxy8ws9qkDcmEomXWJrp/nD+AZB57c7B 14 | bgOedMtuMLDIU4QnZxjBNGIaW7oXDHJQtQwIIiqSiyeg7CSUAJM= 15 | =9WpY 16 | -----END PGP SIGNATURE----- 17 | -------------------------------------------------------------------------------- /patches/CVE-2023-38497/0002-fix-respect-umask-when-unpacking-.crate-files.patch: -------------------------------------------------------------------------------- 1 | From f909434f805893b6f5628534ebd13b7c25d045cf Mon Sep 17 00:00:00 2001 2 | From: Weihang Lo 3 | Date: Fri, 7 Jul 2023 14:50:59 +0100 4 | Subject: [PATCH 2/3] fix: respect `umask` when unpacking `.crate` files 5 | 6 | Without this, an attacker can upload globally writable files buried 7 | in the `.crate` file. After a user downloaded and unpacked the file, 8 | the attacker can then write malicous code to the downloaded sources. 9 | --- 10 | Cargo.lock | 4 ++-- 11 | src/tools/cargo/Cargo.toml | 2 +- 12 | .../cargo/src/cargo/sources/registry/mod.rs | 21 +++++++++++++++++-- 13 | src/tools/cargo/src/cargo/util/mod.rs | 18 ++++++++++++++++ 14 | src/tools/cargo/tests/testsuite/registry.rs | 6 +++--- 15 | src/tools/cargo/tests/testsuite/vendor.rs | 5 +++-- 16 | 6 files changed, 46 insertions(+), 10 deletions(-) 17 | 18 | diff --git a/Cargo.lock b/Cargo.lock 19 | index 8b0972494..cd7052f3b 100644 20 | --- a/Cargo.lock 21 | +++ b/Cargo.lock 22 | @@ -4876,9 +4876,9 @@ dependencies = [ 23 | 24 | [[package]] 25 | name = "tar" 26 | -version = "0.4.38" 27 | +version = "0.4.39" 28 | source = "registry+https://github.com/rust-lang/crates.io-index" 29 | -checksum = "4b55807c0344e1e6c04d7c965f5289c39a8d94ae23ed5c0b57aabac549f871c6" 30 | +checksum = "ec96d2ffad078296368d46ff1cb309be1c23c513b4ab0e22a45de0185275ac96" 31 | dependencies = [ 32 | "filetime", 33 | "libc", 34 | diff --git a/src/tools/cargo/Cargo.toml b/src/tools/cargo/Cargo.toml 35 | index 3c6597b5c..6442bb1c8 100644 36 | --- a/src/tools/cargo/Cargo.toml 37 | +++ b/src/tools/cargo/Cargo.toml 38 | @@ -80,7 +80,7 @@ sha2 = "0.10.6" 39 | shell-escape = "0.1.4" 40 | snapbox = { version = "0.4.0", features = ["diff", "path"] } 41 | strip-ansi-escapes = "0.1.0" 42 | -tar = { version = "0.4.38", default-features = false } 43 | +tar = { version = "0.4.39", default-features = false } 44 | tempfile = "3.1.0" 45 | termcolor = "1.1.2" 46 | time = { version = "0.3", features = ["parsing", "formatting"] } 47 | diff --git a/src/tools/cargo/src/cargo/sources/registry/mod.rs b/src/tools/cargo/src/cargo/sources/registry/mod.rs 48 | index ee27df15d..4e4d794e0 100644 49 | --- a/src/tools/cargo/src/cargo/sources/registry/mod.rs 50 | +++ b/src/tools/cargo/src/cargo/sources/registry/mod.rs 51 | @@ -162,7 +162,9 @@ use std::borrow::Cow; 52 | use std::collections::BTreeMap; 53 | use std::collections::HashSet; 54 | use std::fs::{File, OpenOptions}; 55 | -use std::io::{self, Write}; 56 | +use std::io; 57 | +use std::io::Read; 58 | +use std::io::Write; 59 | use std::path::{Path, PathBuf}; 60 | use std::task::{ready, Poll}; 61 | 62 | @@ -698,7 +700,9 @@ impl<'cfg> RegistrySource<'cfg> { 63 | let size_limit = max_unpack_size(self.config, tarball.metadata()?.len()); 64 | let gz = GzDecoder::new(tarball); 65 | let gz = LimitErrorReader::new(gz, size_limit); 66 | - Archive::new(gz) 67 | + let mut tar = Archive::new(gz); 68 | + set_mask(&mut tar); 69 | + tar 70 | }; 71 | let prefix = unpack_dir.file_name().unwrap(); 72 | let parent = unpack_dir.parent().unwrap(); 73 | @@ -1036,3 +1040,16 @@ mod tests { 74 | assert_eq!(make_dep_prefix("aBcDe"), "aB/cD"); 75 | } 76 | } 77 | + 78 | +/// Set the current [`umask`] value for the given tarball. No-op on non-Unix 79 | +/// platforms. 80 | +/// 81 | +/// On Windows, tar only looks at user permissions and tries to set the "read 82 | +/// only" attribute, so no-op as well. 83 | +/// 84 | +/// [`umask`]: https://man7.org/linux/man-pages/man2/umask.2.html 85 | +#[allow(unused_variables)] 86 | +fn set_mask(tar: &mut Archive) { 87 | + #[cfg(unix)] 88 | + tar.set_mask(crate::util::get_umask()); 89 | +} 90 | diff --git a/src/tools/cargo/src/cargo/util/mod.rs b/src/tools/cargo/src/cargo/util/mod.rs 91 | index e72f8183b..df8dcb0ac 100644 92 | --- a/src/tools/cargo/src/cargo/util/mod.rs 93 | +++ b/src/tools/cargo/src/cargo/util/mod.rs 94 | @@ -207,6 +207,24 @@ pub fn try_canonicalize>(path: P) -> std::io::Result { 95 | }) 96 | } 97 | 98 | +/// Get the current [`umask`] value. 99 | +/// 100 | +/// [`umask`]: https://man7.org/linux/man-pages/man2/umask.2.html 101 | +#[cfg(unix)] 102 | +pub fn get_umask() -> u32 { 103 | + use std::sync::OnceLock; 104 | + static UMASK: OnceLock = OnceLock::new(); 105 | + // SAFETY: Syscalls are unsafe. Calling `umask` twice is even unsafer for 106 | + // multithreading program, since it doesn't provide a way to retrive the 107 | + // value without modifications. We use a static `OnceLock` here to ensure 108 | + // it only gets call once during the entire program lifetime. 109 | + *UMASK.get_or_init(|| unsafe { 110 | + let umask = libc::umask(0o022); 111 | + libc::umask(umask); 112 | + umask 113 | + }) as u32 // it is u16 on macos 114 | +} 115 | + 116 | #[cfg(test)] 117 | mod test { 118 | use super::*; 119 | diff --git a/src/tools/cargo/tests/testsuite/registry.rs b/src/tools/cargo/tests/testsuite/registry.rs 120 | index 42107a5e4..daa96d5a8 100644 121 | --- a/src/tools/cargo/tests/testsuite/registry.rs 122 | +++ b/src/tools/cargo/tests/testsuite/registry.rs 123 | @@ -3452,9 +3452,9 @@ fn set_mask_during_unpacking() { 124 | .unwrap() 125 | }; 126 | 127 | - // Assuming umask is `0o022`. 128 | + let umask = cargo::util::get_umask(); 129 | let metadata = fs::metadata(src_file_path("src/lib.rs")).unwrap(); 130 | - assert_eq!(metadata.mode() & 0o777, 0o666); 131 | + assert_eq!(metadata.mode() & 0o777, 0o666 & !umask); 132 | let metadata = fs::metadata(src_file_path("example.sh")).unwrap(); 133 | - assert_eq!(metadata.mode() & 0o777, 0o777); 134 | + assert_eq!(metadata.mode() & 0o777, 0o777 & !umask); 135 | } 136 | diff --git a/src/tools/cargo/tests/testsuite/vendor.rs b/src/tools/cargo/tests/testsuite/vendor.rs 137 | index 21a1c097c..2b8b090c2 100644 138 | --- a/src/tools/cargo/tests/testsuite/vendor.rs 139 | +++ b/src/tools/cargo/tests/testsuite/vendor.rs 140 | @@ -1051,10 +1051,11 @@ fn vendor_preserves_permissions() { 141 | 142 | p.cargo("vendor --respect-source-config").run(); 143 | 144 | + let umask = cargo::util::get_umask(); 145 | let metadata = fs::metadata(p.root().join("vendor/bar/src/lib.rs")).unwrap(); 146 | - assert_eq!(metadata.mode() & 0o777, 0o644); 147 | + assert_eq!(metadata.mode() & 0o777, 0o644 & !umask); 148 | let metadata = fs::metadata(p.root().join("vendor/bar/example.sh")).unwrap(); 149 | - assert_eq!(metadata.mode() & 0o777, 0o755); 150 | + assert_eq!(metadata.mode() & 0o777, 0o755 & !umask); 151 | } 152 | 153 | #[cargo_test] 154 | -- 155 | 2.34.1 156 | 157 | -------------------------------------------------------------------------------- /patches/CVE-2023-38497/0002-fix-respect-umask-when-unpacking-.crate-files.patch.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQIzBAABCgAdFiEEV2nIi/XdPRSiNKes77mGCudSDawFAmTLWesACgkQ77mGCudS 4 | DayEjRAAm07uEIbm/pn2EwxmU+5zShXieF0/Fl3iNpIBMs4p6JwRwyM+Dq24RX4j 5 | J5LZY9MrdSOIzPoP6kjd+6pnmsQhJ0E/wwbHSYlkebAi7hIeAUHemBkYAWrUtY1u 6 | pHAHEp8X1pRhljT8HQ0T21M8fXIeV/ege+ScGqSj0bTqhbSey3qzdmtBNYnitpGJ 7 | AEwWr03c27F7JxxCQAYSBLeal1iHAbUAHnHfNGO78YvAfCOIvEX1iO/rseU46o1t 8 | elM9bhx8hMiehhaecettflJtA+zqYRETF8Ojch6FIe3n7LEEeBgSTCRcky9+vO6M 9 | wOTbDT+3mTcZ/NAjO/S17yNIVfhgWS1iaANZv+YXO4zozcCs0NA4JCJlr8VT0het 10 | w3yLGROLX4vDj62K5n0FQ1gz+WGvLXBwBro3NABZJ3BKFmDVEa2dqcrIate3ZGrC 11 | tZrMvwcdB8DLQ2Iaf/RdNvePc5XUL/6vblVrMjU56CVIVTVWfXWybft97RaQyj+j 12 | DLBZs5WmTK9PJ1ov8njwr2L0231gx8/+Gkf0tl+Lmfv3zpt+cyTUlpgFUfj3QZqF 13 | 2rDwDw5UbBe+C+gCZeaSZhIl/aXxnT33B95ANjAerBSh0nHxyqlZ6FkRSG5TE+f0 14 | PPLokB2usFVxCyKEmSIa0tz/Ty1LP6PpGvErnTLc1ye7KDPzDRc= 15 | =LFCR 16 | -----END PGP SIGNATURE----- 17 | -------------------------------------------------------------------------------- /patches/CVE-2023-38497/0003-fix-clear-cache-for-old-.cargo-ok-format.patch: -------------------------------------------------------------------------------- 1 | From 9e79b6feb803ff18e8cd90aba9e7346c15323ec9 Mon Sep 17 00:00:00 2001 2 | From: Weihang Lo 3 | Date: Fri, 7 Jul 2023 18:18:39 +0100 4 | Subject: [PATCH 3/3] fix: clear cache for old `.cargo-ok` format 5 | 6 | In 1.71, `.cargo-ok` changed to contain a JSON `{ v: 1 }` to indicate 7 | the version of it. A failure of parsing will result in a heavy-hammer 8 | approach that unpacks the `.crate` file again. This is in response to a 9 | security issue that the unpacking didn't respect umask on Unix systems. 10 | --- 11 | .../cargo/src/cargo/sources/registry/mod.rs | 122 +++++++++++------- 12 | src/tools/cargo/tests/testsuite/registry.rs | 77 ++++++++++- 13 | 2 files changed, 147 insertions(+), 52 deletions(-) 14 | 15 | diff --git a/src/tools/cargo/src/cargo/sources/registry/mod.rs b/src/tools/cargo/src/cargo/sources/registry/mod.rs 16 | index 4e4d794e0..c76ee6142 100644 17 | --- a/src/tools/cargo/src/cargo/sources/registry/mod.rs 18 | +++ b/src/tools/cargo/src/cargo/sources/registry/mod.rs 19 | @@ -161,6 +161,7 @@ 20 | use std::borrow::Cow; 21 | use std::collections::BTreeMap; 22 | use std::collections::HashSet; 23 | +use std::fs; 24 | use std::fs::{File, OpenOptions}; 25 | use std::io; 26 | use std::io::Read; 27 | @@ -174,6 +175,7 @@ use flate2::read::GzDecoder; 28 | use log::debug; 29 | use semver::Version; 30 | use serde::Deserialize; 31 | +use serde::Serialize; 32 | use tar::Archive; 33 | 34 | use crate::core::dependency::{DepKind, Dependency}; 35 | @@ -201,6 +203,14 @@ const CHECKSUM_TEMPLATE: &str = "{sha256-checksum}"; 36 | const MAX_UNPACK_SIZE: u64 = 512 * 1024 * 1024; 37 | const MAX_COMPRESSION_RATIO: usize = 20; // 20:1 38 | 39 | +/// The content inside `.cargo-ok`. 40 | +/// See [`RegistrySource::unpack_package`] for more. 41 | +#[derive(Deserialize, Serialize)] 42 | +struct LockMetadata { 43 | + /// The version of `.cargo-ok` file 44 | + v: u32, 45 | +} 46 | + 47 | /// A "source" for a local (see `local::LocalRegistry`) or remote (see 48 | /// `remote::RemoteRegistry`) registry. 49 | /// 50 | @@ -637,6 +647,50 @@ impl<'cfg> RegistrySource<'cfg> { 51 | /// compiled. 52 | /// 53 | /// No action is taken if the source looks like it's already unpacked. 54 | + /// 55 | + /// # History of interruption detection with `.cargo-ok` file 56 | + /// 57 | + /// Cargo has always included a `.cargo-ok` file ([`PACKAGE_SOURCE_LOCK`]) 58 | + /// to detect if extraction was interrupted, but it was originally empty. 59 | + /// 60 | + /// In 1.34, Cargo was changed to create the `.cargo-ok` file before it 61 | + /// started extraction to implement fine-grained locking. After it was 62 | + /// finished extracting, it wrote two bytes to indicate it was complete. 63 | + /// It would use the length check to detect if it was possibly interrupted. 64 | + /// 65 | + /// In 1.36, Cargo changed to not use fine-grained locking, and instead used 66 | + /// a global lock. The use of `.cargo-ok` was no longer needed for locking 67 | + /// purposes, but was kept to detect when extraction was interrupted. 68 | + /// 69 | + /// In 1.49, Cargo changed to not create the `.cargo-ok` file before it 70 | + /// started extraction to deal with `.crate` files that inexplicably had 71 | + /// a `.cargo-ok` file in them. 72 | + /// 73 | + /// In 1.64, Cargo changed to detect `.crate` files with `.cargo-ok` files 74 | + /// in them in response to [CVE-2022-36113], which dealt with malicious 75 | + /// `.crate` files making `.cargo-ok` a symlink causing cargo to write "ok" 76 | + /// to any arbitrary file on the filesystem it has permission to. 77 | + /// 78 | + /// In 1.71, `.cargo-ok` changed to contain a JSON `{ v: 1 }` to indicate 79 | + /// the version of it. A failure of parsing will result in a heavy-hammer 80 | + /// approach that unpacks the `.crate` file again. This is in response to a 81 | + /// security issue that the unpacking didn't respect umask on Unix systems. 82 | + /// 83 | + /// This is all a long-winded way of explaining the circumstances that might 84 | + /// cause a directory to contain a `.cargo-ok` file that is empty or 85 | + /// otherwise corrupted. Either this was extracted by a version of Rust 86 | + /// before 1.34, in which case everything should be fine. However, an empty 87 | + /// file created by versions 1.36 to 1.49 indicates that the extraction was 88 | + /// interrupted and that we need to start again. 89 | + /// 90 | + /// Another possibility is that the filesystem is simply corrupted, in 91 | + /// which case deleting the directory might be the safe thing to do. That 92 | + /// is probably unlikely, though. 93 | + /// 94 | + /// To be safe, we deletes the directory and starts over again if an empty 95 | + /// `.cargo-ok` file is found. 96 | + /// 97 | + /// [CVE-2022-36113]: https://blog.rust-lang.org/2022/09/14/cargo-cves.html#arbitrary-file-corruption-cve-2022-36113 98 | fn unpack_package(&self, pkg: PackageId, tarball: &File) -> CargoResult { 99 | // The `.cargo-ok` file is used to track if the source is already 100 | // unpacked. 101 | @@ -645,55 +699,23 @@ impl<'cfg> RegistrySource<'cfg> { 102 | let path = dst.join(PACKAGE_SOURCE_LOCK); 103 | let path = self.config.assert_package_cache_locked(&path); 104 | let unpack_dir = path.parent().unwrap(); 105 | - match path.metadata() { 106 | - Ok(meta) if meta.len() > 0 => return Ok(unpack_dir.to_path_buf()), 107 | - Ok(_meta) => { 108 | - // The `.cargo-ok` file is not in a state we expect it to be 109 | - // (with two bytes containing "ok"). 110 | - // 111 | - // Cargo has always included a `.cargo-ok` file to detect if 112 | - // extraction was interrupted, but it was originally empty. 113 | - // 114 | - // In 1.34, Cargo was changed to create the `.cargo-ok` file 115 | - // before it started extraction to implement fine-grained 116 | - // locking. After it was finished extracting, it wrote two 117 | - // bytes to indicate it was complete. It would use the length 118 | - // check to detect if it was possibly interrupted. 119 | - // 120 | - // In 1.36, Cargo changed to not use fine-grained locking, and 121 | - // instead used a global lock. The use of `.cargo-ok` was no 122 | - // longer needed for locking purposes, but was kept to detect 123 | - // when extraction was interrupted. 124 | - // 125 | - // In 1.49, Cargo changed to not create the `.cargo-ok` file 126 | - // before it started extraction to deal with `.crate` files 127 | - // that inexplicably had a `.cargo-ok` file in them. 128 | - // 129 | - // In 1.64, Cargo changed to detect `.crate` files with 130 | - // `.cargo-ok` files in them in response to CVE-2022-36113, 131 | - // which dealt with malicious `.crate` files making 132 | - // `.cargo-ok` a symlink causing cargo to write "ok" to any 133 | - // arbitrary file on the filesystem it has permission to. 134 | - // 135 | - // This is all a long-winded way of explaining the 136 | - // circumstances that might cause a directory to contain a 137 | - // `.cargo-ok` file that is empty or otherwise corrupted. 138 | - // Either this was extracted by a version of Rust before 1.34, 139 | - // in which case everything should be fine. However, an empty 140 | - // file created by versions 1.36 to 1.49 indicates that the 141 | - // extraction was interrupted and that we need to start again. 142 | - // 143 | - // Another possibility is that the filesystem is simply 144 | - // corrupted, in which case deleting the directory might be 145 | - // the safe thing to do. That is probably unlikely, though. 146 | - // 147 | - // To be safe, this deletes the directory and starts over 148 | - // again. 149 | - log::warn!("unexpected length of {path:?}, clearing cache"); 150 | - paths::remove_dir_all(dst.as_path_unlocked())?; 151 | - } 152 | + match fs::read_to_string(path) { 153 | + Ok(ok) => match serde_json::from_str::(&ok) { 154 | + Ok(lock_meta) if lock_meta.v == 1 => { 155 | + return Ok(unpack_dir.to_path_buf()); 156 | + } 157 | + _ => { 158 | + if ok == "ok" { 159 | + log::debug!("old `ok` content found, clearing cache"); 160 | + } else { 161 | + log::warn!("unrecognized .cargo-ok content, clearing cache: {ok}"); 162 | + } 163 | + // See comment of `unpack_package` about why removing all stuff. 164 | + paths::remove_dir_all(dst.as_path_unlocked())?; 165 | + } 166 | + }, 167 | Err(e) if e.kind() == io::ErrorKind::NotFound => {} 168 | - Err(e) => anyhow::bail!("failed to access package completion {path:?}: {e}"), 169 | + Err(e) => anyhow::bail!("unable to read .cargo-ok file at {path:?}: {e}"), 170 | } 171 | dst.create_dir()?; 172 | let mut tar = { 173 | @@ -757,7 +779,9 @@ impl<'cfg> RegistrySource<'cfg> { 174 | .write(true) 175 | .open(&path) 176 | .with_context(|| format!("failed to open `{}`", path.display()))?; 177 | - write!(ok, "ok")?; 178 | + 179 | + let lock_meta = LockMetadata { v: 1 }; 180 | + write!(ok, "{}", serde_json::to_string(&lock_meta).unwrap())?; 181 | 182 | Ok(unpack_dir.to_path_buf()) 183 | } 184 | diff --git a/src/tools/cargo/tests/testsuite/registry.rs b/src/tools/cargo/tests/testsuite/registry.rs 185 | index daa96d5a8..bd5e42b45 100644 186 | --- a/src/tools/cargo/tests/testsuite/registry.rs 187 | +++ b/src/tools/cargo/tests/testsuite/registry.rs 188 | @@ -2546,7 +2546,7 @@ fn package_lock_inside_package_is_overwritten() { 189 | .join("bar-0.0.1") 190 | .join(".cargo-ok"); 191 | 192 | - assert_eq!(ok.metadata().unwrap().len(), 2); 193 | + assert_eq!(ok.metadata().unwrap().len(), 7); 194 | } 195 | 196 | #[cargo_test] 197 | @@ -2586,7 +2586,7 @@ fn package_lock_as_a_symlink_inside_package_is_overwritten() { 198 | let librs = pkg_root.join("src/lib.rs"); 199 | 200 | // Is correctly overwritten and doesn't affect the file linked to 201 | - assert_eq!(ok.metadata().unwrap().len(), 2); 202 | + assert_eq!(ok.metadata().unwrap().len(), 7); 203 | assert_eq!(fs::read_to_string(librs).unwrap(), "pub fn f() {}"); 204 | } 205 | 206 | @@ -3135,7 +3135,7 @@ fn corrupted_ok_overwritten() { 207 | fs::write(&ok, "").unwrap(); 208 | assert_eq!(fs::read_to_string(&ok).unwrap(), ""); 209 | p.cargo("fetch").with_stderr("").run(); 210 | - assert_eq!(fs::read_to_string(&ok).unwrap(), "ok"); 211 | + assert_eq!(fs::read_to_string(&ok).unwrap(), r#"{"v":1}"#); 212 | } 213 | 214 | #[cargo_test] 215 | @@ -3458,3 +3458,74 @@ fn set_mask_during_unpacking() { 216 | let metadata = fs::metadata(src_file_path("example.sh")).unwrap(); 217 | assert_eq!(metadata.mode() & 0o777, 0o777 & !umask); 218 | } 219 | + 220 | +#[cargo_test] 221 | +fn unpack_again_when_cargo_ok_is_unrecognized() { 222 | + Package::new("bar", "1.0.0").publish(); 223 | + 224 | + let p = project() 225 | + .file( 226 | + "Cargo.toml", 227 | + r#" 228 | + [package] 229 | + name = "foo" 230 | + version = "0.1.0" 231 | + 232 | + [dependencies] 233 | + bar = "1.0" 234 | + "#, 235 | + ) 236 | + .file("src/lib.rs", "") 237 | + .build(); 238 | + 239 | + p.cargo("fetch") 240 | + .with_stderr( 241 | + "\ 242 | +[UPDATING] `dummy-registry` index 243 | +[DOWNLOADING] crates ... 244 | +[DOWNLOADED] bar v1.0.0 (registry `dummy-registry`) 245 | +", 246 | + ) 247 | + .run(); 248 | + 249 | + let src_file_path = |path: &str| { 250 | + glob::glob( 251 | + paths::home() 252 | + .join(".cargo/registry/src/*/bar-1.0.0/") 253 | + .join(path) 254 | + .to_str() 255 | + .unwrap(), 256 | + ) 257 | + .unwrap() 258 | + .next() 259 | + .unwrap() 260 | + .unwrap() 261 | + }; 262 | + 263 | + // Change permissions to simulate the old behavior not respecting umask. 264 | + let lib_rs = src_file_path("src/lib.rs"); 265 | + let cargo_ok = src_file_path(".cargo-ok"); 266 | + let mut perms = fs::metadata(&lib_rs).unwrap().permissions(); 267 | + assert!(!perms.readonly()); 268 | + perms.set_readonly(true); 269 | + fs::set_permissions(&lib_rs, perms).unwrap(); 270 | + let ok = fs::read_to_string(&cargo_ok).unwrap(); 271 | + assert_eq!(&ok, r#"{"v":1}"#); 272 | + 273 | + p.cargo("fetch").with_stderr("").run(); 274 | + 275 | + // Without changing `.cargo-ok`, a unpack won't be triggered. 276 | + let perms = fs::metadata(&lib_rs).unwrap().permissions(); 277 | + assert!(perms.readonly()); 278 | + 279 | + // Write "ok" to simulate the old behavior and trigger the unpack again. 280 | + fs::write(&cargo_ok, "ok").unwrap(); 281 | + 282 | + p.cargo("fetch").with_stderr("").run(); 283 | + 284 | + // Permission has been restored and `.cargo-ok` is in the new format. 285 | + let perms = fs::metadata(lib_rs).unwrap().permissions(); 286 | + assert!(!perms.readonly()); 287 | + let ok = fs::read_to_string(&cargo_ok).unwrap(); 288 | + assert_eq!(&ok, r#"{"v":1}"#); 289 | +} 290 | -- 291 | 2.34.1 292 | 293 | -------------------------------------------------------------------------------- /patches/CVE-2023-38497/0003-fix-clear-cache-for-old-.cargo-ok-format.patch.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | 3 | iQIzBAABCgAdFiEEV2nIi/XdPRSiNKes77mGCudSDawFAmTLWfwACgkQ77mGCudS 4 | Daz66BAApY7RzhExWj4gxTSxdBpumd4Vbs8ZUdPIqhAgo4WCXtEnS+PZ1WRm1IlZ 5 | BLTil+oozVtH7kxStEx6Q/8Tz8lXGol8/trDJ6PwYv6QVOyAHmBTh8y6AFn0pX6f 6 | ENIYufwmgH0a8KNDy2mupQbPx35FavBzW+uCs4V18V937zYiZAV2DAGefB4a7gKo 7 | IC0iilp0sxQOjeUqda21+Kw2faA+H7EnQOcmZzuo8tDc2ZxbdaDP+w95dnaT1SlL 8 | PgWVa6+M1ePpqYZQ/ewmZHn0RVkb0u32oHbOZBcb/Bm7LUXEg3tl6bBqaAzpjhuZ 9 | 0IRFzLjfKAGoLvgX8P1ZB6YKPJK4t3P+Ws6iFPtVfw6W40FjnyJowt+yeQunKzYF 10 | XDgdcOf1QmCa1jsdjBcb7CIgh0dTNIwvFLxaw3ONoRnfSKQ0ZKb13FPV9WnofArG 11 | knvjG+isP/dtTVzyaWrir68ZAJTzq7ao47A4C9uXkMIRyRQFRxcdIslGyDjTrGjZ 12 | GUFFUbfxjSd/WYrsjASchMFY6SLYLL/G2Gpb9+YUdX61Sszgp5owaW2R1M4x8sXn 13 | YlyyclnTAwLh1Jlvh4okMlbVsfIQ77AMeQlWEFVDF5B0MPFJgInNeeHhE67hnthY 14 | re61bS4RonVD5r4DwJOUj0ggDZcgC0G0Owi2kkwGiv+myJEY234= 15 | =jix2 16 | -----END PGP SIGNATURE----- 17 | -------------------------------------------------------------------------------- /patches/CVE-2023-38497/README.md: -------------------------------------------------------------------------------- 1 | # Patches for CVE-2023-38497 2 | 3 | This directory contains the patches for [CVE-2023-38497][cve], to be applied on 4 | top of a Rust 1.71.0 source tarball. 5 | 6 | All the patches are released under both the [MIT license][mit] and the [Apache 7 | 2.0 license][apache]. Signatures from the [Rust Security Response WG's GPG 8 | key][key] are provided. 9 | 10 | [cve]: https://www.cve.org/CVERecord?id=CVE-2023-38497 11 | [mit]: https://github.com/rust-lang/wg-security-response/blob/master/LICENSE-MIT 12 | [apache]: https://github.com/rust-lang/wg-security-response/blob/master/LICENSE-APACHE 13 | [key]: https://www.rust-lang.org/static/keys/rust-security-team.gpg.ascii 14 | -------------------------------------------------------------------------------- /with-rust-security-key.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # This script executes the command provided as argument with the gpg 3 | # environment configured to use the Rust Security team key. Sample usage: 4 | # 5 | # ./with-rust-security-key.sh gpg --clearsign announcement.txt 6 | # 7 | # The script has been tested with GnuPG 2.2, and requires jq and the 1password 8 | # CLI 2.x to be installed and configured: 9 | # 10 | # https://support.1password.com/command-line-getting-started/ 11 | # 12 | # The script is designed to leave no traces of the key on the host system after 13 | # it finishes, but a program with your user's privileges can still interact 14 | # with the key as long as the script is running. 15 | set -euo pipefail 16 | IFS=$'\n\t' 17 | 18 | # Directory where to store the gpg keys 19 | export GNUPGHOME="/dev/shm/rust-gpg" 20 | 21 | # 1password UUIDs to import into the temporary gpg environment 22 | IMPORT_KEYS=( 23 | "op://g2m5dg7bk5pr7fsn732apek2km/e2rq3jfyb35tmtfuofhcm7bo6q/bvtddkvn2nezxf7fwtmqpzwbli" # public.asc 24 | "op://g2m5dg7bk5pr7fsn732apek2km/mn7kdu6hnramxkmxd7a2wrdhlu/ivsclfsno5evvf2da7atnbhc6q" # secret.asc 25 | ) 26 | 27 | # 1password URI of the secret key's password 28 | SECRET_KEY_PASSWORD_URI="op://g2m5dg7bk5pr7fsn732apek2km/6a6doblupfhkjr7wt24li2jpk4/password" 29 | 30 | # ID of the key used to sign Rust releases 31 | SIGNING_KEY_ID="EFB9860AE7520DAC" 32 | 33 | ############################################################################## 34 | 35 | ensure_bin() { 36 | name="$1" 37 | if ! which "${name}" >/dev/null 2>&1; then 38 | echo "the binary $1 is missing!" 39 | exit 1 40 | fi 41 | } 42 | 43 | ensure_bin jq 44 | ensure_bin op 45 | 46 | # Ensure the 1Password `op` version is correct 47 | if ! op --version | grep "^2\." -q; then 48 | echo "The version of the \`op\` command must be 2.*" 49 | exit 1 50 | fi 51 | 52 | # Ensure the 1Password account is configured 53 | op_user="$(op account list --format=json | jq -r '.[] | select(.url == "https://rust-lang.1password.com").user_uuid')" 54 | if [[ "${op_user}" == "" ]]; then 55 | echo "1password is not configured, run this command to set it up:" 56 | echo 57 | echo " op account add --address rust-lang.1password.com" 58 | echo 59 | exit 1 60 | fi 61 | op_session="OP_SESSION_${op_user}" 62 | 63 | # Ensure we're signed into 1password 64 | # ${!op_session} fetches the variable with the name contained in the op_session 65 | # variable. This is because 1Password CLI 2.x session variable names contain 66 | # the user ID in the variable name. 67 | if [[ -z "${!op_session+x}" ]]; then 68 | echo "1password auth session is not present, logging in..." 69 | eval "$(op signin --account rust-lang.1password.com)" 70 | else 71 | echo "reusing 1password auth session" 72 | fi 73 | 74 | # Create the directory if it doesn't exist 75 | if [[ -d "${GNUPGHOME}" ]]; then 76 | echo "${GNUPGHOME} already exist, exiting" 77 | exit 1 78 | fi 79 | mkdir "${GNUPGHOME}" 80 | chmod 0700 "${GNUPGHOME}" 81 | 82 | # Ensure no traces are left on the system 83 | cleanup() { 84 | # Flush the gpg agent cache to remove the password 85 | echo RELOADAGENT | gpg-connect-agent 86 | 87 | # Remove the gpg keys from the local machine 88 | rm -rf "${GNUPGHOME}" 89 | } 90 | trap cleanup EXIT 91 | 92 | # Import the keys into the temporary gpg home 93 | echo "importing the gpg keys inside ${GNUPGHOME}" 94 | for uri in "${IMPORT_KEYS[@]}"; do 95 | op read "${uri}" | gpg --import --armor --batch --pinentry-mode loopback 96 | done 97 | 98 | # Load the password into the gpg agent 99 | passphrase="$(op read "${SECRET_KEY_PASSWORD_URI}")" 100 | echo "dummy" | gpg -u "${SIGNING_KEY_ID}" --pinentry-mode loopback --batch --yes --passphrase "${passphrase}" --sign --armor >/dev/null 101 | 102 | # Execute the user-provided program 103 | echo "running:" "$@" 104 | set +e 105 | "$@" 106 | errorcode="$?" 107 | set -e 108 | 109 | # Make sure to return the correct exit code 110 | exit "${errorcode}" 111 | --------------------------------------------------------------------------------