MCPcopy Index your code
hub / github.com/RaunakChhatwal/fhsenv

github.com/RaunakChhatwal/fhsenv @main

Chat with this repo
repository ↗ · DeepWiki ↗ · + Follow
21 symbols 41 edges 2 files 8 documented · 38% updated 18mo ago★ 33
What it actually does AI analysis from the code graph — generated when you open this
loading…
README

fhsenv

fhsenv is a Rust dev-tool to install Nix packages into an FHS-compliant virtual shell. For example, an FHS environment with the clang, clang-tools, eigen, and libcxx.dev packages results in the following /usr/include: - c++/v1/ - eigen3/ - gawkapi.h

The corresponding shell.nix:

with import <nixpkgs> {};
(buildFHSUserEnv {
    name = "c++ environment w/ clangd";
    targetPkgs = pkgs: (with pkgs; [
        clang
        clang-tools   # for clangd
        eigen
        libcxx.dev
    ]);
}).env

Examples: - fhsenv /path/to/shell.nix: enters the FHS environment defined by the input file. - fhsenv -p hello: makes /usr/bin/hello available. - fhsenv --run 'sudo whoami': demonstrates sudo functionality, which is broken in the official implementation.

Installation

Caution: It's not recommended to install SUID programs when not authored by a cybersecurity expert. I however have convinced both myself and o1-preview that privilege escalation is effectively mitigated.

1) Declare the fhsenv package either in flake.nix or using callPackage with fetchFromGitHub. 2) Add fhsenv to environment.systemPackages. 3) Enable setuid in security.wrappers:

security.wrappers.fhsenv = {
  setuid = true;
  owner = "root";
  group = "root";
  source = "${fhsenv}/bin/fhsenv";
};

Implementation

fhsenv is implemented in Rust and leverages advanced Linux kernel features to create an isolated FHS environment. The official implementation of the FHS environment uses bubblewrap (an application sandboxing utility) to awkwardly achieve this goal. However, the goal is not to enter a sandbox, but simply to rearrange the view of the filesystem to comply with the file hierarchy standard. Each Linux namespace isolates a component of user space. For example, the mount namespace isolates the filesystem, the user namespace isolates user capabilities and permissions, the network namespace isolates the network stack, etc. fhsenv only uses the mount namespace* whereas the official implementation uses more. Unfortunately, entering a mount namespace without first isolating user capabilities with the user namespace requires the admin capability (CAP_SYS_ADMIN) because a malicious unprivileged user would bind mount onto sensitive security configuration like /etc/shadow, which stores password hashes. fhsenv is installed with setuid and takes effective measures to prevent privilege escalation inside the FHS environment: - Dropping privileges: only elevate privileges when necessary - creating the namespace and performing mount operations - and drop them afterwards. - protecting system configuration: normal packages use /run/current-system/sw/etc for configuration, whereas /etc stores system configuration. Entries in the host /etc/ take precedence over those of new packages. This mitigates the mount system call's privilege escalation risk.

Apart from these, fhsenv has general mitigations common to SUID programs such as being statically linked, using absolute paths for subprocesses (e.g. /run/current-system/sw/bin/nix-instantiate) instead of leaving it to $PATH, and more.

* As a learning exercise, I also implemented the user namespace but entering it has many of the drawbacks of the official implementation. fhsenv only creates a user namespace when its setuid bit is not enabled.

Core symbols most depended-on inside this repo

Shape

Function 17
Class 2
Enum 1
Method 1

Languages

Rust100%

Modules by API surface

src/main.rs18 symbols
src/prepare_env.rs3 symbols

For agents

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

⬇ download graph artifact

Ask about this repo answers extend the page