Skip to content

Commit

Permalink
Improvements to macOS support
Browse files Browse the repository at this point in the history
  • Loading branch information
smoelius committed Apr 12, 2024
1 parent 569c449 commit 26aabc4
Show file tree
Hide file tree
Showing 6 changed files with 50 additions and 22 deletions.
3 changes: 2 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,16 @@ edition = "2021"
license = "AGPL-3.0"
repository = "https://github.com/trailofbits/build-wrap"

# smoelius: This list of dependencies should match what is in src/wrapper.rs.
[dependencies]
anyhow = "1.0"
once_cell = "1.19"
tempfile = "3.10"

[dev-dependencies]
assert_cmd = "2.0"
cargo_metadata = "0.18"
ctor = "0.2"
once_cell = "1.19"

[lints.clippy]
pedantic = { level = "warn", priority = -1 }
Expand Down
29 changes: 19 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ Installing `build-wrap` requires two steps:
linker = "build-wrap"
```

## Environment variables
## Environment variables that `build-wrap` reads

- `BUILD_WRAP_CMD`: Command used to execute a build script. Linux default:

Expand All @@ -40,15 +40,16 @@ Installing `build-wrap` requires two steps:
sandbox-exec -p
(version\ 1)\
(deny\ default)\
(allow\ file-read*)\ # Allow read-only access everywhere
(allow\ file-write*\ (subpath\ "/dev"))\ # Allow write access to /dev
(allow\ file-write*\ (subpath\ "{OUT_DIR}"))\ # Allow write access to `OUT_DIR`
(allow\ file-write*\ (subpath\ "{TMPDIR}"))\ # Allow write access to `TMPDIR`
(allow\ process-exec)\ # Allow `exec`
(allow\ process-fork)\ # Allow `fork`
(allow\ sysctl-read)\ # Allow reading kernel state
(deny\ network*) # Deny network access
{} # Build script path
(allow\ file-read*)\ # Allow read-only access everywhere
(allow\ file-write*\ (subpath\ "/dev"))\ # Allow write access to /dev
(allow\ file-write*\ (subpath\ "{OUT_DIR}"))\ # Allow write access to `OUT_DIR`
(allow\ file-write*\ (subpath\ "{TMPDIR}"))\ # Allow write access to `TMPDIR`
(allow\ file-write*\ (subpath\ "{PRIVATE_TMPDIR}"))\ # Allow write access to `PRIVATE_TMPDIR` (see below)
(allow\ process-exec)\ # Allow `exec`
(allow\ process-fork)\ # Allow `fork`
(allow\ sysctl-read)\ # Allow reading kernel state
(deny\ network*) # Deny network access
{} # Build script path
```

Note that `(version\ 1)\ ... (deny\ network*)` expands to a single string (see [How `BUILD_WRAP_CMD` is expanded] below).
Expand All @@ -57,6 +58,12 @@ Installing `build-wrap` requires two steps:

Note that the above environment variables are read **when the build script is linked**. So, for example, changing `BUILD_WRAP_CMD` will not change the command used to execute already linked build scripts.

## Environment variables that `build-wrap` treats as set

Note that we say "treats as set" because these are considered only when [`BUILD_WRAP_CMD` is expanded].

- `PRIVATE_TMPDIR`: If `TMPDIR` is set to a path in `/private` (as is typical on macOS), then `PRIVATE_TMPDIR` expands to that path. This is needed for some build scripts that use [`cc-rs`], though the exact reason it is needed is still unknown.

## How `BUILD_WRAP_CMD` is expanded

- `{}` is replaced with the path of a copy of the original build script.
Expand Down Expand Up @@ -89,5 +96,7 @@ Given a build script `B`, its "wrapped" version `B'` contains a copy of `B` and
[Environment variables]: #environment-variables
[How it works]: #how-it-works
[How `BUILD_WRAP_CMD` is expanded]: #how-build_wrap_cmd-is-expanded
[`BUILD_WRAP_CMD` is expanded]: #how-build_wrap_cmd-is-expanded
[`cc-rs`]: https://github.com/rust-lang/cc-rs
[`sandbox-exec`]: https://keith.github.io/xcode-man-pages/sandbox-exec.1.html
[manner described above]: #how-build_wrap_cmd-is-expanded
9 changes: 1 addition & 8 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,21 +21,14 @@ const DEFAULT_CMD: &str = if cfg!(target_os = "linux") {
} else {
// smoelius: The following blog post is a useful `sandbox-exec` reference:
// https://7402.org/blog/2020/macos-sandboxing-of-folder.html
// smoelius: The following package does not build with the current `sandbox-exec` command:
// https://crates.io/crates/psm
// Adding the following line fixes the problem:
// ```
// (allow\ file-write*\ (subpath\ "/private{TMPDIR}"))\
// ```
// However, I don't want to pollute the command for this one package. This issue requires
// further investigation.
r#"sandbox-exec -p
(version\ 1)\
(deny\ default)\
(allow\ file-read*)\
(allow\ file-write*\ (subpath\ "/dev"))\
(allow\ file-write*\ (subpath\ "{OUT_DIR}"))\
(allow\ file-write*\ (subpath\ "{TMPDIR}"))\
(allow\ file-write*\ (subpath\ "{PRIVATE_TMPDIR}"))\
(allow\ process-exec)\
(allow\ process-fork)\
(allow\ sysctl-read)\
Expand Down
24 changes: 22 additions & 2 deletions src/util/common.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
//! This file is included verbatim in the wrapper build script's src/main.rs file.
use anyhow::{anyhow, bail, ensure, Context, Result};
use once_cell::sync::Lazy;
use std::{
env::var,
fs::{set_permissions, Permissions},
env,
fs::{canonicalize, set_permissions, Permissions},
io::Write,
os::unix::fs::PermissionsExt,
path::Path,
Expand Down Expand Up @@ -198,3 +199,22 @@ pub fn __expand_cmd(mut cmd: &str, build_script_path: &Path) -> Result<String> {

Ok(buf)
}

static PRIVATE_TMPDIR: Lazy<Option<String>> = Lazy::new(|| {
var("TMPDIR").ok().and_then(|value| {
let path = canonicalize(value).ok()?;
if path.starts_with("/private") {
path.to_utf8().map(ToOwned::to_owned).ok()
} else {
None
}
})
});

fn var(key: &str) -> Result<String, env::VarError> {
if key == "PRIVATE_TMPDIR" {
return PRIVATE_TMPDIR.clone().ok_or(env::VarError::NotPresent);
}

env::var(key)
}
3 changes: 2 additions & 1 deletion src/wrapper.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,8 @@ publish = false
[dependencies]
anyhow = "1.0"
tempfile = "3.9"
once_cell = "1.19"
tempfile = "3.10"
"#;

/// A wrapper build script's src/main.rs consists of the following:
Expand Down
4 changes: 4 additions & 0 deletions tests/util.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@ publish = false
[build-dependencies]
libc = { version = "0.2", optional = true }
rustc_version = { version = "0.4", optional = true }
# smoelius: `psm` (https://crates.io/crates/psm) is an example of a package that requires write
# access to `PRIVATE_TMPDIR` to build. `psm` isn't actually needed by any of the integration tests.
psm = { version = "0.1", optional = true }
"#;

static METADATA: Lazy<Metadata> = Lazy::new(|| MetadataCommand::new().no_deps().exec().unwrap());
Expand Down

0 comments on commit 26aabc4

Please sign in to comment.