]> git.ipfire.org Git - thirdparty/lxc.git/commitdiff
Add function to determine CAP_LAST_CAP of the current kernel dynamically
authorChristian Seiler <christian@iwakd.de>
Thu, 23 Feb 2012 08:57:13 +0000 (09:57 +0100)
committerDaniel Lezcano <daniel.lezcano@free.fr>
Thu, 23 Feb 2012 08:57:13 +0000 (09:57 +0100)
The function lxc_caps_last_cap() determines CAP_LAST_CAP of the current kernel
dynamically. It first tries to read /proc/sys/kernel/cap_last_cap. If that
fails, because the kernel does not support this interface yet, it loops
through all capabilities and tries to determine whether the current capability
is part of the bounding set. The first capability for which prctl() fails is
considered to be CAP_LAST_CAP.

Signed-off-by: Daniel Lezcano <dlezcano@fr.ibm.com>
src/lxc/caps.c
src/lxc/caps.h

index 46a2766c3c27290547ef9cc67060a10e2786ae80..1610002ac08d9632079f911904e227a0b88992be 100644 (file)
@@ -23,6 +23,9 @@
 
 #define _GNU_SOURCE
 #include <unistd.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <limits.h>
 #include <sys/prctl.h>
 #include <sys/capability.h>
 
@@ -167,3 +170,46 @@ int lxc_caps_init(void)
 
        return 0;
 }
+
+static int _real_caps_last_cap(void)
+{
+       int fd;
+       int result = -1;
+
+       /* try to get the maximum capability over the kernel
+       * interface introduced in v3.2 */
+       fd = open("/proc/sys/kernel/cap_last_cap", O_RDONLY);
+       if (fd >= 0) {
+               char buf[32];
+               char *ptr;
+               int n;
+
+               if ((n = read(fd, buf, 31)) >= 0) {
+                       buf[n] = '\0';
+                       result = strtol(buf, &ptr, 10);
+                       if (!ptr || (*ptr != '\0' && *ptr != '\n') ||
+                           result == LONG_MIN || result == LONG_MAX)
+                               result = -1;
+               }
+
+               close(fd);
+       }
+
+       /* try to get it manually by trying to get the status of
+       * each capability indiviually from the kernel */
+       if (result < 0) {
+               int cap = 0;
+               while (prctl(PR_CAPBSET_READ, cap) >= 0) cap++;
+               result = cap - 1;
+       }
+
+       return result;
+}
+
+int lxc_caps_last_cap(void)
+{
+       static int last_cap = -1;
+       if (last_cap < 0) last_cap = _real_caps_last_cap();
+
+       return last_cap;
+}
index 4c07b69f67dbf3ebc4e2b82f284c8503a8027dd1..e4e0d425e18bd406e30371c973b246c0d41443d2 100644 (file)
@@ -28,6 +28,8 @@ extern int lxc_caps_down(void);
 extern int lxc_caps_up(void);
 extern int lxc_caps_init(void);
 
+extern int lxc_caps_last_cap(void);
+
 #define lxc_priv(__lxc_function)                       \
        ({                                              \
                int __ret, __ret2, __errno = 0;         \