Skip to content

Conversation

@elastic-renovate-prod
Copy link
Contributor

@elastic-renovate-prod elastic-renovate-prod bot commented Sep 25, 2025

This PR contains the following updates:

Package Type Update Change
github.com/cyphar/filepath-securejoin require minor v0.4.1 -> v0.6.0

Release Notes

cyphar/filepath-securejoin (github.com/cyphar/filepath-securejoin)

v0.6.0: -- "By the Power of Greyskull!"

Compare Source

While quite small code-wise, this release marks a very key point in the
development of filepath-securejoin.

filepath-securejoin was originally intended (back in 2017) to simply be a
single-purpose library that would take some common code used in container
runtimes (specifically, Docker's FollowSymlinksInScope) and make it more
general-purpose (with the eventual goals of it ending up in the Go stdlib).

Of course, I quickly discovered that this problem was actually far more
complicated to solve when dealing with racing attackers, which lead to me
developing openat2(2) and libpathrs. I had originally planned for
libpathrs to completely replace filepath-securejoin "once it was ready" but in
the interim we needed to fix several race attacks in runc as part of security
advisories. Obviously we couldn't require the usage of a pre-0.1 Rust library
in runc so it was necessary to port bits of libpathrs into filepath-securejoin.
(Ironically the first prototypes of libpathrs were originally written in Go and
then rewritten to Rust, so the code in filepath-securejoin is actually Go code
that was rewritten to Rust then re-rewritten to Go.)

It then became clear that pure-Go libraries will likely not be willing to
require CGo for all of their builds, so it was necessary to accept that
filepath-securejoin will need to stay. As such, in v0.5.0 we provided more
pure-Go implementations of features from libpathrs but moved them into
pathrs-lite subpackage to clarify what purpose these helpers serve.

This release finally closes the loop and makes it so that pathrs-lite can
transparently use libpathrs (via a libpathrs build-tag). This means that
upstream libraries can use the pure Go version if they prefer, but downstreams
(either downstream library users or even downstream distributions) are able to
migrate to libpathrs for all usages of pathrs-lite in an entire Go binary.

I should make it clear that I do not plan to port the rest of libpathrs to Go,
as I do not wish to maintain two copies of the same codebase. pathrs-lite
already provides the core essentials necessary to operate on paths safely for
most modern systems. Users who want additional hardening or more ergonomic APIs
are free to use cyphar.com/go-pathrs (libpathrs's Go bindings).

Breaking
  • The deprecated MkdirAll, MkdirAllHandle, OpenInRoot, OpenatInRoot and
    Reopen wrappers have been removed. Please switch to using pathrs-lite
    directly.
Added
  • pathrs-lite now has support for using libpathrs as a backend.
    This is opt-in and can be enabled at build time with the libpathrs build
    tag. The intention is to allow for downstream libraries and other projects to
    make use of the pure-Go github.com/cyphar/filepath-securejoin/pathrs-lite
    package and distributors can then opt-in to using libpathrs for the entire
    binary if they wish.

Signed-off-by: Aleksa Sarai [email protected]

v0.5.1: -- "Spooky scary skeletons send shivers down your spine!"

Compare Source

Changed
  • openat2 can return -EAGAIN if it detects a possible attack in certain
    scenarios (namely if there was a rename or mount while walking a path with a
    .. component). While this is necessary to avoid a denial-of-service in the
    kernel, it does require retry loops in userspace.

    In previous versions, pathrs-lite would retry openat2 32 times before
    returning an error, but we've received user reports that this limit can be
    hit on systems with very heavy load. In some synthetic benchmarks (testing
    the worst-case of an attacker doing renames in a tight loop on every core of
    a 16-core machine) we managed to get a ~3% failure rate in runc. We have
    improved this situation in two ways:

    • We have now increased this limit to 128, which should be good enough for
      most use-cases without becoming a denial-of-service vector (the number of
      syscalls called by the O_PATH resolver in a typical case is within the
      same ballpark). The same benchmarks show a failure rate of ~0.12% which
      (while not zero) is probably sufficient for most users.

    • In addition, we now return a unix.EAGAIN error that is bubbled up and can
      be detected by callers. This means that callers with stricter requirements
      to avoid spurious errors can choose to do their own infinite EAGAIN retry
      loop (though we would strongly recommend users use time-based deadlines in
      such retry loops to avoid potentially unbounded denials-of-service).

v0.5.0: -- "Let the past die. Kill it if you have to."

Compare Source

NOTE: With this release, some parts of github.com/cyphar/filepath-securejoin
are now licensed under the Mozilla Public License (version 2). Please see
COPYING.md as well as the the license header in each file for more details.

Breaking
  • The new API introduced in the 0.3.0 release has been moved to a new
    subpackage called pathrs-lite. This was primarily done to better indicate
    the split between the new and old APIs, as well as indicate to users the
    purpose of this subpackage (it is a less complete version of libpathrs).

    We have added some wrappers to the top-level package to ease the transition,
    but those are deprecated and will be removed in the next minor release of
    filepath-securejoin. Users should update their import paths.

    This new subpackage has also been relicensed under the Mozilla Public License
    (version 2), please see COPYING.md for more details.

Added
  • Most of the key bits the safe procfs API have now been exported and are
    available in github.com/cyphar/filepath-securejoin/pathrs-lite/procfs. At
    the moment this primarily consists of a new procfs.Handle API:

    • OpenProcRoot returns a new handle to /proc, endeavouring to make it
      safe if possible (subset=pid to protect against mistaken write attacks
      and leaks, as well as using fsopen(2) to avoid racing mount attacks).

      OpenUnsafeProcRoot returns a handle without attempting to create one
      with subset=pid, which makes it more dangerous to leak. Most users
      should use OpenProcRoot (even if you need to use ProcRoot as the base
      of an operation, as filepath-securejoin will internally open a handle when
      necessary).

    • The (*procfs.Handle).Open* family of methods lets you get a safe
      O_PATH handle to subpaths within /proc for certain subpaths.

      For OpenThreadSelf, the returned ProcThreadSelfCloser needs to be
      called after you completely finish using the handle (this is necessary
      because Go is multi-threaded and ProcThreadSelf references
      /proc/thread-self which may disappear if we do not
      runtime.LockOSThread -- ProcThreadSelfCloser is currently equivalent
      to runtime.UnlockOSThread).

      Note that you cannot open any procfs symlinks (most notably magic-links)
      using this API. At the moment, filepath-securejoin does not support this
      feature (but libpathrs does).

    • ProcSelfFdReadlink lets you get the in-kernel path representation of a
      file descriptor (think readlink("/proc/self/fd/...")), except that we
      verify that there aren't any tricky overmounts that could fool the
      process.

      Please be aware that the returned string is simply a snapshot at that
      particular moment, and an attacker could move the file being pointed to.
      In addition, complex namespace configurations could result in non-sensical
      or confusing paths to be returned. The value received from this function
      should only be used as secondary verification of some security property,
      not as proof that a particular handle has a particular path.

    The procfs handle used internally by the API is the same as the rest of
    filepath-securejoin (for privileged programs this is usually a private
    in-process procfs instance created with fsopen(2)).

    As before, this is intended as a stop-gap before users migrate to
    libpathrs, which provides a far more extensive safe procfs API and is
    generally more robust.

  • Previously, the hardened procfs implementation (used internally within
    Reopen and Open(at)InRoot) only protected against overmount attacks on
    systems with openat2(2) (Linux 5.6) or systems with fsopen(2) or
    open_tree(2) (Linux 5.2) and programs with privileges to use them (with
    some caveats about locked mounts that probably affect very few users). For
    other users, an attacker with the ability to create malicious mounts (on most
    systems, a sysadmin) could trick you into operating on files you didn't
    expect. This attack only really makes sense in the context of container
    runtime implementations.

    This was considered a reasonable trade-off, as the long-term intention was to
    get all users to just switch to libpathrs if they wanted to use the safe
    procfs API (which had more extensive protections, and is what these new
    protections in filepath-securejoin are based on). However, as the API
    is now being exported it seems unwise to advertise the API as "safe" if we do
    not protect against known attacks.

    The procfs API is now more protected against attackers on systems lacking the
    aforementioned protections. However, the most comprehensive of these
    protections effectively rely on statx(STATX_MNT_ID) (Linux 5.8).
    On older kernel versions, there is no effective protection (there is some
    minimal protection against non-procfs filesystem components but a
    sufficiently clever attacker can work around those). In addition,
    STATX_MNT_ID is vulnerable to mount ID reuse attacks by sufficiently
    motivated and privileged attackers -- this problem is mitigated with
    STATX_MNT_ID_UNIQUE (Linux 6.8) but that raises the minimum kernel version
    for more protection.

    The fact that these protections are quite limited despite needing a fair bit
    of extra code to handle was one of the primary reasons we did not initially
    implement this in filepath-securejoin (libpathrs supports all of this,
    of course).

Fixed
  • RHEL 8 kernels have backports of fsopen(2) but in some testing we've found
    that it has very bad (and very difficult to debug) performance issues, and so
    we will explicitly refuse to use fsopen(2) if the running kernel version is
    pre-5.2 and will instead fallback to open("/proc").

Thanks to the following contributors who made this release possible:

Signed-off-by: Aleksa Sarai [email protected]


Configuration

📅 Schedule: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

Rebasing: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR has been generated by Renovate Bot.

@elastic-renovate-prod elastic-renovate-prod bot force-pushed the renovate/github.com-cyphar-filepath-securejoin-0.x branch 2 times, most recently from e9a44eb to e8578fe Compare October 8, 2025 19:45
Copy link
Member

@gtback gtback left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can't upgrade to this dependency as-is:

NOTE: With this release, some parts of github.com/cyphar/filepath-securejoin
are now licensed under the Mozilla Public License (version 2). Please see
COPYING.md as well as the the license header in each file for more details.

This causes an error when trying to update the NOTICE file to use this new version:

❯ make generate
2025/10/08 15:40:40 Failed to detect licences: dependency github.com/cyphar/filepath-securejoin uses licence MPL-2.0 which is not allowed by the rules file
exit status 1
make: *** [generate] Error 1

Although MPL-2.0 is an allowed license in this case (we are complying with the license by not modifying any MPL-licensed files, and the NOTICE file contains a link to the upstream project), we don't currently have a way to say "License X is allowed for dependency Y, without allowing X for all dependencies".

We don't need to upgrade for now, but we'll want to address this eventually.

@elastic-renovate-prod elastic-renovate-prod bot force-pushed the renovate/github.com-cyphar-filepath-securejoin-0.x branch from e8578fe to 8e775de Compare November 1, 2025 14:08
@elastic-renovate-prod elastic-renovate-prod bot changed the title fix(deps): update module github.com/cyphar/filepath-securejoin to v0.5.0 fix(deps): update module github.com/cyphar/filepath-securejoin to v0.5.1 Nov 1, 2025
@elastic-renovate-prod elastic-renovate-prod bot force-pushed the renovate/github.com-cyphar-filepath-securejoin-0.x branch from 8e775de to a555caf Compare November 3, 2025 06:09
@elastic-renovate-prod elastic-renovate-prod bot changed the title fix(deps): update module github.com/cyphar/filepath-securejoin to v0.5.1 fix(deps): update module github.com/cyphar/filepath-securejoin to v0.6.0 Nov 3, 2025
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.

2 participants