
Secure Rust Guidelines - xmmrm
https://anssi-fr.github.io/rust-guide/
======
CJefferson
I personally strongly disagree with:

Functions or instructions that can cause the code to panic at runtime must not
be used.

First of all, they kind of dodge this later by saying "Array indexing must be
properly tested" (else it can panic) -- everyone thinks they write code which
is "properly tested".

Personally, I often write panicing code -- if the code gets in a state where I
have no idea how to fix it, I panic. For some code it is important it does
quit, but I'd much prefer more code paniced than tried to carry on and ended
up creating other problems.

Also, in rust if we don't want to panic we need to never use array indexing
and never use integer division, just to start.

Of course, it's fine to write code which plans to never panic, but I think it
would be better to say "Have a formal 'panic plan'", where either one panics
early, or tries to never panic.

~~~
masklinn
> First of all, they kind of dodge this later by saying "Array indexing must
> be properly tested" (else it can panic) -- everyone thinks they write code
> which is "properly tested".

You're skipping half the recommendation though:

> Array indexing must be properly tested, _or the get method should be used to
> return an Option_.

emphasis mine

> Also, in rust if we don't want to panic we need to never use array indexing
> and never use integer division, just to start.

I mean, that's literally the block above the one you quote:

> Common patterns that can cause panics are:

> * using unwrap or expect,

> * using assert,

> * an unchecked access to an array,

> * integer overflow (in debug mode),

> * division by zero,

> * large allocations,

> * string formatting using format!.

>> Rule LANG-NOPANIC

>> Functions or instructions that can cause the code to panic at runtime must
not be used.

The bit you quote is really a additional reminder that array indexing is not
panic-safe.

~~~
SkyMarshal
_You 're skipping half the recommendation though:_

 _> Array indexing must be properly tested, or the get method should be used
to return an Option._

Fwiw, for anyone who’s dabbled with Haskell this is SOP. Any result that could
be undefined is returned as a Maybe (Haskell’s version of Option). If this
seems odd to anyone, understanding it in Haskell will probably help understand
it better in Rust too:

[http://learnyouahaskell.com/a-fistful-of-monads#getting-
our-...](http://learnyouahaskell.com/a-fistful-of-monads#getting-our-feet-wet-
with-maybe)

[https://en.wikibooks.org/wiki/Haskell/Understanding_monads/M...](https://en.wikibooks.org/wiki/Haskell/Understanding_monads/Maybe)

~~~
geofft
Er, don't Haskell's head and (!!) functions default to throwing an exception?

    
    
        $ ghci
        Prelude> let a = [3, 4, 5]
        Prelude> a !! 0
        3
        Prelude> a !! 3
        *** Exception: Prelude.(!!): index too large
        
        Prelude> head []
        *** Exception: Prelude.head: empty list
    

I don't think Haskell is really different from Rust in this respect. Both have
a wrapper type for optional values with good syntax, but in both, there's
still _some_ syntax so common operations sometimes choose to skip it.

In fact, Hoogle doesn't seem to find me a function like Rust's .get() in the
standard library, just a handful of third-party packages:
[https://hoogle.haskell.org/?hoogle=%5Ba%5D+-%3E+Int+-%3E+May...](https://hoogle.haskell.org/?hoogle=%5Ba%5D+-%3E+Int+-%3E+Maybe+a&scope=set%3Astackage)

~~~
EvilTerran
> Hoogle doesn't seem to find me a function like Rust's .get() in the standard
> library

In practice, you don't really need one - the safe alternative to "xs !! n" is
pattern-matching on the result of "drop n xs", as that's [] if xs has ≤n
elements:

[https://www.haskell.org/onlinereport/standard-
prelude.html#$...](https://www.haskell.org/onlinereport/standard-
prelude.html#$vdrop)

~~~
geofft
Sure, that seems syntactically more cumbersome than 'if let Some(foo) =
xs.get(n)' or 'xs.get(n).map(|foo| ...)' in Rust, but yes, you can do it. As I
said, because _both_ the Rust and Haskell versions are more cumbersome than
using the version that raises an exception/panics, _both_ Rust and Haskell's
standard libraries choose to give you a syntactically-easier alternative that
isn't a total function.

All I'm saying is that Haskell doesn't seem to do anything different here -
Rust has incorporated the lessons from Haskell's type system. (As someone who
fell in love with Haskell a long time ago but never got to use it
professionally, this is basically why I like Rust.) Is there something Haskell
does _that Rust does not do_? I'm not trying to say Haskell is insufficient -
I'm just refuting the claim that Rust is insufficient and should act more like
Haskell.

~~~
EvilTerran
Sure, I don't disagree - I meant only to add context for anyone reading who
was unfamiliar with Haskell, lest they come away with the impression that the
lack of a .get()-equivalent was some kind of egregious oversight.

------
gardaani
I'm having problems fulfilling this requirement in my libs: "Crates providing
libraries should never use functions or instructions that can fail and cause
the code to panic."

The Rust standard library Vec, HashMap etc. can cause a panic in Rust, if the
device (such as a mobile phone with a small memory) runs out of memory.

C and C++ standard libraries (malloc, std::vector, std::map..) can handle
those situations by returning null or throwing an exception.

I wish Rust had some easy way to recover from out-of-memory situations when
using the standard library. I have been considering writing my own out-of-
memory safe Vec, HashMap etc, but it can't be the right way to do it..

~~~
masklinn
Yes that is one of the primary failures of Rust at the moment: to my knowledge
it currently has no good way to safely manage allocation failures (it also has
serious issues with stack overflows).

This is an issue with all heap-allocating construct, not just collections but
also Box or Rc.

> I wish Rust had some easy way to recover from out-of-memory situations when
> using the standard library. I have been considering writing my own out-of-
> memory safe Vec, HashMap etc, but it can't be the right way to do it..

Maybe look at the embedded space there? There might be no_std third-party
libraries which handle these issues. Possibly on top of alloc as the
(unstable[0] and obviously unsafe) `Alloc` trait does have a concept of
allocation failure.

[0] [https://github.com/rust-lang/rust/issues/32838](https://github.com/rust-
lang/rust/issues/32838)

~~~
steveklabnik
> Yes that is one of the primary failures of Rust at the moment: to my
> knowledge it currently has no good way to safely manage allocation failures

So, sort of yes and sort of no.

The data structures that allocate in the standard library do not let you
handle allocation failure. However, if you write your own, the global
allocator lets you determine if failure happened, and then you can do whatever
you want with it.

~~~
rectang
I think Rust got it right, here.

Dealing with allocation failure _gracefully_ is hard and requires a lot of
extra code.

For most applications the best default is to panic and handle it up the stack
rather than pay the programming overhead of handling allocation failure
explicitly in every last nook and cranny. The Rust standard library rightly
optimizes for this use case.

For the embedded or critical-safety application spaces, where you really do
want to handle allocation failure gracefully, you need something other than
the standard library. Letting that "something" develop slowly out in the
community is a good call.

------
maeln
This is published by the ANSSI[1], National Cybersecurity Agency of France.
They do quite a good job at publishing security guide.

[1] [https://www.ssi.gouv.fr/en/](https://www.ssi.gouv.fr/en/)

------
dathinab
I found at least one problematic section when scanning:

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

This is simply not true at all. Mainly build cache systems like sccache work
by wrapping rustc, there is no reason why using a build cache should be
forbidden.

(Through currently rust support of sccache is still not perfect and there are
some limitations, doesn't change that the rules are to broad.)

I also wouldn't be surprised if there are some rustc flags not exposed in
cargo profiles which allow trigger some security mechanisms in llvm which are
not enabled by default but beneficial for your project.

Like always the important think is that you understand what you do and want
implications it had.

------
imjasonmiller
The context that I was missing at first:

> The Agence nationale de la sécurité des systèmes d'information (ANSSI;
> English: National Cybersecurity Agency of France) is a French service
> created on 7 July 2009 with responsibility for computer security [1].

I didn't know about "cargo-outdated". I liked having "npm outdated" within the
JavaScript ecosystem, so I'll give this a try.

1\.
[https://en.wikipedia.org/wiki/Agence_nationale_de_la_s%C3%A9...](https://en.wikipedia.org/wiki/Agence_nationale_de_la_s%C3%A9curit%C3%A9_des_syst%C3%A8mes_d%27information)

~~~
jamwaffles
`cargo-outdated` is mint. If you haven't already, consider installing `cargo-
edit` too! It adds `cargo add`/`cargo rm` to add/remove crates, as well as
`cargo upgrade` to bump semver versions.

[https://github.com/killercup/cargo-edit](https://github.com/killercup/cargo-
edit)

~~~
masklinn
There's also cargo-crev which is pretty neat.

