From e71dabf21ddd2a093ebdfcc6f6c79200415d12b1 Mon Sep 17 00:00:00 2001 From: wujing Date: Tue, 14 Apr 2020 23:30:46 -0400 Subject: [PATCH 27/49] Capabilites security feature enhanced Signed-off-by: wujing --- src/lxc/attach.c | 24 +++++++++++++ src/lxc/conf.c | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/lxc/conf.h | 1 + src/lxc/start.c | 20 +++++++++++ 4 files changed, 148 insertions(+) diff --git a/src/lxc/attach.c b/src/lxc/attach.c index c77b929..231fa5f 100644 --- a/src/lxc/attach.c +++ b/src/lxc/attach.c @@ -832,10 +832,12 @@ static int attach_child_main(struct attach_clone_payload *payload) goto on_error; } +#ifndef HAVE_ISULAD close(payload->ipc_socket); payload->ipc_socket = -EBADF; lxc_proc_put_context_info(init_ctx); payload->init_ctx = NULL; +#endif /* The following is done after the communication socket is shut down. * That way, all errors that might (though unlikely) occur up until this @@ -895,6 +897,11 @@ static int attach_child_main(struct attach_clone_payload *payload) new_gid = LXC_INVALID_GID; #ifdef HAVE_ISULAD + if (prctl(PR_SET_KEEPCAPS, 1) < 0) { + SYSERROR("Failed to keep permitted capabilities"); + goto on_error; + } + if (!lxc_setgroups(init_ctx->container->lxc_conf->init_groups_len, init_ctx->container->lxc_conf->init_groups)) goto on_error; @@ -908,6 +915,23 @@ static int attach_child_main(struct attach_clone_payload *payload) if (!lxc_switch_uid_gid(new_uid, new_gid)) goto on_error; +#ifdef HAVE_ISULAD + if (prctl(PR_SET_KEEPCAPS, 0) < 0) { + SYSERROR("Failed to clear permitted capabilities"); + goto on_error; + } + + if (lxc_drop_caps(init_ctx->container->lxc_conf) != 0) { + ERROR("Failed to drop caps."); + goto on_error; + } + + close(payload->ipc_socket); + payload->ipc_socket = -EBADF; + lxc_proc_put_context_info(init_ctx); + payload->init_ctx = NULL; +#endif + /* We're done, so we can now do whatever the user intended us to do. */ _exit(payload->exec_function(payload->exec_payload)); diff --git a/src/lxc/conf.c b/src/lxc/conf.c index 43ef067..325e0c2 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -2902,6 +2902,16 @@ static int dropcaps_except(struct lxc_list *caps) lxc_list_for_each (iterator, caps) { keep_entry = iterator->elem; +#ifdef HAVE_ISULAD + /* Do not keep any cap*/ + if (strcmp(keep_entry, "ISULAD_KEEP_NONE") == 0) { + DEBUG("Do not keep any capability"); + for(i = 0; i < numcaps; i++) { + caplist[i] = 0; + } + break; + } +#endif capid = parse_cap(keep_entry); if (capid == -2) continue; @@ -4703,6 +4713,99 @@ int lxc_setup(struct lxc_handler *handler) return 0; } +#ifdef HAVE_ISULAD +/* isulad drop caps for container*/ +int lxc_drop_caps(struct lxc_conf *conf) +{ +#define __DEF_CAP_TO_MASK(x) (1U << ((x) & 31)) +#if HAVE_LIBCAP + int ret = 0; + struct lxc_list *iterator = NULL; + char *keep_entry = NULL; + size_t i = 0; + int capid; + size_t numcaps = (size_t)lxc_caps_last_cap() + 1; + struct lxc_list *caps = NULL; + int *caplist = NULL; + + if (lxc_list_empty(&conf->keepcaps)) + return 0; + + caps = &conf->keepcaps; + + if (numcaps <= 0 || numcaps > 200) + return -1; + + // caplist[i] is 1 if we keep capability i + caplist = malloc(numcaps * sizeof(int)); + if (caplist == NULL) { + ERROR("Out of memory"); + return -1; + } + (void)memset(caplist, 0, numcaps * sizeof(int)); + + lxc_list_for_each(iterator, caps) { + + keep_entry = iterator->elem; + /* isulad: Do not keep any cap*/ + if (strcmp(keep_entry, "ISULAD_KEEP_NONE") == 0) { + DEBUG("Do not keep any capability"); + for(i = 0; i < numcaps; i++) { + caplist[i] = 0; + } + break; + } + + capid = parse_cap(keep_entry); + + if (capid == -2) + continue; + + if (capid < 0) { + ERROR("unknown capability %s", keep_entry); + ret = -1; + goto out; + } + + DEBUG("keep capability '%s' (%d)", keep_entry, capid); + + caplist[capid] = 1; + } + + struct __user_cap_header_struct cap_header_data; + struct __user_cap_data_struct cap_data_data[2]; + + cap_user_header_t cap_header = &cap_header_data; + cap_user_data_t cap_data = &cap_data_data[0]; + + memset(cap_header, 0,sizeof(struct __user_cap_header_struct)); + memset(cap_data, 0, sizeof(struct __user_cap_data_struct) * 2); + + cap_header->pid = 0; + cap_header->version = _LINUX_CAPABILITY_VERSION_3; + + for (i = 0; i < numcaps; i++) { + if (caplist[i]) { + cap_data[CAP_TO_INDEX(i)].effective = cap_data[CAP_TO_INDEX(i)].effective | (i > 31 ? __DEF_CAP_TO_MASK(i % 32) : __DEF_CAP_TO_MASK(i)); + cap_data[CAP_TO_INDEX(i)].permitted = cap_data[CAP_TO_INDEX(i)].permitted | (i > 31 ? __DEF_CAP_TO_MASK(i % 32) : __DEF_CAP_TO_MASK(i)); + cap_data[CAP_TO_INDEX(i)].inheritable = cap_data[CAP_TO_INDEX(i)].inheritable | (i > 31 ? __DEF_CAP_TO_MASK(i % 32) : __DEF_CAP_TO_MASK(i)); + } + } + + if (capset(cap_header, cap_data)) { + SYSERROR("Failed to set capabilitys"); + ret = -1; + goto out; + } + +#endif + +out: + free(caplist); + return ret; +} +#endif + int run_lxc_hooks(const char *name, char *hookname, struct lxc_conf *conf, char *argv[]) { diff --git a/src/lxc/conf.h b/src/lxc/conf.h index 879e427..7b6fd3b 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -555,6 +555,7 @@ int lxc_clear_init_groups(struct lxc_conf *lxc_conf); int lxc_clear_populate_devices(struct lxc_conf *c); int lxc_clear_rootfs_masked_paths(struct lxc_conf *c); int lxc_clear_rootfs_ro_paths(struct lxc_conf *c); +int lxc_drop_caps(struct lxc_conf *conf); int run_oci_hooks(const char *name, const char *hookname, struct lxc_conf *conf, const char *lxcpath); #endif #endif /* __LXC_CONF_H */ diff --git a/src/lxc/start.c b/src/lxc/start.c index e2311ec..bb2e74a 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -1652,6 +1652,13 @@ static int do_start(void *data) } } +#ifdef HAVE_ISULAD + if (prctl(PR_SET_KEEPCAPS, 1) < 0) { + SYSERROR("Failed to keep permitted capabilities"); + goto out_warn_father; + } +#endif + /* The container has been setup. We can now switch to an unprivileged * uid/gid. */ @@ -1705,6 +1712,19 @@ static int do_start(void *data) goto out_warn_father; } +#ifdef HAVE_ISULAD + /* isulad: drop the cap of current process */ + if (prctl(PR_SET_KEEPCAPS, 0) < 0) { + SYSERROR("Failed to clear permitted capabilities"); + goto out_warn_father; + } + + if (lxc_drop_caps(handler->conf)) { + SYSERROR("Failed to drop caps"); + goto out_warn_father; + } +#endif + if (handler->conf->monitor_signal_pdeath != SIGKILL) { ret = lxc_set_death_signal(handler->conf->monitor_signal_pdeath, handler->monitor_pid, status_fd); -- 1.8.3.1