This crate implements utilities for working with fs-verity
functionality of the Linux kernel.
It allows you to make a file permanently immutable and have the kernel calculate and store a Merkle tree-based hash for the file that will be instantly retrievable from the file from that point on.
The kernel will also verify all data read from the file agains the Merkle tree data, and refure to read it if there is a mismatch. This means (as long as you trust the running kernel) you can be absolutely sure that this instantly retrievable hash will match the data you read from the file.
You are expected to determine whether the hash is the expected one through other means, such as checking whether it is in a list of accepted hashes which has been signed by some key.
The kernel's fs-verity
code does implement a basic (and optional) in-kernel signature
verification scheme. However, because you still have to manually check whether an opened file
has fs-verity
enabled, it does not add much value and is probably more of a proof-of-concept.
This crate currently has no support for this scheme.
Currently fs-verity
is only supported on f2fs
and ext4
filesystems, and you may need to
turn on the fs-verity
option on your filesystem. See the
Linux documentation for details.
You can think of it as a pure Rust replacement for the main parts of
fsverity-utils
/ libfsverity
.
It consists of two parts:
- An implementation of [
sha2::digest::Digest
] which can calculate anfs-verity
measurement in userland Rust code. This is useful for e.g. servers and build systems which may not want to (or be able to) enablefs-verity
for files, but still need to know the digest values so they can be used to create e.g. a signed manifest file containing all the digests. - On Linux systems, two functions which allow you to enable
fs-verity
for a file, and to fetch the digest for the file from the kernel once it's enabled. This uses theioctl
interface directly.
This was mostly produced as a coding exercise. It works and is pretty clean (well, as much
as is possible under the API constraints I set myself) and thoroughly commented, but it is
currently a bit slower than the C implementation because that uses libcrypto
's assembly
code for SHA256, and the SHA256 implementation in RustCrypto is not quite as fast.
One neat aspect of this implementation is that it works in a completely streaming manner, accepting any amount of input in chunks of whatever size.
This crate should work with latest stable Rust. In case it does not work with older versions of Rust and you need this, please file an issue.
This crate calls the unsafe libc::ioctl
function in the two function in the [linux
] module. No other unsafe
is used.
The underlying SHA256 and SHA512 hash functions from Rust Crypto are used. The asm
feature of Rust Crypto is not enabled by default.
To run unit tests, first generate the test files using python3 make_testfiles.py
.
The "known good" hashes were generated using the official fsverity
tool from the fsverity-utils
or 'fsverity` package:
sudo apt install fsverity
for f in testfiles/*; do fsverity enable $f; done
fsverity measure testfiles/*
If that doesn't work your filesystem may not support fs-verity
or you may need to turn on the feature in the fs superblock, see the excellent fs-verity
documentation for details.
Very recent versions (you may have to compile from source) of the fsverity
tool also support the digest
subcommmand, which allows you to hash the files without kernel or filesystem support:
fsverity digest testfiles/*
This crate is licensed under either of
at your option.
Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.