From 6cf23c3e8fa12e6bf297ca87d1b47889bf115d52 Mon Sep 17 00:00:00 2001
From: Eelco Dolstra <edolstra@gmail.com>
Date: Tue, 4 Jul 2017 15:43:06 +0200
Subject: [PATCH] Add allow-new-privileges option
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This allows builds to call setuid binaries. This was previously
possible until we started using seccomp. Turns out that seccomp by
default disallows processes from acquiring new privileges. Generally,
any use of setuid binaries (except those created by the builder
itself) is by definition impure, but some people were relying on this
ability for certain tests.

Example:

  $ nix build '(with import <nixpkgs> {}; runCommand "foo" {} "/run/wrappers/bin/ping -c 1 8.8.8.8; exit 1")' --no-allow-new-privileges
  builder for ‘/nix/store/j0nd8kv85hd6r4kxgnwzvr0k65ykf6fv-foo.drv’ failed with exit code 1; last 2 log lines:
    cannot raise the capability into the Ambient set
    : Operation not permitted

  $ nix build '(with import <nixpkgs> {}; runCommand "foo" {} "/run/wrappers/bin/ping -c 1 8.8.8.8; exit 1")' --allow-new-privileges
  builder for ‘/nix/store/j0nd8kv85hd6r4kxgnwzvr0k65ykf6fv-foo.drv’ failed with exit code 1; last 6 log lines:
    PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
    64 bytes from 8.8.8.8: icmp_seq=1 ttl=46 time=15.2 ms

Fixes #1429.
---
 doc/manual/command-ref/conf-file.xml | 17 +++++++++++++++++
 src/libstore/build.cc                |  3 +++
 src/libstore/globals.hh              |  6 ++++++
 3 files changed, 26 insertions(+)

diff --git a/doc/manual/command-ref/conf-file.xml b/doc/manual/command-ref/conf-file.xml
index 616983bc7..cde32b35f 100644
--- a/doc/manual/command-ref/conf-file.xml
+++ b/doc/manual/command-ref/conf-file.xml
@@ -643,6 +643,23 @@ password <replaceable>my-password</replaceable>
   </varlistentry>
 
 
+  <varlistentry xml:id="conf-allow-new-privileges"><term><literal>allow-new-privileges</literal></term>
+
+    <listitem><para>(Linux-specific.) By default, builders on Linux
+    cannot acquire new privileges by calling setuid/setgid programs or
+    programs that have file capabilities. For example, programs such
+    as <command>sudo</command> or <command>ping</command> will
+    fail. (Note that in sandbox builds, no such programs are available
+    unless you bind-mount them into the sandbox via the
+    <option>build-sandbox-paths</option> option.) You can allow the
+    use of such programs by enabling this option. This is impure and
+    usually undesirable, but may be useful in certain scenarios
+    (e.g. to spin up containers or set up userspace network interfaces
+    in tests).</para></listitem>
+
+  </varlistentry>
+
+
 </variablelist>
 
 </para>
diff --git a/src/libstore/build.cc b/src/libstore/build.cc
index f40a8c549..355fb3b7d 100644
--- a/src/libstore/build.cc
+++ b/src/libstore/build.cc
@@ -2340,6 +2340,9 @@ void setupSeccomp()
         seccomp_rule_add(ctx, SCMP_ACT_ERRNO(ENOTSUP), SCMP_SYS(fsetxattr), 0) != 0)
         throw SysError("unable to add seccomp rule");
 
+    if (seccomp_attr_set(ctx, SCMP_FLTATR_CTL_NNP, settings.allowNewPrivileges ? 0 : 1) != 0)
+        throw SysError("unable to set 'no new privileges' seccomp attribute");
+
     if (seccomp_load(ctx) != 0)
         throw SysError("unable to load seccomp BPF program");
 #endif
diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh
index af37ec61d..c8d67b071 100644
--- a/src/libstore/globals.hh
+++ b/src/libstore/globals.hh
@@ -321,6 +321,12 @@ public:
 
     Setting<std::string> userAgentSuffix{this, "", "user-agent-suffix",
         "String appended to the user agent in HTTP requests."};
+
+#if __linux__
+    Setting<bool> allowNewPrivileges{this, false, "allow-new-privileges",
+        "Whether builders can acquire new privileges by calling programs with "
+        "setuid/setgid bits or with file capabilities."};
+#endif
 };