| Crates.io | build-wrap |
| lib.rs | build-wrap |
| version | 0.5.1 |
| created_at | 2024-03-14 16:31:31.155082+00 |
| updated_at | 2025-02-04 12:57:43.201393+00 |
| description | Help protect against malicious build scripts |
| homepage | |
| repository | https://github.com/trailofbits/build-wrap |
| max_upload_size | |
| id | 1173520 |
| size | 116,816 |
A linker replacement to help protect against malicious build scripts
build-wrap "re-links" a build script so that it is executed under another command. By default, the command is Bubblewrap (Linux) or sandbox-exec (macOS), though this is configurable. See Environment variables that build-wrap reads and How build-wrap works for more information.
Installing build-wrap requires two steps:
build-wrap with Cargo:
cargo install build-wrap
.cargo/config.toml file in your home directory with the following contents:
[target.'cfg(all())']
linker = "build-wrap"
Ubuntu's default AppArmor profiles changed with version 24.04. The changes affect Bubblewrap, which in turn affect build-wrap. Thus, installing build-wrap on Ubuntu 24.04 requires some additional steps:
sudo apt install apparmor-profiles
sudo cp /usr/share/apparmor/extra-profiles/bwrap-userns-restrict /etc/apparmor.d
sudo systemctl reload apparmor
Note that following these additional steps, Bubblewrap still runs unprivileged. More information on AppArmor profiles can be found on Ubuntu Server and the Ubuntu Community Wiki.
build-wrap readsNote that the below environment variables are read when a build script is linked. So, for example, changing BUILD_WRAP_CMD will not change the command used to execute already linked build scripts.
BUILD_WRAP_ALLOW: When set to a value other than 0, build-wrap uses the following weakened strategy. If running a build script under BUILD_WRAP_CMD fails, report the failure and rerun the build script normally.
Note that to see the reported failures, you must invoke Cargo with the -vv ("very verbose") flag, e.g.:
BUILD_WRAP_ALLOW=1 cargo build -vv
If a package must always be built with this strategy, put the package's name in $HOME/.config/build-wrap/allow.txt (see below).
BUILD_WRAP_CMD: Command used to execute a build script. Linux default:
With comments:
bwrap
--ro-bind / / # Allow read-only access everywhere
--dev-bind /dev /dev # Allow device access
--bind {OUT_DIR} {OUT_DIR} # Allow write access to `OUT_DIR`
--bind /tmp /tmp # Allow write access to /tmp
--unshare-net # Deny network access
{} # Build script path
On one line (for copying-and-pasting):
bwrap --ro-bind / / --dev-bind /dev /dev --bind {OUT_DIR} {OUT_DIR} --bind /tmp /tmp --unshare-net {}
Note that bwrap is Bubblewrap.
macOS default:
sandbox-exec -f {BUILD_WRAP_PROFILE_PATH} {}
See Environment variables that build-wrap treats as set regarding BUILD_WRAP_PROFILE_PATH.
BUILD_WRAP_LD: Linker to use. Default: cc
BUILD_WRAP_PROFILE: macOS only. build-wrap expands BUILD_WRAP_PROFILE as it would BUILD_WRAP_CMD, and writes the results to a temporary file. BUILD_WRAP_PROFILE_PATH then expands to the absolute path of that temporary file. Default:
(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 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
$HOME/.config/build-wrap/allow.txtIf a file at $HOME/.config/build-wrap/allow.txt exists, build-wrap treats each line as the name of a package. Such packages are built as though BUILD_WRAP_ALLOW were set to 1.
For example, svm-rs-builds downloads information about Solc releases when it is built. So if you build svm-rs frequently, you might do the following:
mkdir -p "$HOME/.config/build-wrap"
echo 'svm-rs-builds' > "$HOME/.config/build-wrap/allow.txt"
build-wrap treats as setNote that we say "treats as set" because these are considered only when BUILD_WRAP_CMD is expanded.
BUILD_WRAP_PROFILE_PATH: Expands to the absolute path of a temporary file containing the expanded contents of BUILD_WRAP_PROFILE.
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.
BUILD_WRAP_CMD is expanded{} is replaced with the path of a renamed copy of the original build script.{VAR} is replaced with the value of environment variable VAR.{{ is replaced with {.}} is replaced with }.\ followed by a whitespace character is replaced with that whitespace character.\\ is replaced with \.build-wrap worksWhen invoked, build-wrap does the following:
BUILD_WRAP_LD.B be the build script's original name.B'.B, create a "wrapped" version of the build script whose behavior is described next.The "wrapped" version of the build script does the following when invoked:
BUILD_WRAP_CMD in the manner described above, with {} expanding to B'.build-wrap should not require a user to adjust their normal workflow.