bootc-docs/exec-in-host-mount-namespace/bootc-exec-in-host-mount-namespace-technical-guide.md
robojerk 526f1c1afd Initial commit: Comprehensive Debian bootc documentation
- Complete documentation for all bootc commands and subcommands
- Debian-specific adaptations and workarounds
- Manual installation methods to bypass bootc reliability issues
- Technical guides with Rust source code analysis
- Flowcharts and external command references
- Hidden command documentation (bootc internals, state, etc.)
- Composefs integration analysis
- Base image creation guides (with and without bootc binary)
- Management scripts and automation
- Comprehensive troubleshooting and examples
2025-09-15 14:02:28 -07:00

13 KiB

bootc exec-in-host-mount-namespace - Technical Guide

Overview

bootc exec-in-host-mount-namespace is a hidden command that executes a given command in the host mount namespace. This is a critical low-level operation used internally by bootc for system operations that need to access the host's mount namespace from within a container or isolated environment.

Purpose

The exec-in-host-mount-namespace command serves several critical functions:

  1. Namespace Isolation: Execute commands in the host mount namespace from within containers
  2. System Operations: Perform operations that require access to the host's filesystem view
  3. Installation Support: Support installation operations that need host mount access
  4. Debugging: Provide access to host mount namespace for debugging and maintenance

Command Structure

/// Execute the given command in the host mount namespace
#[clap(hide = true)]
ExecInHostMountNamespace {
    #[clap(trailing_var_arg = true, allow_hyphen_values = true)]
    args: Vec<OsString>,
}

Core Functionality

Purpose

The command executes a specified command in the host mount namespace, allowing operations that need to access the host's filesystem view from within a container or isolated environment.

Usage

bootc exec-in-host-mount-namespace [ARGS]...

Implementation

#[context("Re-exec in host mountns")]
pub(crate) fn exec_in_host_mountns(args: &[std::ffi::OsString]) -> Result<()> {
    let (cmd, args) = args
        .split_first()
        .ok_or_else(|| anyhow::anyhow!("Missing command"))?;
    tracing::trace!("{cmd:?} {args:?}");
    
    // Open the host mount namespace
    let pid1mountns = std::fs::File::open("/proc/1/ns/mnt").context("open pid1 mountns")?;
    
    // Move into the host mount namespace
    rustix::thread::move_into_link_name_space(
        pid1mountns.as_fd(),
        Some(rustix::thread::LinkNameSpaceType::Mount),
    )
    .context("setns")?;
    
    // Change to root directory
    rustix::process::chdir("/").context("chdir")?;
    
    // Work around supermin doing chroot() and not pivot_root
    if !Utf8Path::new("/usr").try_exists().context("/usr")?
        && Utf8Path::new("/root/usr")
            .try_exists()
            .context("/root/usr")?
    {
        tracing::debug!("Using supermin workaround");
        rustix::process::chroot("/root").context("chroot")?;
    }
    
    // Execute the command
    Err(Command::new(cmd).args(args).arg0(bootc_utils::NAME).exec()).context("exec")?
}

Technical Details

1. Mount Namespace Operations

The command uses Linux mount namespace operations to switch to the host's mount namespace:

// Open the host mount namespace (PID 1)
let pid1mountns = std::fs::File::open("/proc/1/ns/mnt").context("open pid1 mountns")?;

// Move into the host mount namespace
rustix::thread::move_into_link_name_space(
    pid1mountns.as_fd(),
    Some(rustix::thread::LinkNameSpaceType::Mount),
)
.context("setns")?;

2. Directory Operations

After switching namespaces, the command ensures proper directory context:

// Change to root directory
rustix::process::chdir("/").context("chdir")?;

// Work around supermin doing chroot() and not pivot_root
if !Utf8Path::new("/usr").try_exists().context("/usr")?
    && Utf8Path::new("/root/usr")
        .try_exists()
        .context("/root/usr")?
{
    tracing::debug!("Using supermin workaround");
    rustix::process::chroot("/root").context("chroot")?;
}

3. Command Execution

The command executes the specified command with proper argument handling:

// Execute the command
Err(Command::new(cmd).args(args).arg0(bootc_utils::NAME).exec()).context("exec")?

Command Routing

The command is routed through the main CLI dispatcher:

Opt::ExecInHostMountNamespace { args } => {
    crate::install::exec_in_host_mountns(args.as_slice())
}

Helper Functions

1. run_in_host_mountns

A helper function to create a command that will execute in the host mount namespace:

/// Run a command in the host mount namespace
pub(crate) fn run_in_host_mountns(cmd: &str) -> Result<Command> {
    let mut c = Command::new(bootc_utils::reexec::executable_path()?);
    c.lifecycle_bind()
        .args(["exec-in-host-mount-namespace", cmd]);
    Ok(c)
}

2. ensure_self_unshared_mount_namespace

A function to ensure the process is in an unshared mount namespace:

#[context("Ensuring mountns")]
pub(crate) fn ensure_self_unshared_mount_namespace() -> Result<()> {
    let uid = rustix::process::getuid();
    if !uid.is_root() {
        tracing::debug!("Not root, assuming no need to unshare");
        return Ok(());
    }
    
    let recurse_env = "_ostree_unshared";
    let ns_pid1 = std::fs::read_link("/proc/1/ns/mnt").context("Reading /proc/1/ns/mnt")?;
    let ns_self = std::fs::read_link("/proc/self/ns/mnt").context("Reading /proc/self/ns/mnt")?;
    
    // If we already appear to be in a mount namespace, or we're already pid1, we're done
    if ns_pid1 != ns_self {
        tracing::debug!("Already in a mount namespace");
        return Ok(());
    }
    
    if std::env::var_os(recurse_env).is_some() {
        let am_pid1 = rustix::process::getpid().is_init();
        if am_pid1 {
            tracing::debug!("We are pid 1");
            return Ok(());
        } else {
            anyhow::bail!("Failed to unshare mount namespace");
        }
    }
    
    bootc_utils::reexec::reexec_with_guardenv(recurse_env, &["unshare", "-m", "--"])
}

Use Cases

1. Container Operations

When running inside a container, this command allows access to the host's mount namespace:

# Execute a command in the host mount namespace
bootc exec-in-host-mount-namespace ls /host/path

# Mount something in the host namespace
bootc exec-in-host-mount-namespace mount /dev/sda1 /mnt

2. Installation Support

During installation operations, this command provides access to the host filesystem:

# Access host filesystem during installation
bootc exec-in-host-mount-namespace mkdir -p /host/var/lib/bootc

# Copy files to host filesystem
bootc exec-in-host-mount-namespace cp /source/file /host/destination/

3. Debugging and Maintenance

For debugging and maintenance operations that need host access:

# Check host filesystem
bootc exec-in-host-mount-namespace df -h

# View host processes
bootc exec-in-host-mount-namespace ps aux

# Check host system status
bootc exec-in-host-mount-namespace systemctl status

4. System Integration

For system integration operations that require host mount namespace access:

# Update host bootloader
bootc exec-in-host-mount-namespace grub-mkconfig -o /boot/grub/grub.cfg

# Update host initramfs
bootc exec-in-host-mount-namespace update-initramfs -u

Technical Implementation

1. Namespace Switching

The command uses the setns system call to switch to the host mount namespace:

rustix::thread::move_into_link_name_space(
    pid1mountns.as_fd(),
    Some(rustix::thread::LinkNameSpaceType::Mount),
)
.context("setns")?;

2. Process Execution

The command uses exec to replace the current process with the target command:

Err(Command::new(cmd).args(args).arg0(bootc_utils::NAME).exec()).context("exec")?

3. Error Handling

Comprehensive error handling with context:

#[context("Re-exec in host mountns")]
pub(crate) fn exec_in_host_mountns(args: &[std::ffi::OsString]) -> Result<()> {
    // Implementation with automatic error context
}

Security Considerations

1. Privilege Requirements

The command requires appropriate privileges to access mount namespaces:

let uid = rustix::process::getuid();
if !uid.is_root() {
    tracing::debug!("Not root, assuming no need to unshare");
    return Ok(());
}

2. Namespace Access

The command accesses the host mount namespace through /proc/1/ns/mnt:

let pid1mountns = std::fs::File::open("/proc/1/ns/mnt").context("open pid1 mountns")?;

3. Process Isolation

The command executes in a different mount namespace, which provides isolation:

  • Mount Isolation: Commands run in the host mount namespace
  • Process Replacement: The current process is replaced with the target command
  • Namespace Switching: Uses setns to switch mount namespaces

Performance Characteristics

1. Execution Time

  • Fast: Minimal overhead for namespace switching
  • Atomic: Single atomic operation
  • Efficient: Direct system call usage

2. Resource Usage

  • Low CPU: Minimal CPU usage
  • Low Memory: Minimal memory usage
  • Namespace Overhead: Small overhead for namespace operations

3. System Impact

  • Namespace Switch: Changes mount namespace
  • Process Replacement: Replaces current process
  • Host Access: Provides access to host filesystem

Integration Points

1. Installation System

The command is used by the installation system for host operations:

// Used during installation
pub(crate) fn run_in_host_mountns(cmd: &str) -> Result<Command> {
    let mut c = Command::new(bootc_utils::reexec::executable_path()?);
    c.lifecycle_bind()
        .args(["exec-in-host-mount-namespace", cmd]);
    Ok(c)
}

2. Mount Namespace Management

The command integrates with mount namespace management:

// Ensure unshared mount namespace
ensure_self_unshared_mount_namespace()?;

3. Container Operations

The command supports container operations that need host access:

// Used in container contexts
if !external_source && std::env::var_os("BOOTC_SKIP_UNSHARE").is_none() {
    super::cli::ensure_self_unshared_mount_namespace()?;
}

Error Handling

1. Common Error Scenarios

Missing Command

let (cmd, args) = args
    .split_first()
    .ok_or_else(|| anyhow::anyhow!("Missing command"))?;

Namespace Access Error

let pid1mountns = std::fs::File::open("/proc/1/ns/mnt").context("open pid1 mountns")?;

Namespace Switch Error

rustix::thread::move_into_link_name_space(
    pid1mountns.as_fd(),
    Some(rustix::thread::LinkNameSpaceType::Mount),
)
.context("setns")?;

2. Error Recovery

The command provides comprehensive error context:

#[context("Re-exec in host mountns")]
pub(crate) fn exec_in_host_mountns(args: &[std::ffi::OsString]) -> Result<()> {
    // Implementation with automatic error context
}

Testing and Validation

1. Unit Tests

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_exec_in_host_mountns() {
        // Test command execution
        let args = vec!["ls".into(), "/".into()];
        let result = exec_in_host_mountns(&args);
        // Verify result
    }
}

2. Integration Tests

#[tokio::test]
async fn test_exec_in_host_mountns_integration() {
    // Test namespace switching
    let test_env = TestEnvironment::new().await.unwrap();
    
    // Test command execution in host namespace
    let result = test_env.run_command("bootc", &["exec-in-host-mount-namespace", "ls", "/"]).await;
    assert!(result.is_ok());
}

Best Practices

1. Usage Guidelines

  • Internal Use: This is an internal command, not for direct user use
  • Container Context: Use within container environments
  • Host Access: Use when host mount namespace access is needed
  • Debugging: Use for debugging and maintenance operations

2. Security Considerations

  • Privilege Requirements: Ensure appropriate privileges
  • Namespace Access: Verify namespace access permissions
  • Command Validation: Validate commands before execution
  • Error Handling: Implement proper error handling

3. Performance Optimization

  • Minimal Overhead: Use only when necessary
  • Efficient Execution: Use direct system calls
  • Resource Management: Manage resources appropriately
  • Error Recovery: Implement proper error recovery

Future Enhancements

1. Additional Namespace Support

Potential support for other namespaces:

pub(crate) enum NamespaceType {
    Mount,
    PID,
    Network,
    User,
    IPC,
    UTS,
    Cgroup,
}

2. Enhanced Security

Enhanced security features:

pub(crate) struct SecurityOptions {
    pub drop_capabilities: bool,
    pub restrict_filesystem: bool,
    pub sandbox_command: bool,
}

3. Monitoring and Logging

Enhanced monitoring and logging:

pub(crate) struct ExecutionOptions {
    pub log_execution: bool,
    pub monitor_resources: bool,
    pub track_namespace_changes: bool,
}

This technical guide provides comprehensive understanding of the bootc exec-in-host-mount-namespace system's functionality, implementation, and usage patterns.