6 releases

new 0.3.1 Jul 22, 2024
0.3.0 May 7, 2024
0.2.1 Apr 14, 2024
0.1.1 Mar 25, 2024

#42 in Build Utils

Download history 146/week @ 2024-04-03 157/week @ 2024-04-10 19/week @ 2024-04-17 99/week @ 2024-05-01 43/week @ 2024-05-08 2/week @ 2024-05-15 4/week @ 2024-05-22 2/week @ 2024-06-05 95/week @ 2024-07-17

95 downloads per month

AGPL-3.0

35KB
563 lines

build-wrap

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.

Installation

Installing build-wrap requires two steps:

  1. Install build-wrap with Cargo:
    cargo install build-wrap
    
  2. Create a .cargo/config.toml file in your home directory with the following contents:
    [target.'cfg(all())']
    linker = "build-wrap"
    

Environment variables that build-wrap reads

Note 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
    
  • 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
    

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.

  • 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.

How BUILD_WRAP_CMD is expanded

  • {} is replaced with the path of a 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 \.

How build-wrap works

When invoked, build-wrap does the following:

  1. Link normally using BUILD_WRAP_LD.
  2. Parse the arguments to determine whether the output file is a build script.
  3. If so, replace the build script B with its "wrapped" version B', described next.

Given a build script B, its "wrapped" version B' contains a copy of B and does the following when invoked:

  1. Create a temporary file with the contents of B. (Recall: B' contains a copy of B).
  2. Make the temporary file executable.
  3. Expand BUILD_WRAP_CMD in the manner described above.
  4. Execute the expanded command.

Goals

  • Aside from configuration and dealing with an occasional warning, build-wrap should not require a user to adjust their normal workflow.

Dependencies

~2–11MB
~120K SLoC