Patching Vendored Rust Dependencies

Recently I had a difficult time trying to patch a CVE in librsvg. The issue itself was simple to patch because Federico kindly backported the series of commits required to fix it to the branch we are using downstream. Problem was, one of the vendored deps in the old librsvg tarball did not build with our modern rustc, because the code contained a borrow error that was not caught by older versions of rustc. After finding the appropriate upstream fix, I tried naively patching the vendored dep, but that failed because cargo tries very hard to prevent you from patching its dependencies, and complains if the dependency does not match its checksum in Cargo.lock. I tried modifying the checksum in Cargo.lock, but then it complains that you modified the Cargo.lock. It seems cargo is designed to make patching dependencies as difficult as possible, and that not much thought was put into how cargo would be used from rpmbuild with no network access.

Anyway, it seems the kosher way to patch Rust dependencies is to add a [patch] section to librsvg’s Cargo.toml, but I could not figure out how to make that work. Eventually, I got some help: you can edit the .cargo-checksum.json of the vendored dependency and change “files” to an empty array, like so:

diff --git a/vendor/cssparser/.cargo-checksum.json b/vendor/cssparser/.cargo-checksum.json
index 246bb70..713372d 100644
--- a/vendor/cssparser/.cargo-checksum.json
+++ b/vendor/cssparser/.cargo-checksum.json
@@ -1 +1 @@
\ No newline at end of file

Then cargo will stop complaining and you can patch the dependency. Success!

5 Replies to “Patching Vendored Rust Dependencies”

  1. I encountered the same issue some months ago, and wasn’t able to find a workable solution. Thanks!

    However, did you take the time to report this issue with a proposal of enhancement against cargo? I didn’t at the time because I thought I was trying to do a very niche thing, but it seems more widespread than I thought.

    1. I didn’t report it. I guess someone involved in the Rust community might want to do that.

  2. Language package managers are catering to their restricted audience, which allows them to ignore the broader ecosystem. I assume they didn’t have rpmbuild or any other generic build system in mind. It’s always lucky when language package managers reinvent the wheel just right, as in not making it too hard for generic package managers. There’s the occasional bump in the road for sure. Besides the bump you’ve hit I remember a few years back Guix trying to create ruby packages. It was very hard; they tried repurposing ruby gems but they are akin to binary outputs, as they often don’t contain tests or docs, just the plain sources. That clashed with Guix’ requirements, among them that tests be run. I don’t remember the outcome.

  3. You add the patch section *to the thing that’s going to be using the patched dependency*. That is, you don’t say “here, this is a libsrvg that is patched”, you say “this package is going to depend on this patched libsvrg instead of the usual one.”

Comments are closed.