From eb12d34669676227b6973d7d2aa8a1d1ee595d79 Mon Sep 17 00:00:00 2001 From: LiFeng Date: Tue, 15 Jan 2019 22:55:06 -0500 Subject: [PATCH 036/138] drop_caps: add drop caps of current process Signed-off-by: LiFeng --- src/lxc/attach.c | 26 +++++++++++++--- src/lxc/cgroups/cgfsng.c | 35 ++++++++++----------- src/lxc/conf.c | 79 ++++++++++++++++++++++++++++++++++++++++++++++++ src/lxc/conf.h | 1 + src/lxc/start.c | 16 ++++++++++ 5 files changed, 135 insertions(+), 22 deletions(-) diff --git a/src/lxc/attach.c b/src/lxc/attach.c index 8cbbf96..3f60fe1 100644 --- a/src/lxc/attach.c +++ b/src/lxc/attach.c @@ -936,11 +936,6 @@ static int attach_child_main(struct attach_clone_payload *payload) TRACE("Loaded seccomp profile"); } - close(payload->ipc_socket); - payload->ipc_socket = -EBADF; - lxc_proc_put_context_info(init_ctx); - payload->init_ctx = NULL; - /* The following is done after the communication socket is shut down. * That way, all errors that might (though unlikely) occur up until this * point will have their messages printed to the original stderr (if @@ -997,9 +992,30 @@ static int attach_child_main(struct attach_clone_payload *payload) if (new_gid == ns_root_gid) new_gid = LXC_INVALID_GID; + if (prctl(PR_SET_KEEPCAPS, 1) < 0) { + SYSERROR("Failed to keep permitted capabilities"); + goto on_error; + } + if (!lxc_switch_uid_gid(new_uid, new_gid)) goto on_error; + if (prctl(PR_SET_KEEPCAPS, 0) < 0) { + SYSERROR("Failed to clear permitted capabilities"); + goto on_error; + } + + if (init_ctx->container && init_ctx->container->lxc_conf && + 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; + /* We're done, so we can now do whatever the user intended us to do. */ _exit(payload->exec_function(payload->exec_payload, msg_fd)); diff --git a/src/lxc/cgroups/cgfsng.c b/src/lxc/cgroups/cgfsng.c index 8b913a6..bc1481d 100644 --- a/src/lxc/cgroups/cgfsng.c +++ b/src/lxc/cgroups/cgfsng.c @@ -2664,11 +2664,11 @@ __cgfsng_ops static bool cgfsng_data_init(struct cgroup_ops *ops, struct lxc_han { const char *cgroup_pattern; char *container_cgroup, *tmp; - struct lxc_conf *conf = handler->conf; + struct lxc_conf *conf = NULL; size_t len; - if (!conf) - return false; + if (handler) + conf = handler->conf; /* copy system-wide cgroup information */ cgroup_pattern = lxc_global_config_value("lxc.cgroup.pattern"); @@ -2680,21 +2680,22 @@ __cgfsng_ops static bool cgfsng_data_init(struct cgroup_ops *ops, struct lxc_han ops->cgroup_pattern = must_copy_string(cgroup_pattern); /* isulad: init ops->container_cgroup here instead of in cgfsng_payload_create*/ - if (conf->cgroup_meta.dir) - tmp = lxc_string_join("/", (const char *[]){conf->cgroup_meta.dir, handler->name, NULL}, false); - else - tmp = lxc_string_replace("%n", handler->name, ops->cgroup_pattern); - if (!tmp) { - ERROR("Failed expanding cgroup name pattern"); - return false; - } - - len = strlen(tmp) + 1; - container_cgroup = must_realloc(NULL, len); - (void)strlcpy(container_cgroup, tmp, len); - free(tmp); - ops->container_cgroup = container_cgroup; + if (conf) { + if (conf->cgroup_meta.dir) + tmp = lxc_string_join("/", (const char *[]){conf->cgroup_meta.dir, handler->name, NULL}, false); + else + tmp = lxc_string_replace("%n", handler->name, ops->cgroup_pattern); + if (!tmp) { + ERROR("Failed expanding cgroup name pattern"); + return false; + } + len = strlen(tmp) + 1; + container_cgroup = must_realloc(NULL, len); + (void)strlcpy(container_cgroup, tmp, len); + free(tmp); + ops->container_cgroup = container_cgroup; + } return true; } diff --git a/src/lxc/conf.c b/src/lxc/conf.c index fea0f59..6134ed3 100644 --- a/src/lxc/conf.c +++ b/src/lxc/conf.c @@ -4220,6 +4220,85 @@ int lxc_setup(struct lxc_handler *handler) return 0; } +/* 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 + struct lxc_list *iterator; + char *keep_entry; + int i, capid; + int numcaps = lxc_caps_last_cap() + 1; + struct lxc_list *caps = 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 + int *caplist = alloca(numcaps * sizeof(int)); + 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); + return -1; + } + + 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; + + for (i = 0; i < numcaps; i++) { + if (caplist[i]) { + cap_data[CAP_TO_INDEX(i)].effective = cap_data[CAP_TO_INDEX(i)].effective | __DEF_CAP_TO_MASK(i); + cap_data[CAP_TO_INDEX(i)].permitted = cap_data[CAP_TO_INDEX(i)].permitted | __DEF_CAP_TO_MASK(i); + cap_data[CAP_TO_INDEX(i)].inheritable = cap_data[CAP_TO_INDEX(i)].inheritable | __DEF_CAP_TO_MASK(i); + } + } + + if (capset(cap_header, cap_data)) { + SYSERROR("Failed to set capabilitys"); + return -1; + } + +#endif + return 0; +} + struct oci_hook_conf { defs_hook *ocihook; diff --git a/src/lxc/conf.h b/src/lxc/conf.h index 44feb98..b92c48e 100644 --- a/src/lxc/conf.h +++ b/src/lxc/conf.h @@ -498,6 +498,7 @@ int lxc_clear_init_args(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); /* isulad add end */ diff --git a/src/lxc/start.c b/src/lxc/start.c index 040909c..357e81d 100644 --- a/src/lxc/start.c +++ b/src/lxc/start.c @@ -1411,6 +1411,11 @@ static int do_start(void *data) } } + if (prctl(PR_SET_KEEPCAPS, 1) < 0) { + SYSERROR("Failed to keep permitted capabilities"); + goto out_warn_father; + } + /* The container has been setup. We can now switch to an unprivileged * uid/gid. */ @@ -1448,6 +1453,17 @@ static int do_start(void *data) goto out_warn_father; } + /* 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; + } + /* After this call, we are in error because this ops should not return * as it execs. */ -- 1.8.3.1