Skip to contentSkip to conversation

add lsm name and lsm_info (policy header) to container info

PATCH New Serge E. Hallyn 1 participant 2 messages Oct 15, 2009 1 message not in the archive Security (LSM)

lore
Share & tools
lore
#0 lore raw

PATCH 1/1 add lsm name and lsm_info (policy header) to container info

The LSM name is 'selinux', 'smack', 'tomoyo', or 'dummy'. We add that to the container configuration section. We also add a LSM policy configuration section. That is placed after the LSM name. It is written by the LSM in security_checkpoint_header(), called during checkpoint container(), and read by the LSM during security_may_restart(), which is called from restore_lsm() in restore_container().

---
 checkpoint/checkpoint.c          |   13 ++++++++-
 checkpoint/restart.c             |   41 ++++++++++++++++++++++++++
 checkpoint/sys.c                 |   21 +++++++++++++
 include/linux/checkpoint.h       |    7 ++++-
 include/linux/checkpoint_hdr.h   |   16 ++++++++++
 include/linux/checkpoint_types.h |    2 +
 include/linux/security.h         |   58 ++++++++++++++++++++++++++++++++++++++
 security/capability.c            |   24 +++++++++++++++
 security/security.c              |   26 +++++++++++++++++
 9 files changed, 206 insertions(+), 2 deletions(-)
checkpoint/checkpoint.c +12 -1
index 6eb8f3b..b8c323c 100644
@@ -366,7 +366,18 @@ static int checkpoint_container(struct ckpt_ctx *ctx)
 	ret = ckpt_write_obj(ctx, &h->h);
 	ckpt_hdr_put(ctx, h);
 
-	return ret;
+	if (ret < 0)
+		return ret;
+
+	memset(ctx->lsm_name, 0, CHECKPOINT_LSM_NAME_MAX + 1);
+	strlcpy(ctx->lsm_name, security_get_lsm_name(),
+				CHECKPOINT_LSM_NAME_MAX + 1);
+	ret = ckpt_write_buffer(ctx, ctx->lsm_name,
+				CHECKPOINT_LSM_NAME_MAX + 1);
+	if (ret < 0)
+		return ret;
+
+	return security_checkpoint_header(ctx);
 }
 
 /* write the checkpoint trailer */
checkpoint/restart.c +41 -0

53 lines not on this page · raw message

checkpoint/sys.c +21 -0
index 260a1ee..5b65eb0 100644
@@ -169,6 +169,27 @@ void *ckpt_hdr_get_type(struct ckpt_ctx *ctx, int len, int type)
 	return h;
 }
 
+#define DUMMY_LSM_INFO "dummy"
+
+int ckpt_write_dummy_lsm_info(struct ckpt_ctx *ctx)
+{
+	return ckpt_write_obj_type(ctx, DUMMY_LSM_INFO,
+			strlen(DUMMY_LSM_INFO), CKPT_HDR_LSM_INFO);
+}
+
+/*
+ * ckpt_snarf_lsm_info
+ * If there is a CKPT_HDR_LSM_INFO field, toss it.
+ * Used when the current LSM doesn't care about this field.
+ */
+void ckpt_snarf_lsm_info(struct ckpt_ctx *ctx)
+{
+	struct ckpt_hdr *h;
+
+	h = ckpt_read_buf_type(ctx, CKPT_LSM_INFO_LEN, CKPT_HDR_LSM_INFO);
+	if (!IS_ERR(h))
+		ckpt_hdr_put(ctx, h);
+}
 
 /*
  * Helpers to manage c/r contexts: allocated for each checkpoint and/or
include/linux/checkpoint.h +6 -1
index 914176c..d62631a 100644
@@ -10,7 +10,7 @@
  *  distribution for more details.
  */
 
-#define CHECKPOINT_VERSION  3
+#define CHECKPOINT_VERSION  4
 
 /* checkpoint user flags */
 #define CHECKPOINT_SUBTREE	0x1
@@ -19,6 +19,7 @@
 #define RESTART_TASKSELF	0x1
 #define RESTART_FROZEN		0x2
 #define RESTART_GHOST		0x4
+#define RESTART_KEEP_LSM	0x8
 
 #ifdef __KERNEL__
 #ifdef CONFIG_CHECKPOINT
@@ -48,7 +49,9 @@
 #define RESTART_USER_FLAGS  \
 	(RESTART_TASKSELF | \
 	 RESTART_FROZEN | \
+	 RESTART_KEEP_LSM | \
 	 RESTART_GHOST)
+#define CKPT_LSM_INFO_LEN 200
 
 extern int walk_task_subtree(struct task_struct *task,
 			     int (*func)(struct task_struct *, void *),
@@ -62,6 +65,8 @@ extern void _ckpt_hdr_put(struct ckpt_ctx *ctx, void *ptr, int n);
 extern void ckpt_hdr_put(struct ckpt_ctx *ctx, void *ptr);
 extern void *ckpt_hdr_get(struct ckpt_ctx *ctx, int n);
 extern void *ckpt_hdr_get_type(struct ckpt_ctx *ctx, int n, int type);
+extern int ckpt_write_dummy_lsm_info(struct ckpt_ctx *ctx);
+extern void ckpt_snarf_lsm_info(struct ckpt_ctx *ctx);
 
 extern int ckpt_write_obj(struct ckpt_ctx *ctx, struct ckpt_hdr *h);
 extern int ckpt_write_obj_type(struct ckpt_ctx *ctx,
include/linux/checkpoint_hdr.h +16 -0
index ff2e4aa..636e189 100644
@@ -27,6 +27,15 @@
 #endif
 
 /*
+ * /usr/include/linux/security.h is not exported to userspace, so
+ * we need this value here for userspace restart.c to read.
+ *
+ * CHECKPOINT_LSM_NAME_MAX should be SECURITY_NAME_MAX
+ * security_may_restart() has a BUILD_BUG_ON to enforce that.
+ */
+#define CHECKPOINT_LSM_NAME_MAX 10
+
+/*
  * To maintain compatibility between 32-bit and 64-bit architecture flavors,
  * keep data 64-bit aligned: use padding for structure members, and use
  * __attribute__((aligned (8))) for the entire structure.
@@ -71,6 +80,8 @@ enum {
 #define CKPT_HDR_STRING CKPT_HDR_STRING
 	CKPT_HDR_OBJREF,
 #define CKPT_HDR_OBJREF CKPT_HDR_OBJREF
+	CKPT_HDR_LSM_INFO,
+#define CKPT_HDR_LSM_INFO CKPT_HDR_LSM_INFO
 
 	CKPT_HDR_TREE = 101,
 #define CKPT_HDR_TREE CKPT_HDR_TREE
@@ -252,6 +263,11 @@ struct ckpt_const {
 /* container configuration section header */
 struct ckpt_hdr_container {
 	struct ckpt_hdr h;
+	/*
+	 * the header is followed by the string:
+	 *   char lsm_name[SECURITY_NAME_MAX + 1]
+	 * plus the CKPT_HDR_LSM_INFO section
+	 */
 };
 
 /* checkpoint image header */
include/linux/checkpoint_types.h +2 -0
index fa57cdc..b7d3053 100644
@@ -21,6 +21,7 @@
 #include <linux/fs.h>
 #include <linux/ktime.h>
 #include <linux/wait.h>
+#include <linux/security.h>
 
 struct ckpt_stats {
 	int uts_ns;
@@ -42,6 +43,7 @@ struct ckpt_ctx {
 	struct task_struct *root_task;		/* [container] root task */
 	struct nsproxy *root_nsproxy;		/* [container] root nsproxy */
 	struct task_struct *root_freezer;	/* [container] root task */
+	char lsm_name[SECURITY_NAME_MAX + 1];   /* security module at ckpt */
 
 	unsigned long kflags;	/* kerenl flags */
 	unsigned long uflags;	/* user flags */
include/linux/security.h +58 -0

94 lines not on this page · raw message

security/capability.c +24 -0
index 88f752e..23026e2 100644
@@ -792,6 +792,26 @@ static void cap_release_secctx(char *secdata, u32 seclen)
 {
 }
 
+#ifdef CONFIG_CHECKPOINT
+static int cap_may_restart(struct ckpt_ctx *ctx)
+{
+	/*
+	 * Note that all construction of kernel resources, credentials,
+	 * etc is already authorized per the caller's credentials.  This
+	 * hook is intended for the LSM to make further decisions about
+	 * a task not being allowed to restart at all, for instance if
+	 * the policy has changed since checkpoint.
+	 */
+	ckpt_snarf_lsm_info(ctx);
+	return 0;
+}
+
+static int cap_checkpoint_header(struct ckpt_ctx *ctx)
+{
+	return ckpt_write_dummy_lsm_info(ctx);
+}
+#endif
+
 #ifdef CONFIG_KEYS
 static int cap_key_alloc(struct key *key, const struct cred *cred,
 			 unsigned long flags)
@@ -992,6 +1012,10 @@ void security_fixup_ops(struct security_operations *ops)
 	set_to_cap_if_null(ops, secid_to_secctx);
 	set_to_cap_if_null(ops, secctx_to_secid);
 	set_to_cap_if_null(ops, release_secctx);
+#ifdef CONFIG_CHECKPOINT
+	set_to_cap_if_null(ops, may_restart);
+	set_to_cap_if_null(ops, checkpoint_header);
+#endif
 #ifdef CONFIG_SECURITY_NETWORK
 	set_to_cap_if_null(ops, unix_stream_connect);
 	set_to_cap_if_null(ops, unix_may_send);
security/security.c +26 -0
index dc7674f..e4fa91a 100644
@@ -16,6 +16,9 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/security.h>
+#ifdef CONFIG_CHECKPOINT
+#include <linux/checkpoint.h>
+#endif
 
 /* Boot-time LSM user choice */
 static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1];
@@ -122,6 +125,11 @@ int register_security(struct security_operations *ops)
 	return 0;
 }
 
+char *security_get_lsm_name(void)
+{
+	return security_ops->name;
+}
+
 /* Security operations */
 
 int security_ptrace_may_access(struct task_struct *child, unsigned int mode)
@@ -959,6 +967,24 @@ void security_release_secctx(char *secdata, u32 seclen)
 }
 EXPORT_SYMBOL(security_release_secctx);
 
+#ifdef CONFIG_CHECKPOINT
+int security_may_restart(struct ckpt_ctx *ctx)
+{
+	/*
+	 * SECURITY_NAME_MAX is defined in linux/security.h,
+	 * CHECKPOINT_LSM_NAME_MAX in linux/checkpoint_hdr.h
+	 */
+	BUILD_BUG_ON(CHECKPOINT_LSM_NAME_MAX != SECURITY_NAME_MAX);
+
+	return security_ops->may_restart(ctx);
+}
+
+int security_checkpoint_header(struct ckpt_ctx *ctx)
+{
+	return security_ops->checkpoint_header(ctx);
+}
+#endif
+
 #ifdef CONFIG_SECURITY_NETWORK
 
 int security_unix_stream_connect(struct socket *sock, struct socket *other,
Signature · 1 line
1.6.1

A message that is not in the archive (sent off-list or not yet received): 20091015203721.GA5030-r/[email protected]

#2 lore raw

PATCH 1/1 restart: accept the lsm_name field in header and add -k flag (v2)

The checkpoint file header now has an 11-character string containing the name of the active LSM, following the uts info, and a variable length buffer type conaining LSM-specific version information (for instance a sha1sum of policy). Handle these.

Also add a -k (--keeplsm) flag to tell restart to set the RESTART_KEEP_LSM flag to sys_restart().

Changelog:
oct 15: separate out from container config section patch oct 05: 1. move keep_lsm into arg struct
2. read a separate container config section
3. use CHECKPOINT_LSM_NAME_MAX

---
 restart.c |   39 +++++++++++++++++++++++++++++++++++++--
 1 files changed, 37 insertions(+), 2 deletions(-)
restart.c +37 -2
index fa786ef..588ab97 100644
@@ -68,6 +68,7 @@ static char usage_str[] =
 "     --signal=SIG       send SIG to root task on SIGINT (default: SIGKILL\n"
 "                        to container root, SIGINT otherwise)\n"
 "  -w,--wait             wait for root task to termiate (default)\n"
+"  -k,--keeplsm          Try to recreate original LSM labels on all objects\n"
 "     --show-status      show exit status of root task (implies -w)\n"
 "     --copy-status      imitate exit status of root task (implies -w)\n"
 "  -W,--no-wait          do not wait for root task to terminate\n"
@@ -350,6 +351,7 @@ struct args {
 	int copy_status;
 	char *freezer;
 	char *input;
+	int keep_lsm;
 };
 
 static void usage(char *str)
@@ -380,6 +382,7 @@ static void parse_args(struct args *args, int argc, char *argv[])
 		{ "self",	no_argument,		NULL, 6},
 		{ "signal",	required_argument,	NULL, 4 },
 		{ "inspect",	no_argument,		NULL, 5 },
+		{ "keeplsm",	no_argument,		NULL, 'k' },
 		{ "input",	required_argument,	NULL, 'i' },
 		{ "root",	required_argument,	NULL, 'r' },
 		{ "wait",	no_argument,		NULL, 'w' },
@@ -391,7 +394,7 @@ static void parse_args(struct args *args, int argc, char *argv[])
 		{ "debug",	no_argument,		NULL, 'd' },
 		{ NULL,		0,			NULL, 0 }
 	};
-	static char optc[] = "hdvpPwWF:r:i:";
+	static char optc[] = "hdvpkPwWF:r:i:";
 
 	int sig;
 
@@ -446,6 +449,9 @@ static void parse_args(struct args *args, int argc, char *argv[])
 		case 'w':
 			args->wait = 1;
 			break;
+		case 'k':
+			args->keep_lsm = RESTART_KEEP_LSM;
+			break;
 		case 'W':
 			args->wait = 0;
 			break;
@@ -936,6 +942,7 @@ static int ckpt_coordinator(struct ckpt_ctx *ctx)
 	if (ctx->args->freezer)
 		flags |= RESTART_FROZEN;
 
+	flags |= ctx->args->keep_lsm;
 	ret = restart(root_pid, STDIN_FILENO, flags);
 
 	if (ret < 0) {
@@ -1584,6 +1591,8 @@ static int ckpt_make_tree(struct ckpt_ctx *ctx, struct task *task)
 	if (task->flags & (TASK_GHOST | TASK_DEAD))
 		flags |= RESTART_GHOST;
 
+	flags |= ctx->args->keep_lsm;
+
 	/* on success this doesn't return */
 	ckpt_dbg("about to call sys_restart(), flags %#lx\n", flags);
 	ret = restart(0, STDIN_FILENO, flags);
@@ -2116,10 +2125,23 @@ static int ckpt_read_header_arch(struct ckpt_ctx *ctx)
 
 static int ckpt_read_container(struct ckpt_ctx *ctx)
 {
+	int ret;
 	struct ckpt_hdr_container *h;
+	char *ptr;
 
 	h = (struct ckpt_hdr_container *) ctx->container;
-	return ckpt_read_obj_type(ctx, h, sizeof(*h), CKPT_HDR_CONTAINER);
+	ret = ckpt_read_obj_type(ctx, h, sizeof(*h), CKPT_HDR_CONTAINER);
+	if (ret < 0)
+		return ret;
+
+	ptr = (char *) h;
+	ptr += ((struct ckpt_hdr *) ptr)->len;
+	ret = ckpt_read_obj_buffer(ctx, ptr, CHECKPOINT_LSM_NAME_MAX + 1);
+	if (ret < 0)
+		return ret;
+
+	ptr += ((struct ckpt_hdr *) ptr)->len;
+	return ckpt_read_obj_type(ctx, ptr, 200, CKPT_HDR_LSM_INFO);
 }
 
 static int ckpt_read_tree(struct ckpt_ctx *ctx)
@@ -2197,9 +2219,22 @@ static int ckpt_write_header_arch(struct ckpt_ctx *ctx)
 static int ckpt_write_container(struct ckpt_ctx *ctx)
 {
 	char *ptr;
+	int ret;
 
 	ptr = (char *) ctx->container;
 	/* write the container info section */
+	ret = ckpt_write_obj(ctx, (struct ckpt_hdr *) ptr);
+	if (ret < 0)
+		return ret;
+
+	/* write the lsm name buffer */
+	ptr += ((struct ckpt_hdr *) ptr)->len;
+	ret = ckpt_write_obj(ctx, (struct ckpt_hdr *) ptr);
+	if (ret < 0)
+		return ret;
+
+	/* write the lsm policy section */
+	ptr += ((struct ckpt_hdr *) ptr)->len;
 	return ckpt_write_obj(ctx, (struct ckpt_hdr *) ptr);
 }
 
Signature · 1 line
1.6.1.1