Hello community,

here is the log from the commit of package bubblewrap for openSUSE:Factory 
checked in at 2019-12-28 13:40:14
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/bubblewrap (Old)
 and      /work/SRC/openSUSE:Factory/.bubblewrap.new.6675 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "bubblewrap"

Sat Dec 28 13:40:14 2019 rev:10 rq:759115 version:0.4.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/bubblewrap/bubblewrap.changes    2019-07-08 
15:04:48.662878022 +0200
+++ /work/SRC/openSUSE:Factory/.bubblewrap.new.6675/bubblewrap.changes  
2019-12-28 13:40:18.562926637 +0100
@@ -1,0 +2,12 @@
+Fri Dec 20 22:59:52 UTC 2019 - Bjørn Lie <[email protected]>
+
+- Update to version 0.4.0:
+  + The biggest feature in this release is the support for joining
+    existing user and pid namespaces. This doesn't work in the
+    setuid mode (at the moment).
+  + Other changes:
+    - Stores namespace info in status json.
+    - In setuid mode pid 1 is now marked dumpable.
+    - Now builds with musl libc.
+
+-------------------------------------------------------------------

Old:
----
  bubblewrap-0.3.3.tar.xz

New:
----
  bubblewrap-0.4.0.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ bubblewrap.spec ++++++
--- /var/tmp/diff_new_pack.Zz5AcS/_old  2019-12-28 13:40:19.898927311 +0100
+++ /var/tmp/diff_new_pack.Zz5AcS/_new  2019-12-28 13:40:19.934927329 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package bubblewrap
 #
-# Copyright (c) 2019 SUSE LINUX GmbH, Nuernberg, Germany.
+# Copyright (c) 2019 SUSE LLC
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -17,13 +17,13 @@
 
 
 Name:           bubblewrap
-Version:        0.3.3
+Version:        0.4.0
 Release:        0
 Summary:        Core execution tool for unprivileged containers
 License:        LGPL-2.0-or-later
 Group:          Productivity/Security
-Url:            https://github.com/projectatomic/bubblewrap
-Source0:        
https://github.com/projectatomic/bubblewrap/releases/download/v%{version}/%{name}-%{version}.tar.xz
+URL:            https://github.com/projectatomic/bubblewrap
+Source0:        %{url}/releases/download/v%{version}/%{name}-%{version}.tar.xz
 BuildRequires:  autoconf
 BuildRequires:  automake
 BuildRequires:  docbook-xsl-stylesheets
@@ -41,7 +41,7 @@
 user namespaces.
 
 %prep
-%autosetup -n %{name}-%{version}
+%autosetup -p1 -n %{name}-%{version}
 sed -i '1d' completions/bash/bwrap
 %if 0%{?suse_version} < 1500
 sed -i '1s,/usr/bin/env bash,/bin/bash,' demos/bubblewrap-shell.sh

++++++ bubblewrap-0.3.3.tar.xz -> bubblewrap-0.4.0.tar.xz ++++++
++++ 15274 lines of diff (skipped)
++++    retrying with extended exclude list
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/bubblewrap-0.3.3/bubblewrap.c new/bubblewrap-0.4.0/bubblewrap.c
--- old/bubblewrap-0.3.3/bubblewrap.c   2019-05-01 10:44:10.000000000 +0200
+++ new/bubblewrap-0.4.0/bubblewrap.c   2019-11-27 13:34:31.000000000 +0100
@@ -42,6 +42,15 @@
 #define CLONE_NEWCGROUP 0x02000000 /* New cgroup namespace */
 #endif
 
+#ifndef TEMP_FAILURE_RETRY
+#define TEMP_FAILURE_RETRY(expression) \
+  (__extension__                                                              \
+    ({ long int __result;                                                     \
+       do __result = (long int) (expression);                                 \
+       while (__result == -1L && errno == EINTR);                             \
+       __result; }))
+#endif
+
 /* Globals to avoid having to use getuid(), since the uid/gid changes during 
runtime */
 static uid_t real_uid;
 static gid_t real_gid;
@@ -77,10 +86,34 @@
 int opt_seccomp_fd = -1;
 const char *opt_sandbox_hostname = NULL;
 char *opt_args_data = NULL;  /* owned */
+int opt_userns_fd = -1;
+int opt_userns2_fd = -1;
+int opt_pidns_fd = -1;
 
 #define CAP_TO_MASK_0(x) (1L << ((x) & 31))
 #define CAP_TO_MASK_1(x) CAP_TO_MASK_0(x - 32)
 
+typedef struct _NsInfo NsInfo;
+
+struct _NsInfo {
+  const char *name;
+  bool       *do_unshare;
+  ino_t       id;
+};
+
+static NsInfo ns_infos[] = {
+  {"cgroup", &opt_unshare_cgroup, 0},
+  {"ipc",    &opt_unshare_ipc,    0},
+  {"mnt",    NULL,                0},
+  {"net",    &opt_unshare_net,    0},
+  {"pid",    &opt_unshare_pid,    0},
+  /* user namespace info omitted because it
+   * is not (yet) valid when we obtain the
+   * namespace info (get un-shared later) */
+  {"uts",    &opt_unshare_uts,    0},
+  {NULL,     NULL,                0}
+};
+
 typedef enum {
   SETUP_BIND_MOUNT,
   SETUP_RO_BIND_MOUNT,
@@ -200,8 +233,11 @@
            "    --unshare-uts                Create new uts namespace\n"
            "    --unshare-cgroup             Create new cgroup namespace\n"
            "    --unshare-cgroup-try         Create new cgroup namespace if 
possible else continue by skipping it\n"
-           "    --uid UID                    Custom uid in the sandbox 
(requires --unshare-user)\n"
-           "    --gid GID                    Custom gid in the sandbox 
(requires --unshare-user)\n"
+           "    --userns FD                  Use this user namespace (cannot 
combine with --unshare-user)\n"
+           "    --userns2 FD                 After setup switch to this user 
namspace, only useful with --userns\n"
+           "    --pidns FD                   Use this user namespace (as 
parent namespace if using --unshare-pid)\n"
+           "    --uid UID                    Custom uid in the sandbox 
(requires --unshare-user or --userns)\n"
+           "    --gid GID                    Custom gid in the sandbox 
(requires --unshare-user or --userns)\n"
            "    --hostname NAME              Custom hostname in the sandbox 
(requires --unshare-uts)\n"
            "    --chdir DIR                  Change directory to DIR\n"
            "    --setenv VAR VALUE           Set an environment variable\n"
@@ -539,7 +575,8 @@
 static uint32_t requested_caps[2] = {0, 0};
 
 /* low 32bit caps needed */
-#define REQUIRED_CAPS_0 (CAP_TO_MASK_0 (CAP_SYS_ADMIN) | CAP_TO_MASK_0 
(CAP_SYS_CHROOT) | CAP_TO_MASK_0 (CAP_NET_ADMIN) | CAP_TO_MASK_0 (CAP_SETUID) | 
CAP_TO_MASK_0 (CAP_SETGID))
+/* CAP_SYS_PTRACE is needed to dereference the symlinks in /proc/<pid>/ns/, 
see namespaces(7) */
+#define REQUIRED_CAPS_0 (CAP_TO_MASK_0 (CAP_SYS_ADMIN) | CAP_TO_MASK_0 
(CAP_SYS_CHROOT) | CAP_TO_MASK_0 (CAP_NET_ADMIN) | CAP_TO_MASK_0 (CAP_SETUID) | 
CAP_TO_MASK_0 (CAP_SETGID) | CAP_TO_MASK_0 (CAP_SYS_PTRACE))
 /* high 32bit caps needed */
 #define REQUIRED_CAPS_1 0
 
@@ -768,9 +805,19 @@
 switch_to_user_with_privs (void)
 {
   /* If we're in a new user namespace, we got back the bounding set, clear it 
again */
-  if (opt_unshare_user)
+  if (opt_unshare_user || opt_userns_fd != -1)
     drop_cap_bounding_set (FALSE);
 
+  /* If we switched to a new user namespace it may allow other uids/gids, so 
switch to the target one */
+  if (opt_userns_fd != -1)
+    {
+      if (opt_sandbox_uid != real_uid && setuid (opt_sandbox_uid) < 0)
+        die_with_error ("unable to switch to uid %d", opt_sandbox_uid);
+
+      if (opt_sandbox_gid != real_gid && setgid (opt_sandbox_gid) < 0)
+        die_with_error ("unable to switch to gid %d", opt_sandbox_gid);
+    }
+
   if (!is_privileged)
     return;
 
@@ -791,10 +838,14 @@
 {
   assert (!keep_requested_caps || !is_privileged);
   /* Drop root uid */
-  if (getuid () == 0 && setuid (opt_sandbox_uid) < 0)
+  if (geteuid () == 0 && setuid (opt_sandbox_uid) < 0)
     die_with_error ("unable to drop root uid");
 
   drop_all_caps (keep_requested_caps);
+
+  /* We don't have any privs now, so mark us dumpable which makes /proc/self 
be owned by the user instead of root */
+  if (prctl (PR_SET_DUMPABLE, 1, 0, 0, 0) != 0)
+    die_with_error ("can't set dumpable");
 }
 
 static char *
@@ -1066,7 +1117,7 @@
           if (ensure_dir (dest, 0755) != 0)
             die_with_error ("Can't mkdir %s", op->dest);
 
-          if (unshare_pid)
+          if (unshare_pid || opt_pidns_fd != -1)
             {
               /* Our own procfs */
               privileged_op (privileged_op_socket,
@@ -1854,6 +1905,57 @@
           argv += 1;
           argc -= 1;
         }
+      else if (strcmp (arg, "--userns") == 0)
+        {
+          int the_fd;
+          char *endptr;
+
+          if (argc < 2)
+            die ("--userns takes an argument");
+
+          the_fd = strtol (argv[1], &endptr, 10);
+          if (argv[1][0] == 0 || endptr[0] != 0 || the_fd < 0)
+            die ("Invalid fd: %s", argv[1]);
+
+          opt_userns_fd = the_fd;
+
+          argv += 1;
+          argc -= 1;
+        }
+      else if (strcmp (arg, "--userns2") == 0)
+        {
+          int the_fd;
+          char *endptr;
+
+          if (argc < 2)
+            die ("--userns2 takes an argument");
+
+          the_fd = strtol (argv[1], &endptr, 10);
+          if (argv[1][0] == 0 || endptr[0] != 0 || the_fd < 0)
+            die ("Invalid fd: %s", argv[1]);
+
+          opt_userns2_fd = the_fd;
+
+          argv += 1;
+          argc -= 1;
+        }
+      else if (strcmp (arg, "--pidns") == 0)
+        {
+          int the_fd;
+          char *endptr;
+
+          if (argc < 2)
+            die ("--pidns takes an argument");
+
+          the_fd = strtol (argv[1], &endptr, 10);
+          if (argv[1][0] == 0 || endptr[0] != 0 || the_fd < 0)
+            die ("Invalid fd: %s", argv[1]);
+
+          opt_pidns_fd = the_fd;
+
+          argv += 1;
+          argc -= 1;
+        }
       else if (strcmp (arg, "--setenv") == 0)
         {
           if (argc < 3)
@@ -2041,6 +2143,65 @@
     die ("Can't parse /proc/sys/kernel/overflowgid");
 }
 
+static void
+namespace_ids_read (pid_t  pid)
+{
+  cleanup_free char *dir = NULL;
+  cleanup_fd int ns_fd = -1;
+  NsInfo *info;
+
+  dir = xasprintf ("%d/ns", pid);
+  ns_fd = openat (proc_fd, dir, O_PATH);
+
+  if (ns_fd < 0)
+    die_with_error ("open /proc/%s/ns failed", dir);
+
+  for (info = ns_infos; info->name; info++)
+    {
+      bool *do_unshare = info->do_unshare;
+      struct stat st;
+      int r;
+
+      /* if we don't unshare this ns, ignore it */
+      if (do_unshare && *do_unshare == FALSE)
+        continue;
+
+      r = fstatat (ns_fd, info->name, &st, 0);
+
+      /* if we can't get the information, ignore it */
+      if (r != 0)
+        continue;
+
+      info->id = st.st_ino;
+    }
+}
+
+static void
+namespace_ids_write (int    fd,
+                     bool   in_json)
+{
+  NsInfo *info;
+
+  for (info = ns_infos; info->name; info++)
+    {
+      cleanup_free char *output = NULL;
+      const char *indent;
+      uintmax_t nsid;
+
+      nsid = (uintmax_t) info->id;
+
+      /* if we don't have the information, we don't write it */
+      if (nsid == 0)
+        continue;
+
+      indent = in_json ? " " : "\n    ";
+      output = xasprintf (",%s\"%s-namespace\": %ju",
+                          indent, info->name, nsid);
+
+      dump_info (fd, output, TRUE);
+    }
+}
+
 int
 main (int    argc,
       char **argv)
@@ -2063,6 +2224,7 @@
   size_t seccomp_len;
   struct sock_fprog seccomp_prog;
   cleanup_free char *args_data = NULL;
+  int intermediate_pids_sockets[2] = {-1, -1};
 
   /* Handle --version early on before we try to acquire/drop
    * any capabilities so it works in a build environment;
@@ -2113,14 +2275,35 @@
   if (opt_userns_block_fd != -1 && opt_info_fd == -1)
     die ("--userns-block-fd requires --info-fd");
 
+  if (opt_userns_fd != -1 && opt_unshare_user)
+    die ("--userns not compatible --unshare-user");
+
+  if (opt_userns_fd != -1 && opt_unshare_user_try)
+    die ("--userns not compatible --unshare-user-try");
+
+  /* Technically using setns() is probably safe even in the privileged
+   * case, because we got passed in a file descriptor to the
+   * namespace, and that can only be gotten if you have ptrace
+   * permissions against the target, and then you could do whatever to
+   * the namespace anyway.
+   *
+   * However, for practical reasons this isn't possible to use,
+   * because (as described in acquire_privs()) setuid bwrap causes
+   * root to own the namespaces that it creates, so you will not be
+   * able to access these namespaces anyway. So, best just not support
+   * it anway.
+   */
+  if (opt_userns_fd != -1 && is_privileged)
+    die ("--userns doesn't work in setuid mode");
+
   /* We have to do this if we weren't installed setuid (and we're not
    * root), so let's just DWIM */
-  if (!is_privileged && getuid () != 0)
+  if (!is_privileged && getuid () != 0 && opt_userns_fd == -1)
     opt_unshare_user = TRUE;
 
 #ifdef ENABLE_REQUIRE_USERNS
   /* In this build option, we require userns. */
-  if (is_privileged && getuid () != 0)
+  if (is_privileged && getuid () != 0 && opt_userns_fd == -1)
     opt_unshare_user = TRUE;
 #endif
 
@@ -2165,11 +2348,11 @@
   if (opt_sandbox_gid == -1)
     opt_sandbox_gid = real_gid;
 
-  if (!opt_unshare_user && opt_sandbox_uid != real_uid)
-    die ("Specifying --uid requires --unshare-user");
+  if (!opt_unshare_user && opt_userns_fd == -1 && opt_sandbox_uid != real_uid)
+    die ("Specifying --uid requires --unshare-user or --userns");
 
-  if (!opt_unshare_user && opt_sandbox_gid != real_gid)
-    die ("Specifying --gid requires --unshare-user");
+  if (!opt_unshare_user && opt_userns_fd == -1 && opt_sandbox_gid != real_gid)
+    die ("Specifying --gid requires --unshare-user or --userns");
 
   if (!opt_unshare_uts && opt_sandbox_hostname != NULL)
     die ("Specifying --hostname requires --unshare-uts");
@@ -2209,7 +2392,7 @@
   clone_flags = SIGCHLD | CLONE_NEWNS;
   if (opt_unshare_user)
     clone_flags |= CLONE_NEWUSER;
-  if (opt_unshare_pid)
+  if (opt_unshare_pid && opt_pidns_fd == -1)
     clone_flags |= CLONE_NEWPID;
   if (opt_unshare_net)
     clone_flags |= CLONE_NEWNET;
@@ -2229,8 +2412,11 @@
       clone_flags |= CLONE_NEWCGROUP;
     }
   if (opt_unshare_cgroup_try)
-    if (!stat ("/proc/self/ns/cgroup", &sbuf))
-      clone_flags |= CLONE_NEWCGROUP;
+    {
+      opt_unshare_cgroup = !stat ("/proc/self/ns/cgroup", &sbuf);
+      if (opt_unshare_cgroup)
+        clone_flags |= CLONE_NEWCGROUP;
+    }
 
   child_wait_fd = eventfd (0, EFD_CLOEXEC);
   if (child_wait_fd == -1)
@@ -2245,6 +2431,22 @@
         die_with_error ("pipe2()");
     }
 
+  /* Switch to the custom user ns before the clone, gets us privs in that ns 
(assuming its a child of the current and thus allowed) */
+  if (opt_userns_fd > 0 && setns (opt_userns_fd, CLONE_NEWUSER) != 0)
+    {
+      if (errno == EINVAL)
+        die ("Joining the specified user namespace failed, it might not be a 
descendant of the current user namespace.");
+      die_with_error ("Joining specified user namespace failed");
+    }
+
+  /* Sometimes we have uninteresting intermediate pids during the setup, set 
up code to pass the real pid down */
+  if (opt_pidns_fd != -1)
+    {
+      /* Mark us as a subreaper, this way we can get exit status from 
grandchildren */
+      prctl (PR_SET_CHILD_SUBREAPER, 1, 0, 0, 0);
+      create_pid_socketpair (intermediate_pids_sockets);
+    }
+
   pid = raw_clone (clone_flags, NULL);
   if (pid == -1)
     {
@@ -2266,6 +2468,16 @@
     {
       /* Parent, outside sandbox, privileged (initially) */
 
+      if (intermediate_pids_sockets[0] != -1)
+        {
+          close (intermediate_pids_sockets[1]);
+          pid = read_pid_from_socket (intermediate_pids_sockets[0]);
+          close (intermediate_pids_sockets[0]);
+        }
+
+      /* Discover namespace ids before we drop privileges */
+      namespace_ids_read (pid);
+
       if (is_privileged && opt_unshare_user && opt_userns_block_fd == -1)
         {
           /* We're running as euid 0, but the uid we want to map is
@@ -2281,7 +2493,10 @@
                              pid, TRUE, opt_needs_devpts);
         }
 
-      /* Initial launched process, wait for exec:ed command to exit */
+      /* Initial launched process, wait for pid 1 or exec:ed command to exit */
+
+      if (opt_userns2_fd > 0 && setns (opt_userns2_fd, CLONE_NEWUSER) != 0)
+        die_with_error ("Setting userns2 failed");
 
       /* We don't need any privileges in the launcher, drop them immediately. 
*/
       drop_privs (FALSE);
@@ -2291,14 +2506,18 @@
 
       if (opt_info_fd != -1)
         {
-          cleanup_free char *output = xasprintf ("{\n    \"child-pid\": 
%i\n}\n", pid);
+          cleanup_free char *output = xasprintf ("{\n    \"child-pid\": %i", 
pid);
           dump_info (opt_info_fd, output, TRUE);
+          namespace_ids_write (opt_info_fd, FALSE);
+          dump_info (opt_info_fd, "\n}\n", TRUE);
           close (opt_info_fd);
         }
       if (opt_json_status_fd != -1)
         {
-          cleanup_free char *output = xasprintf ("{ \"child-pid\": %i }\n", 
pid);
+          cleanup_free char *output = xasprintf ("{ \"child-pid\": %i", pid);
           dump_info (opt_json_status_fd, output, TRUE);
+          namespace_ids_write (opt_json_status_fd, TRUE);
+          dump_info (opt_json_status_fd, " }\n", TRUE);
         }
 
       if (opt_userns_block_fd != -1)
@@ -2317,6 +2536,31 @@
       return monitor_child (event_fd, pid, setup_finished_pipe[0]);
     }
 
+  if (opt_pidns_fd > 0)
+    {
+      if (setns (opt_pidns_fd, CLONE_NEWPID) != 0)
+        die_with_error ("Setting pidns failed");
+
+      /* fork to get the passed in pid ns */
+      fork_intermediate_child ();
+
+      /* We might both have specified an --pidns *and* --unshare-pid, so set 
up a new child pid namespace under the specified one */
+      if (opt_unshare_pid)
+        {
+          if (unshare (CLONE_NEWPID))
+            die_with_error ("unshare pid ns");
+
+          /* fork to get the new pid ns */
+          fork_intermediate_child ();
+        }
+
+      /* We're back, either in a child or grandchild, so message the actual 
pid to the monitor */
+
+      close (intermediate_pids_sockets[0]);
+      send_pid_on_socket (intermediate_pids_sockets[1]);
+      close (intermediate_pids_sockets[1]);
+    }
+
   /* Child, in sandbox, privileged in the parent or in the user namespace (if 
--unshare-user).
    *
    * Note that for user namespaces we run as euid 0 during clone(), so
@@ -2505,6 +2749,9 @@
       die_with_error ("chdir /");
   }
 
+  if (opt_userns2_fd > 0 && setns (opt_userns2_fd, CLONE_NEWUSER) != 0)
+    die_with_error ("Setting userns2 failed");
+
   if (opt_unshare_user &&
       (ns_uid != opt_sandbox_uid || ns_gid != opt_sandbox_gid) &&
       opt_userns_block_fd == -1)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/bubblewrap-0.3.3/build-aux/compile new/bubblewrap-0.4.0/build-aux/compile
--- old/bubblewrap-0.3.3/build-aux/compile      2019-05-01 10:49:13.000000000 
+0200
+++ new/bubblewrap-0.4.0/build-aux/compile      2019-11-27 09:47:09.000000000 
+0100
@@ -1,4 +1,4 @@
-#!/usr/bin/sh
+#! /bin/sh
 # Wrapper for compilers which do not understand '-c -o'.
 
 scriptversion=2018-03-07.03; # UTC
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/bubblewrap-0.3.3/build-aux/missing new/bubblewrap-0.4.0/build-aux/missing
--- old/bubblewrap-0.3.3/build-aux/missing      2019-05-01 10:49:13.000000000 
+0200
+++ new/bubblewrap-0.4.0/build-aux/missing      2019-11-27 09:47:09.000000000 
+0100
@@ -1,4 +1,4 @@
-#!/usr/bin/sh
+#! /bin/sh
 # Common wrapper for a few potentially missing GNU programs.
 
 scriptversion=2018-03-07.03; # UTC
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/bubblewrap-0.3.3/build-aux/tap-driver.sh 
new/bubblewrap-0.4.0/build-aux/tap-driver.sh
--- old/bubblewrap-0.3.3/build-aux/tap-driver.sh        2019-05-01 
10:49:14.000000000 +0200
+++ new/bubblewrap-0.4.0/build-aux/tap-driver.sh        2019-11-27 
09:47:09.000000000 +0100
@@ -1,4 +1,4 @@
-#!/usr/bin/sh
+#! /bin/sh
 # Copyright (C) 2011-2018 Free Software Foundation, Inc.
 #
 # This program is free software; you can redistribute it and/or modify
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/bubblewrap-0.3.3/build-aux/test-driver 
new/bubblewrap-0.4.0/build-aux/test-driver
--- old/bubblewrap-0.3.3/build-aux/test-driver  2019-05-01 10:49:14.000000000 
+0200
+++ new/bubblewrap-0.4.0/build-aux/test-driver  2019-11-27 09:47:09.000000000 
+0100
@@ -1,4 +1,4 @@
-#!/usr/bin/sh
+#! /bin/sh
 # test-driver - basic testsuite driver script.
 
 scriptversion=2018-03-07.03; # UTC
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/bubblewrap-0.3.3/bwrap.xml new/bubblewrap-0.4.0/bwrap.xml
--- old/bubblewrap-0.3.3/bwrap.xml      2019-03-04 14:44:18.000000000 +0100
+++ new/bubblewrap-0.4.0/bwrap.xml      2019-11-27 13:34:31.000000000 +0100
@@ -131,6 +131,21 @@
       <listitem><para>Unshare all possible namespaces. Currently equivalent 
with: <option>--unshare-user-try</option> <option>--unshare-ipc</option> 
<option>--unshare-pid</option> <option>--unshare-net</option> 
<option>--unshare-uts</option> 
<option>--unshare-cgroup-try</option></para></listitem>
     </varlistentry>
     <varlistentry>
+      <term><option>--userns <arg choice="plain">FD</arg></option></term>
+      <listitem><para>Use an existing user namespace instead of creating a new 
one. The namespace must fulfil the permission requirements for setns(), which 
generally means that it must be a decendant of the currently active user 
namespace, owned by the same user. </para>
+      <para>This is incompatible with --unshare-user, and doesn't work in the 
setuid version of bubblewrap.</para></listitem>
+    </varlistentry>
+    <varlistentry>
+      <term><option>--userns2 <arg choice="plain">FD</arg></option></term>
+      <listitem><para>After setting up the new namespace, switch into the 
specified namespace. For this to work the specified namespace must be a 
decendant of the user namespace used for the setup, so this is only useful in 
combination with --userns.</para>
+      <para>This is useful because sometimes bubblewrap itself creates nested 
user namespaces (to work around some kernel issues) and --userns2 can be used 
to enter these.</para></listitem>
+    </varlistentry>
+    <varlistentry>
+      <term><option>--pidns <arg choice="plain">FD</arg></option></term>
+      <listitem><para>Use an existing pid namespace instead of creating one. 
This is often used with --userns, because the pid namespace must be owned by 
the same user namespace that bwrap uses. </para>
+      <para>Note that this can be combined with --unshare-pid, and in that 
case it means that the sandbox will be in its own pid namespace, which is a 
child of the passed in one.</para></listitem>
+    </varlistentry>
+    <varlistentry>
       <term><option>--uid <arg choice="plain">UID</arg></option></term>
       <listitem><para>Use a custom user id in the sandbox (requires 
<option>--unshare-user</option>)</para></listitem>
     </varlistentry>
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/bubblewrap-0.3.3/configure.ac new/bubblewrap-0.4.0/configure.ac
--- old/bubblewrap-0.3.3/configure.ac   2019-05-01 10:51:30.000000000 +0200
+++ new/bubblewrap-0.4.0/configure.ac   2019-11-27 13:40:58.000000000 +0100
@@ -1,5 +1,5 @@
 AC_PREREQ([2.63])
-AC_INIT([bubblewrap], [0.3.3], [[email protected]])
+AC_INIT([bubblewrap], [0.4.0], [[email protected]])
 AC_CONFIG_HEADER([config.h])
 AC_CONFIG_MACRO_DIR([m4])
 AC_CONFIG_AUX_DIR([build-aux])
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/bubblewrap-0.3.3/tests/libtest-core.sh 
new/bubblewrap-0.4.0/tests/libtest-core.sh
--- old/bubblewrap-0.3.3/tests/libtest-core.sh  2019-03-04 14:44:18.000000000 
+0100
+++ new/bubblewrap-0.4.0/tests/libtest-core.sh  2019-11-27 13:34:31.000000000 
+0100
@@ -75,6 +75,18 @@
     fatal "$@"
 }
 
+_fatal_print_files() {
+    file1="$1"
+    shift
+    file2="$1"
+    shift
+    ls -al "$file1" >&2
+    sed -e 's/^/# /' < "$file1" >&2
+    ls -al "$file2" >&2
+    sed -e 's/^/# /' < "$file2" >&2
+    fatal "$@"
+}
+
 assert_not_has_file () {
     if test -f "$1"; then
         _fatal_print_file "$1" "File '$1' exists"
@@ -135,8 +147,18 @@
     fi
 }
 
+assert_files_equal() {
+    if ! cmp "$1" "$2"; then
+        _fatal_print_files "$1" "$2" "File '$1' and '$2' is not equal"
+    fi
+}
+
 # Use to skip all of these tests
 skip() {
     echo "1..0 # SKIP" "$@"
     exit 0
 }
+
+extract_child_pid() {
+    grep child-pid "$1" | sed "s/^.*: \([0-9]*\).*/\1/"
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/bubblewrap-0.3.3/tests/test-run.sh new/bubblewrap-0.4.0/tests/test-run.sh
--- old/bubblewrap-0.3.3/tests/test-run.sh      2019-05-01 10:44:10.000000000 
+0200
+++ new/bubblewrap-0.4.0/tests/test-run.sh      2019-11-27 13:34:31.000000000 
+0100
@@ -80,7 +80,7 @@
     skip Seems like bwrap is not working at all. Maybe setuid is not working
 fi
 
-echo "1..46"
+echo "1..49"
 
 # Test help
 ${BWRAP} --help > help.txt
@@ -149,6 +149,17 @@
 assert_file_has_content_literal json-status.json '"exit-code": 42'
 echo "ok info and json-status fd"
 
+DATA=$($RUN --proc /proc --unshare-all --info-fd 42 --json-status-fd 43 -- 
bash -c 'stat -L --format "%n %i" /proc/self/ns/*' 42>info.json 
43>json-status.json 2>err.txt)
+
+for NS in "ipc" "mnt" "net" "pid" "uts"; do
+
+    want=$(echo "$DATA" | grep "/proc/self/ns/$NS" | awk '{print $2}')
+    assert_file_has_content info.json "$want"
+    assert_file_has_content json-status.json "$want"
+done
+
+echo "ok namespace id info in info and json-status fd"
+
 if ! which strace 2>/dev/null || ! strace -h | grep -v -e default | grep -e 
fault; then
     echo "ok - # SKIP no strace fault injection"
 else
@@ -329,4 +340,40 @@
 fi
 echo "ok - we can mount another directory inside /tmp"
 
+# These tests need user namespaces
+if test -n "${bwrap_is_suid:-}"; then
+    echo "ok - # SKIP no setuid support for --unshare-user"
+    echo "ok - # SKIP no setuid support for --unshare-user"
+else
+    mkfifo donepipe
+
+    $RUN --info-fd 42 --unshare-user sh -c 'readlink /proc/self/ns/user > 
sandbox-userns; cat < donepipe' 42>info.json &
+    while ! test -f sandbox-userns; do sleep 1; done
+    SANDBOX1PID=$(extract_child_pid info.json)
+
+    $RUN  --userns 11 readlink /proc/self/ns/user > sandbox2-userns 11< 
/proc/$SANDBOX1PID/ns/user
+    echo foo > donepipe
+
+    assert_files_equal sandbox-userns sandbox2-userns
+
+    rm donepipe info.json sandbox-userns
+
+    echo "ok - Test --userns"
+
+    mkfifo donepipe
+    $RUN --info-fd 42 --unshare-user --unshare-pid sh -c 'readlink 
/proc/self/ns/pid > sandbox-pidns; cat < donepipe' 42>info.json &
+    while ! test -f sandbox-pidns; do sleep 1; done
+    SANDBOX1PID=$(extract_child_pid info.json)
+
+    $RUN --userns 11 --pidns 12 readlink /proc/self/ns/pid > sandbox2-pidns 
11< /proc/$SANDBOX1PID/ns/user 12< /proc/$SANDBOX1PID/ns/pid
+    echo foo > donepipe
+
+    assert_files_equal sandbox-pidns sandbox2-pidns
+
+    rm donepipe info.json sandbox-pidns
+
+    echo "ok - Test --pidns"
+fi
+
+
 echo "ok - End of test"
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/bubblewrap-0.3.3/utils.c new/bubblewrap-0.4.0/utils.c
--- old/bubblewrap-0.3.3/utils.c        2019-03-04 14:44:18.000000000 +0100
+++ new/bubblewrap-0.4.0/utils.c        2019-11-27 13:34:31.000000000 +0100
@@ -19,6 +19,7 @@
 
 #include "utils.h"
 #include <sys/syscall.h>
+#include <sys/socket.h>
 #ifdef HAVE_SELINUX
 #include <selinux/selinux.h>
 #endif
@@ -79,6 +80,19 @@
   exit (1);
 }
 
+/* Fork, return in child, exiting the previous parent */
+void
+fork_intermediate_child (void)
+{
+  int pid = fork ();
+  if (pid == -1)
+    die_with_error ("Can't fork for --pidns");
+
+  /* Parent is an process not needed */
+  if (pid != 0)
+    exit (0);
+}
+
 void *
 xmalloc (size_t size)
 {
@@ -670,6 +684,86 @@
   return 0;
 }
 
+/* Send an ucred with current pid/uid/gid over a socket, it can be
+   read back with read_pid_from_socket(), and then the kernel has
+   translated it between namespaces as needed. */
+void
+send_pid_on_socket (int socket)
+{
+  char buf[1] = { 0 };
+  struct msghdr msg = {};
+  struct iovec iov = { buf, sizeof (buf) };
+  const ssize_t control_len_snd = CMSG_SPACE(sizeof(struct ucred));
+  char control_buf_snd[control_len_snd];
+  struct cmsghdr *cmsg;
+  struct ucred *cred;
+
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+  msg.msg_control = control_buf_snd;
+  msg.msg_controllen = control_len_snd;
+
+  cmsg = CMSG_FIRSTHDR(&msg);
+  cmsg->cmsg_level = SOL_SOCKET;
+  cmsg->cmsg_type = SCM_CREDENTIALS;
+  cmsg->cmsg_len = CMSG_LEN(sizeof(struct ucred));
+  cred = (struct ucred *)CMSG_DATA(cmsg);
+
+  cred->pid = getpid ();
+  cred->uid = geteuid ();
+  cred->gid = getegid ();
+
+  if (sendmsg (socket, &msg, 0) < 0)
+    die_with_error ("Can't send pid");
+}
+
+void
+create_pid_socketpair (int sockets[2])
+{
+  int enable = 1;
+
+  if (socketpair (AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sockets) != 0)
+    die_with_error ("Can't create intermediate pids socket");
+
+  if (setsockopt (sockets[0], SOL_SOCKET, SO_PASSCRED, &enable, sizeof 
(enable)) < 0)
+    die_with_error ("Can't set SO_PASSCRED");
+}
+
+int
+read_pid_from_socket (int socket)
+{
+  char recv_buf[1] = { 0 };
+  struct msghdr msg = {};
+  struct iovec iov = { recv_buf, sizeof (recv_buf) };
+  const ssize_t control_len_rcv = CMSG_SPACE(sizeof(struct ucred));
+  char control_buf_rcv[control_len_rcv];
+  struct cmsghdr* cmsg;
+
+  msg.msg_iov = &iov;
+  msg.msg_iovlen = 1;
+  msg.msg_control = control_buf_rcv;
+  msg.msg_controllen = control_len_rcv;
+
+  if (recvmsg (socket, &msg, 0) < 0)
+    die_with_error ("Cant read pid from socket");
+
+  if (msg.msg_controllen <= 0)
+    die ("Unexpected short read from pid socket");
+
+  for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; cmsg = CMSG_NXTHDR(&msg, cmsg))
+    {
+      const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0);
+      if (cmsg->cmsg_level == SOL_SOCKET &&
+          cmsg->cmsg_type == SCM_CREDENTIALS &&
+          payload_len == sizeof(struct ucred))
+        {
+          struct ucred *cred = (struct ucred *)CMSG_DATA(cmsg);
+          return cred->pid;
+        }
+    }
+  die ("No pid returned on socket");
+}
+
 int
 raw_clone (unsigned long flags,
            void         *child_stack)
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/bubblewrap-0.3.3/utils.h new/bubblewrap-0.4.0/utils.h
--- old/bubblewrap-0.3.3/utils.h        2019-03-04 14:44:18.000000000 +0100
+++ new/bubblewrap-0.4.0/utils.h        2019-11-27 13:34:31.000000000 +0100
@@ -54,6 +54,8 @@
 void  die_oom (void) __attribute__((__noreturn__));
 void  die_unless_label_valid (const char *label);
 
+void  fork_intermediate_child (void);
+
 void *xmalloc (size_t size);
 void *xcalloc (size_t size);
 void *xrealloc (void  *ptr,
@@ -107,6 +109,9 @@
 int   mkdir_with_parents (const char *pathname,
                           int         mode,
                           bool        create_last);
+void create_pid_socketpair (int sockets[2]);
+void send_pid_on_socket (int socket);
+int  read_pid_from_socket (int socket);
 
 /* syscall wrappers */
 int   raw_clone (unsigned long flags,


Reply via email to