Skip to main content

Crate lisy

Crate lisy 

Source
Expand description

§Linux specific System API

Higher level APIs targeting newer Linux kernel features.

This crate provides somewhat higher level access to more modern features of the Linux kernel, such as builder-style access to the new mount API, openat2(2) call with a builder for the struct open_how parameters, all the new features of the statx(2) system call (such as finding out whether a path is a mount point), or to build user namespace file descriptors (which requires spawning processes and is therefore somewhat inconvenient to do manually).

§The new open API:

In the standard library files are simply opened by path, but this leaves out some important features:

  • Opening files relative to a directory handle.
  • Treating such a handle as if we were chrooted into the directory.
  • Deciding whether or not symlinks should be followed, not only for the final component, but also during the entire path traversal.

The OpenHow builder can be used for these things.

use lisy::open::OpenHow;

let ct_dir = OpenHow::new_directory()       // start with `O_DIRECTORY | O_CLOEXEC | O_NOCTTY`
    .resolve_no_symlinks(true)              // do not allow *any* symlinks in the path
    .resolve_no_xdev(true)                  // do not allow crossing file system boundaries
    .open("/my/container")                  // returns an `OwnedFd`
    .context("failed to open /my/container")?;

// Now open a file within `/my/container` as if it was the root file system:
let file_in_container = OpenHow::new_read()
    .at_fd(&ct_dir)                         // open relative to `ct_dir`
    .resolve_in_root(true)                  // virtually "chroot" into `ct_dir`
    .open_file("/usr/share/some/file")      // convenience method to get a `std::fs::File`
    .context("failed to open /my/container/usr/share/some/file")?;

§The new mount API:

This provides handles representing file systems, superblocks and mount trees.

use lisy::mount::{Mount, MountSetAttr, MoveMount, OpenTree};
use lisy::userns::{IdMapping, Userns};

// Open a directory as a new detached mount tree:
let mount = Mount::open_tree("/mnt/a", OpenTree::CLOEXEC | OpenTree::CLONE, 0)
    .context("failed to clone tree at /mnt/a")?;

// Prepare a user namespace for ID mapping
let userns = Userns::builder().context("failed to prepare user namespace")?;
userns.map_gids(&[IdMapping::new(0..65536, 100000)])?;
userns.map_uids(&[IdMapping::new(0..65536, 100000)])?;
let userns = userns
    .into_fd()
    .context("failed to finish creating user namespace")?;

// Apply the namespace
mount
    .setattr(
        &MountSetAttr::new().idmap(&userns),
        libc::AT_RECURSIVE | libc::AT_NO_AUTOMOUNT,
    )
    .context("failed to apply idmapping to mount tree")?;

// Bind-mount into place:
mount
    .move_mount("/mnt/mapped", MoveMount::empty())
    .context("failed to move id-mapped mount into place")?;

Modules§

fs
Some higher-level file system operations found in std::fs with file descriptor support, such as create_dir_all but with a file descriptor as first parameter.
mount
Linux >=5.2 file system mount API.
ns
Marker types for namespace types.
open
Higher level openat2 interface.
pidfd
pidfds are handles to processes which can be polled and used to send signals and other operations, they are much more powerful than numerical PIDs.
userns
Module for simplified user namespace creation. Requires kernel >=5.3.