Skip to content

VERSION: release v0.2.5#397

Merged
cyphar merged 3 commits into
mainfrom
release-0.2.5
Jun 18, 2026
Merged

VERSION: release v0.2.5#397
cyphar merged 3 commits into
mainfrom
release-0.2.5

Conversation

@cyphar

@cyphar cyphar commented Jun 18, 2026

Copy link
Copy Markdown
Owner
libpathrs v0.2.5 -- "Or, to save on postage, I'll just poison him with this!"

This release includes the final set of changes needed by runc 1.5
(namely the new pathrs_version API), including some final "cleanup"
breaking API changes that we needed to get in before everyone packaged
libpathrs and it was depended on by real runc builds in distributions.
It also includes some very important fixes for when running inside a
container.

+------------------------------ Important -------------------------------+
| Due to the rising tide of supply chain attacks, we have stopped using  |
| "Trusted" Publishing for our crates.io and PyPi releases. Their UIs    |
| imply that such releases are "more trusted" but as the recent attacks  |
| have shown, they actually grant your code forge's *entire              |
| infrastructure* the right to release things on your behalf.            |
|                                                                        |
| It would be nice if `crates.io` and PyPI supported a proper signing    |
| model where developers control their keys, but that is sadly not the   |
| case today. For PyPI, detached PGP keys in PyPI are basically security |
| theatre[1] and PEP 480 has stalled; for `crates.io` there appears to   |
| be *no* mechanism for signing your releases with a key you control     |
| directly!                                                              |
+------------------------------------------------------------------------+

Breaking:

* pathrs_inroot_hardlink and pathrs_inroot_symlink have been switched to
  using the standard argument order from their respective system calls
  (previously the order was swapped, which lead to possible confusion).

  - Previously compiled programs will continue to work (thanks to symbol
    versioning) but rebuilt programs will need to adjust their argument
    order.

  - Rust users are not affected by this change.

  - For the Go and Python bindings, the wrappers have also had their
    argument orders swapped to match the C API and so will also need to
    be updated when rebuilding. **This is a very important point!**
    Users must ensure that they use pre-0.2.5 bindings with pre-0.2.5
    libpathrs library installs, and post-0.2.5 bindings with post-0.2.5
    library installs. Mixing and matching them will cause bugs (most
    likely spurious ENOENT errors).

  - For the sake of future extensions (and to ease the migration),
    pathrs_inroot_hardlink now accepts both an old_root_fd and
    new_root_fd. At the moment, callers must pass *the same value* to
    both arguments (this means the same numeric file descriptor value,
    not just a reference to the same underlying file).

    - The Go and Python bindings for pathrs_inroot_hardlink have not had
      their APIs changed, and so they still only permit operating within
      a single root.

* pathrs_inroot_rename also now accepts both an old_root_fd and
  new_root_fd, with the same caveats as pathrs_inroot_hardlink above.

   - The Go and Python bindings for pathrs_inroot_rename have not had
     their APIs changed, and so they still only permit operating within
     a single root.

* RenameFlags is now backed by a u64 (instead of libc::c_uint) so that
  we can accommodate future extension bits beyond the kernel's current
  32-bit ABI. Rust callers using RenameFlags::bits() or storing the raw
  value will need to adjust their types.

  - As part of this, pathrs_inroot_rename now also takes a uint64_t, and
    thus the the Go (*Root).Rename wrapper takes a uint64 as well.

- OpenFlags is now bkaced by a u64 (instead of libc::c_int), as recent
  kernel changes such as OPENAT2_REGULAR will likely start to use some
  of the upper flag bits available from openat2(2). This has an impact
  on all C APIs (and thus Go bindings) that accept OpenFlags arguments
  (we do provide old symbol versions to ease the transition):

  - pathrs_reopen
  - pathrs_inroot_open
  - pathrs_inroot_creat
  - pathrs_proc_open
  - pathrs_proc_openat

Added:

- capi: We now have a new pathrs_version API that provides runtime
  version information, which loosely matches other libraries like
  libseccomp. The API is based on extensible structs, so we can add more
  information here in the future.
- install.sh now supports --disable-static and --disable-dynamic to
  limit what files are installed (their --enable-* inverses are also
  available for completeness, but they both are enabled by default).

Fixed:

- Containers often have /proc/sys overmounted with a read-only mount to
  avoid container escapes, this caused the O_PATH resolver to panic
  because the hardened procfs lookup for /proc/sys/fs/protected_symlinks
  would fail. We now conservatively assume that fs.protected_symlinks is
  enabled if we cannot access the file for any reason.

  This also causes attempts to access /proc/sys files using ProcfsHandle
  to also fail (by design). In the future we plan to provide some
  quality-of-life improvements to permit access in those cases, but at
  the moment users need to be aware that those kinds of accesses can
  fail.

- Root::readlink and ProcfsHandle::readlink would previously return
  ENOENT if the target path existed but was not a symlink. This occurred
  because of a peculiar asymmetry in the kernel APIs for readlinkat(2),
  but users found it confusing and so we now remap the error in that
  case to EINVAL (as you would get from readlink(2) with a path). This
  will make it easier to distinguish the "target path does not exist"
  and "target path is not a symlink" cases.


Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>

@cyphar cyphar added this to the 0.2.5 milestone Jun 18, 2026
@codecov

codecov Bot commented Jun 18, 2026

Copy link
Copy Markdown

Codecov Report

✅ All modified and coverable lines are covered by tests.

📢 Thoughts on this report? Let us know!

cyphar added 3 commits June 18, 2026 08:38
These are actually far more dangerous than you would expect and while I
was never fully comfortable with allowing GitHub to publish releases on
my behalf, the recent supply chain attacks (such as Mini Shai-Hulud)
kind of show that doing this is a really bad idea.

It would be great if crates.io and PyPI provided a way for you to sign
releases with your own key that is on some kind of hardware-backed
device, but sadly those don't really exist (detached PGP signatures in
PyPI are useless and PEP 480 has stalled, while crates.io just straight
up has no mechanism for actual signing?!).

Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
Signed-off-by: Aleksa Sarai <cyphar@cyphar.com>
@cyphar cyphar merged commit 859824e into main Jun 18, 2026
139 checks passed
@cyphar cyphar deleted the release-0.2.5 branch June 18, 2026 09:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant