Skip to content

Commit

Permalink
Make go run work on macOS with go 1.21 (metalbear-co#2207)
Browse files Browse the repository at this point in the history
* Strip prefix in exec, work on temp binary.

* doc

* don't change tracing.

* changelog

* conditional comp

* oops
  • Loading branch information
t4lz authored Jan 28, 2024
1 parent 19acf76 commit 2e83f3d
Show file tree
Hide file tree
Showing 9 changed files with 566 additions and 884 deletions.
1,391 changes: 526 additions & 865 deletions Cargo.lock

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions changelog.d/2202.fixed.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Running `mirrod exec go run EXECUTABLE` on macOS with go1.21.
11 changes: 8 additions & 3 deletions mirrord/layer/src/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,16 +82,21 @@ impl CheckedInto<String> for *const c_char {
}
}

#[cfg(target_os = "macos")]
pub fn strip_mirrord_path(path_str: &str) -> Option<&str> {
path_str
.strip_prefix(MIRRORD_TEMP_BIN_DIR_STRING.as_str())
.or_else(|| path_str.strip_prefix(MIRRORD_TEMP_BIN_DIR_CANONIC_STRING.as_str()))
}

impl CheckedInto<PathBuf> for *const c_char {
/// Do the checked conversion to str, bypass if the str starts with temp dir's path, construct
/// a `PathBuf` out of the str.
fn checked_into(self) -> Detour<PathBuf> {
let str_det = CheckedInto::<&str>::checked_into(self);
#[cfg(target_os = "macos")]
let str_det = str_det.and_then(|path_str| {
let optional_stripped_path = path_str
.strip_prefix(MIRRORD_TEMP_BIN_DIR_STRING.as_str())
.or_else(|| path_str.strip_prefix(MIRRORD_TEMP_BIN_DIR_CANONIC_STRING.as_str()));
let optional_stripped_path = strip_mirrord_path(path_str);
if let Some(stripped_path) = optional_stripped_path {
// actually stripped, so bypass and provide a pointer to after the temp dir.
// `stripped_path` is a reference to a later character in the same string as
Expand Down
7 changes: 6 additions & 1 deletion mirrord/layer/src/exec_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use null_terminated::Nul;
use tracing::{trace, warn};

use crate::{
common::CheckedInto,
common::{strip_mirrord_path, CheckedInto},
detour::{
Bypass::{
ExecOnNonExistingFile, FileOperationInMirrordBinTempDir, NoSipDetected, TooManyArgs,
Expand Down Expand Up @@ -185,6 +185,11 @@ unsafe fn patch_sip_for_new_process(
trace!("Executable {} called execve/posix_spawn", calling_exe);

let path_str = path.checked_into()?;
// If an application is trying to run an executable from our tmp dir, strip our tmp dir from the
// path. The file might not even exist in our tmp dir, and the application is expecting it there
// only because it somehow found out about its own patched location in our tmp dir.
// If original path is SIP, and actually exists in our dir that patched executable will be used.
let path_str = strip_mirrord_path(path_str).unwrap_or(path_str);
let path_c_string = patch_if_sip(path_str)
.and_then(|new_path| Success(CString::new(new_path)?))
// Continue also on error, use original path, don't bypass yet, try cleaning argv.
Expand Down
5 changes: 3 additions & 2 deletions mirrord/sip/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,10 @@ publish.workspace = true
edition.workspace = true

[dependencies]
object = "0.29"
apple-codesign = { version = "0.27", default-features = false}
memchr = "2"
apple-codesign = { version = "0.22", default-features = false}
object = "0.32"
tempfile = "3"

once_cell.workspace = true
tracing.workspace = true
Expand Down
3 changes: 3 additions & 0 deletions mirrord/sip/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,7 @@ pub enum SipError {

#[error("Got invalid string.")]
NonUtf8Str(#[from] std::str::Utf8Error),

#[error("Could not move temporary SIP-patched binary into temp dir. IO error: `{0}`.")]
BinaryMoveFailed(std::io::Error),
}
23 changes: 18 additions & 5 deletions mirrord/sip/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ mod main {
use std::{
env,
ffi::OsStr,
io::{self, Read},
io::{self, ErrorKind::AlreadyExists, Read},
os::{macos::fs::MetadataExt, unix::fs::PermissionsExt},
path::{Path, PathBuf},
str::from_utf8,
Expand Down Expand Up @@ -274,6 +274,10 @@ mod main {
return Ok(output);
}

// If the same file is executed in parallel, parallel signing could fail. So do the work on
// a temp file, and then move it to its final destination once ready and signed.
let temp_binary = tempfile::NamedTempFile::new()?;

trace!(
"{:?} is a SIP protected binary, making non protected version at: {:?}",
path,
Expand All @@ -290,18 +294,27 @@ mod main {
.get(binary_info.offset..binary_info.offset + binary_info.size)
.expect("invalid SIP binary");

std::fs::write(&output, binary)?;
std::fs::write(&temp_binary, binary)?;

if let Err(err) = get_rpath_entries(binary)
.and_then(|rpath_entries| add_rpath_entries(&rpath_entries, path, output.as_ref()))
.and_then(|rpath_entries| add_rpath_entries(&rpath_entries, path, temp_binary.as_ref()))
{
warn!("Adding Rpath loader commands to SIP-patched binary failed with {err:?}.")
// Not stopping the SIP-patching as most binaries don't need the rpath fix.
}

// Give the new file the same permissions as the old file.
std::fs::set_permissions(&output, std::fs::metadata(path)?.permissions())?;
codesign::sign(&output)?;
trace!("Setting permissions for {temp_binary:?}");
std::fs::set_permissions(&temp_binary, std::fs::metadata(path)?.permissions())?;
trace!("Signing {temp_binary:?}");
codesign::sign(&temp_binary)?;

// Move the temp binary into its final location if no other process/thread already did.
if let Err(err) = temp_binary.persist_noclobber(&output) {
if err.error.kind() != AlreadyExists {
return Err(SipError::BinaryMoveFailed(err.error));
}
}
Ok(output)
}

Expand Down
2 changes: 1 addition & 1 deletion tests/go-e2e/go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module go-e2e

go 1.19
go 1.21

require github.com/gin-gonic/gin v1.9.1

Expand Down
7 changes: 0 additions & 7 deletions tests/go-e2e/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,13 @@ github.com/chenzhuoyu/base64x v0.0.0-20230717121745-296ad89f973d/go.mod h1:8EPpV
github.com/chenzhuoyu/iasm v0.9.0 h1:9fhXjVzq5hUy2gkhhgHl95zG2cEAhw9OSGs8toWWAwo=
github.com/chenzhuoyu/iasm v0.9.0/go.mod h1:Xjy2NpN3h7aUqeqM+woSuuvxmIe6+DDsiNLIrkAmYog=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/gabriel-vasile/mimetype v1.4.2 h1:w5qFW6JKBz9Y393Y4q372O9A7cUSequkh1Q7OhCmWKU=
github.com/gabriel-vasile/mimetype v1.4.2/go.mod h1:zApsH/mKG4w07erKIaJPFiX0Tsq9BFQgN3qGY5GnNgA=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.9.1 h1:4idEAncQnU5cB7BeOkPtxjfCSye0AAm1R0RVIqJ+Jmg=
github.com/gin-gonic/gin v1.9.1/go.mod h1:hPrL7YrpYKXt5YId3A/Tnip5kqbEAP+KLuI3SUcPTeU=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
Expand All @@ -27,7 +25,6 @@ github.com/go-playground/validator/v10 v10.15.4/go.mod h1:9iXMNT7sEkjXb0I+enO7QX
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
Expand All @@ -47,7 +44,6 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/pelletier/go-toml/v2 v2.1.0 h1:FnwAJ4oYMvbT/34k9zzHuZNrhlz48GB3/s6at6/MHO4=
github.com/pelletier/go-toml/v2 v2.1.0/go.mod h1:tJU2Z3ZkXwnxa4DPO899bsyIoywizdUvyaeZurnPPDc=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
Expand All @@ -58,7 +54,6 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
Expand All @@ -77,12 +72,10 @@ golang.org/x/sys v0.12.0 h1:CM0HF96J0hcLAwsHPJZjfdNzs0gftsLfgKt57wWHJ0o=
golang.org/x/sys v0.12.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.13.0 h1:ablQoSUd0tRdKxZewP80B+BaqeKJuVhuRxj/dkrun3k=
golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.31.0 h1:g0LDEJHgrBl9N9r17Ru3sqWhkIx2NB67okBHPwC7hs8=
google.golang.org/protobuf v1.31.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
Expand Down

0 comments on commit 2e83f3d

Please sign in to comment.