astrid-runtime/astrid · error

mountpoint ancestor is writable without sticky protection: {

Error message

mountpoint ancestor is writable without sticky protection: {}

What it means

This error is raised by validate_mountpoint_ancestors when walking up every ancestor directory of a mountpoint and finding a directory that is group/other-writable (mode & 0o022 != 0) without the sticky bit set (mode & 0o1000 == 0). Such a directory lets any local user swap or replace the mountpoint path, enabling a symlink/mount-target attack, so the FSKit provider refuses to mount or unmount through it. It is a local-security hardening check, not a functional failure.

Source

Thrown at crates/astrid-storage-provider-fskit/src/main.rs:509

        bail!(
            "macOS did not activate an astridfs mount at {}",
            mountpoint.display()
        );
    }
    Ok(())
}

#[cfg(unix)]
fn validate_mountpoint_ancestors(mountpoint: &Path) -> Result<()> {
    use std::os::unix::fs::MetadataExt as _;

    let mut ancestor = mountpoint.parent();
    while let Some(path) = ancestor {
        let metadata = std::fs::symlink_metadata(path)
            .with_context(|| format!("inspect mountpoint ancestor {}", path.display()))?;
        let mode = metadata.mode();
        if mode & 0o022 != 0 && mode & 0o1000 == 0 {
            bail!(
                "mountpoint ancestor is writable without sticky protection: {}",
                path.display()
            );
        }
        ancestor = path.parent();
    }
    Ok(())
}

#[cfg(not(unix))]
fn validate_mountpoint_ancestors(mountpoint: &Path) -> Result<()> {
    let _ = mountpoint;
    Ok(())
}

fn validate_mountpoint_layout(mountpoint: &Path) -> Result<()> {
    if !mountpoint.is_absolute() {
        bail!("mountpoint must be absolute");

View on GitHub (pinned to affd8760f4)

Solutions

  1. Move the mountpoint under a root-owned, non-world-writable directory such as /Volumes or /mnt
  2. Set the sticky bit on the ancestor: chmod +t /path/to/ancestor
  3. Tighten the ancestor permissions: chmod o-w,g-w /path/to/ancestor
  4. Verify with ls -ld each ancestor of the mountpoint until none are world-writable without +t

Example fix

// before (ancestor /srv/scratch is 0777)
mountpoint = /srv/scratch/fs/mnt
// after
sudo chmod 0755 /srv/scratch  # or chmod +t /srv/scratch
mountpoint = /srv/scratch/fs/mnt
Defensive patterns

Strategy: validation

Validate before calling

fn mountpoint_ancestors_are_safe(mp: &std::path::Path) -> std::io::Result<()> {
    let mut ancestor = mp.parent();
    while let Some(path) = ancestor {
        let mode = std::fs::symlink_metadata(path)?.mode();
        if mode & 0o022 != 0 && mode & 0o1000 == 0 {
            return Err(std::io::Error::new(
                std::io::ErrorKind::PermissionDenied,
                format!("{} writable without sticky", path.display()),
            ));
        }
        ancestor = path.parent();
    }
    Ok(())
}

Type guard

fn is_protected_dir(md: &std::fs::Metadata) -> bool {
    let mode = md.mode();
    mode & 0o022 == 0 || mode & 0o1000 != 0
}

Prevention

When it happens

Trigger: Calling mount/unmount (directly or via prepare_mountpoint, validate_mounted_mountpoint, validate_unmounted_mountpoint) when any parent directory of the mountpoint — e.g. /tmp/mnt with mode 0777 — is writable by non-owner and lacks the sticky bit.

Common situations: Mounting under a world-writable scratch directory such as /tmp/mymount where the user created a non-sticky subdirectory; CI containers where /var/mnt was created with 0777; reusing a shared build-artifact directory as a mount parent.

Understand the failure class

Background: "You do not have permission" / 403 Forbidden errors: authenticated but not allowed — causes and fixes across open-source libraries — this error's family across 31 libraries.

Related errors


AI-assisted analysis of astrid-runtime/astrid@affd8760f4 (2026-09-09). Data as JSON: /api/errors/96bd5de6e8d240ce. Report an issue: GitHub.