Skip to contentSkip to conversation

debug: add a few ckpt_debugs

PATCH In review Serge E. Hallyn 5 participants 11 messages Oct 9, 2009 – Oct 16, 2009 4 messages not in the archive

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

PATCH 1/4 debug: add a few ckpt_debugs

[
this set is available at
http://git.kernel.org/gitweb.cgi?p=linux/kernel/git/sergeh/linux-cr.git;a=shortlog;h=refs/heads/oct9.lsm5
]

These were pulled out of the lsm-related patches into which they had been embedded.

---
 checkpoint/files.c   |    3 +++
 checkpoint/process.c |   20 ++++++++++++++++----
 kernel/cred.c        |    2 ++
 3 files changed, 21 insertions(+), 4 deletions(-)
checkpoint/files.c +3 -0
index 27e29a0..f6de07e 100644
@@ -159,6 +159,9 @@ int checkpoint_file_common(struct ckpt_ctx *ctx, struct file *file,
 	if (h->f_credref < 0)
 		return h->f_credref;
 
+	ckpt_debug("file %s credref %d", file->f_dentry->d_name.name,
+		h->f_credref);
+
 	/* FIX: need also file->f_owner, etc */
 
 	return 0;
checkpoint/process.c +16 -4
index c51e036..7463158 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 realcred (ref %d)\n",
+			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)\n",
+			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\n", 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 < 0) {
+		ckpt_debug("restore_task_creds returned %d\n", ret);
+		return ret;
+	}
+	ret = restore_task_ns(ctx);
+	if (ret < 0) {
+		ckpt_debug("restore_task_ns returned %d\n", 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\n");
 		return PTR_ERR(h);
+	}
 
 	ret = restore_obj_file_table(ctx, h->files_objref);
 	ckpt_debug("file_table: ret %d (%p)\n", ret, current->files);
kernel/cred.c +2 -0
index 9710cae..62d28a4 100644
@@ -724,6 +724,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\n", cred->uid, cred->fsuid,
+			cred->gid);
 	h->uid = cred->uid;
 	h->suid = cred->suid;
 	h->euid = cred->euid;
Signature · 1 line
1.6.1

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

#2 lore raw

PATCH 2/4 cr: add generic LSM c/r 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 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)

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. oct 05: address set of Oren comments, including:
1. fix memleak in restore_msg_contents_one
2. use a separate container checkpoint image section
3. define SECURITY_CTX_NONE
4. allocate the right size to l in security_checkpoint_obj
5. fix ckpt_hdr_lsm alignment
oct 09: at checkpoint, key on the void*security in the objhash,
and don't cache the ckpt_stored_lsm at all. At restart, do_restore_security (now moved to security/security.c) creates and caches the ckpt_stored_lsm.

---
 Documentation/checkpoint/readme.txt |   37 ++++++-
 checkpoint/checkpoint.c             |   29 +++++
 checkpoint/files.c                  |   35 ++++++-
 checkpoint/objhash.c                |   70 +++++++++++--
 checkpoint/restart.c                |   61 +++++++++++-
 checkpoint/sys.c                    |   22 ++++
 include/linux/checkpoint.h          |   23 ++++-
 include/linux/checkpoint_hdr.h      |   39 +++++++
 include/linux/checkpoint_types.h    |    9 ++
 include/linux/security.h            |  198 +++++++++++++++++++++++++++++++++++
 ipc/checkpoint.c                    |   35 +++++--
 ipc/checkpoint_msg.c                |   28 +++++-
 ipc/checkpoint_sem.c                |    4 +-
 ipc/checkpoint_shm.c                |    4 +-
 ipc/util.h                          |    6 +-
 kernel/cred.c                       |   24 ++++-
 security/capability.c               |   72 +++++++++++++
 security/security.c                 |  187 +++++++++++++++++++++++++++++++++
 18 files changed, 844 insertions(+), 39 deletions(-)
Documentation/checkpoint/readme.txt +34 -3
index 571c469..9c6422c 100644
@@ -161,9 +161,10 @@ in-userspace conversion tools.
 
 The general format of the checkpoint image is as follows:
 1. Image header
-2. Task hierarchy
-3. Tasks' state
-4. Image trailer
+2. Container configuration
+3. Task hierarchy
+4. Tasks' state
+5. Image trailer
 
 The image always begins with a general header that holds a magic
 number, an architecture identifier (little endian format), a format
@@ -172,6 +173,11 @@ version number (@rev), followed by information about the kernel
 checkpoint and the flags given to sys_checkpoint(). This header is
 followed by an arch-specific header.
 
+The container configuration section contains details about the
+security (LSM) configuration.  Network configuration and
+container-wide mounts may also go here, so that the userspace
+restart coordinator can re-create a suitable environment.
+
 The task hierarchy comes next so that userspace tools can read it
 early (even from a stream) and re-create the restarting tasks. This is
 basically an array of all checkpointed tasks, and their relationships
@@ -333,6 +339,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 +29 -0
index eaa9105..b258883 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>
 
@@ -354,6 +355,31 @@ static int checkpoint_write_header(struct ckpt_ctx *ctx)
 	return checkpoint_write_header_arch(ctx);
 }
 
+/* write the container configuration section */
+static int checkpoint_container(struct ckpt_ctx *ctx)
+{
+	struct ckpt_hdr_container *h;
+	int ret;
+
+	h = ckpt_hdr_get_type(ctx, sizeof(*h), CKPT_HDR_CONTAINER);
+	if (!h)
+		return -ENOMEM;
+	ret = ckpt_write_obj(ctx, &h->h);
+	ckpt_hdr_put(ctx, h);
+	if (ret < 0)
+		return ret;
+
+	memset(ctx->lsm_name, 0, CHECKPOINT_LSM_NAME_MAX + 1);
+	strlcpy(ctx->lsm_name, security_get_lsm_name(),
+				CHECKPOINT_LSM_NAME_MAX + 1);
+	ret = ckpt_write_buffer(ctx, ctx->lsm_name,
+				CHECKPOINT_LSM_NAME_MAX + 1);
+	if (ret < 0)
+		return ret;
+
+	return security_checkpoint_header(ctx);
+}
+
 /* write the checkpoint trailer */
 static int checkpoint_write_tail(struct ckpt_ctx *ctx)
 {
@@ -765,6 +791,9 @@ long do_checkpoint(struct ckpt_ctx *ctx, pid_t pid)
 	ret = checkpoint_write_header(ctx);
 	if (ret < 0)
 		goto out;
+	ret = checkpoint_container(ctx);
+	if (ret < 0)
+		goto out;
 	ret = checkpoint_tree(ctx);
 	if (ret < 0)
 		goto out;
checkpoint/files.c +33 -2
index f6de07e..6561ab5 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,8 +172,15 @@ int checkpoint_file_common(struct ckpt_ctx *ctx, struct file *file,
 	if (h->f_credref < 0)
 		return h->f_credref;
 
-	ckpt_debug("file %s credref %d", file->f_dentry->d_name.name,
-		h->f_credref);
+	h->f_secref = checkpoint_file_security(ctx, file);
+	if (h->f_secref == -EOPNOTSUPP)
+		h->f_secref = SECURITY_CTX_NONE;
+	else if (h->f_secref < 0)
+		return h->f_secref;
+
+	ckpt_debug("file %s credref %d secref %d\n",
+		file->f_dentry->d_name.name, h->f_credref,
+		h->f_secref);
 
 	/* FIX: need also file->f_owner, etc */
 
@@ -510,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 (ckpt_restore_lsm_label(ctx, h->f_secref)) {
+		struct ckpt_stored_lsm *l;
+		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 +60 -10

106 lines not on this page · raw message

checkpoint/restart.c +60 -1

79 lines not on this page · raw message

checkpoint/sys.c +22 -0
index 260a1ee..05370d3 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 +22 -1
index dd75bc2..19d0274 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,
@@ -77,6 +82,8 @@ extern int ckpt_write_string(struct ckpt_ctx *ctx, char *str, int len);
 extern void __ckpt_write_err(struct ckpt_ctx *ctx, char *fmt0, char *fmt, ...);
 extern int ckpt_write_err(struct ckpt_ctx *ctx, char *fmt0, char *fmt, ...);
 
+extern int _ckpt_read_obj(struct ckpt_ctx *ctx, struct ckpt_hdr *h,
+			  void *ptr, int len, int max);
 extern int _ckpt_read_obj_type(struct ckpt_ctx *ctx,
 			       void *ptr, int len, int type);
 extern int _ckpt_read_buffer(struct ckpt_ctx *ctx, void *ptr, int len);
@@ -125,6 +132,8 @@ extern void ckpt_obj_hash_free(struct ckpt_ctx *ctx);
 extern int ckpt_obj_hash_alloc(struct ckpt_ctx *ctx);
 
 extern int restore_obj(struct ckpt_ctx *ctx, struct ckpt_hdr_objref *h);
+extern int ckpt_write_objref(struct ckpt_ctx *ctx, enum obj_type type,
+			     int ref);
 extern int checkpoint_obj(struct ckpt_ctx *ctx, void *ptr,
 			  enum obj_type type);
 extern int ckpt_obj_collect(struct ckpt_ctx *ctx, void *ptr,
@@ -370,6 +379,18 @@ static inline void restore_debug_free(struct ckpt_ctx *ctx) {}
 
 #endif /* CONFIG_CHECKPOINT_DEBUG */
 
+/*
+ * We restore a security label only if
+ * 1. sys_restart specified RESTART_KEEP_LSM
+ * 2. the checkpointed security context was not SECURITY_CTX_NONE
+ */
+static inline int ckpt_restore_lsm_label(struct ckpt_ctx *ctx, int sec_ref)
+{
+	if ((ctx->uflags & RESTART_KEEP_LSM) && (sec_ref != SECURITY_CTX_NONE))
+		return 1;
+	return 0;
+}
+
 #endif /* CONFIG_CHECKPOINT */
 #endif /* __KERNEL__ */
 
include/linux/checkpoint_hdr.h +39 -0
index b5f958e..69b14b3 100644
@@ -23,6 +23,16 @@
 #endif
 
 /*
+ * /usr/include/linux/security.h sometimes does not exist, so
+ * we need this value here for userspace restart.c to read.
+ *
+ * CHECKPOINT_LSM_NAME_MAX should be SECURITY_NAME_MAX
+ * But I don't want to #include it here to do a
+ * BUILD_BUG_ON(CHECKPOINT_LSM_NAME_MAX!=SECURITY_NAME_MAX)
+ */
+#define CHECKPOINT_LSM_NAME_MAX 10
+
+/*
  * To maintain compatibility between 32-bit and 64-bit architecture flavors,
  * keep data 64-bit aligned: use padding for structure members, and use
  * __attribute__((aligned (8))) for the entire structure.
@@ -57,9 +67,12 @@ struct ckpt_hdr {
 enum {
 	CKPT_HDR_HEADER = 1,
 	CKPT_HDR_HEADER_ARCH,
+	CKPT_HDR_CONTAINER,
 	CKPT_HDR_BUFFER,
 	CKPT_HDR_STRING,
 	CKPT_HDR_OBJREF,
+	CKPT_HDR_SEC,
+	CKPT_HDR_LSM_INFO,
 
 	CKPT_HDR_TREE = 101,
 	CKPT_HDR_TASK,
@@ -149,6 +162,8 @@ enum obj_type {
 	CKPT_OBJ_GROUPINFO,
 	CKPT_OBJ_SOCK,
 	CKPT_OBJ_TTY,
+	CKPT_OBJ_CHECKPOINT_SEC,
+	CKPT_OBJ_SEC,
 	CKPT_OBJ_MAX
 };
 
@@ -174,6 +189,16 @@ struct ckpt_const {
 	__u16 tty_termios_ncc;
 } __attribute__((aligned(8)));
 
+/* container configuration section header */
+struct ckpt_hdr_container {
+	struct ckpt_hdr h;
+	/*
+	 * the header is followed by the string:
+	 *   char lsm_name[SECURITY_NAME_MAX + 1]
+	 * plus the CKPT_HDR_LSM_INFO section
+	 */
+};
+
 /* checkpoint image header */
 struct ckpt_hdr_header {
 	struct ckpt_hdr h;
@@ -268,6 +293,7 @@ struct ckpt_hdr_cred {
 	__u32 gid, sgid, egid, fsgid;
 	__s32 user_ref;
 	__s32 groupinfo_ref;
+	__s32 sec_ref;
 	struct ckpt_capabilities cap_s;
 } __attribute__((aligned(8)));
 
@@ -280,6 +306,16 @@ struct ckpt_hdr_groupinfo {
 	__u32 groups[0];
 } __attribute__((aligned(8)));
 
+struct ckpt_hdr_lsm {
+	__u8 sectype;
+	__u8 padding;
+	__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
@@ -395,6 +431,7 @@ struct ckpt_hdr_file {
 	__s32 f_credref;
 	__u64 f_pos;
 	__u64 f_version;
+	__s32 f_secref;
 } __attribute__((aligned(8)));
 
 struct ckpt_hdr_file_generic {
@@ -645,6 +682,7 @@ struct ckpt_hdr_ipc_perms {
 	__u32 mode;
 	__u32 _padding;
 	__u64 seq;
+	__s32 sec_ref;
 } __attribute__((aligned(8)));
 
 struct ckpt_hdr_ipc_shm {
@@ -678,6 +716,7 @@ struct ckpt_hdr_ipc_msg_msg {
 	struct ckpt_hdr h;
 	__s32 m_type;
 	__u32 m_ts;
+	__s32 sec_ref;
 } __attribute__((aligned(8)));
 
 struct ckpt_hdr_ipc_sem {
include/linux/checkpoint_types.h +9 -0
index fa57cdc..8e29d5f 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 */
@@ -87,6 +89,13 @@ struct ckpt_ctx {
 #endif
 };
 
+/* 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 +198 -0

334 lines not on this page · raw message

ipc/checkpoint.c +25 -10
index 8e6e9ba..e7be1fa 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 = SECURITY_CTX_NONE;
+		else if (h->sec_ref < 0)
+			return h->sec_ref;
+	} else
+		h->sec_ref = SECURITY_CTX_NONE;
 
 	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,18 @@ 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 (ckpt_restore_lsm_label(ctx, h->sec_ref)) {
+		int ret;
+		struct ckpt_stored_lsm *l;
+
+		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 +25 -3
index b933c19..cee0dc5 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 = SECURITY_CTX_NONE;
+
+	if (msg->security) {
+		sec_ref = security_checkpoint_obj(ctx, msg->security,
+						CKPT_SECURITY_MSG_MSG);
+		if (sec_ref == -EOPNOTSUPP)
+			sec_ref = SECURITY_CTX_NONE;
+		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,18 @@ static struct msg_msg *restore_msg_contents_one(struct ckpt_ctx *ctx, int *clen)
 	msg->next = NULL;
 	pseg = &msg->next;
 
+	if (ckpt_restore_lsm_label(ctx, h->sec_ref)) {
+		struct ckpt_stored_lsm *l;
+		l = ckpt_obj_fetch(ctx, h->sec_ref, CKPT_OBJ_SEC);
+		if (IS_ERR(l)) {
+			ret = PTR_ERR(l);
+			goto out;
+		}
+		ret = security_msg_msg_restore(msg, l->string);
+		if (ret)
+			goto out;
+	}
+
 	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 +21 -3
index 62d28a4..f88f07f 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 = SECURITY_CTX_NONE;
 	struct ckpt_hdr_cred *h;
 
 	groupinfo_ref = checkpoint_obj(ctx, cred->group_info,
@@ -719,13 +719,21 @@ 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 = SECURITY_CTX_NONE;
+	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)
 		return -ENOMEM;
 
-	ckpt_debug("cred uid %d fsuid %d gid %d\n", cred->uid, cred->fsuid,
-			cred->gid);
+	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;
@@ -735,6 +743,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);
 
@@ -808,6 +817,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 (ckpt_restore_lsm_label(ctx, h->sec_ref)) {
+		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 +72 -0

126 lines not on this page · raw message

security/security.c +187 -0

231 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): 20091009205626.GA5823-r/[email protected]

#4 lore raw

Re: [PATCH 2/4] cr: add generic LSM c/r support (v5)

Quoted 30 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 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.

Quoted 5 lines

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

[...]

Can you please pull this part, which adds a global "container" section to the checkpoint image, into a separate patch ?

(It will be helpful for folding the patches into ckpt-v19 eventually).

And IIRC, this needs to be accompanied by a user-cr patch, right ?

Quoted 33 lines
Documentation/checkpoint/readme.txt +9 -3
index 571c469..9c6422c 100644
@@ -161,9 +161,10 @@ in-userspace conversion tools.
 
 The general format of the checkpoint image is as follows:
 1. Image header
-2. Task hierarchy
-3. Tasks' state
-4. Image trailer
+2. Container configuration
+3. Task hierarchy
+4. Tasks' state
+5. Image trailer
 
 The image always begins with a general header that holds a magic
 number, an architecture identifier (little endian format), a format
@@ -172,6 +173,11 @@ version number (@rev), followed by information about the kernel
 checkpoint and the flags given to sys_checkpoint(). This header is
 followed by an arch-specific header.
 
+The container configuration section contains details about the
+security (LSM) configuration.  Network configuration and
+container-wide mounts may also go here, so that the userspace
+restart coordinator can re-create a suitable environment.
+
 The task hierarchy comes next so that userspace tools can read it
 early (even from a stream) and re-create the restarting tasks. This is
 basically an array of all checkpointed tasks, and their relationships
@@ -333,6 +339,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.

[...]

Documentation/checkpoint/readme.txt

Quoted 6 lines
Documentation/checkpoint/readme.txt +6 -0
+/*
+ * We restore a security label only if
+ * 1. sys_restart specified RESTART_KEEP_LSM
+ * 2. the checkpointed security context was not SECURITY_CTX_NONE
+ */
+static inline int ckpt_restore_lsm_label(struct ckpt_ctx *ctx, int sec_ref)

Maybe add 'may' somewhere inside tol make it more descriptive ? (e.g. ckpt_may_restore_lsm_label)

Quoted 6 lines
Documentation/checkpoint/readme.txt +6 -0
+{
+	if ((ctx->uflags & RESTART_KEEP_LSM) && (sec_ref != SECURITY_CTX_NONE))
+		return 1;
+	return 0;
+}
+

[...]

Documentation/checkpoint/readme.txt

Quoted 7 lines
Documentation/checkpoint/readme.txt +6 -0
+/* stored on hashtable */
+struct ckpt_stored_lsm {
+	struct kref kref;
+	int sectype;
+	char *string;
+};

Nit: maybe ckpt_lsm_str(ing) ?

[...]

Quoted 42 lines
Documentation/checkpoint/readme.txt +42 -0
+#ifdef CONFIG_CHECKPOINT
+
+/**
+ * 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 secref, len, new, ret, fulllen;
+	char *str;
+	struct ckpt_hdr_lsm *h;
+
+	if (!security)
+		return -EOPNOTSUPP;
+
+	secref = ckpt_obj_lookup_add(ctx, security, CKPT_OBJ_CHECKPOINT_SEC,
+					&new);
+	if (!new)
+		return secref;
+
+	ret = ckpt_write_objref(ctx, CKPT_OBJ_SEC, secref);
+	if (ret < 0)
+		return ret;
+
+	switch (sectype) {
+	case CKPT_SECURITY_MSG_MSG:
+		str = security_msg_msg_checkpoint(security);
+		break;
+	case CKPT_SECURITY_IPC:
+		str = security_ipc_checkpoint(security);
+		break;

Documentation/checkpoint/readme.txt

Quoted 10 lines
Documentation/checkpoint/readme.txt +10 -0
+	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;
+	}

Let me suggest a different scheme (also last night's IRC); I think it's less hackish and uses better the existing {checkpoint,restore}_obj().

* Define one obj type CKPT_OBJ_SEC_{IPC, MSG_MSG, FILE, CRED}, with matching c/r functions security_{c,r}_{ipc,msg_msg,file,cred}_obj()

* Define one obj type for the string representation CKPT_OBJ_SEC_STR with matchin c/r functions security_{c,r}_string_obj()

* The helper will now:

	security_checkpoint_obj()
	{
		switch (type) {
		case CKPT_OBJ_SEC_IPC:
			ret = checkpoint_obj(ctx, sec, CKPT_OBJ_SEC_IPC);
			break;
		case CKPT_OBJ_SEC_CRED:
			ret = checkpoint_obj(ctx, sec, CKPT_OBJ_SEC_CRED);
		...
	}

	security_checkpoint_ipc_obj()
	{
		...
		ckpt_lsm_str = str_from_sec_ipc();   /* like you do now */
		objref = checkpoint_obj(ctx, ckpt_lsm_str, CKPT_OBJ_SEC_STR);
		...
		h->objref = objref;
		ckpt_write_obj();
	}

Perhaps a variation on this where the string is checkpoint_obj()'ed first would also work.

I haven't looked at all the details, but I hope something along these lines would help untangle the current mess.

Oren.

#5 lore raw

Re: [PATCH 2/4] cr: add generic LSM c/r support (v5)

Quoting Oren Laadan ([email protected]):
...

Quoted 50 lines
Quoted 7 lines
security/security.c +7 -0
+	switch (sectype) {
+	case CKPT_SECURITY_MSG_MSG:
+		str = security_msg_msg_checkpoint(security);
+		break;
+	case CKPT_SECURITY_IPC:
+		str = security_ipc_checkpoint(security);
+		break;

security/security.c int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule, · line 1361

Quoted 10 lines
security/security.c +10 -0
+	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;
+	}

Let me suggest a different scheme (also last night's IRC); I think it's less hackish and uses better the existing {checkpoint,restore}_obj().

* Define one obj type CKPT_OBJ_SEC_{IPC, MSG_MSG, FILE, CRED}, with matching c/r functions security_{c,r}_{ipc,msg_msg,file,cred}_obj()

* Define one obj type for the string representation CKPT_OBJ_SEC_STR with matchin c/r functions security_{c,r}_string_obj()

* The helper will now:

	security_checkpoint_obj()
	{
		switch (type) {
		case CKPT_OBJ_SEC_IPC:
			ret = checkpoint_obj(ctx, sec, CKPT_OBJ_SEC_IPC);
			break;
		case CKPT_OBJ_SEC_CRED:
			ret = checkpoint_obj(ctx, sec, CKPT_OBJ_SEC_CRED);
		...
	}

	security_checkpoint_ipc_obj()
	{
		...
		ckpt_lsm_str = str_from_sec_ipc();   /* like you do now */
		objref = checkpoint_obj(ctx, ckpt_lsm_str, CKPT_OBJ_SEC_STR);
		...
		h->objref = objref;
		ckpt_write_obj();
	}
Quoted 5 lines

Perhaps a variation on this where the string is checkpoint_obj()'ed first would also work.

I haven't looked at all the details, but I hope something along these lines would help untangle the current mess.

So as discussed on irc, that by itself won't work bc (a) smack will checkpoint the same void* as multiple objtypes, and the objhash will complain.

Since we've gone over several possibilities on irc, let me summarize some here:

1. do the restore_security() in the code instead of using an objref to have it called automatically. That stops me having to write an objref by hand before writing out the CKT_HDR_CRED. That's fine with me, but then I won't be using checkpoint_obj() either, so I want to make sure I'm not going to change all the restore callers just to end up nixing that path.

2. alter the objhash to not complain if the same void* is checkpointed as a different type. That may have safety implications for the rest of the objhash users, especially at restart where we can't really trust the input.

3. have security_checkpoint_obj() 'reserve' a dummy objsec by stuffing the void* security, then assume that the objref for the string representation will be objref(void*security)+1. This might cause problems if we later parallelize checkpoint so that objref+1 is no longer valid.

4. Add a new field to the struct ckpt_obj which lets us store the objref for the string pointer in the ckpt_obj for the void*.

For completeness, the latest version which I actually sent out did:

5. Define two objhash object types for the lsm obj, one to use at checkpoint, and one at restart. At checkpoint, it stuffs the void* security into the objhash and manually writes out a checkpoint entry for the context string. At restart, it places a struct containing the context string in the objhash. The type used at restart must have ->get/->drop defined so that the struct is freed at the end of restart, while at checkpoint we can't hvae ->get/->drop bc the void* is opaque (and persistand relative to the checkpoint operation).

And what I was starting on until the latest irc conversation was (3).

At the moment (4) seems to me like the best path.

-serge

#6 lore raw

Re: [PATCH 2/4] cr: add generic LSM c/r support (v5)

Quoted 64 lines · Serge E. Hallyn

Quoting Oren Laadan ([email protected]):
...

Quoted 49 lines
Quoted 7 lines
security/security.c +7 -0
+	switch (sectype) {
+	case CKPT_SECURITY_MSG_MSG:
+		str = security_msg_msg_checkpoint(security);
+		break;
+	case CKPT_SECURITY_IPC:
+		str = security_ipc_checkpoint(security);
+		break;

security/security.c int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule, · line 1361

Quoted 10 lines
security/security.c +10 -0
+	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;
+	}

Let me suggest a different scheme (also last night's IRC); I think it's less hackish and uses better the existing {checkpoint,restore}_obj().

* Define one obj type CKPT_OBJ_SEC_{IPC, MSG_MSG, FILE, CRED}, with matching c/r functions security_{c,r}_{ipc,msg_msg,file,cred}_obj()

* Define one obj type for the string representation CKPT_OBJ_SEC_STR with matchin c/r functions security_{c,r}_string_obj()

* The helper will now:

	security_checkpoint_obj()
	{
		switch (type) {
		case CKPT_OBJ_SEC_IPC:
			ret = checkpoint_obj(ctx, sec, CKPT_OBJ_SEC_IPC);
			break;
		case CKPT_OBJ_SEC_CRED:
			ret = checkpoint_obj(ctx, sec, CKPT_OBJ_SEC_CRED);
		...
	}

	security_checkpoint_ipc_obj()
	{
		...
		ckpt_lsm_str = str_from_sec_ipc();   /* like you do now */
		objref = checkpoint_obj(ctx, ckpt_lsm_str, CKPT_OBJ_SEC_STR);
		...
		h->objref = objref;
		ckpt_write_obj();
	}
Quoted 5 lines

Perhaps a variation on this where the string is checkpoint_obj()'ed first would also work.

I haven't looked at all the details, but I hope something along these lines would help untangle the current mess.

So as discussed on irc, that by itself won't work bc (a) smack will checkpoint the same void* as multiple objtypes, and the objhash will complain.

Since we've gone over several possibilities on irc, let me summarize some here:

Quoted 6 lines

1. do the restore_security() in the code instead of using an objref to have it called automatically. That stops me having to write an objref by hand before writing out the CKT_HDR_CRED. That's fine with me, but then I won't be using checkpoint_obj() either, so I want to make sure I'm not going to change all the restore callers just to end up nixing that path.

This is similar to how pipes/fifo are handled: first check for a common inode (CKPT_OBJ_INODE only used during restart).

I agree that it is not as pretty to use it for security void* that are kind of an independent shared object. However, it is clean.

Quoted 5 lines

2. alter the objhash to not complain if the same void* is checkpointed as a different type. That may have safety implications for the rest of the objhash users, especially at restart where we can't really trust the input.

Agree with your concerns, this is not my favorite.

Quoted 6 lines

3. have security_checkpoint_obj() 'reserve' a dummy objsec by stuffing the void* security, then assume that the objref for the string representation will be objref(void*security)+1. This might cause problems if we later parallelize checkpoint so that objref+1 is no longer valid.

I don't like this. Too hacky.

Quoted 3 lines

4. Add a new field to the struct ckpt_obj which lets us store the objref for the string pointer in the ckpt_obj for the void*.

Can you elaborate on what this entails ?

E.g., do you want to be able to store an arbitrary data field for an object, and add interface to set and get it ? (If so, what is the proposed api ?)

Quoted 4 lines

For completeness, the latest version which I actually sent out did:

Quoted 9 lines

5. Define two objhash object types for the lsm obj, one to use at checkpoint, and one at restart. At checkpoint, it stuffs the void* security into the objhash and manually writes out a checkpoint entry for the context string. At restart, it places a struct containing the context string in the objhash. The type used at restart must have ->get/->drop defined so that the struct is freed at the end of restart, while at checkpoint we can't hvae ->get/->drop bc the void* is opaque (and persistand relative to the checkpoint operation).

:(

Quoted 5 lines

And what I was starting on until the latest irc conversation was (3).

At the moment (4) seems to me like the best path.

There is a 6th option: allow callers of checkpoint_obj() to pass another arbitrary argument to the obj-type-specific checkpoint function. So you'd pass the type of the security void* along to it.

Oren.

#7 lore raw

Re: [PATCH 2/4] cr: add generic LSM c/r support (v5)

Quoted 8 lines · Oren Laadan
Quoted 2 lines

4. Add a new field to the struct ckpt_obj which lets us store the objref for the string pointer in the ckpt_obj for the void*.

Can you elaborate on what this entails ?

E.g., do you want to be able to store an arbitrary data field for an object, and add interface to set and get it ? (If so, what is the proposed api ?)

Well we could do it either way - just make it a typeless field that anyone coudl use as a sideband, or make it a signed int only meant to be a link to another objref.

Don't much care about the API, but one way it could be used in checkpoint_security() would be:

	objref = ckpt_obj_lookup_add(ctx, security, CKPT_OBJ_VOIDSEC, &new);
	if (!new)
		return ckpt_obj_getlink(ctx, objref);

	/* ... get the string context from the lsm and construct
	 * the struct ckpt_lsm_string */
	construct_lsm_string(ctx, &l, security, CKPT_SECTYPE_FILE);
	linkref = checkpoint_obj(ctx, l, CKPT_OBJ_SEC);
	ckpt_obj_setlink(ctx, objref, linkref);
	return linkref;

But really, the only point of doing this is so that we can use checkpoint_obj() instead of doing

	h = ckpt_hdr_get_type(ctx, sizeof(*h), CKPT_HDR_SEC);
	ckpt_write_obj(ctx, &h->h);
	ckpt_hdr_put(ctx, h);
	ckpt_write_string(ctx, context_string, strlen(context_string)+1);

-serge

#8 lore raw

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

In reply to a message not in the archive

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 41d306b..a5351ab 100644
@@ -647,6 +647,7 @@ static int restore_lsm(struct ckpt_ctx *ctx)
 	}
 
 	if (strcmp(ctx->lsm_name, "lsm_none") != 0 &&
+			strcmp(ctx->lsm_name, "smack") != 0 &&
 			strcmp(ctx->lsm_name, "default") != 0) {
 		ckpt_debug("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
#9 lore raw

PATCH 4/4 cr: add selinux support (v6)

In reply to a message not in the archive

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 09: fix memory overrun in selinux_cred_checkpoint. 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 +
 security/selinux/hooks.c                     |  366 ++++++++++++++++++++++++++
 security/selinux/include/av_perm_to_string.h |    5 +
 security/selinux/include/av_permissions.h    |    5 +
 4 files changed, 377 insertions(+), 0 deletions(-)
checkpoint/restart.c +1 -0
index a5351ab..dbe8b2d 100644
@@ -648,6 +648,7 @@ static int restore_lsm(struct ckpt_ctx *ctx)
 
 	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) {
 		ckpt_debug("c/r: RESTART_KEEP_LSM unsupported for %s\n",
 				ctx->lsm_name);
security/selinux/hooks.c +366 -0

416 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

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

#11 lore raw

Re: [PATCH 4/4] cr: add selinux support (v6)

Quoted 561 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 09: fix memory overrun in selinux_cred_checkpoint. 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 +
 security/selinux/hooks.c                     |  366 ++++++++++++++++++++++++++
 security/selinux/include/av_perm_to_string.h |    5 +
 security/selinux/include/av_permissions.h    |    5 +
 4 files changed, 377 insertions(+), 0 deletions(-)
checkpoint/restart.c +1 -0
index a5351ab..dbe8b2d 100644
@@ -648,6 +648,7 @@ static int restore_lsm(struct ckpt_ctx *ctx)
 
 	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) {
 		ckpt_debug("c/r: RESTART_KEEP_LSM unsupported for %s\n",
 				ctx->lsm_name);
security/selinux/hooks.c +366 -0
index 8d8b69c..e6994eb 100644
@@ -76,6 +76,7 @@
 #include <linux/selinux.h>
 #include <linux/mutex.h>
 #include <linux/posix-timers.h>
+#include <linux/checkpoint.h>
 
 #include "avc.h"
 #include "objsec.h"
@@ -2961,6 +2962,104 @@ 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 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);
+	if (ret) {
+		kfree(s1);
+		return ERR_PTR(ret);
+	}
+	len2--;
+	lenfull = len1 + len2 + 3;
+	sfull = kmalloc(lenfull + 1, GFP_KERNEL);
+	if (!sfull) {
+		sfull = ERR_PTR(-ENOMEM);
+		goto out;
+	}
+	sfull[lenfull] = '\0';
+	sprintf(sfull, "%s:::%s", s1, s2);
+
+out:
+	kfree(s1);
+	kfree(s2);
+	return sfull;
+}
+
+static 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 (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;
+	}
+
+	ret = 0;
+
+out:
+	kfree(s1);
+	return ret;
+}
+
 static int selinux_file_alloc_security(struct file *file)
 {
 	return file_alloc_security(file);
@@ -3219,6 +3318,186 @@ 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 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 };
+
+	if (sids[0] == 0 || sids[1] == 0)
+		/* SECSID_NULL is not valid for osid or sid */
+		return ERR_PTR(-EINVAL);
+
+	ret = security_sid_to_context(sids[0], &sfull, &runlen);
+	if (ret)
+		return ERR_PTR(ret);
+	runlen--;
+
+	for (i = 1; i < NUMTASKSIDS; i++) {
+		if (sids[i] == 0) {
+			stmp = NULL;
+			slen = 0;
+		} else {
+			ret = security_sid_to_context(sids[i], &stmp, &slen);
+			if (ret) {
+				kfree(sfull);
+				return ERR_PTR(ret);
+			}
+			slen--;
+		}
+		/* slen + runlen + ':::' + \0 */
+		sfull = krealloc(sfull, slen + runlen + 3 + 1,
+				 GFP_KERNEL);
+		if (!sfull) {
+			kfree(stmp);
+			return ERR_PTR(-ENOMEM);
+		}
+		sprintf(sfull+runlen, ":::%s", stmp ? stmp : "");
+		runlen += slen + 3;
+		kfree(stmp);
+	}
+
+	return sfull;
+}
+
+static inline int credrestore_nullvalid(int which)
+{
+	int valid_array[NUMTASKSIDS] = {
+		0, /* task osid */
+		0, /* task sid */
+		1, /* exec sid */
+		1, /* create sid */
+		1, /* keycreate_sid */
+		1, /* sockcreate_sid */
+	};
+
+	return valid_array[which];
+}
+
+static 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;
+
+	/*
+	 * objhash made sure the string is null-terminated
+	 * now we want our own copy so we can chop it up with \0's
+	 */
+	s = kstrdup(ctx, GFP_KERNEL);
+	if (!s)
+		return -ENOMEM;
+
+	s1 = s;
+	for (i = 0; i < NUMTASKSIDS; i++) {
+		if (i < NUMTASKSIDS-1) {
+			ret = -EINVAL;
+			s2 = strstr(s1, ":::");
+			if (!s2)
+				goto out;
+			*s2 = '\0';
+			s2 += 3;
+		}
+		if (strlen(s1) == 0) {
+			ret = -EINVAL;
+			if (credrestore_nullvalid(i))
+				sids[i] = 0;
+			else
+				goto out;
+		} else {
+			ret = security_context_to_sid(s1, strlen(s1), &sids[i]);
+			if (ret)
+				goto out;
+		}
+		s1 = s2;
+	}
+
+	/*
+	 * Check that these transitions are allowed, and effect them.
+	 * XXX: Do these checks suffice?
+	 */
+	if (tsec->osid != sids[0]) {
+		ret = avc_has_perm(current_sid(), sids[0], SECCLASS_PROCESS,
+					PROCESS__RESTORE, NULL);
+		if (ret)
+			goto out;
+		 tsec->osid = sids[0];
+	}
+
+	if (tsec->sid != sids[1]) {
+		struct inode_security_struct *isec;
+		ret = avc_has_perm(current_sid(), sids[1], SECCLASS_PROCESS,
+					PROCESS__RESTORE, NULL);
+		if (ret)
+			goto out;
+
+		/* check whether checkpoint file type is a valid entry
+		 * point to the new domain:  we may want a specific
+		 * 'restore_entrypoint' permission for this, but let's
+		 * see if just entrypoint is deemed sufficient
+		 */
+
+		AVC_AUDIT_DATA_INIT(&ad, FS);
+		ad.u.fs.path = file->f_path;
+
+		isec = ctx_inode->i_security;
+		ret = avc_has_perm(sids[1], isec->sid, SECCLASS_FILE,
+				FILE__ENTRYPOINT, &ad);
+		if (ret)
+			goto out;
+		/* TODO: do we need to check for shared state? */
+		tsec->sid = sids[1];
+	}
+
+	ret = -EPERM;
+	if (sids[2] != tsec->exec_sid) {
+		if (!current_has_perm(current, PROCESS__SETEXEC))
+			goto out;
+		tsec->exec_sid = sids[2];
+	}
+
+	if (sids[3] != tsec->create_sid) {
+		if (!current_has_perm(current, PROCESS__SETFSCREATE))
+			goto out;
+		tsec->create_sid = sids[3];
+	}
+
+	if (tsec->keycreate_sid != sids[4]) {
+		if (!current_has_perm(current, PROCESS__SETKEYCREATE))
+			goto out;
+		if (!may_create_key(sids[4], current))
+			goto out;
+		tsec->keycreate_sid = sids[4];
+	}
+
+	if (tsec->sockcreate_sid != sids[5]) {
+		if (!current_has_perm(current, PROCESS__SETSOCKCREATE))
+			goto out;
+		tsec->sockcreate_sid = sids[5];
+	}
+
+	ret = 0;
+
+out:
+	kfree(s);
+	return ret;
+}
+
+
 /*
  * detach and free the LSM part of a set of credentials
  */
@@ -4658,6 +4937,44 @@ static void ipc_free_security(struct kern_ipc_perm *perm)
 	kfree(isec);
 }
 
+static char *selinux_msg_msg_checkpoint(void *security)
+{
+	struct msg_security_struct *msec = security;
+	char *s;
+	u32 len;
+	int ret;
+
+	if (msec->sid == 0)
+		return ERR_PTR(-EINVAL);
+
+	ret = security_sid_to_context(msec->sid, &s, &len);
+	if (ret)
+		return ERR_PTR(ret);
+	return s;
+}
+
+static int selinux_msg_msg_restore(struct msg_msg *msg, char *ctx)
+{
+	struct msg_security_struct *msec = msg->security;
+	int ret;
+	u32 sid = 0;
+
+	ret = security_context_to_sid(ctx, strlen(ctx), &sid);
+	if (ret)
+		return ret;
+
+	if (msec->sid == sid)
+		return 0;
+
+	ret = avc_has_perm(current_sid(), sid, SECCLASS_MSG,
+				MSG__RESTORE, NULL);
+	if (ret)
+		return ret;
+
+	msec->sid = sid;
+	return 0;
+}
+
 static int msg_msg_alloc_security(struct msg_msg *msg)
 {
 	struct msg_security_struct *msec;
@@ -5061,6 +5378,47 @@ static void selinux_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid)
 	*secid = isec->sid;
 }
 
+static char *selinux_ipc_checkpoint(void *security)
+{
+	struct ipc_security_struct *isec = security;
+	char *s;
+	u32 len;
+	int ret;
+
+	if (isec->sid == 0)
+		return ERR_PTR(-EINVAL);
+
+	ret = security_sid_to_context(isec->sid, &s, &len);
+	if (ret)
+		return ERR_PTR(ret);
+	return s;
+}
+
+static int selinux_ipc_restore(struct kern_ipc_perm *ipcp, char *ctx)
+{
+	struct ipc_security_struct *isec = ipcp->security;
+	int ret;
+	u32 sid = 0;
+	struct avc_audit_data ad;
+
+	ret = security_context_to_sid(ctx, strlen(ctx), &sid);
+	if (ret)
+		return ret;
+
+	if (isec->sid == sid)
+		return 0;
+
+	AVC_AUDIT_DATA_INIT(&ad, IPC);
+	ad.u.ipc_id = ipcp->key;
+	ret = avc_has_perm(current_sid(), sid, SECCLASS_IPC,
+				IPC__RESTORE, &ad);
+	if (ret)
+		return ret;
+
+	isec->sid = sid;
+	return 0;
+}
+
 static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
 {
 	if (inode)
@@ -5382,6 +5740,8 @@ static struct security_operations selinux_ops = {
 	.inode_getsecid =		selinux_inode_getsecid,
 
 	.file_permission =		selinux_file_permission,
+	.file_checkpoint =		selinux_file_checkpoint,
+	.file_restore =			selinux_file_restore,
 	.file_alloc_security =		selinux_file_alloc_security,
 	.file_free_security =		selinux_file_free_security,
 	.file_ioctl =			selinux_file_ioctl,
@@ -5396,6 +5756,8 @@ static struct security_operations selinux_ops = {
 	.dentry_open =			selinux_dentry_open,
 
 	.task_create =			selinux_task_create,
+	.cred_checkpoint =		selinux_cred_checkpoint,
+	.cred_restore =			selinux_cred_restore,
 	.cred_free =			selinux_cred_free,
 	.cred_prepare =			selinux_cred_prepare,
 	.kernel_act_as =		selinux_kernel_act_as,
@@ -5417,8 +5779,12 @@ static struct security_operations selinux_ops = {
 
 	.ipc_permission =		selinux_ipc_permission,
 	.ipc_getsecid =			selinux_ipc_getsecid,
+	.ipc_checkpoint =		selinux_ipc_checkpoint,
+	.ipc_restore =			selinux_ipc_restore,
 
 	.msg_msg_alloc_security =	selinux_msg_msg_alloc_security,
+	.msg_msg_checkpoint =		selinux_msg_msg_checkpoint,
+	.msg_msg_restore =		selinux_msg_msg_restore,
 	.msg_msg_free_security =	selinux_msg_msg_free_security,
 
 	.msg_queue_alloc_security =	selinux_msg_queue_alloc_security,
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 +4 -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

security/selinux/include/av_permissions.h line 493

Quoted 7 lines
security/selinux/include/av_permissions.h +1 -0
@@ -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

I think you need to be careful with this. We do not want the process to start with the same MCS Label as when it stopped in case some other virtual machine has grabbed the MCS Label. When the image is taken down it should give up probably give up its labels and allow the system to relabel to a known state. When it starts the image again, new labels should be selected and set on disk and the process resumed with the new label.

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

#13 lore raw

Re: [PATCH 4/4] cr: add selinux support (v6)

Quoted 7 lines · Daniel J Walsh

On 10/09/2009 04:57 PM, Serge E. Hallyn wrote:
I think you need to be careful with this. We do not want the process to start with the same MCS Label as when it stopped in case some other virtual machine has grabbed the MCS Label. When the image is taken down it should give up probably give up its labels and allow the system to relabel to a known state. When it starts the image again, new labels should be selected and set on disk and the process resumed with the new label.

With this patchset, the default behavior remains to simply run the restarted task in whatever context is calculated by the usual TE rules (i.e. current context unless the type of the 'restart' program was an entry type to some domain and a domain transition was requested or automatic). The request to restore checkpointed labels is done with a special flag.

What you actually are suggesting is the ability to make fine-grained changes to some of the checkpointed labels, but to still restore the checkpointed labels (with changes). I think it is pretty generally accepted that such things should be done by editing the checkpoint image in userspace. A pretty simple program could run through the image looking for CKPT_HDR_SEC fields and change the MCS labels where appropriate.

I haven't written such a program (or used MCS), but if you like I'll certainly write it and I suspect Oren would be happy to have it in user-cr/ (where the checkpoint and restart programs live) as an example of how to make such substitutions generally.

thanks,
-serge

#14 lore raw
In reply to a message not in the archive

Pulled...

Quoted 96 lines · Serge E. Hallyn

[
this set is available at
http://git.kernel.org/gitweb.cgi?p=linux/kernel/git/sergeh/linux-cr.git;a=shortlog;h=refs/heads/oct9.lsm5
]

These were pulled out of the lsm-related patches into which they had been embedded.

---
 checkpoint/files.c   |    3 +++
 checkpoint/process.c |   20 ++++++++++++++++----
 kernel/cred.c        |    2 ++
 3 files changed, 21 insertions(+), 4 deletions(-)
checkpoint/files.c +3 -0
index 27e29a0..f6de07e 100644
@@ -159,6 +159,9 @@ int checkpoint_file_common(struct ckpt_ctx *ctx, struct file *file,
 	if (h->f_credref < 0)
 		return h->f_credref;
 
+	ckpt_debug("file %s credref %d", file->f_dentry->d_name.name,
+		h->f_credref);
+
 	/* FIX: need also file->f_owner, etc */
 
 	return 0;
checkpoint/process.c +16 -4
index c51e036..7463158 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 realcred (ref %d)\n",
+			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)\n",
+			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\n", 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 < 0) {
+		ckpt_debug("restore_task_creds returned %d\n", ret);
+		return ret;
+	}
+	ret = restore_task_ns(ctx);
+	if (ret < 0) {
+		ckpt_debug("restore_task_ns returned %d\n", 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\n");
 		return PTR_ERR(h);
+	}
 
 	ret = restore_obj_file_table(ctx, h->files_objref);
 	ckpt_debug("file_table: ret %d (%p)\n", ret, current->files);
kernel/cred.c +2 -0
index 9710cae..62d28a4 100644
@@ -724,6 +724,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\n", cred->uid, cred->fsuid,
+			cred->gid);
 	h->uid = cred->uid;
 	h->suid = cred->suid;
 	h->euid = cred->euid;