Skip to content

libpathrs v0.2.1 -- "やられたらやり返す。倍返しだ!"

Choose a tag to compare

@cyphar cyphar released this 02 Nov 18:09
· 86 commits to main since this release
v0.2.1
f900452

This is a minor release of libpathrs which includes some fairly critical
bugfixes, as well as some Rust-specific packaging fixes that should make
it easier to use libpathrs in Rust projects.

Security

  • When using ProcfsHandle::open_follow on non-magic-link symlinks,
    libpathrs could fall victim to an overmount attack because we had incorrectly
    assumed that opening a symlink as a final component would be "atomic" (this
    is only true for magic-links, which was the primary usecase we had in mind
    for this API).

    We now try to use the safe procfs resolver even on symlinks to handle the
    "regular symlink case". Note that (due to a separate bug in
    ProcfsHandle::open_follow that has also been fixed), privileged users would
    likely still get an error in this case.

Added

  • Error and ErrorKind now have a can_retry helper that can be used to
    make retry loops easier for callers.
  • libpathrs now has fairly comprehensive end-to-end tests for all our bindings
    (written in a language-agnostic way), to ensure correctness and uniformty
    when you use libpathrs, no matter which language you use.

Fixed

  • python bindings: fix pathrs.procfs examples in README.
  • go bindings: fix the internal os.FileMode to S_IF* conversion to not
    auto-include S_IFREG for non-Mknod operations (previously this would
    cause MkdirAll to error out).
  • Root::create_file now supports O_TMPFILE.
  • Previously, trying to use ProcfsHandle::open_follow with a path whose
    penultimate component was a symlink (i.e.,
    ProcfsHandle::open_follow(ProcfsBase::ProcRoot, "self/status")) would
    result in an error due to a mistake in how we handled looking up parent
    directories. This has been fixed, and this will now work the way you expect
    (though you should still use ProcfsBase::ProcSelf instead in the above
    example).
  • ProcfsHandle::open_follow was missing the logic to temporarily allocate a
    non-subset=pid if the target does not exit. This ended up accidentally
    mitigating the ProcfsHandle::open_follow security issue mentioned above
    (for fsopen(2) users trying to open symlinks in ProcfsBase::ProcRoot --
    note that only ProcfsBase::ProcRoot contains such symlinks in the first
    place).
  • Quite a few Root operations that required resolving the parent directory of
    the user-provided path could crash if passed / or return an unhelpful error
    when passed .. We now return a proper error in these cases.

Changed

  • The openat2 resolver will now return -EAGAIN if the number of openat2
    retries is exceeded -- this allows higher-level users easily detect if an
    error is an indication they should retry (based on their own retry policy).

    In addition, the number of retries done has been bumped from 32 to 128
    based on some benchmarking which showed that 32 could fail up to 3% of the
    time but 128 would only fail ~0.1% of the time in the worst case scenario
    of an attacker that can saturate all cores with rename(2) operations.

    Users that need stronger resiliency guarantees can do their own additional
    retry loop on top of libpathrs by checking the return value for EAGAIN.
    Please note that we would strongly recommend having some restriction to avoid
    denial-of-service attacks (such as a deadline -- for reference, our testing
    showed that even with >50k trials containing >200k operations a deadline of
    1ms was never exceeded even in the most pessimistic attack scenario).

  • The O_PATH resolver for ProcfsHandle will now return ELOOP for
    magic-links that look like foo:[bar] in order to better match openat2(2)
    (examples include anon_inode, nsfs, pipe, and other such special
    inodes). Previously we would just return ENOENT.

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