aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--readme.rst9
-rwxr-xr-xrun_with_inherited_caps.py115
2 files changed, 124 insertions, 0 deletions
diff --git a/readme.rst b/readme.rst
new file mode 100644
index 0000000..f7820b7
--- /dev/null
+++ b/readme.rst
@@ -0,0 +1,9 @@
+The first example drops caps except setuid/gid, then change to a user, then
+regain a specific capability.
+
+The second example sets the inheritable caps and drops all caps except
+setuid/gid, then change to a user, then execve a program which is assumed to
+have same set of inheritable caps sets in its xattrs + effective flag. Thus
+the result is the launched program has only a specific capability and nobody
+can automatically gain (as opposed to effective + permited file caps) the
+allowed capability. Only the runner can do it.
diff --git a/run_with_inherited_caps.py b/run_with_inherited_caps.py
new file mode 100755
index 0000000..063860c
--- /dev/null
+++ b/run_with_inherited_caps.py
@@ -0,0 +1,115 @@
+#!/usr/bin/python3
+
+# resources for cffi:
+# http://eli.thegreenplace.net/2013/03/09/python-ffi-with-ctypes-and-cffi
+
+import cffi
+import os
+import time
+import pwd
+
+pid = os.getpid()
+print('pid:', pid)
+
+ffi = cffi.FFI()
+libcap = ffi.dlopen('libcap.so.2')
+ffi.cdef('''
+typedef struct _cap_struct *cap_t;
+typedef int cap_value_t;
+typedef enum {
+ CAP_EFFECTIVE=0,
+ CAP_PERMITTED=1,
+ CAP_INHERITABLE=2
+} cap_flag_t;
+typedef enum {
+ CAP_CLEAR=0,
+ CAP_SET=1
+} cap_flag_value_t;
+
+cap_t cap_get_proc(void);
+int cap_set_flag(cap_t cap_p, cap_flag_t flag, int ncap,
+ const cap_value_t *caps, cap_flag_value_t value);
+cap_t cap_init(void);
+int cap_free(void *obj_d);
+int cap_set_proc(cap_t cap_p);
+''')
+
+CAP_EFFECTIVE = 0
+CAP_PERMITTED = 1
+CAP_INHERITABLE = 2
+CAP_CLEAR = 0
+CAP_SET = 1
+
+# generated list with command line below:
+# sed -n 's/^#define \(CAP_.*\)\s\+\([0-9]\+\).*$/\1 = \2/p' /usr/include/linux/capability.h
+CAP_CHOWN = 0
+CAP_DAC_OVERRIDE = 1
+CAP_DAC_READ_SEARCH = 2
+CAP_FOWNER = 3
+CAP_FSETID = 4
+CAP_KILL = 5
+CAP_SETGID = 6
+CAP_SETUID = 7
+CAP_SETPCAP = 8
+CAP_LINUX_IMMUTABLE = 9
+CAP_NET_BIND_SERVICE = 10
+CAP_NET_BROADCAST = 11
+CAP_NET_ADMIN = 12
+CAP_NET_RAW = 13
+CAP_IPC_LOCK = 14
+CAP_IPC_OWNER = 15
+CAP_SYS_MODULE = 16
+CAP_SYS_RAWIO = 17
+CAP_SYS_CHROOT = 18
+CAP_SYS_PTRACE = 19
+CAP_SYS_PACCT = 20
+CAP_SYS_ADMIN = 21
+CAP_SYS_BOOT = 22
+CAP_SYS_NICE = 23
+CAP_SYS_RESOURCE = 24
+CAP_SYS_TIME = 25
+CAP_SYS_TTY_CONFIG = 26
+CAP_MKNOD = 27
+CAP_LEASE = 28
+CAP_AUDIT_WRITE = 29
+CAP_AUDIT_CONTROL = 30
+CAP_SETFCAP = 31
+CAP_MAC_OVERRIDE = 32
+CAP_MAC_ADMIN = 33
+CAP_SYSLOG = 34
+CAP_WAKE_ALARM = 35
+CAP_BLOCK_SUSPEND = 36
+
+
+uid, gid = 1000, 1000
+
+
+print("before droping caps")
+os.system("cat /proc/{}/status | grep Cap".format(pid))
+os.system("cp /bin/sleep /tmp/sleep")
+os.system("setcap cap_net_bind_service=ei /tmp/sleep")
+
+cap_values = (CAP_NET_BIND_SERVICE, )
+cap_values_temp = (CAP_SETUID, CAP_SETGID,)
+ccap_values = ffi.new('cap_value_t[]', cap_values)
+ccap_values_temp = ffi.new('cap_value_t[]', cap_values_temp)
+
+print('len cap_values:', len(cap_values))
+caps = libcap.cap_init()
+libcap.cap_set_flag(caps, CAP_INHERITABLE, len(cap_values), ccap_values, CAP_SET)
+libcap.cap_set_flag(caps, CAP_PERMITTED, len(cap_values_temp), ccap_values_temp, CAP_SET)
+libcap.cap_set_flag(caps, CAP_EFFECTIVE, len(cap_values_temp), ccap_values_temp, CAP_SET)
+libcap.cap_set_proc(caps)
+libcap.cap_free(caps)
+
+print("after dropping caps")
+os.system("cat /proc/{}/status | grep Cap".format(pid))
+
+os.setgroups(os.getgrouplist(pwd.getpwuid(uid)[0], gid))
+os.setgid(gid)
+os.setuid(uid)
+
+print("after setgid/setuid/setgroups")
+os.system("cat /proc/{}/status | grep Cap".format(pid))
+
+os.execve("/tmp/sleep", ["/tmp/sleep", "9999"], {})