about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--pkgs/build-support/build-sandbox/default.nix23
-rw-r--r--pkgs/build-support/build-sandbox/src/Makefile2
-rw-r--r--pkgs/build-support/build-sandbox/src/setup.c3
-rw-r--r--tests/sandbox.nix25
4 files changed, 49 insertions, 4 deletions
diff --git a/pkgs/build-support/build-sandbox/default.nix b/pkgs/build-support/build-sandbox/default.nix
index 0e1d4a4d..50b8f78f 100644
--- a/pkgs/build-support/build-sandbox/default.nix
+++ b/pkgs/build-support/build-sandbox/default.nix
@@ -16,6 +16,25 @@ let
   # TODO: get rid of nix & pkg-config if this is enabled (in the Makefile)
   fullNixStore = attrs.fullNixStore or false;
 
+  # The mount and user namespaces are needed for this functionality, so these
+  # namespaces are always enabled.
+  #
+  # However, the following namespaces can be enabled/disabled:
+  # +----------------+---------+--------------------------------------+
+  # | Attribute path | Default | Isolates                             |
+  # +----------------+---------+--------------------------------------+
+  # | namespaces.pid |  true   | Process IDs                          |
+  # | namespaces.uts |  true   | Hostname and NIS domain name         |
+  # | namespaces.ipc |  true   | System V IPC, POSIX message queues   |
+  # | namespaces.net |  false  | Network devices, stacks, ports, etc. |
+  # +----------------+---------+--------------------------------------+
+  extraNamespaceFlags = let
+    flags = lib.optional (attrs.namespaces.pid or true) "CLONE_NEWPID"
+         ++ lib.optional (attrs.namespaces.uts or true) "CLONE_NEWUTS"
+         ++ lib.optional (attrs.namespaces.ipc or true) "CLONE_NEWIPC"
+         ++ lib.optional (attrs.namespaces.net or false) "CLONE_NEWNET";
+  in if flags == [] then "0" else lib.concatStringsSep "|" flags;
+
   # Create code snippets for params.c to add extra_mount() calls.
   mkExtraMountParams = isRequired: lib.concatMapStringsSep "\n" (extra: let
     escaped = lib.escape ["\\" "\""] extra;
@@ -80,8 +99,8 @@ in stdenv.mkDerivation ({
 
   nativeBuildInputs = [ pkgconfig ];
   buildInputs = [ boost nix ];
-  makeFlags = [ "BINDIR=${drv}/bin" ]
+  makeFlags = [ "BINDIR=${drv}/bin" "EXTRA_NS_FLAGS=${extraNamespaceFlags}" ]
            ++ lib.optional allowBinSh "BINSH_EXECUTABLE=${dash}/bin/dash"
            ++ lib.optional fullNixStore "FULL_NIX_STORE=1";
 
-} // removeAttrs attrs [ "paths" "allowBinSh" ])
+} // removeAttrs attrs [ "namespaces" "paths" "allowBinSh" ])
diff --git a/pkgs/build-support/build-sandbox/src/Makefile b/pkgs/build-support/build-sandbox/src/Makefile
index 8e1218f6..ebe66c0e 100644
--- a/pkgs/build-support/build-sandbox/src/Makefile
+++ b/pkgs/build-support/build-sandbox/src/Makefile
@@ -6,6 +6,8 @@ CFLAGS = -g -Wall -std=gnu11 -DFS_ROOT_DIR=\"$(out)\"
 CXXFLAGS = -g -Wall -std=c++14 `pkg-config --cflags nix-main`
 LDFLAGS = -Wl,--copy-dt-needed-entries `pkg-config --libs nix-main`
 
+CFLAGS += -DEXTRA_NS_FLAGS="$(EXTRA_NS_FLAGS)"
+
 ifdef FULL_NIX_STORE
 CFLAGS += -DFULL_NIX_STORE
 else
diff --git a/pkgs/build-support/build-sandbox/src/setup.c b/pkgs/build-support/build-sandbox/src/setup.c
index 98205710..dc8bbf14 100644
--- a/pkgs/build-support/build-sandbox/src/setup.c
+++ b/pkgs/build-support/build-sandbox/src/setup.c
@@ -850,8 +850,7 @@ bool setup_sandbox(void)
             close(sync_pipe[0]);
             _exit(write_maps(parent_pid) ? 0 : 1);
         default:
-            if (unshare(CLONE_NEWNS | CLONE_NEWUSER | CLONE_NEWPID |
-                        CLONE_NEWUTS | CLONE_NEWIPC) == -1) {
+            if (unshare(CLONE_NEWNS | CLONE_NEWUSER | EXTRA_NS_FLAGS) == -1) {
                 perror("unshare");
                 if (write(sync_pipe[1], "X", 1) == -1)
                     perror("signal child exit");
diff --git a/tests/sandbox.nix b/tests/sandbox.nix
index 63d8af6e..b9f087a0 100644
--- a/tests/sandbox.nix
+++ b/tests/sandbox.nix
@@ -17,6 +17,20 @@
     services.xserver.enable = true;
     systemd.services.display-manager.enable = false;
 
+    systemd.sockets.netnstest = {
+      description = "Host Socket for Testing Network Namespaces";
+      requiredBy = [ "sockets.target" ];
+
+      socketConfig.ListenStream = "3000";
+      socketConfig.Accept = true;
+    };
+
+    systemd.services."netnstest@" = {
+      description = "Host Service for Testing Network Namespaces";
+      serviceConfig.StandardInput = "socket";
+      serviceConfig.ExecStart = "${pkgs.coreutils}/bin/tee /tmp/netns.log";
+    };
+
     environment.systemPackages = let
       mkNestedLinksTo = drv: let
         mkLink = name: to: pkgs.runCommandLocal name { inherit to; } ''
@@ -115,6 +129,12 @@
         # Another /bin/sh just to be sure :-)
         /bin/sh -c 'echo /bin/sh works'
       '') { allowBinSh = true; })
+
+      (pkgs.vuizvui.buildSandbox (pkgs.writeScriptBin "test-sandbox3" ''
+        #!${pkgs.stdenv.shell}
+        echo hello network | ${pkgs.netcat-openbsd}/bin/nc -N 127.0.0.1 3000 \
+          || echo netcat has failed
+      '') { namespaces.net = true; })
     ];
     users.users.foo.isNormalUser = true;
   };
@@ -137,5 +157,10 @@
     machine.succeed('test "$(< /home/foo/.cache/xdg/ownpid)" = 1')
 
     machine.succeed('test "$(su -c test-sandbox2 foo)" = "/bin/sh works"')
+
+    machine.succeed('su -c "echo root netns | nc -N 127.0.0.1 3000" foo')
+    machine.succeed('test "$(su -c test-sandbox3 foo)" = "netcat has failed"')
+    machine.fail('grep -F "hello network" /tmp/netns.log')
+    machine.succeed('grep -F "root netns" /tmp/netns.log')
   '';
 }