Skip to content

cyphar/libpathrs

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

937 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

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/.

RustC
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)
}
#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;
}

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/.