diff options
Diffstat (limited to 'fsdev')
-rw-r--r-- | fsdev/virtfs-proxy-helper.c | 100 |
1 files changed, 45 insertions, 55 deletions
diff --git a/fsdev/virtfs-proxy-helper.c b/fsdev/virtfs-proxy-helper.c index 6f132c5ff1..0d4de49dcf 100644 --- a/fsdev/virtfs-proxy-helper.c +++ b/fsdev/virtfs-proxy-helper.c @@ -13,7 +13,6 @@ #include <sys/resource.h> #include <getopt.h> #include <syslog.h> -#include <sys/capability.h> #include <sys/fsuid.h> #include <sys/vfs.h> #include <sys/ioctl.h> @@ -21,6 +20,7 @@ #ifdef CONFIG_LINUX_MAGIC_H #include <linux/magic.h> #endif +#include <cap-ng.h> #include "qemu-common.h" #include "qemu/sockets.h" #include "qemu/xattr.h" @@ -79,49 +79,10 @@ static void do_perror(const char *string) } } -static int do_cap_set(cap_value_t *cap_value, int size, int reset) -{ - cap_t caps; - if (reset) { - /* - * Start with an empty set and set permitted and effective - */ - caps = cap_init(); - if (caps == NULL) { - do_perror("cap_init"); - return -1; - } - if (cap_set_flag(caps, CAP_PERMITTED, size, cap_value, CAP_SET) < 0) { - do_perror("cap_set_flag"); - goto error; - } - } else { - caps = cap_get_proc(); - if (!caps) { - do_perror("cap_get_proc"); - return -1; - } - } - if (cap_set_flag(caps, CAP_EFFECTIVE, size, cap_value, CAP_SET) < 0) { - do_perror("cap_set_flag"); - goto error; - } - if (cap_set_proc(caps) < 0) { - do_perror("cap_set_proc"); - goto error; - } - cap_free(caps); - return 0; - -error: - cap_free(caps); - return -1; -} - static int init_capabilities(void) { /* helper needs following capabilities only */ - cap_value_t cap_list[] = { + int cap_list[] = { CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_FOWNER, @@ -130,7 +91,34 @@ static int init_capabilities(void) CAP_MKNOD, CAP_SETUID, }; - return do_cap_set(cap_list, ARRAY_SIZE(cap_list), 1); + int i; + + capng_clear(CAPNG_SELECT_BOTH); + for (i = 0; i < ARRAY_SIZE(cap_list); i++) { + if (capng_update(CAPNG_ADD, CAPNG_EFFECTIVE | CAPNG_PERMITTED, + cap_list[i]) < 0) { + do_perror("capng_update"); + return -1; + } + } + if (capng_apply(CAPNG_SELECT_BOTH) < 0) { + do_perror("capng_apply"); + return -1; + } + + /* Prepare effective set for setugid. */ + for (i = 0; i < ARRAY_SIZE(cap_list); i++) { + if (cap_list[i] == CAP_DAC_OVERRIDE) { + continue; + } + + if (capng_update(CAPNG_DROP, CAPNG_EFFECTIVE, + cap_list[i]) < 0) { + do_perror("capng_update"); + return -1; + } + } + return 0; } static int socket_read(int sockfd, void *buff, ssize_t size) @@ -295,14 +283,6 @@ static int setugid(int uid, int gid, int *suid, int *sgid) { int retval; - /* - * We still need DAC_OVERRIDE because we don't change - * supplementary group ids, and hence may be subjected DAC rules - */ - cap_value_t cap_list[] = { - CAP_DAC_OVERRIDE, - }; - *suid = geteuid(); *sgid = getegid(); @@ -316,11 +296,21 @@ static int setugid(int uid, int gid, int *suid, int *sgid) goto err_sgid; } - if (uid != 0 || gid != 0) { - if (do_cap_set(cap_list, ARRAY_SIZE(cap_list), 0) < 0) { - retval = -errno; - goto err_suid; - } + if (uid == 0 && gid == 0) { + /* Linux has already copied the permitted set to the effective set. */ + return 0; + } + + /* + * All capabilities have been cleared from the effective set. However + * we still need DAC_OVERRIDE because we don't change supplementary + * group ids, and hence may be subject to DAC rules. init_capabilities + * left the set of capabilities that we want in libcap-ng's state. + */ + if (capng_apply(CAPNG_SELECT_CAPS) < 0) { + retval = -errno; + do_perror("capng_apply"); + goto err_suid; } return 0; |