That’s one of the reasons for which we need the ability to whitelist some trusted crates.
As it were, my proposal is specifically for a whitelist for trusted crates and which
unsafe features of other crates (or
std) they are allowed to use.
Well, the same problem appears with
std::fs, so might as well deal with both in one go.
Although not explicitly stated as such, separating the various unsafe behaviors of
std including I/O subsystems into various “unsafe features” was very much part of the intent of my proposal.
Looking at browser extensions, which have similar permissions system — the permissions do very little. Almost every browser extension needs access to “all data on all websites”, so you just sigh, cringe, click OK, and hope for the best.
With Rust you have
unsafe, native system calls, C libraries (sys crates),
no_mangle and a bunch of other features that can do anything, so any use of any them the permission would have to be “crate can do whatever it wants”.
Indeed, each of these crates would need “permission to do whatever it wants”. However, there aren’t that many crates that need any of this, as far as I can tell.
These unsafe escape hatches are very common things, especially if you look at all dependencies recursively. Any crate that uses any crate that may touch Windows API, random numbers, SIMD acceleration, any
-sys crate, build script, etc.
This creates a new security barrier for these crates, because they not only have to declare their permissions, but also think how their privileges could be abused to escalate other crates’ permissions. It’s a tricky relationship. You may trust
curl crate, because you use it yourself. You may trust
autoupdate crate that uses
curl to update your software. But then what if you install
sneaky-trojan crate that needs no permissions itself, but uses
autoupdate crate with its own URL to exfiltrate data?
Eww. No more lang items please. There are too many of them already which shouldn’t have been.
I feel like some ppl are misunderstanding feature flags and the unsafe lint (which afaik exists).
I probably do. At this stage, I’m not sure how we could both annotate functions/data structures/modules with capabilities-as-feature-flags and still compile the crate accurately and contaminate client crates.
I wonder if there’s a 80% solution here. Maybe we don’t need this for big crates, but could find a version to increase confidence in the many little utility crates that aren’t worth using if you need to audit them.
As a trivial example, I’d never use the default crate if I needed to code audit it – it’s way easier to just re-implement myself. But it also very obviously does nothing scary, in a way that would be nice to expose (and re-confirm when building).
I believe that this is the kind of thing that can be fine-tuned later.
I’m not sure this is a precedent. Nobody has ever broken into my unlocked car, but that doesn’t mean it is a reasonable security policy. How many people have attempted to use an OCaml extention in the MMM web browser to compromise a system?
I think a CSRNG meets the requirements for a lang item, namely:
- Already an important part of the core language
- Low-level primitive with a large variety of potential platform-specific backends which need a common interface (especially on embedded). We’re talking something where on embedded core Rust might need to talk directly to a specific hardware intrinsic (e.g. via a C library)
- Trouble wrapping it up in the crate ecosystem, especially in a way that permits reuse between libcore/libstd and crates
If you have further thoughts on this matter, I’d suggest discussing it on https://github.com/rust-random/rand/issues/648
The main problems with existing
#![forbid(unsafe_code)]is not transitive
As you pointed more or less out in the other recent rust-internals thread on this same subject,
#[no_mangle]can be used for
unsafepurposes without an explicit
Unless there are additional unsafe lints I’m unaware of in the core language, I feel the existing mechanisms aren’t suitable for and are somewhat orthogonal to the proposed goals in this thread.
cargo rustc --min-lint-unsafe_code=forbid (or something - the inverse of what cargo does to lints currently).
additionally: the ability to force the compiler to enable/disable feature flags in a way that code can’t override.
Nightly feature (names) (
#![feature(..)]) are not “stable”, never have been, and never should be. If you’re suggesting using these features to “turn off” features, a) it wouldn’t work for capabilities (most of the language is still
#[stable(feature = "rust1", since = "1.0.0")], including the “dangerous” things in
std::io, etc.) and b) we explicitly don’t want to opt-out of these features, especially if said opt-out is transitive; it’d just lead to language fragmentation, and all of the complaints around default binding modes (match ergonomics) made it clear that this is a firm position that the core team hold.
(If I’m mistaken, and you’re referring to cargo features: the stdlib can’t have cargo features, as both it’s not a cargo dependency and it’s not recompiled locally, plus it goes against the current position of features being transitively additive.)
you enable/disable per-crate and it’s opt-in. and it only applies to the library side of things. and it only applies to the stable features.
my point is the compiler already implements feature flags, we just need to make them usable for this.
fragmentation is a good thing actually.
I think lints should always have non-transitive forms, but clearly many like
#![forbid(unsafe_code)] need transitive forms as well. Also yes some attributes like
#[no_mangle] should be considered, if not unsafe, at least sensitive.
Of all the things you named, the only one which isn’t under the umbrella of
no_mangle. However, if you look at my “unsafe features” proposal, you’ll see I have suggested gating
no_mangle using “unsafe features” as well.