MCPcopy Index your code
hub / github.com/cyphar/libpathrs

github.com/cyphar/libpathrs @v0.2.5

Chat with this repo
repository ↗ · DeepWiki ↗ · release v0.2.5 ↗ · + Follow
827 symbols 2,662 edges 88 files 208 documented · 25%
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

libpathrs

rust docs go docs PyPI package

msrv dependency status

codecov rust-ci build status bindings-c build status bindings-go build status bindings-python build status

This library implements a set of C-friendly APIs (written in Rust) to make path resolution within a potentially-untrusted directory safe on GNU/Linux. There are countless examples of security vulnerabilities caused by bad handling of paths; this library provides an easy-to-use set of VFS APIs to avoid those kinds of issues.

Examples

Here is a toy example of using this library to open a path (/etc/passwd) inside a root filesystem (/path/to/root) safely. More detailed examples can be found in examples/ and tests/.

Rust

use std::fs::File;

use pathrs::{flags::OpenFlags, Root};

fn get_my_fd() -> Result<File, Error> {
    const ROOT_PATH: &'static str = "/path/to/root";
    const UNSAFE_PATH: &'static str = "/etc/passwd";

    let root = Root::open(ROOT_PATH)?;
    let handle = root.resolve(UNSAFE_PATH)?;
    let file = handle.reopen(OpenFlags::O_RDONLY)?;

    // The handle step can be skipped using root.open_subpath().

    Ok(file)
}

C

#define _GNU_SOURCE
#include <unistd.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include <pathrs.h>

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

    int liberr = 0;
    int root = -EBADF,
        handle = -EBADF,
        fd = -EBADF;

    root = pathrs_open_root(root_path);
    if (IS_PATHRS_ERR(root)) {
        liberr = root;
        goto err;
    }

    handle = pathrs_inroot_resolve(root, unsafe_path);
    if (IS_PATHRS_ERR(handle)) {
        liberr = handle;
        goto err;
    }

    fd = pathrs_reopen(handle, O_RDONLY);
    if (IS_PATHRS_ERR(fd)) {
        liberr = fd;
        goto err;
    }

    /* The handle step can be skipped using pathrs_inroot_open(). */

err:
    if (IS_PATHRS_ERR(liberr)) {
        pathrs_error_t *error = pathrs_errorinfo(liberr);
        fprintf(stderr, "Uh-oh: %s (errno=%d)\n", error->description, error->saved_errno);
        pathrs_errorinfo_free(error);
    }
    close(root);
    close(handle);
    return fd;
}

Go

package main

import (
    "os"

    "cyphar.com/go-pathrs"
)

func getMyFD() (*os.File, error) {
    const rootPath = "/path/to/root"
    const unsafePath = "/etc/passwd"

    root, err := pathrs.OpenRoot(rootPath)
    if err != nil {
        return nil, err
    }
    defer root.Close()

    handle, err := root.Resolve(unsafePath)
    if err != nil {
        return nil, err
    }
    defer handle.Close()

    // The handle step can be skipped using root.Open().
    return handle.Open()
}

On Linux, libpathrs also provides an API for safe procfs operations with strict path safety in the procfs module. Click here to see some concrete examples of its usage.

Kernel Support

At the moment, libpathrs only works on Linux as it was designed around Linux-only APIs that are necessary to provide safe path operations. In future, we plan to expand support for other Unix-like operating systems.

While libpathrs will function on very old kernels (in theory back to Linux 2.6.39, though we do not currently test this) we strongly recommend using at least Linux 5.6 to get a reasonable amount of protection against various attacks. The oldest Linux kernel which currently supports all of the features we use for hardening is Linux 6.8.

License

SPDX-License-Identifier: MPL-2.0 OR LGPL-3.0-or-later

libpathrs is licensed under the terms of the Mozilla Public License version 2.0 or the GNU Lesser General Public License version 3, at your option.

Unless otherwise stated, by intentionally submitting any Contribution (as defined by the Mozilla Public License version 2.0) for inclusion into the libpathrs project, you are agreeing to dual-license your Contribution as above, without any additional terms or conditions.

libpathrs: safe path resolution on Linux
Copyright (C) 2019-2025 SUSE LLC
Copyright (C) 2026 Aleksa Sarai <cyphar@cyphar.com>

== MPL-2.0 ==

 This Source Code Form is subject to the terms of the Mozilla Public
 License, v. 2.0. If a copy of the MPL was not distributed with this
 file, You can obtain one at https://mozilla.org/MPL/2.0/.

Alternatively, this Source Code Form may also (at your option) be used
under the terms of the GNU Lesser General Public License Version 3, as
described below:

== LGPL-3.0-or-later ==

 This program is free software: you can redistribute it and/or modify it
 under the terms of the GNU Lesser General Public License as published by
 the Free Software Foundation, either version 3 of the License, or (at
 your option) any later version.

 This program is distributed in the hope that it will be useful, but
 WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
 for more details.

 You should have received a copy of the GNU Lesser General Public License
 along with this program. If not, see <https://www.gnu.org/licenses/>.

Bindings

SPDX-License-Identifier: MPL-2.0

The language-specific bindings (the code in contrib/bindings/ and go-pathrs/) are licensed under the Mozilla Public License version 2.0 (available in LICENSE.MPL-2.0).

NOTE: If you compile libpathrs.so into your binary statically, you still need to abide by the license terms of the main libpathrs project.

libpathrs: safe path resolution on Linux
Copyright (C) 2019-2025 SUSE LLC
Copyright (C) 2026 Aleksa Sarai <cyphar@cyphar.com>

This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at https://mozilla.org/MPL/2.0/.

Examples

SPDX-License-Identifier: MPL-2.0

The example code in examples/ is licensed under the Mozilla Public License version 2.0 (available in LICENSE.MPL-2.0).

libpathrs: safe path resolution on Linux
Copyright (C) 2019-2025 SUSE LLC
Copyright (C) 2026 Aleksa Sarai <cyphar@cyphar.com>

This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at https://mozilla.org/MPL/2.0/.

Extension points exported contracts — how you extend this code

ErrorExt (Interface)
Private trait necessary to work around the "orphan trait" restriction. [4 implementers]
src/error.rs
IntoCReturn (Interface)
(no doc) [8 implementers]
src/capi/ret.rs
HandleImpl (Interface)
(no doc) [6 implementers]
src/tests/traits/handle.rs
CheckRustixFd (Interface)
Rustix will trigger a panic if a [`BorrowedFd`] has a value it deems "unacceptable" (namely, most negative values). In r [1 …
src/syscalls.rs
ToCString (Interface)
(no doc) [2 implementers]
src/utils/path.rs
ThreadCloser (FuncType)
ThreadCloser is a callback that needs to be called when you are done operating on an [os.File] fetched using [Handle.Ope
go-pathrs/procfs/procfs_linux.go
Leakable (Interface)
(no doc) [1 implementers]
src/capi/utils.rs
RootImpl (Interface)
(no doc) [6 implementers]
src/tests/traits/root.rs

Core symbols most depended-on inside this repo

as_ref
called by 58
src/root.rs
as_fd
called by 50
src/utils/maybe_owned.rs
as_ref
called by 48
src/resolvers/procfs.rs
wrap
called by 44
src/error.rs
open
called by 43
src/resolvers/openat2.rs
metadata
called by 29
src/utils/fd.rs
mode
called by 28
src/utils/fd.rs
as_unsafe_path_unchecked
called by 25
src/utils/fd.rs

Shape

Function 435
Method 299
Class 47
Enum 19
Interface 13
Struct 6
FuncType 4
TypeAlias 3
Route 1

Languages

Rust74%
Python13%
Go12%
C1%
C++1%

Modules by API surface

src/procfs.rs45 symbols
src/syscalls.rs44 symbols
src/utils/fd.rs42 symbols
src/capi/procfs.rs36 symbols
contrib/bindings/python/pathrs/_internal.py33 symbols
src/root.rs32 symbols
go-pathrs/internal/libpathrs/libpathrs_linux.go29 symbols
e2e-tests/cmd/rust/src/root.rs28 symbols
src/capi/utils.rs27 symbols
e2e-tests/cmd/python/pathrs-cmd.py27 symbols
contrib/bindings/python/pathrs/_pathrs.py23 symbols
src/utils/kernel_version.rs22 symbols

For agents

$ claude mcp add libpathrs \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact