[][src]Crate pathrs

libpathrs provides a series of primitives for Linux programs to safely handle path operations inside an untrusted directory tree.

The idea is that a Root handle is like a handle for resolution inside a chroot(2), with Handle being an O_PATH descriptor which you can "upgrade" to a proper File. However this library acts far more efficiently than spawning a new process and doing a full chroot(2) for every operation.

In order to ensure the maximum possible number of people can make us of this library to increase the overall security of Linux tooling, it is written in Rust (to be memory-safe) and produces C dylibs for usage with any language that supports C-based FFI.


This library assumes that the kernel supports all of the needed features for at least one libpathrs backend. At time of writing, those are:

  • A working /proc mount, such that /proc/self/fd/ operates correctly. libpathrs will explicitly verify that the /proc mount is actually a bone-fide procfs instance (to avoid potential trickery) and abort if /proc is not actually procfs.
  • Native Backend:
    • openat2 support.


The recommended usage of libpathrs looks something like this:

let (root_path, unsafe_path) = ("/path/to/root", "/etc/passwd");
// Get a root handle for resolution.
let root = Root::open(root_path)?;
// Resolve the path.
let handle = root.resolve(unsafe_path)?;
// Upgrade the handle to a full std::fs::File.
let file = handle.reopen(libc::O_RDONLY)?;

// Or, in one line:
let file = root.resolve(unsafe_path)?

The corresponding C example would be:

#include <pathrs.h>

int get_my_fd(void)
    const char *root_path = "/path/to/root";
    const char *unsafe_path = "/etc/passwd";

    int fd = -1;
    pathrs_root_t *root = NULL;
    pathrs_handle_t *handle = NULL;
    pathrs_error_t *error = NULL;

    root = pathrs_open(root_path);
    error = pathrs_error(PATHRS_ROOT, root);
    if (error)
        goto err;

    handle = pathrs_resolve(root, unsafe_path);
    error = pathrs_error(PATHRS_ROOT, root);
    if (error) /* or (!handle) */
        goto err;

    fd = pathrs_reopen(handle, O_RDONLY);
    error = pathrs_error(PATHRS_HANDLE, handle);
    if (error) /* or (fd < 0) */
        goto err;

    if (error)
        fprintf(stderr, "Uh-oh: %s (errno=%d)\n", error->description, error->saved_errno);
    pathrs_free(PATHRS_ROOT, root);
    pathrs_free(PATHRS_HANDLE, handle);
    pathrs_free(PATHRS_ERROR, error);
    return fd;



Error types for libpathrs.



A handle to an existing inode within a Root.


Wrapper for the underlying libc's O_* flags.


Wrapper for the underlying libc's RENAME_* flags.


Resolover backend and its associated flags.


Optional flags to modify the resolution of paths inside a Root.


A handle to the root of a directory tree.



An inode type to be created with Root::create.


The backend used for path resolution within a Root to get a Handle.