safe_path/lib.rs
1// Copyright (c) 2022 Alibaba Cloud
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5
6//! A library to safely handle filesystem paths, typically for container runtimes.
7//!
8//! Linux [mount namespace](https://man7.org/linux/man-pages/man7/mount_namespaces.7.html)
9//! provides isolation of the list of mounts seen by the processes in each
10//! [namespace](https://man7.org/linux/man-pages/man7/namespaces.7.html) instance.
11//! Thus, the processes in each of the mount namespace instances will see distinct single-directory
12//! hierarchies.
13//!
14//! Containers are used to isolate workloads from the host system. Container on Linux systems
15//! depends on the mount namespace to build an isolated root filesystem for each container,
16//! thus protect the host and containers from each other. When creating containers, the container
17//! runtime needs to setup filesystem mounts for container rootfs/volumes. Configuration for
18//! mounts/paths may be indirectly controlled by end users through:
19//! - container images
20//! - Kubernetes pod specifications
21//! - hook command line arguments
22//!
23//! These volume configuration information may be controlled by end users/malicious attackers,
24//! so it must not be trusted by container runtimes. When the container runtime is preparing mount
25//! namespace for a container, it must be very careful to validate user input configuration
26//! information and ensure data out of the container rootfs directory won't be affected
27//! by the container. There are several types of attacks related to container mount namespace:
28//! - symlink based attack
29//! - Time of check to time of use (TOCTTOU)
30//!
31//! This crate provides several mechanisms for container runtimes to safely handle filesystem paths
32//! when preparing mount namespace for containers.
33//! - [scoped_join()](crate::scoped_join()): safely join `unsafe_path` to `root`, and ensure
34//! `unsafe_path` is scoped under `root`.
35//! - [scoped_resolve()](crate::scoped_resolve()): resolve `unsafe_path` to a relative path,
36//! rooted at and constrained by `root`.
37//! - [struct PinnedPathBuf](crate::PinnedPathBuf): safe version of `PathBuf` to protect from
38//! TOCTTOU style of attacks, which ensures:
39//! - the value of [`PinnedPathBuf::as_path()`] never changes.
40//! - the path returned by [`PinnedPathBuf::as_path()`] is always a symlink.
41//! - the filesystem object referenced by the symlink [`PinnedPathBuf::as_path()`] never changes.
42//! - the value of [`PinnedPathBuf::target()`] never changes.
43//! - [struct ScopedDirBuilder](crate::ScopedDirBuilder): safe version of `DirBuilder` to protect
44//! from symlink race and TOCTTOU style of attacks, which enhances security by:
45//! - ensuring the new directories are created under a specified `root` directory.
46//! - avoiding symlink race attacks during making directories.
47//! - returning a [PinnedPathBuf] for the last level of directory, so it could be used for other
48//! operations safely.
49//!
50//! The work is inspired by:
51//! - [`filepath-securejoin`](https://github.com/cyphar/filepath-securejoin): secure_join() written
52//! in Go.
53//! - [CVE-2021-30465](https://github.com/advisories/GHSA-c3xm-pvg7-gh7r): symlink related TOCTOU
54//! flaw in `runC`.
55
56#![deny(missing_docs)]
57
58mod pinned_path_buf;
59pub use pinned_path_buf::PinnedPathBuf;
60
61mod scoped_dir_builder;
62pub use scoped_dir_builder::ScopedDirBuilder;
63
64mod scoped_path_resolver;
65pub use scoped_path_resolver::{scoped_join, scoped_resolve};