libpathrs v0.1.0 -- "負けたくないことに理由って要る?"
This is the first fully-fledged release of libpathrs. All of the obvious
features have been implemented, and both the C and Rust APIs have been
redesigned a few times so I am fairly sure this design is pretty solid
now. While there was a fairly long hiatus in development, we're back on
track.
Many things have changed since the last release, here are the highlights:
-
cffi: Redesign the entire API to be file descriptor based, removing the need
for complicated freeing logic and matching what most kernel APIs actually
look like. While there is a risk that users would operate on file descriptors
themselves, the benefits of a pure-fd-based API outweigh those issues (and
languages with bindings like Python and Go can easily wrap the file
descriptor to provide helper methods and avoid this mistake by users).Aside from making C users happier, this makes writing bindings much simpler
because every language has native support for handling the freeing of file
objects (Go in particular has *os.File which would be too difficult to
emulate outside of the stdlib because of it's unique Close handling).- Unfortunately, this API change also removed some information from the C API
because it was too difficult to deal with:- Backtraces are no longer provided to the C API. There is no plan to
re-add them because they complicate the C API a fair bit and it turns out
that it's basically impossible to graft backtraces to languages that have
native backtrace support (Go and Python) so providing this information
has no real benefit to anyone. - The configuration API has been removed for now. In the future we will
probably want to re-add it, but figuring out a nice API for this is left
for a future (pre-1.0) release. In practice, the default settings are the
best settings to use for most people anyway.
- Backtraces are no longer provided to the C API. There is no plan to
- Unfortunately, this API change also removed some information from the C API
-
libpathrs now has a "safe procfs resolver" implementation that
verifies all of our operations on /proc are done safely (including
using fsopen(2) or open_tree(2) to create a private /proc to protect
against race attacks).This is mainly motivated by issues like CVE-2019-16884 and
CVE-2019-19921, where an attacker could configure a malicious mount
table such that naively doing /proc operations could result in
security issues. While there are limited things you can do in such a
scenario, it is far more preferable to be able to detect these kinds
of attacks and at least error out if there is a malicious /proc.This is based on similar work I did in filepath-securejoin.
- This API is also exposed to users through the Rust and C FFI because
this is something a fair number of system tools (such as container
runtimes) need.
- This API is also exposed to users through the Rust and C FFI because
-
libpathrs now has an official MSRV of 1.63, which is verified by our
CI. The MSRV was chosen because it's the Rust version in Debian stable
and it has io_safety which is one of the last bits we absolutely need. -
root: new Root methods:
- readlink and resolve_nofollow to allow users to operate on symlinks
directly (though it is still unsafe to use the returned path for
lookups!). - remove_all so that Go users can switch from os.RemoveAll (though
Go's os.RemoveAll is safe against races since Go 1.21.11 and Go
1.22.4). - mkdir_all so that Go users can switch from os.MkdirAll. This is
based on similar work done in filepath-securejoin.
- readlink and resolve_nofollow to allow users to operate on symlinks
-
root: The method for configuring the resolver has changed to be more
akin to a getter-setter style. This allows for more ergonomic usage
(see the RootRef::with_resolver_flags examples) and also lets us avoid
exposing internal types needlessly.As part of this change, the ability to choose the resolver backend was
removed (because the C API also no longer supports it). This will
probably be re-added in the future, but for now it seems best to not
add extra APIs that aren't necessary until someone asks. -
opath resolver: We now emulate fs.protected_symlinks when resolving
symlinks using the emulated opath resolver. This is only done if
fs.protected_symlinks is enabled on the system (to mirror the
behaviour of openat2). -
packaging: Add an autoconf-like install.sh script that generates a
pkg-config specification for libpathrs. This should help distributions
package libpathrs.
-
Handling of // and trailing slashes has been fixed to better match what
users expect and what the kernel does. -
opath resolver: Use reference counting to avoid needlessly cloning files
internally when doing lookups. -
cffi: Building the C API is now optional, so Rust crates won't contain any of
the C FFI code and we only build the C FFI crate types manually in the
makefile. This also lets us remove some dependencies and other annoying
things in the Rust crate (since those things are only needed for the C API). -
python bindings: Switch to setuptools to allow for a proper Python package
install. This also includes some reworking of the layout to avoid leaking
stuff to users that just do import pathrs. -
bindings: All of the bindings were rewritten to use the new API.
-
rust: Rework libpathrs to use the (stabilised in Rust 1.63) io_safety
features. This lets us avoid possible "use after free" issues with file
descriptors that were closed by accident.This required the addition of HandleRef and RootRef to wrap BorrowedFd
(this is needed for the C API, but is almost certainly useful to other
folks). Unfortunately we can't implement Deref so all of the methods need
to be duplicated for the new types. -
Split Root::remove into Root::remove_file (unlink) and
Root::remove_dir (rmdir) so we don't need to do the retry loop anymore.
Some users care about what kind of inode they're removing, and if a user
really wants to nuke a path they would want to use Root::remove_all anyway
because the old Root::remove would not remove non-empty directories.
Thanks to the following contributors who made this release possible:
- Aleksa Sarai cyphar@cyphar.com
- Jakub Wilk jwilk@jwilk.net
- Toru Komatsu k0ma@utam0k.jp
Signed-off-by: Aleksa Sarai cyphar@cyphar.com