Development environment

Rustup

Rustup is the Rust toolchain installer. Among other things, it enables switching between different flavors of the toolchain (stable, beta, nightly), managing additional components installation and keeping them up to date.

Warning

From a security perspective, rustup does perform all downloads over HTTPS, but does not yet validate signatures of downloads. Protection against downgrade attacks, certificate pinning, validation of signatures are still works in progress. In some cases, it may be preferable to opt for an alternative installation method listed in the Install section of the official Rust website.

Rust Editions

Several flavors, called editions, of the Rust language coexist.

The concept of editions has been introduced to clarify new features implementation and to make them incremental. A new edition will be produced every two or three years, as stated in the Edition Guide, but this doesn’t mean that new features and improvements will only be shipped in a new edition.

Some editions bring new keywords and language constructs. Recommendations for secure applications development then remain closely linked to features of the language, that are used in such applications, rather than to Rust editions. In the rest of this guide, best effort will be made to highlight constructions and language features that are specific to a particular Rust edition.

Note

No specific edition is recommended, as long as users follow the recommendations related to the features offered by the edition that has been chosen.

Stable, nightly and beta toolchains

Orthogonally to editions that allow one to select a flavor (a set of features) of the Rust language, the Rust toolchain is provided in three different versions, called release channels:

  • nightly releases are created once a day,
  • beta releases are created every six weeks, from promoted nightly releases,
  • stable releases are created every six weeks, from promoted beta releases.

When playing with different toolchains, it is important to check not only what the default toolchain is, but also if overrides are currently set for some directories.

$ pwd
/tmp/foo
$ rustup toolchain list
stable-x86_64-unknown-linux-gnu (default)
beta-x86_64-unknown-linux-gnu
nightly-x86_64-unknown-linux-gnu
$ rustup override list
/tmp/foo                                    nightly-x86_64-unknown-linux-gnu
$

Rule DENV-STABLE

Development of a secure application must be done using a fully stable toolchain, for limiting potential compiler, runtime or tool bugs.

When using a specific cargo subcommand that requires a nightly component, it is preferable to run it by switching the toolchain only locally, instead of explicitly switching the complete toolchain. For example, to run the (nightly) latest rustfmt:

$ rustup toolchain list
stable-x86_64-unknown-linux-gnu (default)
beta-x86_64-unknown-linux-gnu
nightly-x86_64-unknown-linux-gnu
$ rustup run nightly cargo fmt
$ # or
$ cargo +nightly fmt
$

Cargo

Once Rustup has set up the appropriate Rust toolchain, Cargo is available through the command line program cargo. Cargo is the Rust package manager. It has a fundamental role in most Rust development:

  • It structures project by providing the project skeleton (cargo new),
  • It compiles the project (cargo build),
  • It generates the project's documentation (cargo doc),
  • It runs tests (cargo test) and benchmarks (cargo bench),
  • It manages and download dependencies,
  • It makes packages distributable and publishes them on crates.io,
  • It’s also a front-end to run complementary tools such as those that are described below, in the form of sub-commands.

Warning

Like rustup, cargo does perform all downloads over HTTPS, but does not validate the registry index. Ongoing discussions occur on how to best protect and verify crates. For now, the security relies on the good security of the website crates.io and the GitHub hosted repository containing the registry index. In some cases, it may be preferable to opt for an alternative installation method for dependencies.

Cargo proposes many different commands and options to adapt the build process to your project needs, mainly through the manifest file Cargo.toml. For a complete presentation, see The Cargo Book.

During the development of a secure application, some of the options may require some attention. The [profile.*] sections allow configuring how the compiler is invoked. For example:

  • the debug-assertions variable controls whether debug assertions are enabled,
  • the overflow-checks variable controls whether overflows are checked for integer arithmetic.

Overriding the default options may cause bugs not being detected, even when using the debug profile that normally enables runtime checks (for example integer overflow checks).

Rule DENV-CARGO-OPTS

The variables debug-assertions and overflow-checks must not be overridden in development profiles sections ([profile.dev] and [profile.test]).

Cargo proposes other ways to setup its configuration and change its behavior on a given system. This can be very useful, but it may also be difficult to know and remember at a given time all the options that are effectively used, and in particular passed to the compiler. At the end, this can affect the confidence and robustness of the build process. It is preferable to centralize compiler options and flags in the configuration file Cargo.toml. For the case of environment variable RUSTC_WRAPPER, for example, that may be used to generate part of code or to run external tools before Rust compilation, it is preferable to use the Cargo build scripts feature.

Rule DENV-CARGO-ENVVARS

The environment variables RUSTC, RUSTC_WRAPPER and RUSTFLAGS must not be overriden when using Cargo to build the project.

Clippy

Clippy is a tool that provides and checks many lints (bugs, styling, performance issues, etc.). Since version 1.29, clippy can be used within the stable rustup environment. It is recommended to install clippy as a component (rustup component add clippy) in the stable toolchain instead of installing it as a project dependency.

The tool comes with some lint categories regarding the kind of issues it aims to detect. The warnings should be re-checked by the programmer before committing the fix that is suggested by clippy, especially in the case of lints of the category clippy::nursery since those hints are still under development.

Rule DENV-LINTER

A linter, such as clippy, must be used regularly during the development of a secure application.

Rustfmt

Rustfmt is a tool that formats your code according to style guidelines. The documentation of the tool states some limitations, among others partial support of macro declarations and uses. One should use the --check option that prints proposed changes, review these changes, and finally apply them if the code readability is not affected.

So, to launch it:

$ cargo fmt -- --check
$ # review of the changes
$ cargo fmt

These guidelines can be customized to your needs by creating a rustfmt.toml or .rustfmt.toml file at the root of your project. It will be used to override the default settings, for instance:

# Set the maximum line width to 120
max_width = 120
# Maximum line length for single line if-else expressions
single_line_if_else_max_width = 40

For more information about the guidelines that rustfmt will check, have a look at the Rust Style Guide.

Rule DENV-FORMAT

The tool rustfmt can be used to ensure that the codebase respects style guidelines (as described in rustfmt.toml file), with --check option and manual review.

Rustfix

Included with Rust, since the end of 2018, Rustfix is a tool dedicated in fixing compiler warnings as well as easing transitions between editions.

$ cargo fix

To prepare a Rust 2015 project to transition to Rust 2018, one can run:

$ cargo fix --edition

Rustfix will either fix the code to be compatible with Rust 2018 or print a warning that explains the problem. This problem will have to be fixed manually. By running the command (and possibly fixing manually some issues) until there is no warning, one can ensure the code is compatible with both Rust 2015 and Rust 2018.

To switch definitely to Rust 2018, one may run:

$ cargo fix --edition-idioms

Be advised that this tool provides few guarantees on the soundness of the proposed fixes. In particular mode, some corrections (such as some of those provided with the --edition-idioms) are known to break the compilation or change the program semantics in some case.

Rule DENV-AUTOFIX

In a secure Rust development, any automatic fix (for instance, provided by rustfix) must be verified by the developer.

Others

There exist other useful tools or cargo subcommands for enforcing program security whether by searching for specific code patterns or by providing convenient commands for testing or fuzzing. They are discussed in the following chapters, according to their goals.