Cargo CVE-2022-46176 fix for older releases

Hello,

The CVE-2022-46176 is fixed on 1.66.1 version (Security advisory for Cargo (CVE-2022-46176) | Rust Blog). Is there a plan to release such fixed version for older releases as well? Let us know the timeline if it is going to be fixed on older releases.

Thanks, Sundeep K.

Note: This is only my personal interpretation of the situation, based on my personal general knowledge about Rust and the blog post you linked.

As the blog post you linked explained, this is only being fixed on the latest stable release, 1.66.1. Rust follows semantic versioning, so every user can simply update to 1.66.1. Essentially, this means that yes there are fixes on older releases, the fix is called “version 1.66.1”, just use it! This approach should pose no problems, since all rust versions since 1.0 are the same semver-compatible versions. You can simply upgrade from any Rust version to 1.66.1 and should not expect any breakage.

Reasons why you can’t upgrade nonetheless might include

  • (possibly arbitrary/nonsensical) requirements set up by people who don’t understand Rust’s versioning
    • if there is any concrete reason why you cannot simply use 1.66.1 that does have good (i.e. not arbitrary/nonsensical) reasons, feel free to share more details; I could always have overlooked something
  • you are not using the toolchain published by rustup
    • this might be for example because you are using a toolchain distributed by a linux distribution that wants to be more “stable” by avoiding frequent rustc upgrades
    • in this case, there are patches (for 1.66.0) available, as the blog post explains, and the maintainers of the distribution would be responsible for adapting and including those patches

If all this doesn’t help, or you need some time to upgrade to 1.66.1 (or newer), the “Mitigations” section in the blog post lays out one more alternative approach.

7 Likes

The Rust project only provides security fixes for the current stable version (in this case Rust 1.66.x), and we explicitly do not support older Rust versions.

If you need support for older versions you should use a third-party distribution (a Linux distribution, or a commercial solution) or backport the patches yourself to the older version you care about.

7 Likes

Thanks for your comments. @sundeep-kokkonda and I work on the Yocto Project https://www.yoctoproject.org/ an embedded Linux distribution build system that lets you create your own customized linux distro. Is there a set of tests that prove that any code what works with say Rust-1.59 will work with Rust-1.66.1 ? If there were, then we'd be more willing to consider upgrading rather than back-porting the patches provided. Are you aware, off-hand, of any non-rolling Linux distros that are updating to the latest stable rust release rather than pinning the version?

There's no specific test to point at, but before each release (as well as on specific risky patches) the Rust project uses a tool called Crater to compile and test every single crate on crates-io to catch basically any potential regressions. There's also plans to allow companies a way to subscribe to Crater runs and test their own proprietary code as well.

7 Likes

I maintain Fedora's toolchain, always updating to the latest stable Rust, even on the older of the two active Fedora release branches. I also maintain RHEL's toolchain, and we don't update for every Rust release, but spaced further on our y-stream updates, roughly 6 months apart.

3 Likes

Any code that works with e.g. 1.59 should work with 1.66.1. (Perhaps with some minor caveats that I go into below.) The compiler has an extensive test suite testing behavior of code doesn’t change, and as @CAD97 mentioned, the “crater” tool tests a huge amount of crates for each release. It’s more than just the crates on crates.io, it also includes public projects on GitHub. E.g. the 1.66 run tested a total of 247.167 crates; crates.io only has 102.099 as of today. Testing means not only testing whether the code compiles, but also running the test suite of the each crate. The goal is of course not that every test suite of every crate succeeds, but rather that no compilation and no test regresses (as in: works previously, no loger works afterwards).

Now, caveats w.r.t. rustc stability guarantees include, off the top of my head:

  • There are occasionally minor intentionally breaking changes if this is necessary to fix a language bug. Mostly, such changes would only be done when the language had a soundness issue (“soundness” refers to the memory safety guarantees in safe Rust). Also sometimes a change to fix some bug is considered to have so minor breakage that it seems reasonable to assume that no users should be affected. In either case, of course crater is involved, too, to validate that there really are no known affected users in the latter case; or in case of soundness issues being fixed, in order to ensure that the breakage is kept as small as possible, and all popular libraries are unaffected or fixed.
  • New Rust releases of course also contain new features. As such, while the testing for stability is extensive as explained above, the risk of introducing new bugs is naturally still higher when new features are implemented, compared to what some bug-fixes-only / long-time-support stagnant stable version could offer. Ultimately, it is also a question of “how much effort would this be to maintain and what are the benefits?” trade-off for why the Rust project itself does not maintain one (or many!?) separate “long-time-support” stagnant stable versions. There is no principled reason why supporting such a version would necessarily be bad.[1]
  • In the context of library-semver-compatibility in Rust there are certain changes that are merely “considered not breaking” or “acceptable breakage” because they technically cause breakage in user code. A typical setting is: When user code has glob-imports (“use some_module::*;”) from multiple sources, then if some_module introduces any new items, those could potentially lead to naming conflicts/ambiguity. Still, it is considered acceptable for libraries to introduce new API without that being considered a “breaking change”. (Some further details on what is or isn’t considered breaking library changes.) Since the standard library is a library, these concerns do transfer to rustc itself. However, again, of course, such effects are also monitored with the crater test runs, and the standard library will never just blindly claim “this is fine” based on theoretical “something like this is considered acceptable” claims but instead is more careful with any such changes that could actually affect any reasonable user-code. E.g. the example of problems with using ::* in imports too much leads to recommendations that reasonable/good code should generally avoid such imports (except for crate-internal usage, or with modules intentionally designed to be imported this way).
  • New rust versions can introduce new warnings. If users turn warnings into errors in their builds, then such builds can stop working with new rust versions. This would be considered mostly of a mis-use by the users; e.g. erroring out on warnings in CI can be problematic for this reason, whereas any one-off actions with user-interaction, e.g. pre-commit hooks or automatic testing when PRs are reviewed, can very reasonably fail on warnings, because no-one expects those operations to be re-done automatically at a later time.

  1. Well… depends on the use-case of course. For merely reproducing builds of applications, there is no issue with using older Rust versions, only updated for security issues. For practical Rust development work, there are actual downsides: Rust’s story of allowing crates to specify what “minimal supported Rust version” they work with is still sub-optimal, and many crates assume they can introduce code relying on newer rustc features in minor library version bumps. This means that, unless you locked your dependency versions (which is default behavior for applications), there is potential for breakage in builds if you don’t update rustc regularly enough. On the other hand, locking minor versions of dependencies for too long can in principle be problematic if you are interested in receiving patch-releases of libraries that might be relevant to security. So well… at least, the situation would need to be monitored, and locked library dependencies that are needing to be updated would need to be tested against the old compiler version that’s used. ↩︎

5 Likes

Just a small clarification to this: if you're using cargo for builds, upstream dependencies cannot turn lints into errors. Cargo uses a rustc flag to cap lint levels to warn when building non-workspace-local crates.

General best practice at the moment seems to be to never use #![deny(warnings)]/-Dwarnings on a stable/rolling toolchain CI build, but that if you have a toolchain version pinned CI (e.g. an MSRV build), using -Dwarnings there is acceptable and potentially desirable. (The expectation being that the patch to update the pinned version would also resolve any newly erroring warnings.)

5 Likes

You can use fetch-with-cli as a workaround: Configuration - The Cargo Book

But Rust 1.66.0 and every older version is obsolete and unsupported. The only way is to upgrade to the only one supported version.

Thanks for the excellent explanation.

I see the crater github repo but I haven't been able to find any summaries showing the result of running crater. In the ideal case, it would just say everything compile with no errors and no new warnings but it would be re-assuring to see that or to see cases where a change did in fact cause a regression and that was addressed.

I hope and expect that with that data, I'll be able to convince other people in the Yocto community to do the right thing and follow the latest 1.x release.

  • Thanks in advance.

You can find a sample of crater reports from this issue for 1.67:

And for the actual report, it is linked in the last comment of that thread.

You can see an example of the kind of breakage that is explicitly considered acceptable and you might encounter, but they are always either bugs (that weren't being exercised by either crater or the test suite) or soundness fixes. To see regressions that have been addressed, you can look at the tickets labeled stable-to-beta regression and stable-to-nightly regression, but I would guess that the majority of them weren't detected through crater, instead by end user reports. You can also look at the tickets labeled as stable-to-stable regressions to get a feel for the kind of breakage that you can expect. The closed ones can give you an idea of things that might have you skipping a release or two, while the open ones are the ones that you'd likely be concerned about.

1 Like