Skip to content

Commit

Permalink
MacOS: run codesign on all modified binaries
Browse files Browse the repository at this point in the history
  • Loading branch information
timbertson committed Feb 1, 2024
1 parent 573d810 commit 5d6a690
Show file tree
Hide file tree
Showing 2 changed files with 44 additions and 6 deletions.
48 changes: 42 additions & 6 deletions cli/src/rewrite.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use log::*;
use memmap2::MmapMut;
use std::{path::Path, fs};
use walkdir::WalkDir;
use std::process::{Command, Stdio};
use crate::{paths::{RewritePaths, self}, store::StoreIdentity};

fn windows_mut_each<T>(v: &mut [T], n: usize, mut f: impl FnMut(&mut [T])) {
Expand Down Expand Up @@ -59,6 +60,37 @@ impl RewriteReferences {
}
}

// MacOS will kill processes if their executables (and dynamic libs) aren't signed.
// Thankfully we can use an ad-hoc signature which makes the exe valid, without
// needing an actual certificate etc.
#[cfg(not(target_os = "macos"))]
fn fix_rewritten_file(stat: &s::Metadata, path: &Path) -> Result<()> { Ok(()) }
#[cfg(target_os = "macos")]
fn fix_rewritten_file(stat: &fs::Metadata, path: &Path) -> Result<()> {
// need to cover all binaries and libraries.
// Other "executable" files like bash scripts will
// hit this code path, but codesign seems to happily
// skip those :shrug:

if stat.is_file() && paths::util::is_executable(stat.permissions()) {
let mut cmd = Command::new("codesign");
cmd
.arg("-s").arg("-") // ad-hoc signature
.arg("-f") // replace existing signature
.arg(path)
.stderr(Stdio::null());
debug!("Running {:?}", &cmd);
let output = cmd.output().with_context(||format!("Running {:?}", &cmd))?;
if output.status.success() {
Ok(())
} else {
Err(anyhow!("Command failed: {:?}", &cmd))
}
} else {
Ok(())
}
}

// TODO support for some kind of opt-out via .nix-support/runix?
pub fn rewrite_all_recursively<'a, P: AsRef<Path>, R: IntoIterator<Item=&'a StoreIdentity>>(
src_path: &P,
Expand All @@ -75,13 +107,17 @@ pub fn rewrite_all_recursively<'a, P: AsRef<Path>, R: IntoIterator<Item=&'a Stor
let stat = entry.metadata()?;
if stat.is_file() {
paths::util::ensure_writeable(path)?;
let file = fs::OpenOptions::new()
.read(true)
.write(true)
.open(&path)?;
let mut mmap = unsafe { MmapMut::map_mut(&file)? };
let count = rewrite.replace_all(&mut mmap);
let count = {
// locally scoped so file / mmap are closed immediately
let file = fs::OpenOptions::new()
.read(true)
.write(true)
.open(&path)?;
let mut mmap = unsafe { MmapMut::map_mut(&file)? };
rewrite.replace_all(&mut mmap)
};
if count > 0 {
fix_rewritten_file(&stat, &path)?;
debug!("Replaced {} items in {:?}", count, path);
}
}
Expand Down
2 changes: 2 additions & 0 deletions cli/src/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,8 @@ impl StoreMeta {
#[derive(Clone, Debug)]
pub struct StoreMetaFull {
meta: StoreMeta,

#[allow(dead_code)] // future use
used_timestamp: FileTime,
}

Expand Down

0 comments on commit 5d6a690

Please sign in to comment.