Rust in Chromium

Why?

Handling untrustworthy data in non-trivial ways is a major source of security bugs, and it‘s therefore against Chromium’s security policies to do it in the Browser or Gpu process unless you are working in a memory-safe language.

Rust provides a cross-platform memory-safe language so that all platforms can handle untrustworthy data directly from a privileged process, without the performance overheads and complexity of a utility process.

Status

The Rust toolchain is enabled for and supports all platforms and development environments that are supported by the Chromium project. The first milestone to include full production-ready support was M119.

Rust is approved by Chrome ATLs for production use in certain third-party scenarios.

For questions or help, reach out to rust-dev@chromium.org or #rust on the Chromium Slack.

If you use VSCode, we have additional advice below.

Adding a third-party Rust library

Third-party libraries are pulled from crates.io, but Chromium does not use Cargo as a build system.

Third-party review

All third-party crates need to go through third-party review. See //docs/adding_to_third_party.md for instructions on how to have a library reviewed.

Importing a crate from crates.io

The //third_party/rust/third_party.toml crate defines the set of crates depended on from first-party code. Any transitive dependencies will be found from those listed there. The file is a subset of a standard Cargo.toml file, but only listing the [dependencies] section.

To use a third-party crate “bar” version 3 from first party code, add the following to //third_party/rust/third_party.toml in [dependencies]:

[dependencies]
bar = "3"

To enable a feature “spaceships” in the crate, change the entry in //third_party/rust/third_party.toml to include the feature:

[dependencies]
bar = { version = "3", features = [ "spaceships" ] }

Generating BUILD.gn files for third-party crates

To generate BUILD.gn files for all third-party crates, and find missing transitive dependencies to download, use the gnrt tool:

  1. Change directory to the root src/ dir of Chromium.
  2. Run vpython3 ./tools/crates/run_gnrt.py gen to build and run gnrt with the gen action.

Or, to directly build and run gnrt with the system Rust toolchain:

  1. Change directory to the root src/ dir of Chromium.
  2. Build and run gnrt gen: cargo run --release --manifest-path tools/crates/gnrt/Cargo.toml --target-dir out/gnrt gen.

This will generate a BUILD.gn file for each third-party crate. The BUILD.gn file changes will be visible in git status and can be added with git add.

Downloading missing third-party crates

To download crate “foo”, at version 4.2.3:

  1. Change directory to the root src/ dir of Chromium.
  2. Run gnrt with the download action. e.g. vpython3 ./tools/crates/run_gnrt.py download --security-critical=yes --shipped=yes foo 4.2.3

This will download the crate and unpack it into //third_party/rust/foo/v4/crate. The entire v4 directory, which includes the crate subdirectory as well as a generated README.chromium file, should be added to the repository with git add third_party/rust/foo/v4.

Once all the crates are downloaded and gnrt gen completes, a CL can be uploaded to go through third-party review.

Patching third-party crates.

You may patch a crate in tree, but save any changes made into a diff file in a patches/ directory for the crate. The diff file should be generated by git-format-patch each new patch numbered consecutively so that they can be applied in order. For example, these files might exist if the “foo” crate was patched with a couple of changes:

//third_party/rust/foo/v4/patches/0001-Edit-the-Cargo-toml.diff
//third_party/rust/foo/v4/patches/0002-Other-changes.diff

The recommended procedure to create such patches is:

  1. Commit the plain new version of the crate to your local git branch
  2. Modify the crate as necessary
  3. Commit that modified version
  4. Use git format-patch <unpatched version> to generate the patch files
  5. Add the patch files in a new, third, commit
  6. Squash them, or rely on git cl upload doing so

Updating existing third-party crates

To update a crate “foo” to the latest version you must just re-import it at this time. To update from version “1.2.0” to “1.3.2”:

  1. Remove the //third_party/rust/foo/v1/crate directory, which contains the upstream code.
  2. Re-download the crate at the new version with out/gnrt/release/gnrt download foo 1.3.2.
  3. If there are any, re-apply local patches with for i in $(find third_party/rust/foo/v1/patches/*); do patch -p1 < $i; done
  4. Run vpython3 ./tools/crates/run_gnrt.py gen to re-generate all third-party BUILD.gn files.
  5. Build all_rust to verify things are working.

Directory structure for third-party crates

The directory structure for a crate “foo” version 3.4.2 is:

//third_party/
    rust/
        foo/
            v3/
                BUILD.gn  (generated by gnrt gen)
                README.chromium  (generated by gnrt download)
                crate/
                    Cargo.toml
                    src/
                    ...etc...
                patches/
                    0001-Edit-the-Cargo-toml.diff
                    0002-Other-changes.diff

Writing a wrapper for binding generation

Most Rust libraries will need a more C++-friendly API written on top of them in order to generate C++ bindings to them. The wrapper library can be placed in //third_party/rust/<cratename>/<epoch>/wrapper or at another single place that all C++ goes through to access the library. The CXX is used to generate bindings between C++ and Rust.

See //third_party/rust/serde_json_lenient/v0_1/wrapper/ and //components/qr_code_generator for examples.

Rust libraries should use the rust_static_library GN template (not the built-in rust_library) to integrate properly into the mixed-language Chromium build and get the correct compiler options applied to them.

The CXX tool is used for generating C++ bindings to Rust code. Since it requires explicit declarations in Rust, an wrapper shim around a pure Rust library is needed. Add these Rust shims that contain the CXX bridge macro to the cxx_bindings GN variable in the rust_static_library to have CXX generate a C++ header for that file. To include the C++ header file, rooted in the gen output directory, use

#include "the/path/to/the/rust/file.rs.h"

Using VSCode

  1. Ensure you're using the rust-analyzer extension for VSCode, rather than earlier forms of Rust support.
  2. Run gn with the --export-rust-project flag, such as: gn gen out/Release --export-rust-project.
  3. ln -s out/Release/rust-project.json rust-project.json
  4. When you run VSCode, or any other IDE that uses rust-analyzer it should detect the rust-project.json and use this to give you rich browsing, autocompletion, type annotations etc. for all the Rust within the Chromium codebase.