Unsafe Rust in dependencies
I noticed that ./crates/sel4-platform-info/Cargo.toml depends on serde and serde_yaml which in turn depends on unsafe_libyaml which is a c2rust transpiled unsafe Rust code (which is kind of cool):
cargo tree --manifest-path ./crates/sel4-platform-info/Cargo.toml
...
├── serde v1.0.185 (*)
└── serde_yaml v0.9.25
├── indexmap v2.0.0
│ ├── equivalent v1.0.1
│ └── hashbrown v0.14.0
├── itoa v1.0.9
├── ryu v1.0.15
├── serde v1.0.185 (*)
└── unsafe-libyaml v0.2.9
But the real question is - how much time/effort we should put into using tools like cargo-geiger and other maintained by the Rust secure Code WG to increase the trust in the Rust userspace code?
I don't have any great answers, just would like to raise the visibility of this issue!
I went ahead and had some fun with cargo audit:
rust-sel4$ cargo audit --quiet
Crate: libgit2-sys
Version: 0.14.1+1.5.0
Title: git2 does not verify SSH keys by default
Date: 2023-01-20
ID: RUSTSEC-2023-0003
URL: https://rustsec.org/advisories/RUSTSEC-2023-0003
Solution: Upgrade to >=0.13.5, <0.14.0 OR >=0.14.2
Dependency tree:
libgit2-sys 0.14.1+1.5.0
├── git2 0.16.0
│ ├── git2-curl 0.17.0
│ │ └── cargo 0.70.1
│ │ └── cargo-helpers 0.1.0
│ └── cargo 0.70.1
└── cargo 0.70.1
Crate: time
Version: 0.1.45
Title: Potential segfault in the time crate
Date: 2020-11-18
ID: RUSTSEC-2020-0071
URL: https://rustsec.org/advisories/RUSTSEC-2020-0071
Severity: 6.2 (medium)
Solution: Upgrade to >=0.2.23
Dependency tree:
time 0.1.45
└── chrono 0.4.26
└── mbedtls-platform-support 0.3.0
├── tests-root-task-mbedtls 0.1.0
└── mbedtls 0.11.0
├── tests-root-task-mbedtls 0.1.0
├── sel4-async-network-mbedtls 0.1.0
│ ├── tests-root-task-c 0.1.0
│ └── microkit-http-server-example-server-core 0.1.0
│ └── microkit-http-server-example-server 0.1.0
└── microkit-http-server-example-server-core 0.1.0
Crate: memmap
Version: 0.7.0
Warning: unmaintained
Title: memmap is unmaintained
Date: 2020-12-02
ID: RUSTSEC-2020-0077
URL: https://rustsec.org/advisories/RUSTSEC-2020-0077
Dependency tree:
memmap 0.7.0
└── sel4-backtrace-cli 0.1.0
Crate: rusttype
Version: 0.9.3
Warning: unmaintained
Title: rusttype is Unmaintained
Date: 2021-04-01
ID: RUSTSEC-2021-0140
URL: https://rustsec.org/advisories/RUSTSEC-2021-0140
Dependency tree:
rusttype 0.9.3
└── banscii-assistant-core 0.1.0
├── banscii-assistant-core-test 0.1.0
└── banscii-assistant 0.1.0
Crate: atty
Version: 0.2.14
Warning: unsound
Title: Potential unaligned read
Date: 2021-07-04
ID: RUSTSEC-2021-0145
URL: https://rustsec.org/advisories/RUSTSEC-2021-0145
Dependency tree:
atty 0.2.14
└── clap 3.2.25
├── sel4-render-elf-with-data 0.1.0
│ ├── sel4-kernel-loader-add-payload 0.1.0
│ ├── sel4-capdl-initializer-add-spec 0.1.0
│ └── sel4-backtrace-embedded-debug-info-cli 0.1.0
├── sel4-kernel-loader-add-payload 0.1.0
├── sel4-generate-target-specs 0.1.0
├── sel4-capdl-initializer-add-spec 0.1.0
├── sel4-bitfield-parser-test 0.1.0
├── sel4-backtrace-embedded-debug-info-cli 0.1.0
├── sel4-backtrace-cli 0.1.0
└── cargo-helpers 0.1.0
Crate: zerocopy
Version: 0.6.3
Warning: yanked
Dependency tree:
zerocopy 0.6.3
├── virtio-drivers 0.5.0
│ ├── microkit-http-server-example-virtio-net-driver 0.1.0
│ ├── microkit-http-server-example-virtio-hal-impl 0.1.0
│ │ ├── microkit-http-server-example-virtio-net-driver 0.1.0
│ │ └── microkit-http-server-example-virtio-blk-driver 0.1.0
│ └── microkit-http-server-example-virtio-blk-driver 0.1.0
├── sel4-simple-task-runtime-config-types 0.1.0
│ ├── sel4-simple-task-runtime-config-cli 0.1.0
│ └── sel4-simple-task-runtime 0.1.0
│ ├── tests-capdl-utcover-components-test 0.1.0
│ └── tests-capdl-threads-components-test 0.1.0
├── sel4-shared-ring-buffer-block-io-types 0.1.0
│ ├── sel4-shared-ring-buffer-block-io 0.1.0
│ │ ├── microkit-http-server-example-server 0.1.0
│ │ └── meta 0.1.0
│ ├── microkit-http-server-example-virtio-blk-driver 0.1.0
│ ├── microkit-http-server-example-server 0.1.0
│ └── meta 0.1.0
├── sel4-shared-ring-buffer 0.1.0
│ ├── sel4-shared-ring-buffer-smoltcp 0.1.0
│ │ ├── microkit-http-server-example-server 0.1.0
│ │ └── meta 0.1.0
│ ├── sel4-shared-ring-buffer-block-io-types 0.1.0
│ ├── sel4-shared-ring-buffer-block-io 0.1.0
│ ├── microkit-http-server-example-virtio-net-driver 0.1.0
│ ├── microkit-http-server-example-virtio-blk-driver 0.1.0
│ ├── microkit-http-server-example-server 0.1.0
│ └── meta 0.1.0
├── sel4-microkit-message-types 0.1.0
│ ├── sel4-microkit-message 0.1.0
│ │ ├── microkit-http-server-example-virtio-net-driver 0.1.0
│ │ ├── microkit-http-server-example-sp804-driver 0.1.0
│ │ ├── microkit-http-server-example-server 0.1.0
│ │ ├── meta 0.1.0
│ │ ├── banscii-pl011-driver 0.1.0
│ │ ├── banscii-assistant 0.1.0
│ │ └── banscii-artist 0.1.0
│ └── meta 0.1.0
└── sel4-async-block-io-cpiofs 0.1.0
├── microkit-http-server-example-server-core 0.1.0
│ └── microkit-http-server-example-server 0.1.0
└── meta 0.1.0
error: 2 vulnerabilities found!
warning: 4 allowed warnings found
Something that may be worth considering is supporting configurations that use pre-built code-gen outputs that can be checked into a VCS system and manually inspected.
I went ahead and had some fun with
cargo audit:
cargo-audit should definitely be part of the project's workflow! I've opened https://github.com/seL4/rust-sel4/pull/22, which adds cargo-audit to CI and addresses these vulnerabilities. I've also opened https://github.com/seL4/rust-sel4/issues/23.
I noticed that ./crates/sel4-platform-info/Cargo.toml depends on serde and serde_yaml which in turn depends on unsafe_libyaml which is a c2rust transpiled unsafe Rust code (which is kind of cool)
Interesting. From a risk-management perspective, I feel like this crate's approach isn't fundamentally different from that of a crate which wraps and links against a C library. That said, I would expect the unsafe_libyaml crate to include a clear, ideally executable and reproducible, description of where the C code comes from and exactly how it is transpiled into Rust. I'm surprised not to see even a mention of the libyaml version used nor the version of c2rust used.
Given that serde_yaml is so widely used in the Rust ecosystem, is the only widely used YAML crate for serde, and is a build-time dependency that is only fed trusted input (just platform_gen.yaml), I'm not immediately concerned about its presence in our dependency tree, but we I agree that we should be keeping an eye on this sort of thing.
But the real question is - how much time/effort we should put into using tools like cargo-geiger and other maintained by the Rust secure Code WG to increase the trust in the Rust userspace code?
Great question. I think that applying these tools to the exports of this projects is a especially important. By exports, I mean crates which are visible to users of this project, rather than those which are just used internally to support testing and development. Furthermore, I think that, for certain types of signals, we will get more bang for our buck by being more sensitive to dependencies of crates that run at run-time than dependencies that just run at build-time. For example, I think that stats about unsafe are more meaningful when they are about code that runs in seL4 userspace, as opposed to those about code which just runs at build-time.
In general, I think one key to managing the risk that these tools help us assess is being judicious with permitting run-time dependencies of the most import crates. For example, here is the dependency tree of sel4-microkit:
$ cargo tree -e normal -e no-proc-macro -p sel4-microkit
sel4-microkit v0.1.0 (/home/x/i/rust-sel4/crates/sel4-microkit)
├── cfg-if v1.0.0
├── sel4 v0.1.0 (/home/x/i/rust-sel4/crates/sel4)
│ ├── cfg-if v1.0.0
│ ├── sel4-config v0.1.0 (/home/x/i/rust-sel4/crates/sel4/config)
│ └── sel4-sys v0.1.0 (/home/x/i/rust-sel4/crates/sel4/sys)
│ ├── log v0.4.20
│ ├── sel4-bitfield-types v0.1.0 (/home/x/i/rust-sel4/crates/sel4/bitfield-types)
│ └── sel4-config v0.1.0 (/home/x/i/rust-sel4/crates/sel4/config)
├── sel4-externally-shared v0.1.0 (/home/x/i/rust-sel4/crates/sel4-externally-shared)
├── sel4-immediate-sync-once-cell v0.1.0 (/home/x/i/rust-sel4/crates/sel4-immediate-sync-once-cell)
├── sel4-immutable-cell v0.1.0 (/home/x/i/rust-sel4/crates/sel4-immutable-cell)
├── sel4-panicking v0.1.0 (/home/x/i/rust-sel4/crates/sel4-panicking)
│ ├── cfg-if v1.0.0
│ ├── sel4-immediate-sync-once-cell v0.1.0 (/home/x/i/rust-sel4/crates/sel4-immediate-sync-once-cell)
│ ├── sel4-panicking-env v0.1.0 (/home/x/i/rust-sel4/crates/sel4-panicking/env)
│ └── unwinding v0.1.7
│ └── gimli v0.26.2
├── sel4-panicking-env v0.1.0 (/home/x/i/rust-sel4/crates/sel4-panicking/env)
└── sel4-runtime-common v0.1.0 (/home/x/i/rust-sel4/crates/sel4-runtime-common)
├── cfg-if v1.0.0
├── sel4-dlmalloc v0.1.0 (/home/x/i/rust-sel4/crates/sel4-dlmalloc)
│ ├── dlmalloc v0.2.4
│ │ └── libc v0.2.148
│ └── sel4-sync v0.1.0 (/home/x/i/rust-sel4/crates/sel4-sync)
│ ├── sel4 v0.1.0 (/home/x/i/rust-sel4/crates/sel4) (*)
│ └── sel4-immediate-sync-once-cell v0.1.0 (/home/x/i/rust-sel4/crates/sel4-immediate-sync-once-cell)
├── sel4-initialize-tls-on-stack v0.1.0 (/home/x/i/rust-sel4/crates/sel4-initialize-tls-on-stack)
│ ├── cfg-if v1.0.0
│ └── sel4 v0.1.0 (/home/x/i/rust-sel4/crates/sel4) (*)
├── sel4-sync v0.1.0 (/home/x/i/rust-sel4/crates/sel4-sync) (*)
└── unwinding v0.1.7 (*)
I think this looks pretty good. These are the only external runtime dependencies:
cfg-iflogunwinding(Only whenunwindingfeature is enabled. Full of unsafe code, of course, but provides crucial functionality that we would implement in the very same way.)gimli
dlmalloc(Only whenallocfeature is enabled. Notably also a dependency oflibstd, used on Wasm targets.)libc(Does not actually introduce or link against any C code. For our target platform, it is just a few FFI type declarations.)
Something that may be worth considering is supporting configurations that use pre-built code-gen outputs that can be checked into a VCS system and manually inspected.
@kent-mcleod can you elaborate on the sort of build flow you are envisioning? The generated Rust code in sel4-sys is quite configuration-dependent. Do you imagine downstream developers checking generated Rust code in for each of the configurations they are developing with?
Also, do you think that a feature like this would also be worthwhile in the C case, or is there something about Rust case in particular that necessitates this? At the Summit, you mentioned the dependency on bindgen.