From e71dabf21ddd2a093ebdfcc6f6c79200415d12b1 Mon Sep 17 00:00:00 2001
From: wujing <wujing50@huawei.com>
Date: Tue, 14 Apr 2020 23:30:46 -0400
Subject: [PATCH 27/49] Capabilites security feature enhanced

Signed-off-by: wujing <wujing50@huawei.com>
---
 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

