Skip to contentSkip to conversation

cr: add generic LSM c/r support (v4)

PATCH In review Serge E. Hallyn 5 participants 14 messages Oct 2, 2009 2 messages not in the archive

Subsystems (5)
lore
Share & tools
lore
#0 lore raw

PATCH 1/3 cr: add generic LSM c/r support (v4)

(wasn't versioning the patchsets before, so randomly pick 4 as the version for this patchset...)

Documentation/checkpoint/readme.txt begins:
"""
Application checkpoint/restart is the ability to save the state of a running application so that it can later resume its execution from the time at which it was checkpointed.
"""

This patch adds generic support for c/r of LSM credentials. Support for Smack and SELinux (and TOMOYO if appropriate) will be added later. Capabilities is already supported through generic creds code.

This patch supports ipc_perm, msg_msg, cred (task) and file ->security fields. Inodes, superblocks, netif, and xfrm currently are restored not through sys_restart() but through container creation, and so the security fields should be done then as well. Network should be added when network c/r is added.

Briefly, all security fields must be exported by the LSM as a simple null-terminated string. They are checkpointed through the security_checkpoint_obj() helper, because we must pass it an extra sectype field. Splitting SECURITY_OBJ_SEC into one type per object type would not work because, in Smack, one void* security is used for all object types. But we must pass the sectype field because in SELinux a different type of structure is stashed in each object type.

The RESTART_KEEP_LSM flag indicates that the LSM should attempt to reuse checkpointed security labels. It is always invalid when the LSM at restart differs from that at checkpoint. It is currently only usable for capabilities.

(For capabilities, restart without RESTART_KEEP_LSM is technically not implemented. There actually might be a use case for that, but the safety of it is dubious so for now we always re-create checkpointed capability sets whether RESTART_KEEP_LSM is specified or not)

The result of applying this patchset can be seen at
http://git.kernel.org/gitweb.cgi?p=linux/kernel/git/sergeh/linux-cr.git;a=shortlog;h=ckpt-v18-hallyn.lsm3

Changelog:
sep 3: fix memory leak on LSM restore error path
Sep 3: provide 2 hooks, may_restart and checkpoint_header, to facilitate
an LSM tracking policy changes.
sep 10: merge RESTART_KEEP_LSM patch with basic LSM c/r
support patches.
sep 10: rename security_xyz_get_ctx() to security_xyz_checkpoint(),
in order to avoid confusing with the various other 'context' helpers in the security_ namespace, relating to secids and sysfs xattrs.
sep 10: pass context file to security_cred_restore. SELinux will
want the file's security context to authorize it as an entrypoint for the new process context.
oct 01: roll up some generic c/r debug hunks from selinux patch.

Cc Stephen Smalley <[email protected]>
Cc Casey Schaufler <[email protected]>
---
 Documentation/checkpoint/readme.txt |   25 +++++
 checkpoint/checkpoint.c             |   11 ++
 checkpoint/files.c                  |   34 +++++++
 checkpoint/objhash.c                |   93 +++++++++++++++++
 checkpoint/process.c                |   20 +++-
 checkpoint/restart.c                |   25 +++++
 checkpoint/sys.c                    |   22 ++++
 include/linux/checkpoint.h          |    7 +-
 include/linux/checkpoint_hdr.h      |   24 +++++-
 include/linux/checkpoint_types.h    |    9 ++
 include/linux/security.h            |  188 +++++++++++++++++++++++++++++++++++
 ipc/checkpoint.c                    |   34 +++++--
 ipc/checkpoint_msg.c                |   26 +++++-
 ipc/checkpoint_sem.c                |    4 +-
 ipc/checkpoint_shm.c                |    4 +-
 ipc/util.h                          |    6 +-
 kernel/cred.c                       |   20 ++++-
 security/capability.c               |   74 ++++++++++++++
 security/security.c                 |  131 ++++++++++++++++++++++++
 19 files changed, 731 insertions(+), 26 deletions(-)
Documentation/checkpoint/readme.txt +25 -0
index 571c469..8ec5850 100644
@@ -333,6 +333,31 @@ So that's why we don't want CAP_SYS_ADMIN required up-front. That way
 we will be forced to more carefully review each of those features.
 However, this can be controlled with a sysctl-variable.
 
+LSM
+===
+
+Security modules use custom labels on subjects and objects to
+further mediate access decisions beyond DAC controls.  When
+checkpoint applications, these labels are [ work in progress ]
+checkpointed along with the objects.  At restart, the
+RESTART_KEEP_LSM flag tells the kernel whether re-created objects
+whould keep their checkpointed labels, or get automatically
+recalculated labels.  Since checkpointed labels will only make
+sense to the same LSM which was active at checkpoint time,
+sys_restart() with the RESTART_KEEP_LSM flag will fail with
+-EINVAL if the LSM active at restart is not the same as that
+active at checkpoint.  If RESTART_KEEP_LSM is not specified,
+then objects will be given whatever default labels the LSM and
+their optional policy decide.  Of course, when RESTART_KEEP_LSM
+is specified, the LSM may choose a different label than the
+checkpointed one, or fail the entire restart if the caller
+does not have permission to create objects with the checkpointed
+label.
+
+It should always be safe to take a checkpoint of an application
+under LSM_1, and restart it without the RESTART_KEEP_LSM flag
+under LSM_2.
+
 
 Kernel interfaces
 =================
checkpoint/checkpoint.c +11 -0
index 1eeb557..6722035 100644
@@ -25,6 +25,7 @@
 #include <linux/magic.h>
 #include <linux/hrtimer.h>
 #include <linux/deferqueue.h>
+#include <linux/security.h>
 #include <linux/checkpoint.h>
 #include <linux/checkpoint_hdr.h>
 
@@ -351,6 +352,16 @@ static int checkpoint_write_header(struct ckpt_ctx *ctx)
 	if (ret < 0)
 		return ret;
 
+	memset(ctx->lsm_name, 0, SECURITY_NAME_MAX + 1);
+	strlcpy(ctx->lsm_name, security_get_lsm_name(), SECURITY_NAME_MAX + 1);
+	ret = ckpt_write_buffer(ctx, ctx->lsm_name, SECURITY_NAME_MAX + 1);
+	if (ret < 0)
+		return ret;
+
+	ret = security_checkpoint_header(ctx);
+	if (ret < 0)
+		return ret;
+
 	return checkpoint_write_header_arch(ctx);
 }
 
checkpoint/files.c +34 -0
index 27e29a0..570facb 100644
@@ -145,6 +145,19 @@ static int scan_fds(struct files_struct *files, int **fdtable)
 	return n;
 }
 
+#ifdef CONFIG_SECURITY
+int checkpoint_file_security(struct ckpt_ctx *ctx, struct file *file)
+{
+	return security_checkpoint_obj(ctx, file->f_security,
+					CKPT_SECURITY_FILE);
+}
+#else
+int checkpoint_file_security(struct ckpt_ctx *ctx, struct file *file)
+{
+	return -EOPNOTSUPP;
+}
+#endif
+
 int checkpoint_file_common(struct ckpt_ctx *ctx, struct file *file,
 			   struct ckpt_hdr_file *h)
 {
@@ -159,6 +172,16 @@ int checkpoint_file_common(struct ckpt_ctx *ctx, struct file *file,
 	if (h->f_credref < 0)
 		return h->f_credref;
 
+	h->f_secref = checkpoint_file_security(ctx, file);
+	if (h->f_secref == -EOPNOTSUPP)
+		h->f_secref = -1;
+	else if (h->f_secref < 0)
+		return h->f_secref;
+
+	ckpt_debug("file %s credref %d secref %d",
+		file->f_dentry->d_name.name, h->f_credref,
+		h->f_secref);
+
 	/* FIX: need also file->f_owner, etc */
 
 	return 0;
@@ -507,6 +530,17 @@ int restore_file_common(struct ckpt_ctx *ctx, struct file *file,
 	put_cred(file->f_cred);
 	file->f_cred = get_cred(cred);
 
+	if ((ctx->uflags & RESTART_KEEP_LSM) && (h->f_secref != -1)) {
+		struct ckpt_stored_lsm *l = ckpt_obj_fetch(ctx, h->f_secref,
+					CKPT_OBJ_SEC);
+		if (IS_ERR(l))
+			return PTR_ERR(l);
+
+		ret = security_file_restore(file, l->string);
+		if (ret)
+			return ret;
+	}
+
 	/* safe to set 1st arg (fd) to 0, as command is F_SETFL */
 	ret = vfs_fcntl(0, F_SETFL, h->f_flags & CKPT_SETFL_MASK, file);
 	if (ret < 0)
checkpoint/objhash.c +93 -0

111 lines not on this page · raw message

checkpoint/process.c +16 -4
index 5ba64f0..ed7896c 100644
@@ -581,11 +581,15 @@ static int restore_task_creds(struct ckpt_ctx *ctx)
 
 	realcred = ckpt_obj_fetch(ctx, h->cred_ref, CKPT_OBJ_CRED);
 	if (IS_ERR(realcred)) {
+		ckpt_debug("Error %ld fetching readlcred (ref %d)",
+			PTR_ERR(realcred), h->cred_ref);
 		ret = PTR_ERR(realcred);
 		goto out;
 	}
 	ecred = ckpt_obj_fetch(ctx, h->ecred_ref, CKPT_OBJ_CRED);
 	if (IS_ERR(ecred)) {
+		ckpt_debug("Error %ld fetching ecred (ref %d)",
+			PTR_ERR(ecred), h->ecred_ref);
 		ret = PTR_ERR(ecred);
 		goto out;
 	}
@@ -593,6 +597,7 @@ static int restore_task_creds(struct ckpt_ctx *ctx)
 	ctx->ecred = ecred;
 
 out:
+	ckpt_debug("Returning %d.", ret);
 	ckpt_hdr_put(ctx, h);
 	return ret;
 }
@@ -608,14 +613,21 @@ static int restore_task_objs(struct ckpt_ctx *ctx)
 	 * referenced. See comment in checkpoint_task_objs.
 	 */
 	ret = restore_task_creds(ctx);
-	if (!ret)
-		ret = restore_task_ns(ctx);
-	if (ret < 0)
+	if (ret) {
+		ckpt_debug("restore_task_creds returned %d", ret);
+		return ret;
+	}
+	ret = restore_task_ns(ctx);
+	if (ret) {
+		ckpt_debug("restore_task_ns returned %d", ret);
 		return ret;
+	}
 
 	h = ckpt_read_obj_type(ctx, sizeof(*h), CKPT_HDR_TASK_OBJS);
-	if (IS_ERR(h))
+	if (IS_ERR(h)) {
+		ckpt_debug("Error fetching task obj");
 		return PTR_ERR(h);
+	}
 
 	ret = restore_obj_file_table(ctx, h->files_objref);
 	ckpt_debug("file_table: ret %d (%p)\n", ret, current->files);
checkpoint/restart.c +25 -0
index b12c8bd..bba2b45 100644
@@ -457,6 +457,31 @@ static int restore_read_header(struct ckpt_ctx *ctx)
 	if (ret < 0)
 		goto out;
 
+	ret = _ckpt_read_buffer(ctx, ctx->lsm_name, SECURITY_NAME_MAX + 1);
+	if (ret < 0)
+		goto out;
+	if (ctx->uflags & RESTART_KEEP_LSM) {
+		char *cur = security_get_lsm_name();
+		if (strncmp(cur, ctx->lsm_name, SECURITY_NAME_MAX + 1) != 0) {
+			pr_warning("c/r: checkpointed LSM %s, current is %s.\n",
+				ctx->lsm_name, cur);
+			ret = -EINVAL;
+			goto out;
+		}
+		/* to be implemented later, per-lsm */
+		if (strcmp(ctx->lsm_name, "lsm_none") != 0 &&
+				strcmp(ctx->lsm_name, "default") != 0) {
+			pr_warning("c/r: RESTART_KEEP_LSM unsupported for %s\n",
+					ctx->lsm_name);
+			ret = -ENOSYS;
+			goto out;
+		}
+	}
+
+	ret = security_may_restart(ctx);
+	if (ret < 0)
+		goto out;
+
 	ret = restore_read_header_arch(ctx);
  out:
 	kfree(uts);
checkpoint/sys.c +22 -0
index 7604089..0a1e8a6 100644
@@ -169,6 +169,28 @@ 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 e403dd7..707f9fb 100644
@@ -10,7 +10,7 @@
  *  distribution for more details.
  */
 
-#define CHECKPOINT_VERSION  2
+#define CHECKPOINT_VERSION  3
 
 /* 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 +23 -1
index 2ed523f..61ac537 100644
@@ -58,6 +58,8 @@ enum {
 	CKPT_HDR_BUFFER,
 	CKPT_HDR_STRING,
 	CKPT_HDR_OBJREF,
+	CKPT_HDR_SEC,
+	CKPT_HDR_LSM_INFO,
 
 	CKPT_HDR_TREE = 101,
 	CKPT_HDR_TASK,
@@ -146,6 +148,7 @@ enum obj_type {
 	CKPT_OBJ_GROUPINFO,
 	CKPT_OBJ_SOCK,
 	CKPT_OBJ_TTY,
+	CKPT_OBJ_SEC,
 	CKPT_OBJ_MAX
 };
 
@@ -189,10 +192,11 @@ struct ckpt_hdr_header {
 	__u64 uflags;	/* uflags from checkpoint */
 
 	/*
-	 * the header is followed by three strings:
+	 * the header is followed by four strings:
 	 *   char release[const.uts_release_len];
 	 *   char version[const.uts_version_len];
 	 *   char machine[const.uts_machine_len];
+	 *   char lsm_name[SECURITY_NAME_MAX + 1]
 	 */
 } __attribute__((aligned(8)));
 
@@ -265,6 +269,8 @@ struct ckpt_hdr_cred {
 	__u32 gid, sgid, egid, fsgid;
 	__s32 user_ref;
 	__s32 groupinfo_ref;
+	__s32 sec_ref;
+	__u32 padding;
 	struct ckpt_capabilities cap_s;
 } __attribute__((aligned(8)));
 
@@ -277,6 +283,16 @@ struct ckpt_hdr_groupinfo {
 	__u32 groups[0];
 } __attribute__((aligned(8)));
 
+struct ckpt_hdr_lsm {
+	struct ckpt_hdr h;
+	__u8 sectype;
+	__u16 len;
+	/*
+	 * This is followed by a string of size len+1,
+	 * null-terminated
+	 */
+	__u8 string[0];
+} __attribute__((aligned(8)));
 /*
  * todo - keyrings and LSM
  * These may be better done with userspace help though
@@ -392,6 +408,8 @@ struct ckpt_hdr_file {
 	__s32 f_credref;
 	__u64 f_pos;
 	__u64 f_version;
+	__s32 f_secref;
+	__u32 f_padding;
 } __attribute__((aligned(8)));
 
 struct ckpt_hdr_file_generic {
@@ -634,6 +652,8 @@ struct ckpt_hdr_ipc_perms {
 	__u32 mode;
 	__u32 _padding;
 	__u64 seq;
+	__s32 sec_ref;
+	__u32 padding;
 } __attribute__((aligned(8)));
 
 struct ckpt_hdr_ipc_shm {
@@ -667,6 +687,8 @@ struct ckpt_hdr_ipc_msg_msg {
 	struct ckpt_hdr h;
 	__s32 m_type;
 	__u32 m_ts;
+	__s32 sec_ref;
+	__u32 padding;
 } __attribute__((aligned(8)));
 
 struct ckpt_hdr_ipc_sem {
include/linux/checkpoint_types.h +9 -0
index b9393f4..6a2c9dc 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 */
@@ -82,6 +84,13 @@ struct ckpt_ctx {
 	struct ckpt_stats stats;	/* statistics */
 };
 
+/* stored on hashtable */
+struct ckpt_stored_lsm {
+	struct kref kref;
+	int sectype;
+	char *string;
+};
+
 #endif /* __KERNEL__ */
 
 #endif /* _LINUX_CHECKPOINT_TYPES_H_ */
include/linux/security.h +188 -0

315 lines not on this page · raw message

ipc/checkpoint.c +24 -10
index 8e6e9ba..c0d3f13 100644
@@ -31,7 +31,8 @@ static char *ipc_ind_to_str[] = { "sem", "msg", "shm" };
  * Checkpoint
  */
 
-int checkpoint_fill_ipc_perms(struct ckpt_hdr_ipc_perms *h,
+int checkpoint_fill_ipc_perms(struct ckpt_ctx *ctx,
+			      struct ckpt_hdr_ipc_perms *h,
 			      struct kern_ipc_perm *perm)
 {
 	if (ipcperms(perm, S_IROTH))
@@ -45,6 +46,15 @@ int checkpoint_fill_ipc_perms(struct ckpt_hdr_ipc_perms *h,
 	h->cgid = perm->cgid;
 	h->mode = perm->mode & S_IRWXUGO;
 	h->seq = perm->seq;
+	if (perm->security) {
+		h->sec_ref = security_checkpoint_obj(ctx, perm->security,
+					CKPT_SECURITY_IPC);
+		if (h->sec_ref == -EOPNOTSUPP)
+			h->sec_ref = -1;
+		else if (h->sec_ref < 0)
+			return h->sec_ref;
+	} else
+		h->sec_ref = -1;
 
 	return 0;
 }
@@ -176,7 +186,8 @@ static int validate_created_perms(struct ckpt_hdr_ipc_perms *h)
 	return 1;
 }
 
-int restore_load_ipc_perms(struct ckpt_hdr_ipc_perms *h,
+int restore_load_ipc_perms(struct ckpt_ctx *ctx,
+			   struct ckpt_hdr_ipc_perms *h,
 			   struct kern_ipc_perm *perm)
 {
 	if (h->id < 0)
@@ -205,14 +216,17 @@ int restore_load_ipc_perms(struct ckpt_hdr_ipc_perms *h,
 	perm->cgid = h->cgid;
 	perm->mode = h->mode;
 	perm->seq = h->seq;
-	/*
-	 * Todo: restore perm->security.
-	 * At the moment it gets set by security_x_alloc() called through
-	 * ipcget()->ipcget_public()->ops-.getnew (->nequeue for instance)
-	 * We will want to ask the LSM to consider resetting the
-	 * checkpointed ->security, based on current_security(),
-	 * the checkpointed ->security, and the checkpoint file context.
-	 */
+
+	if ((ctx->uflags & RESTART_KEEP_LSM) && (h->sec_ref != -1)) {
+		int ret;
+		struct ckpt_stored_lsm *l = ckpt_obj_fetch(ctx, h->sec_ref,
+					CKPT_OBJ_SEC);
+		if (IS_ERR(l))
+			return PTR_ERR(l);
+		ret = security_ipc_restore(perm, l->string);
+		if (ret)
+			return ret;
+	}
 
 	return 0;
 }
ipc/checkpoint_msg.c +23 -3
index b933c19..24f4097 100644
@@ -37,7 +37,7 @@ static int fill_ipc_msg_hdr(struct ckpt_ctx *ctx,
 
 	ipc_lock_by_ptr(&msq->q_perm);
 
-	ret = checkpoint_fill_ipc_perms(&h->perms, &msq->q_perm);
+	ret = checkpoint_fill_ipc_perms(ctx, &h->perms, &msq->q_perm);
 	if (ret < 0)
 		goto unlock;
 
@@ -64,13 +64,23 @@ static int checkpoint_msg_contents(struct ckpt_ctx *ctx, struct msg_msg *msg)
 	struct msg_msgseg *seg;
 	int total, len;
 	int ret;
-
+	int sec_ref = -1;
+
+	if (msg->security) {
+		sec_ref = security_checkpoint_obj(ctx, msg->security,
+						CKPT_SECURITY_MSG_MSG);
+		if (sec_ref == -EOPNOTSUPP)
+			sec_ref = -1;
+		else if (sec_ref < 0)
+			return sec_ref;
+	}
 	h = ckpt_hdr_get_type(ctx, sizeof(*h), CKPT_HDR_IPC_MSG_MSG);
 	if (!h)
 		return -ENOMEM;
 
 	h->m_type = msg->m_type;
 	h->m_ts = msg->m_ts;
+	h->sec_ref = sec_ref;
 
 	ret = ckpt_write_obj(ctx, &h->h);
 	ckpt_hdr_put(ctx, h);
@@ -177,7 +187,7 @@ static int load_ipc_msg_hdr(struct ckpt_ctx *ctx,
 {
 	int ret = 0;
 
-	ret = restore_load_ipc_perms(&h->perms, &msq->q_perm);
+	ret = restore_load_ipc_perms(ctx, &h->perms, &msq->q_perm);
 	if (ret < 0)
 		return ret;
 
@@ -224,6 +234,16 @@ static struct msg_msg *restore_msg_contents_one(struct ckpt_ctx *ctx, int *clen)
 	msg->next = NULL;
 	pseg = &msg->next;
 
+	if ((ctx->uflags & RESTART_KEEP_LSM) && (h->sec_ref != -1)) {
+		struct ckpt_stored_lsm *l = ckpt_obj_fetch(ctx, h->sec_ref,
+					CKPT_OBJ_SEC);
+		if (IS_ERR(l))
+			return (struct msg_msg *)l;
+		ret = security_msg_msg_restore(msg, l->string);
+		if (ret)
+			return ERR_PTR(ret);
+	}
+
 	ret = _ckpt_read_buffer(ctx, (msg + 1), len);
 	if (ret < 0)
 		goto out;
ipc/checkpoint_sem.c +2 -2
index 76eb2b9..53a19ed 100644
@@ -37,7 +37,7 @@ static int fill_ipc_sem_hdr(struct ckpt_ctx *ctx,
 
 	ipc_lock_by_ptr(&sem->sem_perm);
 
-	ret = checkpoint_fill_ipc_perms(&h->perms, &sem->sem_perm);
+	ret = checkpoint_fill_ipc_perms(ctx, &h->perms, &sem->sem_perm);
 	if (ret < 0)
 		goto unlock;
 
@@ -113,7 +113,7 @@ static int load_ipc_sem_hdr(struct ckpt_ctx *ctx,
 {
 	int ret = 0;
 
-	ret = restore_load_ipc_perms(&h->perms, &sem->sem_perm);
+	ret = restore_load_ipc_perms(ctx, &h->perms, &sem->sem_perm);
 	if (ret < 0)
 		return ret;
 
ipc/checkpoint_shm.c +2 -2
index 826e430..01091d9 100644
@@ -41,7 +41,7 @@ static int fill_ipc_shm_hdr(struct ckpt_ctx *ctx,
 
 	ipc_lock_by_ptr(&shp->shm_perm);
 
-	ret = checkpoint_fill_ipc_perms(&h->perms, &shp->shm_perm);
+	ret = checkpoint_fill_ipc_perms(ctx, &h->perms, &shp->shm_perm);
 	if (ret < 0)
 		goto unlock;
 
@@ -165,7 +165,7 @@ static int load_ipc_shm_hdr(struct ckpt_ctx *ctx,
 {
 	int ret;
 
-	ret = restore_load_ipc_perms(&h->perms, &shp->shm_perm);
+	ret = restore_load_ipc_perms(ctx, &h->perms, &shp->shm_perm);
 	if (ret < 0)
 		return ret;
 
ipc/util.h +4 -2
index ba080de..ce34de0 100644
@@ -199,9 +199,11 @@ void freeary(struct ipc_namespace *ns, struct kern_ipc_perm *ipcp);
 
 
 #ifdef CONFIG_CHECKPOINT
-extern int checkpoint_fill_ipc_perms(struct ckpt_hdr_ipc_perms *h,
+extern int checkpoint_fill_ipc_perms(struct ckpt_ctx *ctx,
+				     struct ckpt_hdr_ipc_perms *h,
 				     struct kern_ipc_perm *perm);
-extern int restore_load_ipc_perms(struct ckpt_hdr_ipc_perms *h,
+extern int restore_load_ipc_perms(struct ckpt_ctx *ctx,
+				  struct ckpt_hdr_ipc_perms *h,
 				  struct kern_ipc_perm *perm);
 
 extern int ckpt_collect_ipc_shm(int id, void *p, void *data);
kernel/cred.c +19 -1
index 9710cae..06bc676 100644
@@ -709,7 +709,7 @@ int cred_setfsgid(struct cred *new, gid_t gid, gid_t *old_fsgid)
 static int do_checkpoint_cred(struct ckpt_ctx *ctx, struct cred *cred)
 {
 	int ret;
-	int groupinfo_ref, user_ref;
+	int groupinfo_ref, user_ref, sec_ref = -1;
 	struct ckpt_hdr_cred *h;
 
 	groupinfo_ref = checkpoint_obj(ctx, cred->group_info,
@@ -719,6 +719,14 @@ static int do_checkpoint_cred(struct ckpt_ctx *ctx, struct cred *cred)
 	user_ref = checkpoint_obj(ctx, cred->user, CKPT_OBJ_USER);
 	if (user_ref < 0)
 		return user_ref;
+#ifdef CONFIG_SECURITY
+	sec_ref = security_checkpoint_obj(ctx, cred->security,
+					CKPT_SECURITY_CRED);
+	if (sec_ref == -EOPNOTSUPP)
+		sec_ref = -1;
+	else if (sec_ref < 0)
+		return sec_ref;
+#endif  /* else cred->security doesn't exist and sec_ref = -1 */
 
 	h = ckpt_hdr_get_type(ctx, sizeof(*h), CKPT_HDR_CRED);
 	if (!h)
@@ -733,6 +741,7 @@ static int do_checkpoint_cred(struct ckpt_ctx *ctx, struct cred *cred)
 	h->sgid = cred->sgid;
 	h->egid = cred->egid;
 	h->fsgid = cred->fsgid;
+	h->sec_ref = sec_ref;
 
 	checkpoint_capabilities(&h->cap_s, cred);
 
@@ -806,6 +815,15 @@ static struct cred *do_restore_cred(struct ckpt_ctx *ctx)
 	ret = cred_setfsgid(cred, h->fsgid, &oldgid);
 	if (oldgid != h->fsgid && ret < 0)
 		goto err_putcred;
+	if ((ctx->uflags & RESTART_KEEP_LSM) && (h->sec_ref != -1)) {
+		struct ckpt_stored_lsm *l = ckpt_obj_fetch(ctx, h->sec_ref,
+					CKPT_OBJ_SEC);
+		if (IS_ERR(l))
+			return (struct cred *)l;
+		ret = security_cred_restore(ctx->file, cred, l->string);
+		if (ret)
+			goto err_putcred;
+	}
 	ret = restore_capabilities(&h->cap_s, cred);
 	if (ret)
 		goto err_putcred;
security/capability.c +74 -0

128 lines not on this page · raw message

security/security.c +131 -0

169 lines not on this page · raw message

Signature · 1 line
1.6.1

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

#2 lore raw

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

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().

---
 restart.c |   32 +++++++++++++++++++++++++++++++-
 1 files changed, 31 insertions(+), 1 deletions(-)
restart.c +31 -1
index b810ca9..44ae252 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"
@@ -349,6 +350,8 @@ struct args {
 	char *input;
 };
 
+int keep_lsm;
+
 static void usage(char *str)
 {
 	fprintf(stderr, "%s", str);
@@ -377,6 +380,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' },
@@ -388,7 +392,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;
 
@@ -443,6 +447,9 @@ static void parse_args(struct args *args, int argc, char *argv[])
 		case 'w':
 			args->wait = 1;
 			break;
+		case 'k':
+			keep_lsm = RESTART_KEEP_LSM;
+			break;
 		case 'W':
 			args->wait = 0;
 			break;
@@ -927,6 +934,7 @@ static int ckpt_coordinator(struct ckpt_ctx *ctx)
 	if (ctx->args->freezer)
 		flags |= RESTART_FROZEN;
 
+	flags |= keep_lsm;
 	ret = restart(root_pid, STDIN_FILENO, flags);
 
 	if (ret < 0) {
@@ -1581,6 +1589,7 @@ static int ckpt_make_tree(struct ckpt_ctx *ctx, struct task *task)
 	if (task->flags & (TASK_GHOST | TASK_DEAD))
 		flags |= RESTART_GHOST;
 
+	flags |= 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);
@@ -2057,6 +2066,7 @@ static int ckpt_read_obj_buffer(struct ckpt_ctx *ctx, void *buf, int n)
  * read/write the checkpoint image: similar to in-kernel code
  */
 
+#define SECURITY_NAME_MAX 20
 static int ckpt_read_header(struct ckpt_ctx *ctx)
 {
 	struct ckpt_hdr_header *h;
@@ -2090,6 +2100,16 @@ static int ckpt_read_header(struct ckpt_ctx *ctx)
 	if (ret < 0)
 		return ret;
 
+	ptr += ((struct ckpt_hdr *) ptr)->len;
+	ret = ckpt_read_obj_buffer(ctx, ptr, SECURITY_NAME_MAX + 1);
+	if (ret < 0)
+		return ret;
+
+	ptr += ((struct ckpt_hdr *) ptr)->len;
+	ret = ckpt_read_obj_type(ctx, ptr, 200, CKPT_HDR_LSM_INFO);
+	if (ret < 0)
+		return ret;
+
 	/* FIXME: skip version validation for now */
 
 	return 0;
@@ -2169,6 +2189,16 @@ static int ckpt_write_header(struct ckpt_ctx *ctx)
 	ptr += ((struct ckpt_hdr *) ptr)->len;
 	ret = ckpt_write_obj(ctx, (struct ckpt_hdr *) ptr);
 
+	if (ret < 0)
+		return ret;
+	ptr += ((struct ckpt_hdr *) ptr)->len;
+	ret = ckpt_write_obj(ctx, (struct ckpt_hdr *) ptr);
+	if (ret < 0)
+		return ret;
+
+	ptr += ((struct ckpt_hdr *) ptr)->len;
+	ret = ckpt_write_obj(ctx, (struct ckpt_hdr *) ptr);
+
 	return ret;
 }
 
Signature · 1 line
1.6.1.1

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

Acked-by
#4 lore raw

Re: [PATCH 1/1] restart: accept the lsm_name field in header and add -k flag

Quoted 10 lines · Serge E. Hallyn

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().

A couple of comments below. Otherwise:

Quoted 17 lines
---
 restart.c |   32 +++++++++++++++++++++++++++++++-
 1 files changed, 31 insertions(+), 1 deletions(-)
restart.c +1 -0
index b810ca9..44ae252 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"

restart.c struct args { · line 353

Quoted 4 lines
restart.c +1 -0
@@ -349,6 +350,8 @@ struct args {
 	char *input;
 };
 
+int keep_lsm;

Can you please use 'struct args' for this ?

Quoted 48 lines
restart.c +8 -1
+
 static void usage(char *str)
 {
 	fprintf(stderr, "%s", str);
@@ -377,6 +380,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' },
@@ -388,7 +392,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;
 
@@ -443,6 +447,9 @@ static void parse_args(struct args *args, int argc, char *argv[])
 		case 'w':
 			args->wait = 1;
 			break;
+		case 'k':
+			keep_lsm = RESTART_KEEP_LSM;
+			break;
 		case 'W':
 			args->wait = 0;
 			break;
@@ -927,6 +934,7 @@ static int ckpt_coordinator(struct ckpt_ctx *ctx)
 	if (ctx->args->freezer)
 		flags |= RESTART_FROZEN;
 
+	flags |= keep_lsm;
 	ret = restart(root_pid, STDIN_FILENO, flags);
 
 	if (ret < 0) {
@@ -1581,6 +1589,7 @@ static int ckpt_make_tree(struct ckpt_ctx *ctx, struct task *task)
 	if (task->flags & (TASK_GHOST | TASK_DEAD))
 		flags |= RESTART_GHOST;
 
+	flags |= 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);

restart.c static int ckpt_read_obj_buffer(struct ckpt_ctx *ctx, void *buf, int n) · line 2069

Quoted 4 lines
restart.c +1 -0
@@ -2057,6 +2066,7 @@ static int ckpt_read_obj_buffer(struct ckpt_ctx *ctx, void *buf, int n)
  * read/write the checkpoint image: similar to in-kernel code
  */
 
+#define SECURITY_NAME_MAX 20

Why is this ? if it's kernel ABI then define in checkpoint_hdr.h, or include suitable header.

Quoted 37 lines
restart.c +20 -0
 static int ckpt_read_header(struct ckpt_ctx *ctx)
 {
 	struct ckpt_hdr_header *h;
@@ -2090,6 +2100,16 @@ static int ckpt_read_header(struct ckpt_ctx *ctx)
 	if (ret < 0)
 		return ret;
 
+	ptr += ((struct ckpt_hdr *) ptr)->len;
+	ret = ckpt_read_obj_buffer(ctx, ptr, SECURITY_NAME_MAX + 1);
+	if (ret < 0)
+		return ret;
+
+	ptr += ((struct ckpt_hdr *) ptr)->len;
+	ret = ckpt_read_obj_type(ctx, ptr, 200, CKPT_HDR_LSM_INFO);
+	if (ret < 0)
+		return ret;
+
 	/* FIXME: skip version validation for now */
 
 	return 0;
@@ -2169,6 +2189,16 @@ static int ckpt_write_header(struct ckpt_ctx *ctx)
 	ptr += ((struct ckpt_hdr *) ptr)->len;
 	ret = ckpt_write_obj(ctx, (struct ckpt_hdr *) ptr);
 
+	if (ret < 0)
+		return ret;
+	ptr += ((struct ckpt_hdr *) ptr)->len;
+	ret = ckpt_write_obj(ctx, (struct ckpt_hdr *) ptr);
+	if (ret < 0)
+		return ret;
+
+	ptr += ((struct ckpt_hdr *) ptr)->len;
+	ret = ckpt_write_obj(ctx, (struct ckpt_hdr *) ptr);
+
 	return ret;
 }
 
#5 lore raw
In reply to a message not in the archive
Quoted 10 lines · Serge E. Hallyn

(wasn't versioning the patchsets before, so randomly pick 4 as the version for this patchset...)

Documentation/checkpoint/readme.txt begins:
"""
Application checkpoint/restart is the ability to save the state of a running application so that it can later resume its execution from the time at which it was checkpointed.
"""

[...]

Quoted 18 lines

Kernel interfaces
=================

checkpoint/checkpoint.c +1 -0
index 1eeb557..6722035 100644
@@ -25,6 +25,7 @@
 #include <linux/magic.h>
 #include <linux/hrtimer.h>
 #include <linux/deferqueue.h>
+#include <linux/security.h>
 #include <linux/checkpoint.h>
 #include <linux/checkpoint_hdr.h>
 
@@ -351,6 +352,16 @@ static int checkpoint_write_header(struct ckpt_ctx *ctx)
 	if (ret < 0)
 		return ret;
 

checkpoint/checkpoint.c static int checkpoint_write_header(struct ckpt_ctx *ctx) · line 364

Quoted 10 lines
checkpoint/checkpoint.c +10 -0
+	memset(ctx->lsm_name, 0, SECURITY_NAME_MAX + 1);
+	strlcpy(ctx->lsm_name, security_get_lsm_name(), SECURITY_NAME_MAX + 1);
+	ret = ckpt_write_buffer(ctx, ctx->lsm_name, SECURITY_NAME_MAX + 1);
+	if (ret < 0)
+		return ret;
+
+	ret = security_checkpoint_header(ctx);
+	if (ret < 0)
+		return ret;
+

This is actually a case for a 'container-global' section that would appear after the header and before the rest of the image. (Would be useful also for network namespaces).

Quoted 28 lines
checkpoint/checkpoint.c +0 -0
 	return checkpoint_write_header_arch(ctx);
 }
 
checkpoint/files.c +13 -0
index 27e29a0..570facb 100644
@@ -145,6 +145,19 @@ static int scan_fds(struct files_struct *files, int **fdtable)
 	return n;
 }
 
+#ifdef CONFIG_SECURITY
+int checkpoint_file_security(struct ckpt_ctx *ctx, struct file *file)
+{
+	return security_checkpoint_obj(ctx, file->f_security,
+					CKPT_SECURITY_FILE);
+}
+#else
+int checkpoint_file_security(struct ckpt_ctx *ctx, struct file *file)
+{
+	return -EOPNOTSUPP;
+}
+#endif
+
 int checkpoint_file_common(struct ckpt_ctx *ctx, struct file *file,
 			   struct ckpt_hdr_file *h)
 {

checkpoint/files.c int checkpoint_file_common(struct ckpt_ctx *ctx, struct file *file, · line 177

Quoted 6 lines
checkpoint/files.c +3 -0
@@ -159,6 +172,16 @@ int checkpoint_file_common(struct ckpt_ctx *ctx, struct file *file,
 	if (h->f_credref < 0)
 		return h->f_credref;
 
+	h->f_secref = checkpoint_file_security(ctx, file);
+	if (h->f_secref == -EOPNOTSUPP)
+		h->f_secref = -1;

#define CKPT_SECURITY_NONE -1 ??

Quoted 2 lines
checkpoint/files.c +2 -0
+	else if (h->f_secref < 0)
+		return h->f_secref;

[...]

checkpoint/files.c

Quoted 10 lines
checkpoint/files.c +10 -0
+
+static int do_checkpoint_security(struct ckpt_ctx *ctx,
+				const struct ckpt_stored_lsm *l)
+{
+	int ret, len;
+	struct ckpt_hdr_lsm *h;
+
+	len = strlen(l->string);
+	if (len > PAGE_SIZE - sizeof(*h))
+		return -E2BIG;

A call to ckpt_write_err() here may be useful.

Quoted 17 lines
checkpoint/files.c +17 -0
+	h = ckpt_hdr_get_type(ctx, sizeof(*h)+len+1, CKPT_HDR_SEC);
+	if (!h)
+		return -ENOMEM;
+	h->len = len;
+	h->sectype = l->sectype;
+	strncpy(h->string, l->string, len);
+	h->string[len] = '\0';
+	ret = ckpt_write_obj(ctx, &h->h);
+	ckpt_hdr_put(ctx, h);
+	return ret;
+}
+
+static int checkpoint_security(struct ckpt_ctx *ctx, void *ptr)
+{
+	return do_checkpoint_security(ctx, (struct ckpt_stored_lsm *) ptr);
+}
+

checkpoint/files.c

Quoted 10 lines
checkpoint/files.c +10 -0
+static struct ckpt_stored_lsm *do_restore_security(struct ckpt_ctx *ctx)
+{
+	struct ckpt_hdr_lsm *h;
+	struct ckpt_stored_lsm *l;
+
+	h = ckpt_read_buf_type(ctx, PAGE_SIZE, CKPT_HDR_SEC);
+	if (IS_ERR(h))
+		return (struct ckpt_stored_lsm *)h;
+	if (h->len > h->h.len - sizeof(struct ckpt_hdr) ||
+				h->len > PAGE_SIZE) {

The second test (for h->len > PAGE_SIZE) is unnecessary - already done in ckpt_read_buf_type()

checkpoint/files.c

Quoted 7 lines
checkpoint/files.c +7 -0
+		ckpt_hdr_put(ctx, h);
+		return ERR_PTR(-EINVAL);
+	}
+	l = kzalloc(sizeof(*l), GFP_KERNEL);
+	if (!l) {
+		ckpt_hdr_put(ctx, h);
+		return ERR_PTR(-ENOMEM);

Nit: this part is common... set ret = -ENOMEM and use goto ?

[...]

checkpoint/files.c static int restore_task_objs(struct ckpt_ctx *ctx) · line 616

Quoted 8 lines
checkpoint/files.c +1 -3
@@ -608,14 +613,21 @@ static int restore_task_objs(struct ckpt_ctx *ctx)
 	 * referenced. See comment in checkpoint_task_objs.
 	 */
 	ret = restore_task_creds(ctx);
-	if (!ret)
-		ret = restore_task_ns(ctx);
-	if (ret < 0)
+	if (ret) {

Nit: (ret < 0) helps (me) read it.

Quoted 25 lines
checkpoint/files.c +10 -1
+		ckpt_debug("restore_task_creds returned %d", ret);
+		return ret;
+	}
+	ret = restore_task_ns(ctx);
+	if (ret) {
+		ckpt_debug("restore_task_ns returned %d", ret);
 		return ret;
+	}
 
 	h = ckpt_read_obj_type(ctx, sizeof(*h), CKPT_HDR_TASK_OBJS);
-	if (IS_ERR(h))
+	if (IS_ERR(h)) {
+		ckpt_debug("Error fetching task obj");
 		return PTR_ERR(h);
+	}
 
 	ret = restore_obj_file_table(ctx, h->files_objref);
 	ckpt_debug("file_table: ret %d (%p)\n", ret, current->files);
checkpoint/restart.c +0 -0
index b12c8bd..bba2b45 100644
@@ -457,6 +457,31 @@ static int restore_read_header(struct ckpt_ctx *ctx)
 	if (ret < 0)
 		goto out;

checkpoint/restart.c static int restore_read_header(struct ckpt_ctx *ctx) · line 468

Quoted 10 lines
checkpoint/restart.c +9 -0
 
+	ret = _ckpt_read_buffer(ctx, ctx->lsm_name, SECURITY_NAME_MAX + 1);
+	if (ret < 0)
+		goto out;
+	if (ctx->uflags & RESTART_KEEP_LSM) {
+		char *cur = security_get_lsm_name();
+		if (strncmp(cur, ctx->lsm_name, SECURITY_NAME_MAX + 1) != 0) {
+			pr_warning("c/r: checkpointed LSM %s, current is %s.\n",
+				ctx->lsm_name, cur);
+			ret = -EINVAL;

EPERM ?

[...]

checkpoint/restart.c struct ckpt_hdr_groupinfo { · line 289

Quoted 8 lines
checkpoint/restart.c +4 -0
@@ -277,6 +283,16 @@ struct ckpt_hdr_groupinfo {
 	__u32 groups[0];
 } __attribute__((aligned(8)));
 
+struct ckpt_hdr_lsm {
+	struct ckpt_hdr h;
+	__u8 sectype;
+	__u16 len;

Alignment ...

Quoted 10 lines
checkpoint/restart.c +6 -0
+	/*
+	 * This is followed by a string of size len+1,
+	 * null-terminated
+	 */
+	__u8 string[0];
+} __attribute__((aligned(8)));
 /*
  * todo - keyrings and LSM
  * These may be better done with userspace help though

checkpoint/restart.c struct ckpt_hdr_file { · line 412

Quoted 5 lines
checkpoint/restart.c +2 -0
@@ -392,6 +408,8 @@ struct ckpt_hdr_file {
 	__s32 f_credref;
 	__u64 f_pos;
 	__u64 f_version;
+	__s32 f_secref;
+	__u32 f_padding;

No need for padding here.

checkpoint/restart.c struct ckpt_hdr_ipc_perms { · line 656

Quoted 9 lines
checkpoint/restart.c +2 -0
 } __attribute__((aligned(8)));
 
 struct ckpt_hdr_file_generic {
@@ -634,6 +652,8 @@ struct ckpt_hdr_ipc_perms {
 	__u32 mode;
 	__u32 _padding;
 	__u64 seq;
+	__s32 sec_ref;
+	__u32 padding;

Ditto.

[...]

checkpoint/restart.c static struct msg_msg *restore_msg_contents_one(struct ckpt_ctx *ctx, int *clen) · line 241

Quoted 9 lines
checkpoint/restart.c +5 -0
@@ -224,6 +234,16 @@ static struct msg_msg *restore_msg_contents_one(struct ckpt_ctx *ctx, int *clen)
 	msg->next = NULL;
 	pseg = &msg->next;
 
+	if ((ctx->uflags & RESTART_KEEP_LSM) && (h->sec_ref != -1)) {
+		struct ckpt_stored_lsm *l = ckpt_obj_fetch(ctx, h->sec_ref,
+					CKPT_OBJ_SEC);
+		if (IS_ERR(l))
+			return (struct msg_msg *)l;

That's a leak. Need to 'goto out' instead.

checkpoint/restart.c static struct msg_msg *restore_msg_contents_one(struct ckpt_ctx *ctx, int *clen) · line 244

Quoted 3 lines
checkpoint/restart.c +3 -0
+		ret = security_msg_msg_restore(msg, l->string);
+		if (ret)
+			return ERR_PTR(ret);

Here too.

[...]

checkpoint/restart.c static struct cred *do_restore_cred(struct ckpt_ctx *ctx) · line 822

Quoted 9 lines
checkpoint/restart.c +5 -0
@@ -806,6 +815,15 @@ static struct cred *do_restore_cred(struct ckpt_ctx *ctx)
 	ret = cred_setfsgid(cred, h->fsgid, &oldgid);
 	if (oldgid != h->fsgid && ret < 0)
 		goto err_putcred;
+	if ((ctx->uflags & RESTART_KEEP_LSM) && (h->sec_ref != -1)) {
+		struct ckpt_stored_lsm *l = ckpt_obj_fetch(ctx, h->sec_ref,
+					CKPT_OBJ_SEC);
+		if (IS_ERR(l))
+			return (struct cred *)l;

And here too ?

Quoted 43 lines
checkpoint/restart.c +43 -0
+/**
+ * security_checkpoint_obj - if first checkpoint of this void* security,
+ * then 1. ask the LSM for a string representing the context, 2. checkpoint
+ * that string
+ * @ctx: the checkpoint context
+ * @security: the void* security being checkpointed
+ * @sectype: indicates the type of object, because LSMs can (and do) store
+ * different types of data for different types of objects.
+ *
+ * Returns the objref of the checkpointed ckpt_stored_lsm representing the
+ * context, or -error on error.
+ *
+ * This is only used at checkpoint of course.
+ */
+int security_checkpoint_obj(struct ckpt_ctx *ctx, void *security,
+				unsigned sectype)
+{
+	int strref;
+	struct ckpt_stored_lsm *l;
+	char *str;
+	int len;
+
+	/*
+	 * to simplify the LSM code, short-cut a null security
+	 * here.
+	 */
+	if (!security)
+		return -EOPNOTSUPP;
+
+	switch (sectype) {
+	case CKPT_SECURITY_MSG_MSG:
+		str = security_msg_msg_checkpoint(security);
+		break;
+	case CKPT_SECURITY_IPC:
+		str = security_ipc_checkpoint(security);
+		break;
+	case CKPT_SECURITY_FILE:
+		str = security_file_checkpoint(security);
+		break;
+	case CKPT_SECURITY_CRED:
+		str = security_cred_checkpoint(security);
+		break;
+	default:

checkpoint/restart.c static struct cred *do_restore_cred(struct ckpt_ctx *ctx)

Quoted 10 lines
checkpoint/restart.c +10 -0
+		str = ERR_PTR(-EINVAL);
+		break;
+	}
+	/* str will be alloc'ed for us by the LSM.  We will free it when
+	 * we clear out our hashtable */
+	if (IS_ERR(str))
+		return PTR_ERR(str);
+
+	len = strlen(str);
+	l = kzalloc(sizeof(*l) + len + 1, GFP_KERNEL);

Probably a dumb question: why do you allocate with the size of the string when it merely points to the string ?

Quoted 4 lines
checkpoint/restart.c +4 -0
+	if (!l) {
+		kfree(str);
+		return -ENOMEM;
+	}

checkpoint/restart.c

Quoted 10 lines
checkpoint/restart.c +10 -0
+	kref_init(&l->kref);
+	l->sectype = sectype;
+	l->string = str;
+
+	strref = checkpoint_obj(ctx, l, CKPT_OBJ_SEC);
+	/* do we need to free l if strref was err? */
+	return strref;
+}
+
+#endif

Oren.

#6 lore raw
Quoted 34 lines · Oren Laadan
Quoted 10 lines · Serge E. Hallyn

(wasn't versioning the patchsets before, so randomly pick 4 as the version for this patchset...)

Documentation/checkpoint/readme.txt begins:
"""
Application checkpoint/restart is the ability to save the state of a running application so that it can later resume its execution from the time at which it was checkpointed.
"""

[...]

Quoted 18 lines

Kernel interfaces
=================

checkpoint/checkpoint.c +1 -0
index 1eeb557..6722035 100644
@@ -25,6 +25,7 @@
 #include <linux/magic.h>
 #include <linux/hrtimer.h>
 #include <linux/deferqueue.h>
+#include <linux/security.h>
 #include <linux/checkpoint.h>
 #include <linux/checkpoint_hdr.h>
 
@@ -351,6 +352,16 @@ static int checkpoint_write_header(struct ckpt_ctx *ctx)
 	if (ret < 0)
 		return ret;
 
Quoted 14 lines

checkpoint/checkpoint.c static int checkpoint_write_header(struct ckpt_ctx *ctx) · line 364

Quoted 10 lines
checkpoint/checkpoint.c +10 -0
+	memset(ctx->lsm_name, 0, SECURITY_NAME_MAX + 1);
+	strlcpy(ctx->lsm_name, security_get_lsm_name(), SECURITY_NAME_MAX + 1);
+	ret = ckpt_write_buffer(ctx, ctx->lsm_name, SECURITY_NAME_MAX + 1);
+	if (ret < 0)
+		return ret;
+
+	ret = security_checkpoint_header(ctx);
+	if (ret < 0)
+		return ret;
+

This is actually a case for a 'container-global' section that would appear after the header and before the rest of the image. (Would be useful also for network namespaces).

But LSM's are specifically not containerized, so this is a host property, not a container one.

Quoted 31 lines
Quoted 31 lines
checkpoint/checkpoint.c +0 -0
 	return checkpoint_write_header_arch(ctx);
 }
 
checkpoint/files.c +13 -0
index 27e29a0..570facb 100644
@@ -145,6 +145,19 @@ static int scan_fds(struct files_struct *files, int **fdtable)
 	return n;
 }
 
+#ifdef CONFIG_SECURITY
+int checkpoint_file_security(struct ckpt_ctx *ctx, struct file *file)
+{
+	return security_checkpoint_obj(ctx, file->f_security,
+					CKPT_SECURITY_FILE);
+}
+#else
+int checkpoint_file_security(struct ckpt_ctx *ctx, struct file *file)
+{
+	return -EOPNOTSUPP;
+}
+#endif
+
 int checkpoint_file_common(struct ckpt_ctx *ctx, struct file *file,
 			   struct ckpt_hdr_file *h)
 {
@@ -159,6 +172,16 @@ int checkpoint_file_common(struct ckpt_ctx *ctx, struct file *file,
 	if (h->f_credref < 0)
 		return h->f_credref;
 
Quoted 5 lines

checkpoint/files.c int checkpoint_file_common(struct ckpt_ctx *ctx, struct file *file, · line 177

Quoted 3 lines
checkpoint/files.c +3 -0
+	h->f_secref = checkpoint_file_security(ctx, file);
+	if (h->f_secref == -EOPNOTSUPP)
+		h->f_secref = -1;

#define CKPT_SECURITY_NONE -1 ??

Yeah, that'd be cleaner.

Quoted 5 lines
Quoted 2 lines
checkpoint/files.c +2 -0
+	else if (h->f_secref < 0)
+		return h->f_secref;

[...]

Quoted 12 lines

checkpoint/files.c

Quoted 10 lines
checkpoint/files.c +10 -0
+
+static int do_checkpoint_security(struct ckpt_ctx *ctx,
+				const struct ckpt_stored_lsm *l)
+{
+	int ret, len;
+	struct ckpt_hdr_lsm *h;
+
+	len = strlen(l->string);
+	if (len > PAGE_SIZE - sizeof(*h))
+		return -E2BIG;

A call to ckpt_write_err() here may be useful.

ok

Quoted 22 lines
Quoted 22 lines
checkpoint/files.c +22 -0
+	h = ckpt_hdr_get_type(ctx, sizeof(*h)+len+1, CKPT_HDR_SEC);
+	if (!h)
+		return -ENOMEM;
+	h->len = len;
+	h->sectype = l->sectype;
+	strncpy(h->string, l->string, len);
+	h->string[len] = '\0';
+	ret = ckpt_write_obj(ctx, &h->h);
+	ckpt_hdr_put(ctx, h);
+	return ret;
+}
+
+static int checkpoint_security(struct ckpt_ctx *ctx, void *ptr)
+{
+	return do_checkpoint_security(ctx, (struct ckpt_stored_lsm *) ptr);
+}
+
+static struct ckpt_stored_lsm *do_restore_security(struct ckpt_ctx *ctx)
+{
+	struct ckpt_hdr_lsm *h;
+	struct ckpt_stored_lsm *l;
+
Quoted 8 lines

checkpoint/files.c

Quoted 5 lines
checkpoint/files.c +5 -0
+	h = ckpt_read_buf_type(ctx, PAGE_SIZE, CKPT_HDR_SEC);
+	if (IS_ERR(h))
+		return (struct ckpt_stored_lsm *)h;
+	if (h->len > h->h.len - sizeof(struct ckpt_hdr) ||
+				h->len > PAGE_SIZE) {

The second test (for h->len > PAGE_SIZE) is unnecessary - already done in ckpt_read_buf_type()

Huh. I had no idea :)

Quoted 9 lines

checkpoint/files.c

Quoted 7 lines
checkpoint/files.c +7 -0
+		ckpt_hdr_put(ctx, h);
+		return ERR_PTR(-EINVAL);
+	}
+	l = kzalloc(sizeof(*l), GFP_KERNEL);
+	if (!l) {
+		ckpt_hdr_put(ctx, h);
+		return ERR_PTR(-ENOMEM);

Nit: this part is common... set ret = -ENOMEM and use goto ?

ok

Quoted 12 lines

[...]

checkpoint/files.c static int restore_task_objs(struct ckpt_ctx *ctx) · line 616

Quoted 8 lines
checkpoint/files.c +1 -3
@@ -608,14 +613,21 @@ static int restore_task_objs(struct ckpt_ctx *ctx)
 	 * referenced. See comment in checkpoint_task_objs.
 	 */
 	ret = restore_task_creds(ctx);
-	if (!ret)
-		ret = restore_task_ns(ctx);
-	if (ret < 0)
+	if (ret) {

Nit: (ret < 0) helps (me) read it.

Really? Whenever I review something like that it forces me to go through and make sure no >0 codes will be returned for failure... But ok.

Quoted 26 lines
Quoted 26 lines
checkpoint/files.c +10 -1
+		ckpt_debug("restore_task_creds returned %d", ret);
+		return ret;
+	}
+	ret = restore_task_ns(ctx);
+	if (ret) {
+		ckpt_debug("restore_task_ns returned %d", ret);
 		return ret;
+	}
 
 	h = ckpt_read_obj_type(ctx, sizeof(*h), CKPT_HDR_TASK_OBJS);
-	if (IS_ERR(h))
+	if (IS_ERR(h)) {
+		ckpt_debug("Error fetching task obj");
 		return PTR_ERR(h);
+	}
 
 	ret = restore_obj_file_table(ctx, h->files_objref);
 	ckpt_debug("file_table: ret %d (%p)\n", ret, current->files);
checkpoint/restart.c +0 -0
index b12c8bd..bba2b45 100644
@@ -457,6 +457,31 @@ static int restore_read_header(struct ckpt_ctx *ctx)
 	if (ret < 0)
 		goto out;
 
Quoted 11 lines

checkpoint/restart.c static int restore_read_header(struct ckpt_ctx *ctx) · line 468

Quoted 9 lines
checkpoint/restart.c +9 -0
+	ret = _ckpt_read_buffer(ctx, ctx->lsm_name, SECURITY_NAME_MAX + 1);
+	if (ret < 0)
+		goto out;
+	if (ctx->uflags & RESTART_KEEP_LSM) {
+		char *cur = security_get_lsm_name();
+		if (strncmp(cur, ctx->lsm_name, SECURITY_NAME_MAX + 1) != 0) {
+			pr_warning("c/r: checkpointed LSM %s, current is %s.\n",
+				ctx->lsm_name, cur);
+			ret = -EINVAL;

EPERM ?

Hmm... I think of this not as "you're not allowed" but rather "it doesn't
make sense."

Quoted 49 lines

[...]

checkpoint/restart.c struct ckpt_hdr_groupinfo { · line 289

Quoted 8 lines
checkpoint/restart.c +4 -0
@@ -277,6 +283,16 @@ struct ckpt_hdr_groupinfo {
 	__u32 groups[0];
 } __attribute__((aligned(8)));
 
+struct ckpt_hdr_lsm {
+	struct ckpt_hdr h;
+	__u8 sectype;
+	__u16 len;

Alignment ...

Quoted 10 lines
checkpoint/restart.c +6 -0
+	/*
+	 * This is followed by a string of size len+1,
+	 * null-terminated
+	 */
+	__u8 string[0];
+} __attribute__((aligned(8)));
 /*
  * todo - keyrings and LSM
  * These may be better done with userspace help though

checkpoint/restart.c struct ckpt_hdr_file { · line 412

Quoted 5 lines
checkpoint/restart.c +2 -0
@@ -392,6 +408,8 @@ struct ckpt_hdr_file {
 	__s32 f_credref;
 	__u64 f_pos;
 	__u64 f_version;
+	__s32 f_secref;
+	__u32 f_padding;

No need for padding here.

checkpoint/restart.c struct ckpt_hdr_ipc_perms { · line 656

Quoted 9 lines
checkpoint/restart.c +2 -0
 } __attribute__((aligned(8)));
 
 struct ckpt_hdr_file_generic {
@@ -634,6 +652,8 @@ struct ckpt_hdr_ipc_perms {
 	__u32 mode;
 	__u32 _padding;
 	__u64 seq;
+	__s32 sec_ref;
+	__u32 padding;

Ditto.

[...]

Quoted 4 lines
checkpoint/restart.c +0 -0
@@ -224,6 +234,16 @@ static struct msg_msg *restore_msg_contents_one(struct ckpt_ctx *ctx, int *clen)
 	msg->next = NULL;
 	pseg = &msg->next;
 
Quoted 7 lines

checkpoint/restart.c static struct msg_msg *restore_msg_contents_one(struct ckpt_ctx *ctx, int *clen) · line 241

Quoted 5 lines
checkpoint/restart.c +5 -0
+	if ((ctx->uflags & RESTART_KEEP_LSM) && (h->sec_ref != -1)) {
+		struct ckpt_stored_lsm *l = ckpt_obj_fetch(ctx, h->sec_ref,
+					CKPT_OBJ_SEC);
+		if (IS_ERR(l))
+			return (struct msg_msg *)l;

That's a leak. Need to 'goto out' instead.

ok

Quoted 68 lines

checkpoint/restart.c static struct msg_msg *restore_msg_contents_one(struct ckpt_ctx *ctx, int *clen) · line 244

Quoted 3 lines
checkpoint/restart.c +3 -0
+		ret = security_msg_msg_restore(msg, l->string);
+		if (ret)
+			return ERR_PTR(ret);

Here too.

[...]

checkpoint/restart.c static struct cred *do_restore_cred(struct ckpt_ctx *ctx) · line 822

Quoted 9 lines
checkpoint/restart.c +5 -0
@@ -806,6 +815,15 @@ static struct cred *do_restore_cred(struct ckpt_ctx *ctx)
 	ret = cred_setfsgid(cred, h->fsgid, &oldgid);
 	if (oldgid != h->fsgid && ret < 0)
 		goto err_putcred;
+	if ((ctx->uflags & RESTART_KEEP_LSM) && (h->sec_ref != -1)) {
+		struct ckpt_stored_lsm *l = ckpt_obj_fetch(ctx, h->sec_ref,
+					CKPT_OBJ_SEC);
+		if (IS_ERR(l))
+			return (struct cred *)l;

And here too ?

Quoted 48 lines
checkpoint/restart.c +48 -0
+/**
+ * security_checkpoint_obj - if first checkpoint of this void* security,
+ * then 1. ask the LSM for a string representing the context, 2. checkpoint
+ * that string
+ * @ctx: the checkpoint context
+ * @security: the void* security being checkpointed
+ * @sectype: indicates the type of object, because LSMs can (and do) store
+ * different types of data for different types of objects.
+ *
+ * Returns the objref of the checkpointed ckpt_stored_lsm representing the
+ * context, or -error on error.
+ *
+ * This is only used at checkpoint of course.
+ */
+int security_checkpoint_obj(struct ckpt_ctx *ctx, void *security,
+				unsigned sectype)
+{
+	int strref;
+	struct ckpt_stored_lsm *l;
+	char *str;
+	int len;
+
+	/*
+	 * to simplify the LSM code, short-cut a null security
+	 * here.
+	 */
+	if (!security)
+		return -EOPNOTSUPP;
+
+	switch (sectype) {
+	case CKPT_SECURITY_MSG_MSG:
+		str = security_msg_msg_checkpoint(security);
+		break;
+	case CKPT_SECURITY_IPC:
+		str = security_ipc_checkpoint(security);
+		break;
+	case CKPT_SECURITY_FILE:
+		str = security_file_checkpoint(security);
+		break;
+	case CKPT_SECURITY_CRED:
+		str = security_cred_checkpoint(security);
+		break;
+	default:
+		str = ERR_PTR(-EINVAL);
+		break;
+	}
+	/* str will be alloc'ed for us by the LSM.  We will free it when
+	 * we clear out our hashtable */
Quoted 8 lines

checkpoint/restart.c

Quoted 5 lines
checkpoint/restart.c +5 -0
+	if (IS_ERR(str))
+		return PTR_ERR(str);
+
+	len = strlen(str);
+	l = kzalloc(sizeof(*l) + len + 1, GFP_KERNEL);

Probably a dumb question: why do you allocate with the size of the string when it merely points to the string ?

No just dumb code - I used to strcpy it in but don't anymore.

Quoted 8 lines
Quoted 8 lines
checkpoint/restart.c +8 -0
+	if (!l) {
+		kfree(str);
+		return -ENOMEM;
+	}
+	kref_init(&l->kref);
+	l->sectype = sectype;
+	l->string = str;
+
Quoted 8 lines

checkpoint/restart.c

Quoted 6 lines
checkpoint/restart.c +6 -0
+	strref = checkpoint_obj(ctx, l, CKPT_OBJ_SEC);
+	/* do we need to free l if strref was err? */
+	return strref;
+}
+
+#endif

Oren.

Thanks! Will send a new version.

-serge

#7 lore raw
Quoted 13 lines · Serge E. Hallyn
Quoted 12 lines · Oren Laadan
Quoted 10 lines · Serge E. Hallyn

(wasn't versioning the patchsets before, so randomly pick 4 as the version for this patchset...)

Documentation/checkpoint/readme.txt begins:
"""
Application checkpoint/restart is the ability to save the state of a running application so that it can later resume its execution from the time at which it was checkpointed.
"""

[...]

Quoted 14 lines
Quoted 5 lines
Quoted 5 lines
checkpoint/checkpoint.c +5 -0
+	memset(ctx->lsm_name, 0, SECURITY_NAME_MAX + 1);
+	strlcpy(ctx->lsm_name, security_get_lsm_name(), SECURITY_NAME_MAX + 1);
+	ret = ckpt_write_buffer(ctx, ctx->lsm_name, SECURITY_NAME_MAX + 1);
+	if (ret < 0)
+		return ret;
Quoted 8 lines

checkpoint/checkpoint.c static int checkpoint_write_header(struct ckpt_ctx *ctx) · line 364

Quoted 5 lines
checkpoint/checkpoint.c +5 -0
+
+	ret = security_checkpoint_header(ctx);
+	if (ret < 0)
+		return ret;
+

This is actually a case for a 'container-global' section that would appear after the header and before the rest of the image. (Would be useful also for network namespaces).

Quoted 2 lines

But LSM's are specifically not containerized, so this is a host property, not a container one.

Hmmm... does that mean you can't apply one policy to one container and another policy to another ?

Anyway, it belongs to a 'global' section, that may have 2 parts:
host and container. (Putting it between header and arch-header seems weird...)

The header doesn't hold state, it is a declarative section about the properties of the original host (kernel and HW).

Oren.

#8 lore raw
Quoted 33 lines · Oren Laadan
Quoted 13 lines · Serge E. Hallyn
Quoted 12 lines · Oren Laadan
Quoted 10 lines · Serge E. Hallyn

(wasn't versioning the patchsets before, so randomly pick 4 as the version for this patchset...)

Documentation/checkpoint/readme.txt begins:
"""
Application checkpoint/restart is the ability to save the state of a running application so that it can later resume its execution from the time at which it was checkpointed.
"""

[...]

Quoted 14 lines
Quoted 13 lines

checkpoint/checkpoint.c static int checkpoint_write_header(struct ckpt_ctx *ctx) · line 364

Quoted 10 lines
checkpoint/checkpoint.c +10 -0
+	memset(ctx->lsm_name, 0, SECURITY_NAME_MAX + 1);
+	strlcpy(ctx->lsm_name, security_get_lsm_name(), SECURITY_NAME_MAX + 1);
+	ret = ckpt_write_buffer(ctx, ctx->lsm_name, SECURITY_NAME_MAX + 1);
+	if (ret < 0)
+		return ret;
+
+	ret = security_checkpoint_header(ctx);
+	if (ret < 0)
+		return ret;
+

This is actually a case for a 'container-global' section that would appear after the header and before the rest of the image. (Would be useful also for network namespaces).

Quoted 5 lines
Quoted 2 lines

But LSM's are specifically not containerized, so this is a host property, not a container one.

Hmmm... does that mean you can't apply one policy to one container and another policy to another ?

Yup.

Quoted 3 lines

Anyway, it belongs to a 'global' section, that may have 2 parts:
host and container. (Putting it between header and arch-header seems weird...)

Ok, then I'll add that in the next set.

Quoted 2 lines

The header doesn't hold state, it is a declarative section about the properties of the original host (kernel and HW).

Ok, I see.

thanks,
-serge

#9 lore raw

PATCH 2/3 cr: add smack support to lsm c/r (v4)

In reply to Serge E. Hallyn

Documentation/checkpoint/readme.txt begins:
"""
Application checkpoint/restart is the ability to save the state of a running application so that it can later resume its execution from the time at which it was checkpointed.
"""

This patch implements checkpoint and restore of Smack security labels. The rules are the same as in previous versions:

1. when objects are created during restore() they are automatically labeled with current_security().
2. if there was a label checkpointed with the object, and that label != current_security() (which is the same as obj->security), then the object is relabeled if the sys_restart() caller has CAP_MAC_ADMIN. Otherwise we return -EPERM.

This has been tested by checkpointing tasks under labels _, vs1, and vs2, and restarting from tasks under _, vs1, and vs2, with and without CAP_MAC_ADMIN in the bounding set, and with and without the '-k' (keep_lsm) flag to mktree. Expected results:

#shell 1:
echo vs1 > /proc/self/attr/current
ckpt > out
echo vs2 > /proc/self/attr/current
mktree -F /cgroup/2 < out
(frozen)
# shell 2:
cat /proc/pidof ckpt/attr/current
vs2
echo THAWED > /cgroup/2/freezer.state
# shell 1:
mktree -k -F /cgroup/2 < out
(frozen)
# shell 2:
cat /proc/pidof ckpt/attr/current
vs1
echo THAWED > /cgroup/2/freezer.state
# shell 1:
capsh --drop=cap_mac_admin --
mktree -k -F /cgroup/2 < out
(permission denied)

There are testcases in git://git.sr71.net/~hallyn/cr_tests.git
under cr_tests/smack, which automate the above (and pass).

Changelog:
sep 3: add a version to smack lsm, accessible through
/smack/version (Casey and Serge)
sep 10: rename xyz_get_ctx() to xyz_checkpoint()

---
 checkpoint/restart.c       |    1 +
 security/smack/smack.h     |    1 +
 security/smack/smack_lsm.c |  141 ++++++++++++++++++++++++++++++++++++++++++++
 security/smack/smackfs.c   |   83 ++++++++++++++++++++++++++
 4 files changed, 226 insertions(+), 0 deletions(-)
checkpoint/restart.c +1 -0
index bba2b45..55bd2b5 100644
@@ -470,6 +470,7 @@ static int restore_read_header(struct ckpt_ctx *ctx)
 		}
 		/* to be implemented later, per-lsm */
 		if (strcmp(ctx->lsm_name, "lsm_none") != 0 &&
+				strcmp(ctx->lsm_name, "smack") != 0 &&
 				strcmp(ctx->lsm_name, "default") != 0) {
 			pr_warning("c/r: RESTART_KEEP_LSM unsupported for %s\n",
 					ctx->lsm_name);
security/smack/smack.h +1 -0
index 243bec1..b5c1ce6 100644
@@ -216,6 +216,7 @@ u32 smack_to_secid(const char *);
 extern int smack_cipso_direct;
 extern char *smack_net_ambient;
 extern char *smack_onlycap;
+extern char *smack_version;
 extern const char *smack_cipso_option;
 
 extern struct smack_known smack_known_floor;
security/smack/smack_lsm.c +141 -0

203 lines not on this page · raw message

security/smack/smackfs.c +83 -0

113 lines not on this page · raw message

Signature · 1 line
1.6.1
#10 lore raw

PATCH 3/3 cr: add selinux support (v4)

In reply to Serge E. Hallyn

Documentation/checkpoint/readme.txt begins:
"""
Application checkpoint/restart is the ability to save the state of a running application so that it can later resume its execution from the time at which it was checkpointed.
"""

This patch adds the ability to checkpoint and restore selinux contexts for tasks, open files, and sysvipc objects. Contexts are checkpointed as strings. For tasks and files, where a security struct actually points to several contexts, all contexts are written out in one string, separated by ':::'.

The default behaviors are to checkpoint contexts, but not to restore them. To attempt to restore them, sys_restart() must be given the RESTART_KEEP_LSM flag. If this is given then the caller of sys_restart() must have the new 'restore' permission to the target objclass, or for instance PROCESS__SETFSCREATE to itself to specify a create_sid.

There are some tests under cr_tests/selinux at
git://git.sr71.net/~hallyn/cr_tests.git.

A corresponding simple refpolicy (and /usr/share/selinux/devel/include) patch is needed.

The programs to checkpoint and restart (called 'checkpoint' and 'restart') come from git://git.ncl.cs.columbia.edu/pub/git/user-cr.git.
This patch applies against the checkpoint/restart-enabled kernel tree at git://git.ncl.cs.columbia.edu/pub/git/linux-cr.git/.

Changelog:
oct 01: Remove some debugging that is redundant with
avc log data.
sep 10: (Most addressing suggestions by Stephen Smalley)
1. change xyz_get_ctx() to xyz_checkpoint().
2. check entrypoint permission on cred_restore
3. always dec context length by 1
4. don't allow SECSID_NULL when that's not valid
5. when SECSID_NULL is valid, restore it
6. c/r task->osid
7. Just print nothing instead of 'null' for SECSID_NULL
8. sids are __u32, as are lenghts passed to sid_to_context.

---
 checkpoint/restart.c                         |    1 +
 kernel/cred.c                                |    2 +
 security/selinux/hooks.c                     |  371 ++++++++++++++++++++++++++
 security/selinux/include/av_perm_to_string.h |    4 +
 security/selinux/include/av_permissions.h    |    4 +
 5 files changed, 382 insertions(+), 0 deletions(-)
checkpoint/restart.c +1 -0
index 55bd2b5..008a116 100644
@@ -471,6 +471,7 @@ static int restore_read_header(struct ckpt_ctx *ctx)
 		/* to be implemented later, per-lsm */
 		if (strcmp(ctx->lsm_name, "lsm_none") != 0 &&
 				strcmp(ctx->lsm_name, "smack") != 0 &&
+				strcmp(ctx->lsm_name, "selinux") != 0 &&
 				strcmp(ctx->lsm_name, "default") != 0) {
 			pr_warning("c/r: RESTART_KEEP_LSM unsupported for %s\n",
 					ctx->lsm_name);
kernel/cred.c +2 -0
index 06bc676..5eb09b8 100644
@@ -732,6 +732,8 @@ static int do_checkpoint_cred(struct ckpt_ctx *ctx, struct cred *cred)
 	if (!h)
 		return -ENOMEM;
 
+	ckpt_debug("cred uid %d fsuid %d gid %d secref %d\n", cred->uid,
+		cred->fsuid, cred->gid, sec_ref);
 	h->uid = cred->uid;
 	h->suid = cred->suid;
 	h->euid = cred->euid;
security/selinux/hooks.c +371 -0

421 lines not on this page · raw message

security/selinux/include/av_perm_to_string.h +4 -0
index 31df1d7..78945e7 100644
@@ -19,6 +19,7 @@
    S_(SECCLASS_FILE, FILE__ENTRYPOINT, "entrypoint")
    S_(SECCLASS_FILE, FILE__EXECMOD, "execmod")
    S_(SECCLASS_FILE, FILE__OPEN, "open")
+   S_(SECCLASS_FILE, FILE__RESTORE, "restore")
    S_(SECCLASS_CHR_FILE, CHR_FILE__EXECUTE_NO_TRANS, "execute_no_trans")
    S_(SECCLASS_CHR_FILE, CHR_FILE__ENTRYPOINT, "entrypoint")
    S_(SECCLASS_CHR_FILE, CHR_FILE__EXECMOD, "execmod")
@@ -88,9 +89,11 @@
    S_(SECCLASS_PROCESS, PROCESS__EXECHEAP, "execheap")
    S_(SECCLASS_PROCESS, PROCESS__SETKEYCREATE, "setkeycreate")
    S_(SECCLASS_PROCESS, PROCESS__SETSOCKCREATE, "setsockcreate")
+   S_(SECCLASS_PROCESS, PROCESS__RESTORE, "restore")
    S_(SECCLASS_MSGQ, MSGQ__ENQUEUE, "enqueue")
    S_(SECCLASS_MSG, MSG__SEND, "send")
    S_(SECCLASS_MSG, MSG__RECEIVE, "receive")
+   S_(SECCLASS_MSG, MSG__RESTORE, "restore")
    S_(SECCLASS_SHM, SHM__LOCK, "lock")
    S_(SECCLASS_SECURITY, SECURITY__COMPUTE_AV, "compute_av")
    S_(SECCLASS_SECURITY, SECURITY__COMPUTE_CREATE, "compute_create")
@@ -107,6 +110,7 @@
    S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, "syslog_read")
    S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, "syslog_mod")
    S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE, "syslog_console")
+   S_(SECCLASS_IPC, IPC__RESTORE, "restore")
    S_(SECCLASS_CAPABILITY, CAPABILITY__CHOWN, "chown")
    S_(SECCLASS_CAPABILITY, CAPABILITY__DAC_OVERRIDE, "dac_override")
    S_(SECCLASS_CAPABILITY, CAPABILITY__DAC_READ_SEARCH, "dac_read_search")
security/selinux/include/av_permissions.h +4 -0
index d645192..8e066ac 100644
@@ -101,6 +101,7 @@
 #define FILE__ENTRYPOINT                          0x00040000UL
 #define FILE__EXECMOD                             0x00080000UL
 #define FILE__OPEN                                0x00100000UL
+#define FILE__RESTORE                             0x00200000UL
 #define LNK_FILE__IOCTL                           0x00000001UL
 #define LNK_FILE__READ                            0x00000002UL
 #define LNK_FILE__WRITE                           0x00000004UL
@@ -453,6 +454,7 @@
 #define PROCESS__EXECHEAP                         0x08000000UL
 #define PROCESS__SETKEYCREATE                     0x10000000UL
 #define PROCESS__SETSOCKCREATE                    0x20000000UL
+#define PROCESS__RESTORE	                  0x40000000UL
 #define IPC__CREATE                               0x00000001UL
 #define IPC__DESTROY                              0x00000002UL
 #define IPC__GETATTR                              0x00000004UL
@@ -462,6 +464,7 @@
 #define IPC__ASSOCIATE                            0x00000040UL
 #define IPC__UNIX_READ                            0x00000080UL
 #define IPC__UNIX_WRITE                           0x00000100UL
+#define IPC__RESTORE                              0x00000200UL
 #define SEM__CREATE                               0x00000001UL
 #define SEM__DESTROY                              0x00000002UL
 #define SEM__GETATTR                              0x00000004UL
@@ -483,6 +486,7 @@
 #define MSGQ__ENQUEUE                             0x00000200UL
 #define MSG__SEND                                 0x00000001UL
 #define MSG__RECEIVE                              0x00000002UL
+#define MSG__RESTORE                              0x00000004UL
 #define SHM__CREATE                               0x00000001UL
 #define SHM__DESTROY                              0x00000002UL
 #define SHM__GETATTR                              0x00000004UL
Signature · 1 line
1.6.1
#11 lore raw

Re: [PATCH 3/3] cr: add selinux support (v4)

Quoted 18 lines · Serge E. Hallyn

Documentation/checkpoint/readme.txt begins:
"""
Application checkpoint/restart is the ability to save the state of a running application so that it can later resume its execution from the time at which it was checkpointed.
"""

This patch adds the ability to checkpoint and restore selinux contexts for tasks, open files, and sysvipc objects. Contexts are checkpointed as strings. For tasks and files, where a security struct actually points to several contexts, all contexts are written out in one string, separated by ':::'.

security/selinux/hooks.c +0 -0
index 8d8b69c..4fb8b5d 100644

security/selinux/hooks.c static int selinux_file_permission(struct file *file, int mask) · line 2971

Quoted 10 lines
security/selinux/hooks.c +7 -0
@@ -2961,6 +2962,108 @@ static int selinux_file_permission(struct file *file, int mask)
 	return selinux_revalidate_file_permission(file, mask);
 }
 
+/*
+ * for file context, we print both the fsec->sid and fsec->fown_sid
+ * as string representations, separated by ':::'
+ * We don't touch isid - if you wanted that set you shoulda set up the
+ * fs correctly.
+ */
+static inline char *selinux_file_checkpoint(void *security)

Why are these functions declared inline? In any event, just let the compiler figure out when to make them inline if appropriate.

Quoted 43 lines
security/selinux/hooks.c +43 -0
+static inline int selinux_file_restore(struct file *file, char *ctx)
+{
+	char *s1, *s2;
+	__u32 sid1 = 0, sid2 = 0;
+	int ret = -EINVAL;
+	struct file_security_struct *fsec = file->f_security;
+
+	/*
+	 * Objhash made sure the string is null-terminated.
+	 * We make a copy so we can mangle it.
+	 */
+	s1 = kstrdup(ctx, GFP_KERNEL);
+	if (!s1)
+		return -ENOMEM;
+	s2 = strstr(s1, ":::");
+	if (!s2)
+		goto out;
+
+	*s2 = '\0';
+	s2 += 3;
+	if (*s2 == '\0')
+		goto out;
+
+	/* SECSID_NULL is not valid for file sids */
+	if (strlen(s1) == 0 || strlen(s2) == 0)
+		goto out;
+
+	ret = security_context_to_sid(s1, strlen(s1), &sid1);
+	if (ret)
+		goto out;
+	ret = security_context_to_sid(s2, strlen(s2), &sid2);
+	if (ret)
+		goto out;
+
+	if (sid1 && fsec->sid != sid1) {
+		ret = avc_has_perm(current_sid(), sid1, SECCLASS_FILE,
+					FILE__RESTORE, NULL);
+		if (ret)
+			goto out;
+		fsec->sid = sid1;
+	}
+
+#if 0

security/selinux/hooks.c static int selinux_file_permission(struct file *file, int mask) · line 3058

Quoted 10 lines
security/selinux/hooks.c +10 -0
+	/* The following must wait - bc we don't yet support
+	 * c/r of fowners. */
+	if (sid2 && fsec->fown_sid != sid2) {
+		ret = avc_has_perm(current_sid(), sid2, SECCLASS_FILE,
+				FILE__FOWN_RESTORE, NULL);
+		if (ret)
+			goto out;
+	       fsec->fown_sid = sid2;
+	}
+#endif

I'm not sure why you can't enable this code yet. From your comment, it sounds like c/r doesn't yet handle the uid/euid in the fown_struct, but that doesn't mean you can't manage the fown_sid that we store in the file. We just leveraged the fact that a fown_struct is never outside the context of a containing struct file (at least from a send_sigio context) to avoid introducing a separate security field with its own lifecycle there.

Quoted 8 lines
security/selinux/hooks.c +4 -0
@@ -3219,6 +3322,187 @@ static int selinux_task_create(unsigned long clone_flags)
 	return current_has_perm(current, PROCESS__FORK);
 }
 
+#define NUMTASKSIDS 6
+/*
+ * for cred context, we print:
+ *   osid, sid, exec_sid, create_sid, keycreate_sid, sockcreate_sid;

security/selinux/hooks.c static int selinux_task_create(unsigned long clone_flags) · line 3338

Quoted 10 lines
security/selinux/hooks.c +10 -0
+ * as string representations, separated by ':::'
+ */
+static inline char *selinux_cred_checkpoint(void *security)
+{
+	struct task_security_struct *tsec = security;
+	char *stmp, *sfull = NULL;
+	__u32 slen, runlen;
+	int i, ret;
+	__u32 sids[NUMTASKSIDS] = { tsec->osid, tsec->sid, tsec->exec_sid,
+		tsec->create_sid, tsec->keycreate_sid, tsec->sockcreate_sid };

Why are you using __u32 rather than just u32? I think the former is only necessary in certain headers that might be shared with userspace?

security/selinux/hooks.c static int selinux_task_create(unsigned long clone_flags) · line 3400

Quoted 10 lines
security/selinux/hooks.c +10 -0
+static inline int selinux_cred_restore(struct file *file, struct cred *cred,
+					char *ctx)
+{
+	char *s, *s1, *s2 = NULL;
+	int ret = -EINVAL;
+	struct task_security_struct *tsec = cred->security;
+	int i;
+	__u32 sids[NUMTASKSIDS];
+	struct inode *ctx_inode = file->f_dentry->d_inode;
+	struct avc_audit_data ad;

audit code was refactored in mainline to share common data structures and code among security modules, so e.g. this became common_audit_data. Not sure what your baseline is, but this happened in July.

security/selinux/hooks.c static int selinux_task_create(unsigned long clone_flags) · line 3444

Quoted 11 lines
security/selinux/hooks.c +11 -0
+	/*
+	 * Check that these transitions are allowed, and effect them.
+	 * XXX: Do these checks suffice?
+	 */
+	if (tsec->osid != sids[0]) {
+		/*
+		 * Are any security decisions made based on osid?
+		 * Is it worth adding a PROCESS_RESTORE_OSID permission
+		 * for this?
+		 */
+		 tsec->osid = sids[0];

osid is only used in kernel permission checks upon a SID transition, and then it has been updated to ->sid prior to the transition. Userspace however may use it in a permission check (obtained via getprevcon) on the caller when the program runs in its own domain, e.g. passwd(1). I suppose there should be a check for it, although possibly it could be the same as for the ->sid (i.e. PROCESS__RESTORE).

security/selinux/include/av_perm_to_string.h

Quoted 4 lines
security/selinux/include/av_perm_to_string.h +0 -0
index 31df1d7..78945e7 100644

<snip>

Just FYI, this file goes away with the dynamic class/perm discovery patch that I've been posting to selinux list.

security/selinux/include/av_permissions.h

Quoted 4 lines
security/selinux/include/av_permissions.h +0 -0
index d645192..8e066ac 100644

<snip>

Likewise, this file goes away and is replaced by an automatically generated one from the new classmap.h file, which is the only kernel file you'll need to modify to add new permissions.

Signature · 2 lines
Stephen Smalley
National Security Agency
#12 lore raw

Re: [PATCH 3/3] cr: add selinux support (v4)

Quoted 22 lines · Stephen Smalley
Quoted 21 lines · Serge E. Hallyn

Documentation/checkpoint/readme.txt begins:
"""
Application checkpoint/restart is the ability to save the state of a running application so that it can later resume its execution from the time at which it was checkpointed.
"""

This patch adds the ability to checkpoint and restore selinux contexts for tasks, open files, and sysvipc objects. Contexts are checkpointed as strings. For tasks and files, where a security struct actually points to several contexts, all contexts are written out in one string, separated by ':::'.

security/selinux/hooks.c +0 -0
index 8d8b69c..4fb8b5d 100644
@@ -2961,6 +2962,108 @@ static int selinux_file_permission(struct file *file, int mask)
 	return selinux_revalidate_file_permission(file, mask);
 }
 
Quoted 7 lines

security/selinux/hooks.c static int selinux_file_permission(struct file *file, int mask) · line 2971

Quoted 7 lines
security/selinux/hooks.c +7 -0
+/*
+ * for file context, we print both the fsec->sid and fsec->fown_sid
+ * as string representations, separated by ':::'
+ * We don't touch isid - if you wanted that set you shoulda set up the
+ * fs correctly.
+ */
+static inline char *selinux_file_checkpoint(void *security)

Thanks for looking it over again, Stephen.

Quoted 2 lines

Why are these functions declared inline? In any event, just let the compiler figure out when to make them inline if appropriate.

Yikes, I don't know. Must have cut-n-pasted the prototypes from include/linux/security.h. Fixed below.

Quoted 54 lines
Quoted 43 lines
security/selinux/hooks.c +43 -0
+static inline int selinux_file_restore(struct file *file, char *ctx)
+{
+	char *s1, *s2;
+	__u32 sid1 = 0, sid2 = 0;
+	int ret = -EINVAL;
+	struct file_security_struct *fsec = file->f_security;
+
+	/*
+	 * Objhash made sure the string is null-terminated.
+	 * We make a copy so we can mangle it.
+	 */
+	s1 = kstrdup(ctx, GFP_KERNEL);
+	if (!s1)
+		return -ENOMEM;
+	s2 = strstr(s1, ":::");
+	if (!s2)
+		goto out;
+
+	*s2 = '\0';
+	s2 += 3;
+	if (*s2 == '\0')
+		goto out;
+
+	/* SECSID_NULL is not valid for file sids */
+	if (strlen(s1) == 0 || strlen(s2) == 0)
+		goto out;
+
+	ret = security_context_to_sid(s1, strlen(s1), &sid1);
+	if (ret)
+		goto out;
+	ret = security_context_to_sid(s2, strlen(s2), &sid2);
+	if (ret)
+		goto out;
+
+	if (sid1 && fsec->sid != sid1) {
+		ret = avc_has_perm(current_sid(), sid1, SECCLASS_FILE,
+					FILE__RESTORE, NULL);
+		if (ret)
+			goto out;
+		fsec->sid = sid1;
+	}
+
+#if 0

security/selinux/hooks.c static int selinux_file_permission(struct file *file, int mask) · line 3024

Quoted 10 lines
security/selinux/hooks.c +10 -0
+	/* The following must wait - bc we don't yet support
+	 * c/r of fowners. */
+	if (sid2 && fsec->fown_sid != sid2) {
+		ret = avc_has_perm(current_sid(), sid2, SECCLASS_FILE,
+				FILE__FOWN_RESTORE, NULL);
+		if (ret)
+			goto out;
+	       fsec->fown_sid = sid2;
+	}
+#endif
Quoted 7 lines

I'm not sure why you can't enable this code yet. From your comment, it sounds like c/r doesn't yet handle the uid/euid in the fown_struct, but that doesn't mean you can't manage the fown_sid that we store in the file. We just leveraged the fact that a fown_struct is never outside the context of a containing struct file (at least from a send_sigio context) to avoid introducing a separate security field with its own lifecycle there.

Ok, I enabled it (with no resulting problems).

Quoted 13 lines
Quoted 13 lines
security/selinux/hooks.c +9 -0
@@ -3219,6 +3322,187 @@ static int selinux_task_create(unsigned long clone_flags)
 	return current_has_perm(current, PROCESS__FORK);
 }
 
+#define NUMTASKSIDS 6
+/*
+ * for cred context, we print:
+ *   osid, sid, exec_sid, create_sid, keycreate_sid, sockcreate_sid;
+ * as string representations, separated by ':::'
+ */
+static inline char *selinux_cred_checkpoint(void *security)
+{
+	struct task_security_struct *tsec = security;
Quoted 8 lines

security/selinux/hooks.c static int selinux_task_create(unsigned long clone_flags) · line 3338

Quoted 5 lines
security/selinux/hooks.c +5 -0
+	char *stmp, *sfull = NULL;
+	__u32 slen, runlen;
+	int i, ret;
+	__u32 sids[NUMTASKSIDS] = { tsec->osid, tsec->sid, tsec->exec_sid,
+		tsec->create_sid, tsec->keycreate_sid, tsec->sockcreate_sid };

Why are you using __u32 rather than just u32? I think the former is only necessary in certain headers that might be shared with userspace?

Changed below

Quoted 6 lines
Quoted 6 lines
security/selinux/hooks.c +6 -0
+static inline int selinux_cred_restore(struct file *file, struct cred *cred,
+					char *ctx)
+{
+	char *s, *s1, *s2 = NULL;
+	int ret = -EINVAL;
+	struct task_security_struct *tsec = cred->security;
Quoted 8 lines

security/selinux/hooks.c static int selinux_task_create(unsigned long clone_flags) · line 3348

Quoted 4 lines
security/selinux/hooks.c +4 -0
+	int i;
+	__u32 sids[NUMTASKSIDS];
+	struct inode *ctx_inode = file->f_dentry->d_inode;
+	struct avc_audit_data ad;

audit code was refactored in mainline to share common data structures and code among security modules, so e.g. this became common_audit_data. Not sure what your baseline is, but this happened in July.

It was merged by Linus on Sep 11, though, which is 2 days after our latest c/r port to his tree :)

Quoted 11 lines
Quoted 11 lines
security/selinux/hooks.c +10 -0
+	/*
+	 * Check that these transitions are allowed, and effect them.
+	 * XXX: Do these checks suffice?
+	 */
+	if (tsec->osid != sids[0]) {
+		/*
+		 * Are any security decisions made based on osid?
+		 * Is it worth adding a PROCESS_RESTORE_OSID permission
+		 * for this?
+		 */
Quoted 8 lines

security/selinux/hooks.c static int selinux_task_create(unsigned long clone_flags) · line 3359

Quoted 1 line
security/selinux/hooks.c +1 -0
+		 tsec->osid = sids[0];

osid is only used in kernel permission checks upon a SID transition, and then it has been updated to ->sid prior to the transition. Userspace however may use it in a permission check (obtained via getprevcon) on the caller when the program runs in its own domain, e.g. passwd(1). I suppose there should be a check for it, although possibly it could be the same as for the ->sid (i.e. PROCESS__RESTORE).

Ok, done.

Quoted 15 lines

security/selinux/include/av_perm_to_string.h

Quoted 4 lines
security/selinux/include/av_perm_to_string.h +0 -0
index 31df1d7..78945e7 100644

<snip>

Just FYI, this file goes away with the dynamic class/perm discovery patch that I've been posting to selinux list.

Quoted 4 lines
security/selinux/include/av_permissions.h +0 -0
index d645192..8e066ac 100644

<snip>

Quoted 3 lines

Likewise, this file goes away and is replaced by an automatically generated one from the new classmap.h file, which is the only kernel file you'll need to modify to add new permissions.

Ok, that's nice actually.

So I have some work to do when we re-base to Linus' tree, but in the meantime, here is a version addressing the rest of the comments. Or would you prefer I wait and resend after a re-base?

thanks,
-serge

From 77a3a47895fd43e1593752a79b0b09d40744fb41 Mon Sep 17 00:00:00 2001
From: Serge E. Hallyn <[email protected]>
Date: Thu, 27 Aug 2009 08:19:36 -0700
Subject: [PATCH 1/1] cr: add selinux support (v5)

Documentation/checkpoint/readme.txt begins:
"""
Application checkpoint/restart is the ability to save the state of a running application so that it can later resume its execution from the time at which it was checkpointed.
"""

This patch adds the ability to checkpoint and restore selinux contexts for tasks, open files, and sysvipc objects. Contexts are checkpointed as strings. For tasks and files, where a security struct actually points to several contexts, all contexts are written out in one string, separated by ':::'.

The default behaviors are to checkpoint contexts, but not to restore them. To attempt to restore them, sys_restart() must be given the RESTART_KEEP_LSM flag. If this is given then the caller of sys_restart() must have the new 'restore' permission to the target objclass, or for instance PROCESS__SETFSCREATE to itself to specify a create_sid.

There are some tests under cr_tests/selinux at
git://git.sr71.net/~hallyn/cr_tests.git.

A corresponding simple refpolicy (and /usr/share/selinux/devel/include) patch is needed.

The programs to checkpoint and restart (called 'checkpoint' and 'restart') come from git://git.ncl.cs.columbia.edu/pub/git/user-cr.git.
This patch applies against the checkpoint/restart-enabled kernel tree at git://git.ncl.cs.columbia.edu/pub/git/linux-cr.git/.

Changelog:
oct 02: (Stephen Smalley suggestions):
1. s/__u32/u32/
2. enable the fown sid restoration
3. use process_restore to authorize resetting osid
4. don't make new hooks inline.
oct 01: Remove some debugging that is redundant with
avc log data.
sep 10: (Most addressing suggestions by Stephen Smalley)
1. change xyz_get_ctx() to xyz_checkpoint().
2. check entrypoint permission on cred_restore
3. always dec context length by 1
4. don't allow SECSID_NULL when that's not valid
5. when SECSID_NULL is valid, restore it
6. c/r task->osid
7. Just print nothing instead of 'null' for SECSID_NULL
8. sids are __u32, as are lenghts passed to sid_to_context.

---
 checkpoint/restart.c                         |    1 +
 kernel/cred.c                                |    2 +
 security/selinux/hooks.c                     |  367 ++++++++++++++++++++++++++
 security/selinux/include/av_perm_to_string.h |    5 +
 security/selinux/include/av_permissions.h    |    5 +
 5 files changed, 380 insertions(+), 0 deletions(-)
checkpoint/restart.c +1 -0
index 55bd2b5..008a116 100644
@@ -471,6 +471,7 @@ static int restore_read_header(struct ckpt_ctx *ctx)
 		/* to be implemented later, per-lsm */
 		if (strcmp(ctx->lsm_name, "lsm_none") != 0 &&
 				strcmp(ctx->lsm_name, "smack") != 0 &&
+				strcmp(ctx->lsm_name, "selinux") != 0 &&
 				strcmp(ctx->lsm_name, "default") != 0) {
 			pr_warning("c/r: RESTART_KEEP_LSM unsupported for %s\n",
 					ctx->lsm_name);
kernel/cred.c +2 -0
index 06bc676..5eb09b8 100644
@@ -732,6 +732,8 @@ static int do_checkpoint_cred(struct ckpt_ctx *ctx, struct cred *cred)
 	if (!h)
 		return -ENOMEM;
 
+	ckpt_debug("cred uid %d fsuid %d gid %d secref %d\n", cred->uid,
+		cred->fsuid, cred->gid, sec_ref);
 	h->uid = cred->uid;
 	h->suid = cred->suid;
 	h->euid = cred->euid;
security/selinux/hooks.c +367 -0

417 lines not on this page · raw message

security/selinux/include/av_perm_to_string.h +5 -0
index 31df1d7..a2c35d7 100644
@@ -19,6 +19,8 @@
    S_(SECCLASS_FILE, FILE__ENTRYPOINT, "entrypoint")
    S_(SECCLASS_FILE, FILE__EXECMOD, "execmod")
    S_(SECCLASS_FILE, FILE__OPEN, "open")
+   S_(SECCLASS_FILE, FILE__RESTORE, "restore")
+   S_(SECCLASS_FILE, FILE__FOWN_RESTORE, "fown_restore")
    S_(SECCLASS_CHR_FILE, CHR_FILE__EXECUTE_NO_TRANS, "execute_no_trans")
    S_(SECCLASS_CHR_FILE, CHR_FILE__ENTRYPOINT, "entrypoint")
    S_(SECCLASS_CHR_FILE, CHR_FILE__EXECMOD, "execmod")
@@ -88,9 +90,11 @@
    S_(SECCLASS_PROCESS, PROCESS__EXECHEAP, "execheap")
    S_(SECCLASS_PROCESS, PROCESS__SETKEYCREATE, "setkeycreate")
    S_(SECCLASS_PROCESS, PROCESS__SETSOCKCREATE, "setsockcreate")
+   S_(SECCLASS_PROCESS, PROCESS__RESTORE, "restore")
    S_(SECCLASS_MSGQ, MSGQ__ENQUEUE, "enqueue")
    S_(SECCLASS_MSG, MSG__SEND, "send")
    S_(SECCLASS_MSG, MSG__RECEIVE, "receive")
+   S_(SECCLASS_MSG, MSG__RESTORE, "restore")
    S_(SECCLASS_SHM, SHM__LOCK, "lock")
    S_(SECCLASS_SECURITY, SECURITY__COMPUTE_AV, "compute_av")
    S_(SECCLASS_SECURITY, SECURITY__COMPUTE_CREATE, "compute_create")
@@ -107,6 +111,7 @@
    S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_READ, "syslog_read")
    S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_MOD, "syslog_mod")
    S_(SECCLASS_SYSTEM, SYSTEM__SYSLOG_CONSOLE, "syslog_console")
+   S_(SECCLASS_IPC, IPC__RESTORE, "restore")
    S_(SECCLASS_CAPABILITY, CAPABILITY__CHOWN, "chown")
    S_(SECCLASS_CAPABILITY, CAPABILITY__DAC_OVERRIDE, "dac_override")
    S_(SECCLASS_CAPABILITY, CAPABILITY__DAC_READ_SEARCH, "dac_read_search")
security/selinux/include/av_permissions.h +5 -0
index d645192..58ad588 100644
@@ -101,6 +101,8 @@
 #define FILE__ENTRYPOINT                          0x00040000UL
 #define FILE__EXECMOD                             0x00080000UL
 #define FILE__OPEN                                0x00100000UL
+#define FILE__RESTORE                             0x00200000UL
+#define FILE__FOWN_RESTORE                        0x00400000UL
 #define LNK_FILE__IOCTL                           0x00000001UL
 #define LNK_FILE__READ                            0x00000002UL
 #define LNK_FILE__WRITE                           0x00000004UL
@@ -453,6 +455,7 @@
 #define PROCESS__EXECHEAP                         0x08000000UL
 #define PROCESS__SETKEYCREATE                     0x10000000UL
 #define PROCESS__SETSOCKCREATE                    0x20000000UL
+#define PROCESS__RESTORE	                  0x40000000UL
 #define IPC__CREATE                               0x00000001UL
 #define IPC__DESTROY                              0x00000002UL
 #define IPC__GETATTR                              0x00000004UL
@@ -462,6 +465,7 @@
 #define IPC__ASSOCIATE                            0x00000040UL
 #define IPC__UNIX_READ                            0x00000080UL
 #define IPC__UNIX_WRITE                           0x00000100UL
+#define IPC__RESTORE                              0x00000200UL
 #define SEM__CREATE                               0x00000001UL
 #define SEM__DESTROY                              0x00000002UL
 #define SEM__GETATTR                              0x00000004UL
@@ -483,6 +487,7 @@
 #define MSGQ__ENQUEUE                             0x00000200UL
 #define MSG__SEND                                 0x00000001UL
 #define MSG__RECEIVE                              0x00000002UL
+#define MSG__RESTORE                              0x00000004UL
 #define SHM__CREATE                               0x00000001UL
 #define SHM__DESTROY                              0x00000002UL
 #define SHM__GETATTR                              0x00000004UL
Signature · 1 line
1.6.1
#13 lore raw

Re: [PATCH 3/3] cr: add selinux support (v4)

In reply to Serge E. Hallyn
Quoted 44 lines · Serge E. Hallyn

Documentation/checkpoint/readme.txt begins:
"""
Application checkpoint/restart is the ability to save the state of a running application so that it can later resume its execution from the time at which it was checkpointed.
"""

This patch adds the ability to checkpoint and restore selinux contexts for tasks, open files, and sysvipc objects. Contexts are checkpointed as strings. For tasks and files, where a security struct actually points to several contexts, all contexts are written out in one string, separated by ':::'.

The default behaviors are to checkpoint contexts, but not to restore them. To attempt to restore them, sys_restart() must be given the RESTART_KEEP_LSM flag. If this is given then the caller of sys_restart() must have the new 'restore' permission to the target objclass, or for instance PROCESS__SETFSCREATE to itself to specify a create_sid.

There are some tests under cr_tests/selinux at
git://git.sr71.net/~hallyn/cr_tests.git.

A corresponding simple refpolicy (and /usr/share/selinux/devel/include) patch is needed.

The programs to checkpoint and restart (called 'checkpoint' and 'restart') come from git://git.ncl.cs.columbia.edu/pub/git/user-cr.git.
This patch applies against the checkpoint/restart-enabled kernel tree at git://git.ncl.cs.columbia.edu/pub/git/linux-cr.git/.

Changelog:
oct 01: Remove some debugging that is redundant with
avc log data.
sep 10: (Most addressing suggestions by Stephen Smalley)
1. change xyz_get_ctx() to xyz_checkpoint().
2. check entrypoint permission on cred_restore
3. always dec context length by 1
4. don't allow SECSID_NULL when that's not valid
5. when SECSID_NULL is valid, restore it
6. c/r task->osid
7. Just print nothing instead of 'null' for SECSID_NULL
8. sids are __u32, as are lenghts passed to sid_to_context.

Quoted 2 lines

I don't know much about SElinux, so this is only for the strict c/r code...

Quoted 13 lines
---
 checkpoint/restart.c                         |    1 +
 kernel/cred.c                                |    2 +
 security/selinux/hooks.c                     |  371 ++++++++++++++++++++++++++
 security/selinux/include/av_perm_to_string.h |    4 +
 security/selinux/include/av_permissions.h    |    4 +
 5 files changed, 382 insertions(+), 0 deletions(-)
checkpoint/restart.c +0 -0
index 55bd2b5..008a116 100644

checkpoint/restart.c static int restore_read_header(struct ckpt_ctx *ctx) · line 475

Quoted 5 lines
checkpoint/restart.c +1 -0
@@ -471,6 +471,7 @@ static int restore_read_header(struct ckpt_ctx *ctx)
 		/* to be implemented later, per-lsm */
 		if (strcmp(ctx->lsm_name, "lsm_none") != 0 &&
 				strcmp(ctx->lsm_name, "smack") != 0 &&
+				strcmp(ctx->lsm_name, "selinux") != 0 &&
 				strcmp(ctx->lsm_name, "default") != 0) {

If we expect this to grow, it may make sense to look it up in an array.

kernel/cred.c static int do_checkpoint_cred(struct ckpt_ctx *ctx, struct cred *cred) · line 736

Quoted 12 lines
checkpoint/restart.c +0 -0
 			pr_warning("c/r: RESTART_KEEP_LSM unsupported for %s\n",
 					ctx->lsm_name);
kernel/cred.c +2 -0
index 06bc676..5eb09b8 100644
@@ -732,6 +732,8 @@ static int do_checkpoint_cred(struct ckpt_ctx *ctx, struct cred *cred)
 	if (!h)
 		return -ENOMEM;
 
+	ckpt_debug("cred uid %d fsuid %d gid %d secref %d\n", cred->uid,
+		cred->fsuid, cred->gid, sec_ref);

Please place this (and a few others also in other patches) debug-only changes in a separate patch - it will make my life tremendously easier when merging v18-dev to a nice and clean v19.

[...]

Quoted 11 lines
kernel/cred.c +11 -0
+static inline char *selinux_file_checkpoint(void *security)
+{
+	struct file_security_struct *fsec = security;
+	char *s1 = NULL, *s2 = NULL, *sfull;
+	__u32 len1, len2, lenfull;
+	int ret;
+
+	if (fsec->sid == 0 || fsec->fown_sid == 0)
+		return ERR_PTR(-EINVAL);
+
+	ret = security_sid_to_context(fsec->sid, &s1, &len1);

kernel/cred.c static int do_checkpoint_cred(struct ckpt_ctx *ctx, struct cred *cred)

Quoted 10 lines
kernel/cred.c +10 -0
+	if (ret)
+		return ERR_PTR(ret);
+	len1--;
+	ret = security_sid_to_context(fsec->fown_sid, &s2, &len2);
+	if (ret) {
+		kfree(s1);
+		return ERR_PTR(ret);
+	}
+	len2--;
+	lenfull = len1+len2+3;

Would checkpatch.pl complain about no spaces here ?

[...]

Hmm... the rest doesn't make sense to me anyway :o

Oren.

#14 lore raw

Re: [PATCH 3/3] cr: add selinux support (v4)

Quoted 15 lines · Oren Laadan

checkpoint/restart.c static int restore_read_header(struct ckpt_ctx *ctx) · line 475

Quoted 10 lines · Serge E. Hallyn
checkpoint/restart.c +1 -0
index 55bd2b5..008a116 100644
@@ -471,6 +471,7 @@ static int restore_read_header(struct ckpt_ctx *ctx)
 		/* to be implemented later, per-lsm */
 		if (strcmp(ctx->lsm_name, "lsm_none") != 0 &&
 				strcmp(ctx->lsm_name, "smack") != 0 &&
+				strcmp(ctx->lsm_name, "selinux") != 0 &&
 				strcmp(ctx->lsm_name, "default") != 0) {

If we expect this to grow, it may make sense to look it up in an array.

We don't :) The only other LSM in the kernel right now is TOMOYO.

Quoted 10 lines
Quoted 10 lines
checkpoint/restart.c +0 -0
 			pr_warning("c/r: RESTART_KEEP_LSM unsupported for %s\n",
 					ctx->lsm_name);
kernel/cred.c +0 -0
index 06bc676..5eb09b8 100644
@@ -732,6 +732,8 @@ static int do_checkpoint_cred(struct ckpt_ctx *ctx, struct cred *cred)
 	if (!h)
 		return -ENOMEM;
 
Quoted 6 lines

kernel/cred.c static int do_checkpoint_cred(struct ckpt_ctx *ctx, struct cred *cred) · line 736

Quoted 2 lines
kernel/cred.c +2 -0
+	ckpt_debug("cred uid %d fsuid %d gid %d secref %d\n", cred->uid,
+		cred->fsuid, cred->gid, sec_ref);

Please place this (and a few others also in other patches) debug-only changes in a separate patch - it will make my life tremendously easier when merging v18-dev to a nice and clean v19.

Ok, I'll resend those just to containers@ to spare the lsm folks.

Quoted 17 lines

[...]

Quoted 15 lines
kernel/cred.c +15 -0
+static inline char *selinux_file_checkpoint(void *security)
+{
+	struct file_security_struct *fsec = security;
+	char *s1 = NULL, *s2 = NULL, *sfull;
+	__u32 len1, len2, lenfull;
+	int ret;
+
+	if (fsec->sid == 0 || fsec->fown_sid == 0)
+		return ERR_PTR(-EINVAL);
+
+	ret = security_sid_to_context(fsec->sid, &s1, &len1);
+	if (ret)
+		return ERR_PTR(ret);
+	len1--;
+	ret = security_sid_to_context(fsec->fown_sid, &s2, &len2);
Quoted 8 lines

kernel/cred.c

Quoted 6 lines
kernel/cred.c +6 -0
+	if (ret) {
+		kfree(s1);
+		return ERR_PTR(ret);
+	}
+	len2--;
+	lenfull = len1+len2+3;

Would checkpatch.pl complain about no spaces here ?

Hmm, it doesn't, actually... you'd think it should! I'll change that in the split-up version I'll send in a bit.

thanks,
-serge

#15 lore raw

Re: [PATCH 3/3] cr: add selinux support (v4)

Quoted 6 lines · Serge E. Hallyn
Quoted 3 lines · Oren Laadan

Please place this (and a few others also in other patches) debug-only changes in a separate patch - it will make my life tremendously easier when merging v18-dev to a nice and clean v19.

Ok, I'll resend those just to containers@ to spare the lsm folks.

Oops, I was thinking this was the patch 1/3. I won't spare the lsm folks from revised patches 2/3 or 3/3 :)

-serge