diff --git a/src/apt/keyring.rs b/src/apt/keyring.rs index f6357f5..40eec9c 100644 --- a/src/apt/keyring.rs +++ b/src/apt/keyring.rs @@ -89,24 +89,27 @@ pub async fn download_cache_keyrings( keyring_dir.display() ) })?; + // Upgrade cache directories created by versions that made them + // private: mmdebstrap's unshare-mode hooks cannot read them. } else { // Remote contexts (e.g. ssh) have no stat/metadata access through // the context API, so the ownership guard cannot be performed; // keep the previous best-effort behavior of tightening the - // directory permissions instead (0700 instead of the former - // world-writable a+rwx). - ctx.command("chmod").arg("700").arg(&keyring_dir).status()?; + // directory permissions instead (no group/others write). } + ctx.command("chmod").arg("755").arg(&keyring_dir).status()?; } else { - // Create the directory private to the invoking user (0700). This is - // sufficient for mmdebstrap in unshare mode: it runs with the same - // real uid (the user namespace only maps that uid to root, file - // access still happens as the real uid), so no world-accessible - // permissions are needed. + // Create the directory readable but not writable by group/others. + // mmdebstrap's unshare-mode hooks run under an identity that cannot + // read the invoking user's private directories, so 0700 breaks the + // keyring copy into the chroot; the planting guard stays on the + // ownership and no-write checks of validate_keyring_dir (the + // skip-if-exists logic below trusts pre-existing keyrings, so the + // directory must never be writable by anyone else). ctx.command("mkdir") .arg("-p") .arg("-m") - .arg("700") + .arg("755") .arg(&keyring_dir) .status()?; } @@ -178,6 +181,11 @@ pub async fn download_cache_keyrings( binary_path.display() ); } + + // Readable like the directory: mmdebstrap's hooks copy these into + // the chroot. Applies to legacy files too, which a restrictive + // umask may have left private, and a permissive one group-writable. + let _ = ctx.command("chmod").arg("644").arg(&binary_path).status(); } log::info!( @@ -348,6 +356,10 @@ mod tests { assert!(validate_keyring_dir(1000, 0o750, 1000).is_ok()); assert!(validate_keyring_dir(1000, 0o1744, 1000).is_ok()); assert!(validate_keyring_dir(0, 0o700, 0).is_ok()); + // The world-readable modes the cache now uses: readable so that + // mmdebstrap's unshare-mode hooks can copy the keyrings, while the + // ownership and no-write checks keep the planting guard. + assert!(validate_keyring_dir(1000, 0o755, 1000).is_ok()); } #[test]