Skip to content

Commit

Permalink
Merge pull request lxc#2332 from brauner/2018-05-16/use_ambient_capab…
Browse files Browse the repository at this point in the history
…ilities

capabilities: raise ambient capabilities
  • Loading branch information
hallyn authored May 16, 2018
2 parents 02d6227 + 611ddd3 commit 23cf184
Show file tree
Hide file tree
Showing 3 changed files with 198 additions and 35 deletions.
130 changes: 130 additions & 0 deletions src/lxc/caps.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -126,6 +147,115 @@ int lxc_caps_up(void)
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();
Expand Down
89 changes: 55 additions & 34 deletions src/lxc/caps.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,70 +27,91 @@
#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
14 changes: 13 additions & 1 deletion src/lxc/start.c
Original file line number Diff line number Diff line change
Expand Up @@ -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");
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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.
*/
Expand Down

0 comments on commit 23cf184

Please sign in to comment.