caps: bugfixes

Signed-off-by: Christian Brauner <christian.brauner@ubuntu.com>
This commit is contained in:
Christian Brauner 2018-08-04 20:12:56 +02:00
parent 279c45eed3
commit 4e60664a9a
No known key found for this signature in database
GPG Key ID: 8EB056D53EECB12D

View File

@ -33,6 +33,7 @@
#include "caps.h" #include "caps.h"
#include "log.h" #include "log.h"
#include "macro.h"
lxc_log_define(caps, lxc); lxc_log_define(caps, lxc);
@ -66,51 +67,52 @@ lxc_log_define(caps, lxc);
int lxc_caps_down(void) int lxc_caps_down(void)
{ {
cap_t caps; cap_t caps;
int ret; int ret = -1;
/* when we are run as root, we don't want to play /* When we are root, we don't want to play with capabilities. */
* with the capabilities */
if (!getuid()) if (!getuid())
return 0; return 0;
caps = cap_get_proc(); caps = cap_get_proc();
if (!caps) { if (!caps) {
SYSERROR("Failed to cap_get_proc"); SYSERROR("Failed to retrieve capabilities");
return -1; return ret;
} }
ret = cap_clear_flag(caps, CAP_EFFECTIVE); ret = cap_clear_flag(caps, CAP_EFFECTIVE);
if (ret) { if (ret) {
SYSERROR("Failed to cap_clear_flag"); SYSERROR("Failed to clear effective capabilities");
goto out; goto on_error;
} }
ret = cap_set_proc(caps); ret = cap_set_proc(caps);
if (ret) { if (ret) {
SYSERROR("Failed to cap_set_proc"); SYSERROR("Failed to change effective capabilities");
goto out; goto on_error;
} }
out: ret = 0;
on_error:
cap_free(caps); cap_free(caps);
return 0;
return ret;
} }
int lxc_caps_up(void) int lxc_caps_up(void)
{ {
cap_t caps; cap_t caps;
cap_value_t cap; cap_value_t cap;
int ret; int ret = -1;
/* when we are run as root, we don't want to play /* When we are root, we don't want to play with capabilities. */
* with the capabilities */
if (!getuid()) if (!getuid())
return 0; return 0;
caps = cap_get_proc(); caps = cap_get_proc();
if (!caps) { if (!caps) {
SYSERROR("Failed to cap_get_proc"); SYSERROR("Failed to retrieve capabilities");
return -1; return ret;
} }
for (cap = 0; cap <= CAP_LAST_CAP; cap++) { for (cap = 0; cap <= CAP_LAST_CAP; cap++) {
@ -119,30 +121,34 @@ int lxc_caps_up(void)
ret = cap_get_flag(caps, cap, CAP_PERMITTED, &flag); ret = cap_get_flag(caps, cap, CAP_PERMITTED, &flag);
if (ret) { if (ret) {
if (errno == EINVAL) { if (errno == EINVAL) {
INFO("Last supported cap was %d", cap-1); INFO("Last supported cap was %d", cap - 1);
break; break;
} else { } else {
SYSERROR("Failed to cap_get_flag"); SYSERROR("Failed to retrieve setting for "
goto out; "permitted capability %d", cap - 1);
goto on_error;
} }
} }
ret = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, flag); ret = cap_set_flag(caps, CAP_EFFECTIVE, 1, &cap, flag);
if (ret) { if (ret) {
SYSERROR("Failed to cap_set_flag"); SYSERROR("Failed to set effective capability %d", cap - 1);
goto out; goto on_error;
} }
} }
ret = cap_set_proc(caps); ret = cap_set_proc(caps);
if (ret) { if (ret) {
SYSERROR("Failed to cap_set_proc"); SYSERROR("Failed to change effective capabilities");
goto out; goto on_error;
} }
out: ret = 0;
on_error:
cap_free(caps); cap_free(caps);
return 0;
return ret;
} }
int lxc_ambient_caps_up(void) int lxc_ambient_caps_up(void)
@ -153,7 +159,7 @@ int lxc_ambient_caps_up(void)
int last_cap = CAP_LAST_CAP; int last_cap = CAP_LAST_CAP;
char *cap_names = NULL; char *cap_names = NULL;
/* When we are run as root, we don't want to play with the capabilities. */ /* When we are root, we don't want to play with capabilities. */
if (!getuid()) if (!getuid())
return 0; return 0;
@ -220,7 +226,7 @@ int lxc_ambient_caps_down(void)
cap_t caps; cap_t caps;
cap_value_t cap; cap_value_t cap;
/* When we are run as root, we don't want to play with the capabilities. */ /* When we are root, we don't want to play with capabilities. */
if (!getuid()) if (!getuid())
return 0; return 0;
@ -257,79 +263,84 @@ out:
int lxc_caps_init(void) int lxc_caps_init(void)
{ {
uid_t uid = getuid(); uid_t euid, uid;
gid_t gid = getgid();
uid_t euid = geteuid();
if (!uid) { uid = getuid();
INFO("command is run as 'root'"); if (!uid)
return 0; return 0;
}
euid = geteuid();
if (uid && !euid) { if (uid && !euid) {
INFO("command is run as setuid root (uid : %d)", uid); int ret;
gid_t gid;
if (prctl(PR_SET_KEEPCAPS, 1)) { INFO("Command is run as setuid root (uid: %d)", uid);
SYSERROR("Failed to 'PR_SET_KEEPCAPS'");
ret = prctl(PR_SET_KEEPCAPS, 1);
if (ret < 0) {
SYSERROR("Failed to set PR_SET_KEEPCAPS");
return -1; return -1;
} }
if (setresgid(gid, gid, gid)) { gid = getgid();
SYSERROR("Failed to change gid to '%d'", gid); ret = setresgid(gid, gid, gid);
if (ret < 0) {
SYSERROR("Failed to change rgid, egid, and sgid to %d", gid);
return -1; return -1;
} }
if (setresuid(uid, uid, uid)) { ret = setresuid(uid, uid, uid);
SYSERROR("Failed to change uid to '%d'", uid); if (ret < 0) {
SYSERROR("Failed to change ruid, euid, and suid to %d", uid);
return -1; return -1;
} }
if (lxc_caps_up()) { ret = lxc_caps_up();
if (ret < 0) {
SYSERROR("Failed to restore capabilities"); SYSERROR("Failed to restore capabilities");
return -1; return -1;
} }
} }
if (uid == euid) if (uid == euid)
INFO("command is run as user '%d'", uid); INFO("Command is run with uid %d", uid);
return 0; return 0;
} }
static int _real_caps_last_cap(void) static int _real_caps_last_cap(void)
{ {
int fd; int fd, result = -1;
int result = -1;
/* try to get the maximum capability over the kernel /* Try to get the maximum capability over the kernel interface
* interface introduced in v3.2 */ * introduced in v3.2.
fd = open("/proc/sys/kernel/cap_last_cap", O_RDONLY); */
fd = open("/proc/sys/kernel/cap_last_cap", O_RDONLY | O_CLOEXEC);
if (fd >= 0) { if (fd >= 0) {
char buf[32]; ssize_t n;
char *ptr; char *ptr;
int n; char buf[LXC_NUMSTRLEN64 + 1];
again: again:
n = read(fd, buf, 31); n = read(fd, buf, LXC_NUMSTRLEN64);
if (n < 0 && errno == EINTR) { if (n < 0 && errno == EINTR) {
goto again; goto again;
} else if (n >= 0) { } else if (n >= 0) {
buf[n] = '\0'; buf[n] = '\0';
errno = 0;
errno = 0;
result = strtol(buf, &ptr, 10); result = strtol(buf, &ptr, 10);
if (!ptr || (*ptr != '\0' && *ptr != '\n') || errno != 0) if (!ptr || (*ptr != '\0' && *ptr != '\n') || errno != 0)
result = -1; result = -1;
} }
close(fd); close(fd);
} } else {
/* try to get it manually by trying to get the status of
* each capability indiviually from the kernel */
if (result < 0) {
int cap = 0; int cap = 0;
/* Try to get it manually by trying to get the status of each
* capability individually from the kernel.
*/
while (prctl(PR_CAPBSET_READ, cap) >= 0) while (prctl(PR_CAPBSET_READ, cap) >= 0)
cap++; cap++;
@ -356,7 +367,7 @@ static bool lxc_cap_is_set(cap_t caps, cap_value_t cap, cap_flag_t flag)
ret = cap_get_flag(caps, cap, flag, &flagval); ret = cap_get_flag(caps, cap, flag, &flagval);
if (ret < 0) { if (ret < 0) {
SYSERROR("Failed to perform cap_get_flag()"); SYSERROR("Failed to retrieve current setting for capability %d", cap);
return false; return false;
} }
@ -365,7 +376,7 @@ static bool lxc_cap_is_set(cap_t caps, cap_value_t cap, cap_flag_t flag)
bool lxc_file_cap_is_set(const char *path, cap_value_t cap, cap_flag_t flag) bool lxc_file_cap_is_set(const char *path, cap_value_t cap, cap_flag_t flag)
{ {
#if LIBCAP_SUPPORTS_FILE_CAPABILITIES #if LIBCAP_SUPPORTS_FILE_CAPABILITIES
bool cap_is_set; bool cap_is_set;
cap_t caps; cap_t caps;
@ -377,7 +388,7 @@ bool lxc_file_cap_is_set(const char *path, cap_value_t cap, cap_flag_t flag)
* case errno will be set to ENODATA. * case errno will be set to ENODATA.
*/ */
if (errno != ENODATA) if (errno != ENODATA)
SYSERROR("Failed to perform cap_get_file()"); SYSERROR("Failed to retrieve capabilities for file %s", path);
return false; return false;
} }
@ -385,10 +396,10 @@ bool lxc_file_cap_is_set(const char *path, cap_value_t cap, cap_flag_t flag)
cap_is_set = lxc_cap_is_set(caps, cap, flag); cap_is_set = lxc_cap_is_set(caps, cap, flag);
cap_free(caps); cap_free(caps);
return cap_is_set; return cap_is_set;
#else #else
errno = ENODATA; errno = ENODATA;
return false; return false;
#endif #endif
} }
bool lxc_proc_cap_is_set(cap_value_t cap, cap_flag_t flag) bool lxc_proc_cap_is_set(cap_value_t cap, cap_flag_t flag)
@ -398,7 +409,7 @@ bool lxc_proc_cap_is_set(cap_value_t cap, cap_flag_t flag)
caps = cap_get_proc(); caps = cap_get_proc();
if (!caps) { if (!caps) {
SYSERROR("Failed to perform cap_get_proc()"); SYSERROR("Failed to retrieve capabilities");
return false; return false;
} }
@ -406,5 +417,4 @@ bool lxc_proc_cap_is_set(cap_value_t cap, cap_flag_t flag)
cap_free(caps); cap_free(caps);
return cap_is_set; return cap_is_set;
} }
#endif #endif