]> git.proxmox.com Git - mirror_lxc.git/commitdiff
capabilities: raise ambient capabilities
authorChristian Brauner <christian.brauner@ubuntu.com>
Tue, 15 May 2018 19:33:48 +0000 (21:33 +0200)
committerChristian Brauner <christian.brauner@ubuntu.com>
Wed, 16 May 2018 13:56:57 +0000 (15:56 +0200)
Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
Suggested-by: Jonathan Calmels <jcalmels@nvidia.com>
src/lxc/caps.c
src/lxc/caps.h
src/lxc/start.c

index 2d3261da09ec3bb7ab05e43ba1ac3693bdcbbc51..6665af217609d02e9ec336ed62c127a598df318c 100644 (file)
@@ -42,6 +42,27 @@ lxc_log_define(lxc_caps, lxc);
 #define PR_CAPBSET_READ 23
 #endif
 
+/* Control the ambient capability set */
+#ifndef PR_CAP_AMBIENT
+#define PR_CAP_AMBIENT 47
+#endif
+
+#ifndef PR_CAP_AMBIENT_IS_SET
+#define PR_CAP_AMBIENT_IS_SET 1
+#endif
+
+#ifndef PR_CAP_AMBIENT_RAISE
+#define PR_CAP_AMBIENT_RAISE 2
+#endif
+
+#ifndef PR_CAP_AMBIENT_LOWER
+#define PR_CAP_AMBIENT_LOWER 3
+#endif
+
+#ifndef PR_CAP_AMBIENT_CLEAR_ALL
+#define PR_CAP_AMBIENT_CLEAR_ALL 4
+#endif
+
 int lxc_caps_down(void)
 {
        cap_t caps;
@@ -126,6 +147,115 @@ out:
        return 0;
 }
 
+int lxc_ambient_caps_up(void)
+{
+       int ret;
+       cap_t caps;
+       cap_value_t cap;
+       int last_cap = CAP_LAST_CAP;
+       char *cap_names = NULL;
+
+       /* When we are run as root, we don't want to play with the capabilities. */
+       if (!getuid())
+               return 0;
+
+       caps = cap_get_proc();
+       if (!caps) {
+               SYSERROR("Failed to retrieve capabilities");
+               return -1;
+       }
+
+       for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
+               cap_flag_value_t flag;
+
+               ret = cap_get_flag(caps, cap, CAP_PERMITTED, &flag);
+               if (ret < 0) {
+                       if (errno == EINVAL) {
+                               last_cap = (cap - 1);
+                               INFO("Last supported cap was %d", last_cap);
+                               break;
+                       }
+
+                       SYSERROR("Failed to retrieve capability flag");
+                       goto out;
+               }
+
+               ret = cap_set_flag(caps, CAP_INHERITABLE, 1, &cap, flag);
+               if (ret < 0) {
+                       SYSERROR("Failed to set capability flag");
+                       goto out;
+               }
+       }
+
+       ret = cap_set_proc(caps);
+       if (ret < 0) {
+               SYSERROR("Failed to set capabilities");
+               goto out;
+       }
+
+       for (cap = 0; cap <= last_cap; cap++) {
+               ret = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap, 0, 0);
+               if (ret < 0) {
+                       WARN("%s - Failed to raise ambient capability %d",
+                            strerror(errno), cap);
+                       goto out;
+               }
+       }
+
+       cap_names = cap_to_text(caps, NULL);
+       if (!cap_names)
+               goto out;
+
+       TRACE("Raised %s in inheritable and ambient capability set", cap_names);
+
+out:
+
+       cap_free(cap_names);
+       cap_free(caps);
+       return 0;
+}
+
+int lxc_ambient_caps_down(void)
+{
+       int ret;
+       cap_t caps;
+       cap_value_t cap;
+
+       /* When we are run as root, we don't want to play with the capabilities. */
+       if (!getuid())
+               return 0;
+
+       ret = prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_CLEAR_ALL, 0, 0, 0);
+       if (ret < 0) {
+               SYSERROR("Failed to clear ambient capability set");
+               return -1;
+       }
+
+       caps = cap_get_proc();
+       if (!caps) {
+               SYSERROR("Failed to retrieve capabilities");
+               return -1;
+       }
+
+       for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
+               ret = cap_set_flag(caps, CAP_INHERITABLE, 1, &cap, CAP_CLEAR);
+               if (ret < 0) {
+                       SYSERROR("Failed to remove capability from inheritable set");
+                       goto out;
+               }
+       }
+
+       ret = cap_set_proc(caps);
+       if (ret < 0) {
+               SYSERROR("Failed to set capabilities");
+               goto out;
+       }
+
+out:
+       cap_free(caps);
+       return 0;
+}
+
 int lxc_caps_init(void)
 {
        uid_t uid = getuid();
index 2b3b1a502fe978ab6648e19dd228ce50fc1657d9..14c498ae7baf6e690952accb2a35becc17395a9f 100644 (file)
 #include "config.h"
 #include <stdbool.h>
 
-
 #if HAVE_LIBCAP
 #include <linux/types.h> /* workaround for libcap < 2.17 bug */
 #include <sys/capability.h>
 
 extern int lxc_caps_down(void);
 extern int lxc_caps_up(void);
+extern int lxc_ambient_caps_up(void);
+extern int lxc_ambient_caps_down(void);
 extern int lxc_caps_init(void);
-
 extern int lxc_caps_last_cap(void);
-
 extern bool lxc_proc_cap_is_set(cap_value_t cap, cap_flag_t flag);
-extern bool lxc_file_cap_is_set(const char *path, cap_value_t cap, cap_flag_t flag);
+extern bool lxc_file_cap_is_set(const char *path, cap_value_t cap,
+                               cap_flag_t flag);
 #else
-static inline int lxc_caps_down(void) {
+static inline int lxc_caps_down(void)
+{
        return 0;
 }
-static inline int lxc_caps_up(void) {
+
+static inline int lxc_caps_up(void)
+{
        return 0;
 }
-static inline int lxc_caps_init(void) {
+
+static inline int lxc_ambient_caps_up(void)
+{
+       return 0;
+}
+
+static inline int lxc_ambient_caps_down(void)
+{
+       return 0;
+}
+
+static inline int lxc_caps_init(void)
+{
        return 0;
 }
 
-static inline int lxc_caps_last_cap(void) {
+static inline int lxc_caps_last_cap(void)
+{
        return 0;
 }
 
 typedef int cap_value_t;
 typedef int cap_flag_t;
-static inline bool lxc_proc_cap_is_set(cap_value_t cap, cap_flag_t flag) {
+static inline bool lxc_proc_cap_is_set(cap_value_t cap, cap_flag_t flag)
+{
        return false;
 }
 
-static inline bool lxc_file_cap_is_set(const char *path, cap_value_t cap, cap_flag_t flag) {
+static inline bool lxc_file_cap_is_set(const char *path, cap_value_t cap,
+                                      cap_flag_t flag)
+{
        return false;
 }
 #endif
 
-#define lxc_priv(__lxc_function)                       \
-       ({                                              \
-               __label__ out;                          \
-               int __ret, __ret2, ___errno = 0;                \
-               __ret = lxc_caps_up();                  \
-               if (__ret)                              \
-                       goto out;                       \
-               __ret = __lxc_function;                 \
-               if (__ret)                              \
-                       ___errno = errno;               \
-               __ret2 = lxc_caps_down();               \
-       out:    __ret ? errno = ___errno,__ret : __ret2;        \
+#define lxc_priv(__lxc_function)                          \
+       ({                                                \
+               __label__ out;                            \
+               int __ret, __ret2, ___errno = 0;          \
+               __ret = lxc_caps_up();                    \
+               if (__ret)                                \
+                       goto out;                         \
+               __ret = __lxc_function;                   \
+               if (__ret)                                \
+                       ___errno = errno;                 \
+               __ret2 = lxc_caps_down();                 \
+       out:                                              \
+               __ret ? errno = ___errno, __ret : __ret2; \
        })
 
-#define lxc_unpriv(__lxc_function)                     \
-       ({                                              \
-               __label__ out;                          \
-               int __ret, __ret2, ___errno = 0;                \
-               __ret = lxc_caps_down();                \
-               if (__ret)                              \
-                       goto out;                       \
-               __ret = __lxc_function;                 \
-               if (__ret)                              \
-                       ___errno = errno;               \
-               __ret2 = lxc_caps_up();                 \
-       out:    __ret ? errno = ___errno,__ret : __ret2;        \
+#define lxc_unpriv(__lxc_function)                        \
+       ({                                                \
+               __label__ out;                            \
+               int __ret, __ret2, ___errno = 0;          \
+               __ret = lxc_caps_down();                  \
+               if (__ret)                                \
+                       goto out;                         \
+               __ret = __lxc_function;                   \
+               if (__ret)                                \
+                       ___errno = errno;                 \
+               __ret2 = lxc_caps_up();                   \
+       out:                                              \
+               __ret ? errno = ___errno, __ret : __ret2; \
        })
 #endif
index e9b0efe5f2d7cd3cb5203a0c6343b0f0dc82a9a2..b8404f99e0cc18e6ea50e412b44da31ffef48567 100644 (file)
@@ -1049,6 +1049,12 @@ static int do_start(void *data)
                goto out_warn_father;
        }
 
+       ret = lxc_ambient_caps_up();
+       if (ret < 0) {
+               SYSERROR("Failed to raise ambient capabilities");
+               goto out_warn_father;
+       }
+
        ret = sigprocmask(SIG_SETMASK, &handler->oldmask, NULL);
        if (ret < 0) {
                SYSERROR("Failed to set signal mask");
@@ -1081,7 +1087,7 @@ static int do_start(void *data)
         */
        ret = lxc_sync_barrier_parent(handler, LXC_SYNC_CONFIGURE);
        if (ret < 0)
-               return -1;
+               goto out_error;
 
        ret = lxc_network_recv_veth_names_from_parent(handler);
        if (ret < 0) {
@@ -1348,6 +1354,12 @@ static int do_start(void *data)
        if (ret < 0)
                goto out_warn_father;
 
+       ret = lxc_ambient_caps_down();
+       if (ret < 0) {
+               SYSERROR("Failed to clear ambient capabilities");
+               goto out_warn_father;
+       }
+
        /* After this call, we are in error because this ops should not return
         * as it execs.
         */