Implemented native capability dropping, eliminated capsh dependency
Sapan Bhatia [Tue, 25 Feb 2014 05:03:55 +0000 (00:03 -0500)]
lxcsu
setns.c

diff --git a/lxcsu b/lxcsu
index d5f26cc..85b1ff7 100755 (executable)
--- a/lxcsu
+++ b/lxcsu
@@ -7,8 +7,6 @@ import pdb
 
 from argparse import ArgumentParser
 
-drop_capabilities='cap_sys_admin,cap_sys_boot,cap_sys_module'
-
 # can set to True here, but also use the -d option
 debug = False
 
@@ -232,19 +230,6 @@ def main ():
 
     fork_pid = os.fork()
 
-    # capsh has a --user option starting with f14
-    # so if only for f12 we need to fake this one
-    #
-    # capsh.c does essentially the following when invoked with --user:
-    #          pwd = getpwnam(user); ...
-    #          ngroups = MAX_GROUPS; 
-    #          status = getgrouplist(user, pwd->pw_gid, groups, &ngroups); ...
-    #          status = setgroups(ngroups, groups); ...
-    #          status = setgid(pwd->pw_gid); ...
-    #          status = setuid(pwd->pw_uid); ...
-    # however we cannot simulate that ourselves because if we did in this process then
-    # capsh could not be allowed to mess with caps any more
-
     def getuid (slicename):
         import pwd
         try:
@@ -253,22 +238,21 @@ def main ():
             return
 
     if (fork_pid == 0):
-        cap_arg = '--drop='+drop_capabilities
-
         if (not args.root):
+            setns.drop_caps() 
             if (args.nosliceuid):
                 # we still want to drop capabilities, but don't want to switch UIDs
-                exec_args = [arch,'/usr/sbin/capsh',cap_arg,'--','--login',]+args.command_to_run
+                exec_args = [arch,'/bin/sh','--login',]+args.command_to_run
             else:
                 uid = getuid (slice_name)
                 if not uid:
                     print "lxcsu could not spot %s in /etc/passwd - exiting"%slice_name
                     exit(1)
-                exec_args = [arch,'/usr/sbin/capsh',cap_arg,'--uid=%s'%uid,'--','--login',]+args.command_to_run
+                exec_args = [arch,'/bin/sh','--uid=%s'%uid,'--login',]+args.command_to_run
 # once we can drop f12, it would be nicer to instead go for
-# exec_args = [arch,'/usr/sbin/capsh',cap_arg,'--user=%s'%slice_name,'--','--login',]+args.command_to_run
+# exec_args = [arch,'/usr/sbin/capsh',cap_arg,'--user=%s'%slice_name,'--login',]+args.command_to_run
         else:
-            exec_args = [arch,'/usr/sbin/capsh','--','--login']+args.command_to_run
+            exec_args = [arch,'/bin/sh','--login']+args.command_to_run
 
         os.environ['SHELL'] = '/bin/sh'
         if os.path.exists('/etc/planetlab/lib/bind_public.so'):
diff --git a/setns.c b/setns.c
index 36aa360..aa907b0 100644 (file)
--- a/setns.c
+++ b/setns.c
@@ -4,6 +4,22 @@
 #include <asm/unistd.h>
 #include <sys/mount.h>
 #include <errno.h>
+#include <sys/prctl.h>
+#include <linux/capability.h>
+
+static PyObject *
+drop_caps(PyObject *self, PyObject *args)
+{
+       unsigned int to_drop[128] = {CAP_NET_ADMIN,CAP_SYS_ADMIN,CAP_SYS_BOOT,CAP_MKNOD,CAP_MAC_ADMIN,CAP_SYS_MODULE};
+       unsigned int i;
+       for (i = 0;i<6;i++) {
+               if (prctl(PR_CAPBSET_DROP, to_drop[i], 0, 0, 0) == -1) {
+                       perror("prctl");
+                       return Py_BuildValue("i", 2);
+               }
+       }
+       return Py_BuildValue("i", 0);
+}
 
 static PyObject *
 proc_mount(PyObject *self, PyObject *args)
@@ -78,6 +94,7 @@ static PyMethodDef SetnsMethods[] =
          {"proc_mount", proc_mount, METH_VARARGS, "Mount a volume via the mount system call."},
          {"proc_umount", proc_umount, METH_VARARGS, "Umount a volume via the umount system call."},
          {"chcontext", chcontext, METH_VARARGS, "Switch into an lxc container."},
+         {"drop_caps", drop_caps, METH_VARARGS, "Drop dangerous capabilities."},
          {"chfscontext", chfscontext, METH_VARARGS, "Switch into an lxc container."},
               {NULL, NULL, 0, NULL}
 };