[PATCH] Skip some steps when run in a Linux-vServer guest



Certain operations can't be done inside a Linux-vServer guest, even when
SYS_CAP_ADMIN may be granted in the guiest configuration. The following
are skipped when /proc/sys/kernel/vshelper is present:

- Setting CLONE_NEWNET.
- Using prctl() to change protection bits.

This makes linux-user-chroot useable inside vServer guests.
---
 src/linux-user-chroot.c | 23 +++++++++++++++++------
 1 file changed, 17 insertions(+), 6 deletions(-)

diff --git a/src/linux-user-chroot.c b/src/linux-user-chroot.c
index 217d651..84c7e92 100644
--- a/src/linux-user-chroot.c
+++ b/src/linux-user-chroot.c
@@ -131,6 +131,7 @@ main (int      argc,
   int unshare_pid = 0;
   int clone_flags = 0;
   int child_status = 0;
+  int under_vserver = 0;
   pid_t child;
 
   if (argc <= 0)
@@ -143,6 +144,13 @@ main (int      argc,
   if (argc < 1)
     fatal ("ROOTDIR argument must be specified");
 
+  /*
+   * Check whether inside a Linux-vServer guest. The check is a bit lame,
+   * but works and is simple. A (maybe?) more robust solution would be to
+   * search for "VxID: NNN" in /proc/self/status and check that "NNN > 0".
+   */
+  under_vserver = !access ("/proc/sys/kernel/vshelper", F_OK);
+
   after_mount_arg_index = 0;
   while (after_mount_arg_index < argc)
     {
@@ -271,7 +279,7 @@ main (int      argc,
     clone_flags |= CLONE_NEWPID;
 
   /* Isolated networking */
-  if (unshare_net)
+  if (unshare_net && !under_vserver)
     clone_flags |= CLONE_NEWNET;
 
   if ((child = syscall (__NR_clone, clone_flags, NULL)) < 0)
@@ -291,11 +299,14 @@ main (int      argc,
        * Following the belt-and-suspenders model, we also make a
        * MS_NOSUID bind mount below.
        */
-      if (prctl (PR_SET_NO_NEW_PRIVS, 1) < 0 && errno != EINVAL)
-        fatal_errno ("prctl (PR_SET_NO_NEW_PRIVS)");
-      else if (prctl (PR_SET_SECUREBITS,
-                 SECBIT_NOROOT | SECBIT_NOROOT_LOCKED) < 0)
-        fatal_errno ("prctl (SECBIT_NOROOT)");
+      if (!under_vserver)
+        {
+          if (prctl (PR_SET_NO_NEW_PRIVS, 1) < 0 && errno != EINVAL)
+            fatal_errno ("prctl (PR_SET_NO_NEW_PRIVS)");
+          else if (prctl (PR_SET_SECUREBITS,
+                     SECBIT_NOROOT | SECBIT_NOROOT_LOCKED) < 0)
+            fatal_errno ("prctl (SECBIT_NOROOT)");
+        }
 
       /* This is necessary to undo the damage "sandbox" creates on Fedora
        * by making / a shared mount instead of private.  This isn't
-- 
1.7.12



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]