Skip to contentSkip to conversation

cred: #include init.h in cred.h

PATCH In review Serge E. Hallyn 5 participants 18 messages Jun 10, 2009 6 messages not in the archive

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

PATCH 1/10 cred: #include init.h in cred.h

cred.h can't be included as first header because it uses __init and doesn't include init.h which is enough to break compilation on at least ia64.

---
 include/linux/cred.h |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)
include/linux/cred.h +1 -0
index 3282ee4..4fa9996 100644
@@ -13,6 +13,7 @@
 #define _LINUX_CRED_H
 
 #include <linux/capability.h>
+#include <linux/init.h>
 #include <linux/key.h>
 #include <asm/atomic.h>
 
Signature · 1 line
1.6.1

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

#2 lore raw

PATCH 2/10 groups: move code to kernel/groups.c

Move supplementary groups implementation to kernel/groups.c . kernel/sys.c already accumulated quite a few random stuff.

Do strictly copy/paste + add required headers to compile. Compile-tested on many configs and archs.

---
 kernel/Makefile |    1 +
 kernel/groups.c |  288 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 kernel/sys.c    |  283 ------------------------------------------------------
 3 files changed, 289 insertions(+), 283 deletions(-)
 create mode 100644 kernel/groups.c
kernel/Makefile +1 -0
index 6bc638d..4d4f741 100644
@@ -11,6 +11,7 @@ obj-y     = sched.o fork.o exec_domain.o panic.o printk.o \
 	    hrtimer.o rwsem.o nsproxy.o srcu.o semaphore.o \
 	    notifier.o ksysfs.o pm_qos_params.o sched_clock.o cred.o \
 	    async.o
+obj-y += groups.o
 
 ifdef CONFIG_FUNCTION_TRACER
 # Do not trace debug files and internal ftrace files
kernel/groups.c new file +288 -0

288 lines not on this page · raw message

kernel/sys.c +0 -283

289 lines not on this page · raw message

Signature · 1 line
1.6.1
#3 lore raw

PATCH 3/10 cr: break out new_user_ns()

In reply to a message not in the archive

Break out the core function which checks privilege and (if allowed) creates a new user namespace, with the passed-in creating user_struct. Note that a user_namespace, unlike other namespace pointers, is not stored in the nsproxy. Rather it is purely a property of user_structs.

This will let us keep the task restore code simpler.

---
 include/linux/user_namespace.h |    8 ++++++
 kernel/user_namespace.c        |   53 ++++++++++++++++++++++++++++------------
 2 files changed, 45 insertions(+), 16 deletions(-)
include/linux/user_namespace.h +8 -0
index cc4f453..a2b82d5 100644
@@ -20,6 +20,8 @@ extern struct user_namespace init_user_ns;
 
 #ifdef CONFIG_USER_NS
 
+struct user_namespace *new_user_ns(struct user_struct *creator,
+				   struct user_struct **newroot);
 static inline struct user_namespace *get_user_ns(struct user_namespace *ns)
 {
 	if (ns)
@@ -38,6 +40,12 @@ static inline void put_user_ns(struct user_namespace *ns)
 
 #else
 
+static inline struct user_namespace *new_user_ns(struct user_struct *creator,
+				   struct user_struct **newroot)
+{
+	return -EINVAL;
+}
+
 static inline struct user_namespace *get_user_ns(struct user_namespace *ns)
 {
 	return &init_user_ns;
kernel/user_namespace.c +37 -16

80 lines not on this page · raw message

Signature · 1 line
1.6.1
#4 lore raw

PATCH 4/10 cr: split core function out of some set*{u,g}id functions

In reply to a message not in the archive

When restarting tasks, we want to be able to change xuid and xgid in a struct cred, and do so with security checks. Break the core functionality of set{fs,res}{u,g}id into cred_setX which performs the access checks based on current_cred(), but performs the requested change on a passed-in cred.

This will allow us to securely construct struct creds based on a checkpoint image, constrained by the caller's permissions, and apply them to the caller at the end of sys_restart().

---
 include/linux/cred.h |    8 +++
 kernel/cred.c        |  114 ++++++++++++++++++++++++++++++++++++++++++
 kernel/sys.c         |  134 ++++++++------------------------------------------
 3 files changed, 143 insertions(+), 113 deletions(-)
include/linux/cred.h +8 -0
index 4fa9996..2ffffbe 100644
@@ -21,6 +21,9 @@ struct user_struct;
 struct cred;
 struct inode;
 
+/* defined in sys.c, used in cred_setresuid */
+extern int set_user(struct cred *new);
+
 /*
  * COW Supplementary groups list
  */
@@ -344,4 +347,9 @@ do {						\
 	*(_fsgid) = __cred->fsgid;		\
 } while(0)
 
+int cred_setresuid(struct cred *new, uid_t ruid, uid_t euid, uid_t suid);
+int cred_setresgid(struct cred *new, gid_t rgid, gid_t egid, gid_t sgid);
+int cred_setfsuid(struct cred *new, uid_t uid, uid_t *old_fsuid);
+int cred_setfsgid(struct cred *new, gid_t gid, gid_t *old_fsgid);
+
 #endif /* _LINUX_CRED_H */
kernel/cred.c +114 -0

117 lines not on this page · raw message

kernel/sys.c +21 -113

210 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): 20090610014456.GC5658-r/[email protected]

#6 lore raw

Re: [PATCH 04/10] cr: split core function out of some set*{u,g}id functions

Quoted 6 lines · Serge E. Hallyn

When restarting tasks, we want to be able to change xuid and xgid in a struct cred, and do so with security checks. Break the core functionality of set{fs,res}{u,g}id into cred_setX which performs the access checks based on current_cred(), but performs the requested change on a passed-in cred.

Please cc the lsm list when making changes to security.

Signature · 2 lines
James Morris
<jmorris-gx6/[email protected]>
#7 lore raw

Re: [PATCH 04/10] cr: split core function out of some set*{u,g}id functions

Quoted 10 lines · James Morris
Quoted 6 lines · Serge E. Hallyn

When restarting tasks, we want to be able to change xuid and xgid in a struct cred, and do so with security checks. Break the core functionality of set{fs,res}{u,g}id into cred_setX which performs the access checks based on current_cred(), but performs the requested change on a passed-in cred.

Please cc the lsm list when making changes to security.

Argh, they were cc:d on my last version, and I was sure I'd put them in the list of headers for this set.

FWIW, the thread can be seen here
https://lists.linux-foundation.org/pipermail/containers/2009-June/018509.html

thanks,
-serge

#8 lore raw

PATCH 5/10 cr: ipc: reset kern_ipc_perms

In reply to a message not in the archive

Reset the checkpointed uid and gid info on ipc objects.

Right now, we return -EPERM if the user calling sys_restart() isn't allowed to create an object with the checkpointed uid. We may prefer to simply use the caller's uid in that case - but that could lead to subtle userspace bugs? Unsure, so going for the stricter behavior.

TODO: restore kern_ipc_perms->security.

---
 ipc/checkpoint.c |   33 +++++++++++++++++++++++++++++++--
 1 files changed, 31 insertions(+), 2 deletions(-)
ipc/checkpoint.c +31 -2
index f621226..bc77743 100644
@@ -119,6 +119,26 @@ int checkpoint_ipc_ns(struct ckpt_ctx *ctx, struct ipc_namespace *ipc_ns)
  * Restart
  */
 
+/*
+ * check whether current task may create ipc object with
+ * checkpointed uids and gids.
+ * Return 1 if ok, 0 if not.
+ */
+static int validate_created_perms(struct ckpt_hdr_ipc_perms *h)
+{
+	const struct cred *cred = current_cred();
+	uid_t uid = cred->uid, euid = cred->euid;
+
+	/* actually I don't know - is CAP_IPC_OWNER the right one? */
+	if (((h->uid != uid && h->uid == euid) ||
+			(h->cuid != uid && h->cuid != euid) ||
+			!in_group_p(h->cgid) ||
+			!in_group_p(h->gid)) &&
+			!capable(CAP_IPC_OWNER))
+		return 0;
+	return 1;
+}
+
 int restore_load_ipc_perms(struct ckpt_hdr_ipc_perms *h,
 			   struct kern_ipc_perm *perm)
 {
@@ -139,14 +159,23 @@ int restore_load_ipc_perms(struct ckpt_hdr_ipc_perms *h,
 
 	perm->id = h->id;
 	perm->key = h->key;
-#if 0 /* FIX: requires security checks */
+
+	if (!validate_created_perms(h))
+		return -EPERM;
 	perm->uid = h->uid;
 	perm->gid = h->gid;
 	perm->cuid = h->cuid;
 	perm->cgid = h->cgid;
-#endif
 	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.
+	 */
 
 	return 0;
 }
Signature · 1 line
1.6.1
#9 lore raw

PATCH 6/10 cr: capabilities: define checkpoint and restore fns

In reply to a message not in the archive

[ Andrew: I am punting on dealing with the subsystem cooperation issues in this version, in favor of trying to get LSM issues straightened out ]

An application checkpoint image will store capability sets (and the bounding set) as __u64s. Define checkpoint and restart functions to translate between those and kernel_cap_t's.

Define a common function do_capset_tocred() which applies capability set changes to a passed-in struct cred.

The restore function uses do_capset_tocred() to apply the restored capabilities to the struct cred being crafted, subject to the current task's (task executing sys_restart()) permissions.

Changelog:
Jun 09: Can't choose securebits or drop bounding set if
file capabilities aren't compiled into the kernel. Also just store caps in __u32s (looks cleaner).
Jun 01: Made the checkpoint and restore functions and the
ckpt_hdr_capabilities struct more opaque to the rest of the c/r code, as suggested by Andrew Morgan, and using naming suggested by Oren.
Jun 01: Add commented BUILD_BUG_ON() to point out that the
current implementation depends on 64-bit capabilities. (Andrew Morgan and Alexey Dobriyan).
May 28: add helpers to c/r securebits

---
 include/linux/capability.h     |    6 ++
 include/linux/checkpoint_hdr.h |   11 +++
 kernel/capability.c            |  162 +++++++++++++++++++++++++++++++++++++---
 security/commoncap.c           |   19 +----
 4 files changed, 170 insertions(+), 28 deletions(-)
include/linux/capability.h +6 -0
index c302110..3a74655 100644
@@ -568,6 +568,12 @@ extern int capable(int cap);
 struct dentry;
 extern int get_vfs_caps_from_disk(const struct dentry *dentry, struct cpu_vfs_cap_data *cpu_caps);
 
+struct cred;
+int apply_securebits(unsigned securebits, struct cred *new);
+struct ckpt_capabilities;
+int restore_capabilities(struct ckpt_capabilities *h, struct cred *new);
+void checkpoint_capabilities(struct ckpt_capabilities *h, struct cred * cred);
+
 #endif /* __KERNEL__ */
 
 #endif /* !_LINUX_CAPABILITY_H */
include/linux/checkpoint_hdr.h +11 -0
index 874518c..37f2d4d 100644
@@ -56,6 +56,7 @@ enum {
 	CKPT_HDR_NS,
 	CKPT_HDR_UTS_NS,
 	CKPT_HDR_IPC_NS,
+	CKPT_HDR_CAPABILITIES,
 
 	/* 201-299: reserved for arch-dependent */
 
@@ -166,6 +167,16 @@ struct ckpt_hdr_task {
 	__u32 task_comm_len;
 } __attribute__((aligned(8)));
 
+/* Posix capabilities */
+struct ckpt_capabilities {
+	__u32 cap_i_0, cap_i_1; /* inheritable set */
+	__u32 cap_p_0, cap_p_1; /* permitted set */
+	__u32 cap_e_0, cap_e_1; /* effective set */
+	__u32 cap_b_0, cap_b_1; /* bounding set */
+	__u32 securebits;
+	__u32 padding;
+} __attribute__((aligned(8)));
+
 /* namespaces */
 struct ckpt_hdr_task_ns {
 	struct ckpt_hdr h;
kernel/capability.c +151 -11

191 lines not on this page · raw message

security/commoncap.c +2 -17
index beac025..528da3b 100644
@@ -861,24 +861,9 @@ int cap_task_prctl(int option, unsigned long arg2, unsigned long arg3,
 	 * capability-based-privilege environment.
 	 */
 	case PR_SET_SECUREBITS:
-		error = -EPERM;
-		if ((((new->securebits & SECURE_ALL_LOCKS) >> 1)
-		     & (new->securebits ^ arg2))			/*[1]*/
-		    || ((new->securebits & SECURE_ALL_LOCKS & ~arg2))	/*[2]*/
-		    || (arg2 & ~(SECURE_ALL_LOCKS | SECURE_ALL_BITS))	/*[3]*/
-		    || (cap_capable(current, current_cred(), CAP_SETPCAP,
-				    SECURITY_CAP_AUDIT) != 0)		/*[4]*/
-			/*
-			 * [1] no changing of bits that are locked
-			 * [2] no unlocking of locks
-			 * [3] no setting of unsupported bits
-			 * [4] doing anything requires privilege (go read about
-			 *     the "sendmail capabilities bug")
-			 */
-		    )
-			/* cannot change a locked bit */
+		error = apply_securebits(arg2, new);
+		if (error)
 			goto error;
-		new->securebits = arg2;
 		goto changed;
 
 	case PR_GET_SECUREBITS:
Signature · 1 line
1.6.1
#10 lore raw

PATCH 7/10 cr: checkpoint and restore task credentials

In reply to a message not in the archive

This patch adds the checkpointing and restart of credentials (uids, gids, and capabilities) to Oren's c/r patchset (on top of v14). It goes to great pains to re-use (and define when needed) common helpers, in order to make sure that as security code is modified, the cr code will be updated. Some of the helpers should still be moved (i.e. _creds() functions should be in kernel/cred.c).

When building the credentials for the restarted process, I
1. create a new struct cred as a copy of the running task's cred (using prepare_cred())
2. always authorize any changes to the new struct cred based on the permissions of current_cred() (not the current transient state of the new cred).

While this may mean that certain transient_cred1->transient_cred2 states are allowed which otherwise wouldn't be allowed, the fact remains that current_cred() is allowed to transition to transient_cred2.

The reconstructed creds are applied to the task at the very end of the sys_restart call. This ensures that any objects which need to be re-created (file, socket, etc) are re-created using the creds of the task calling sys_restart - preventing an unpriv user from creating a privileged object, and ensuring that a root task can restart a process which had started out privileged, created some privileged objects, then dropped its privilege.

With these patches, the root user can restart checkpoint images (created by either hallyn or root) of user hallyn's tasks, resulting in a program owned by hallyn.

Changelog:
Jun 01: Don't check ordering of groups in group_info, bc
set_groups() will sort it for us.
May 28: 1. Restore securebits
2. Address Alexey's comments: move prototypes out of sched.h, validate ngroups < NGROUPS_MAX, validate groups are sorted, and get rid of ckpt_hdr_cred->version.
3. remove bogus unused flag RESTORE_CREATE_USERNS
May 26: Move group, user, userns, creds c/r functions out
of checkpoint/process.c and into the appropriate files.
May 26: Define struct ckpt_hdr_task_creds and move task cred
objref c/r into {checkpoint_restore}_task_shared().
May 26: Take cred refs around checkpoint_write_creds() May 20: Remove the limit on number of groups in groupinfo
at checkpoint time
May 20: Remove the depth limit on empty user namespaces May 20: Better document checkpoint_user
May 18: fix more refcounting: if (userns 5, uid 0) had
no active tasks or child user_namespaces, then it shouldn't exist at restart or it, its namespace, and its whole chain of creators will be leaked.
May 14: fix some refcounting:
1. a new user_ns needs a ref to remain pinned
by its root user
2. current_user_ns needs an extra ref bc objhash drops two on restart
3. cred needs a ref for the real credentials bc commit_creds eats one ref.
May 13: folded in fix to userns refcounting.

---
 checkpoint/objhash.c             |  146 +++++++++++++++++++++++++++++++++----
 checkpoint/process.c             |  152 +++++++++++++++++++++++++++++++++++++-
 include/linux/checkpoint.h       |   11 +++
 include/linux/checkpoint_hdr.h   |   60 +++++++++++++++
 include/linux/checkpoint_types.h |    1 +
 include/linux/cred.h             |   13 +++
 include/linux/user_namespace.h   |    6 ++
 kernel/cred.c                    |  113 ++++++++++++++++++++++++++++
 kernel/groups.c                  |   59 +++++++++++++++
 kernel/user.c                    |  147 ++++++++++++++++++++++++++++++++++++
 kernel/user_namespace.c          |   86 +++++++++++++++++++++
 11 files changed, 778 insertions(+), 16 deletions(-)
checkpoint/objhash.c +132 -14
index 50a124b..84f003d 100644
@@ -17,6 +17,7 @@
 #include <linux/fdtable.h>
 #include <linux/sched.h>
 #include <linux/ipc_namespace.h>
+#include <linux/user_namespace.h>
 #include <linux/checkpoint.h>
 #include <linux/checkpoint_hdr.h>
 
@@ -181,6 +182,71 @@ static int obj_ipc_ns_users(void *ptr)
 	return atomic_read(&((struct ipc_namespace *) ptr)->count);
 }
 
+static int obj_cred_grab(void *ptr)
+{
+	get_cred((struct cred *) ptr);
+	return 0;
+}
+
+static void obj_cred_drop(void *ptr)
+{
+	put_cred((struct cred *) ptr);
+}
+
+static int obj_cred_users(void *ptr)
+{
+	return atomic_read(&((struct cred *) ptr)->usage);
+}
+
+static int obj_user_grab(void *ptr)
+{
+	struct user_struct *u = ptr;
+	(void) get_uid(u);
+	return 0;
+}
+
+static void obj_user_drop(void *ptr)
+{
+	free_uid((struct user_struct *) ptr);
+}
+
+static int obj_user_users(void *ptr)
+{
+	return atomic_read(&((struct user_struct *) ptr)->__count);
+}
+
+static int obj_userns_grab(void *ptr)
+{
+	get_user_ns((struct user_namespace *) ptr);
+	return 0;
+}
+
+static void obj_userns_drop(void *ptr)
+{
+	put_user_ns((struct user_namespace *) ptr);
+}
+
+static int obj_user_ns_users(void *ptr)
+{
+	return atomic_read(&((struct user_namespace *) ptr)->kref.refcount);
+}
+
+static int obj_groupinfo_grab(void *ptr)
+{
+	get_group_info((struct group_info *) ptr);
+	return 0;
+}
+
+static void obj_groupinfo_drop(void *ptr)
+{
+	put_group_info((struct group_info *) ptr);
+}
+
+static int obj_groupinfo_users(void *ptr)
+{
+	return atomic_read(&((struct group_info *) ptr)->usage);
+}
+
 static struct ckpt_obj_ops ckpt_obj_ops[] = {
 	/* ignored object */
 	{
@@ -258,6 +324,46 @@ static struct ckpt_obj_ops ckpt_obj_ops[] = {
 		.checkpoint = checkpoint_bad,
 		.restore = restore_bad,
 	},
+	/* user_ns object */
+	{
+		.obj_name = "USER_NS",
+		.obj_type = CKPT_OBJ_USER_NS,
+		.ref_drop = obj_userns_drop,
+		.ref_grab = obj_userns_grab,
+		.ref_users = obj_user_ns_users,
+		.checkpoint = checkpoint_userns,
+		.restore = restore_userns,
+	},
+	/* struct cred */
+	{
+		.obj_name = "CRED",
+		.obj_type = CKPT_OBJ_CRED,
+		.ref_drop = obj_cred_drop,
+		.ref_grab = obj_cred_grab,
+		.ref_users = obj_cred_users,
+		.checkpoint = checkpoint_cred,
+		.restore = restore_cred,
+	},
+	/* user object */
+	{
+		.obj_name = "USER",
+		.obj_type = CKPT_OBJ_USER,
+		.ref_drop = obj_user_drop,
+		.ref_grab = obj_user_grab,
+		.ref_users = obj_user_users,
+		.checkpoint = checkpoint_user,
+		.restore = restore_user,
+	},
+	/* struct groupinfo */
+	{
+		.obj_name = "GROUPINFO",
+		.obj_type = CKPT_OBJ_GROUPINFO,
+		.ref_drop = obj_groupinfo_drop,
+		.ref_grab = obj_groupinfo_grab,
+		.ref_users = obj_groupinfo_users,
+		.checkpoint = checkpoint_groupinfo,
+		.restore = restore_groupinfo,
+	},
 };
 
 
@@ -313,6 +419,32 @@ int ckpt_obj_hash_alloc(struct ckpt_ctx *ctx)
 	return 0;
 }
 
+static struct ckpt_obj *obj_find_by_ptr(struct ckpt_ctx *ctx, void *ptr)
+{
+	struct hlist_head *h;
+	struct hlist_node *n;
+	struct ckpt_obj *obj;
+
+	h = &ctx->obj_hash->head[hash_long((unsigned long) ptr,
+					   CKPT_OBJ_HASH_NBITS)];
+	hlist_for_each_entry(obj, n, h, hash)
+		if (obj->ptr == ptr)
+			return obj;
+	return NULL;
+}
+
+/*
+ * look up an obj and return objref if in hash, else
+ * return 0.  Used during checkpoint.
+ */
+int obj_lookup(struct ckpt_ctx *ctx, void *ptr)
+{
+	struct ckpt_obj *obj = obj_find_by_ptr(ctx, ptr);
+	if (obj)
+		return obj->objref;
+	return 0;
+}
+
 /**
  * ckpt_obj_new - add an object to the obj_hash
  * @ctx: checkpoint context
@@ -370,20 +502,6 @@ static struct ckpt_obj *obj_new(struct ckpt_ctx *ctx, void *ptr,
  * Checkpoint
  */
 
-static struct ckpt_obj *obj_find_by_ptr(struct ckpt_ctx *ctx, void *ptr)
-{
-	struct hlist_head *h;
-	struct hlist_node *n;
-	struct ckpt_obj *obj;
-
-	h = &ctx->obj_hash->head[hash_long((unsigned long) ptr,
-					   CKPT_OBJ_HASH_NBITS)];
-	hlist_for_each_entry(obj, n, h, hash)
-		if (obj->ptr == ptr)
-			return obj;
-	return NULL;
-}
-
 /**
  * obj_lookup_add - lookup object and add if not in objhash
  * @ctx: checkpoint context
checkpoint/process.c +150 -2

214 lines not on this page · raw message

include/linux/checkpoint.h +11 -0
index 7005227..db47d47 100644
@@ -97,6 +97,7 @@ extern void *ckpt_obj_fetch(struct ckpt_ctx *ctx, int objref,
 			    enum obj_type type);
 extern int ckpt_obj_lookup_add(struct ckpt_ctx *ctx, void *ptr,
 			       enum obj_type type, int *first);
+extern int obj_lookup(struct ckpt_ctx *ctx, void *ptr);
 extern int ckpt_obj_insert(struct ckpt_ctx *ctx, void *ptr, int objref,
 			   enum obj_type type);
 
@@ -163,6 +164,16 @@ extern int checkpoint_file_common(struct ckpt_ctx *ctx, struct file *file,
 extern int restore_file_common(struct ckpt_ctx *ctx, struct file *file,
 			       struct ckpt_hdr_file *h);
 
+/* credentials */
+int checkpoint_groupinfo(struct ckpt_ctx *ctx, void *ptr);
+int checkpoint_userns(struct ckpt_ctx *ctx, void *ptr);
+int checkpoint_user(struct ckpt_ctx *ctx, void *ptr);
+int checkpoint_cred(struct ckpt_ctx *ctx, void *ptr);
+void *restore_groupinfo(struct ckpt_ctx *ctx);
+void *restore_userns(struct ckpt_ctx *ctx);
+void *restore_user(struct ckpt_ctx *ctx);
+void *restore_cred(struct ckpt_ctx *ctx);
+
 /* memory */
 extern void ckpt_pgarr_free(struct ckpt_ctx *ctx);
 
include/linux/checkpoint_hdr.h +60 -0

84 lines not on this page · raw message

include/linux/checkpoint_types.h +1 -0
index df88c55..452cd57 100644
@@ -65,6 +65,7 @@ struct ckpt_ctx {
 	atomic_t tasks_count;		/* sync of tasks: used to coordinate */
 	struct completion complete;	/* container root and other tasks on */
 	wait_queue_head_t waitq;	/* start, end, and restart ordering */
+	struct cred *realcred, *ecred;	/* tmp storage for cred at restart */
 };
 
 #endif /* __KERNEL__ */
include/linux/cred.h +13 -0
index 2ffffbe..e3269d5 100644
@@ -77,6 +77,14 @@ extern int groups_search(const struct group_info *, gid_t);
 extern int in_group_p(gid_t);
 extern int in_egroup_p(gid_t);
 
+#ifdef CONFIG_CHECKPOINT
+struct ckpt_ctx;
+int checkpoint_write_groupinfo(struct ckpt_ctx *, struct group_info *);
+struct group_info *restore_read_groupinfo(struct ckpt_ctx *);
+int checkpoint_write_user(struct ckpt_ctx *, struct user_struct *);
+struct user_struct *restore_read_user(struct ckpt_ctx *);
+#endif
+
 /*
  * The common credentials for a thread group
  * - shared by CLONE_THREAD
@@ -352,4 +360,9 @@ int cred_setresgid(struct cred *new, gid_t rgid, gid_t egid, gid_t sgid);
 int cred_setfsuid(struct cred *new, uid_t uid, uid_t *old_fsuid);
 int cred_setfsgid(struct cred *new, gid_t gid, gid_t *old_fsgid);
 
+#ifdef CONFIG_CHECKPOINT
+int checkpoint_write_cred(struct ckpt_ctx *, const struct cred *);
+struct cred *restore_read_cred(struct ckpt_ctx *);
+#endif
+
 #endif /* _LINUX_CRED_H */
include/linux/user_namespace.h +6 -0
index a2b82d5..3eeee40 100644
@@ -62,4 +62,10 @@ static inline void put_user_ns(struct user_namespace *ns)
 
 #endif
 
+#ifdef CONFIG_CHECKPOINT
+struct ckpt_ctx;
+int checkpoint_write_userns(struct ckpt_ctx *, struct user_namespace *);
+struct user_namespace *restore_read_userns(struct ckpt_ctx *);
+#endif
+
 #endif /* _LINUX_USER_H */
kernel/cred.c +113 -0

122 lines not on this page · raw message

kernel/groups.c +59 -0

68 lines not on this page · raw message

kernel/user.c +147 -0

156 lines not on this page · raw message

kernel/user_namespace.c +86 -0

95 lines not on this page · raw message

Signature · 1 line
1.6.1
#11 lore raw

PATCH 8/10 cr: restore file->f_cred

In reply to a message not in the archive

Restore a file's f_cred. This is set to the cred of the task doing the open, so often it will be the same as that of the restarted task.

---
 checkpoint/files.c             |   16 ++++++++++++++--
 include/linux/checkpoint_hdr.h |    2 +-
 2 files changed, 15 insertions(+), 3 deletions(-)
checkpoint/files.c +14 -2
index 5ca2e6c..5be7d1b 100644
@@ -151,7 +151,11 @@ int checkpoint_file_common(struct ckpt_ctx *ctx, struct file *file,
 	h->f_pos = file->f_pos;
 	h->f_version = file->f_version;
 
-	/* FIX: need also file->uid, file->gid, file->f_owner, etc */
+	h->f_credref = checkpoint_obj(ctx, file->f_cred, CKPT_OBJ_CRED);
+	if (h->f_credref < 0)
+		return h->f_credref;
+
+	/* FIX: need also file->f_owner, etc */
 
 	return 0;
 }
@@ -440,8 +444,16 @@ int restore_file_common(struct ckpt_ctx *ctx, struct file *file,
 			struct ckpt_hdr_file *h)
 {
 	int ret;
+	struct cred *cred;
+
+	/* FIX: need to restore owner etc */
 
-	/* FIX: need to restore uid, gid, owner etc */
+	/* restore the cred */
+	cred = ckpt_obj_fetch(ctx, h->f_credref, CKPT_OBJ_CRED);
+	if (IS_ERR(cred))
+		return PTR_ERR(cred);
+	put_cred(file->f_cred);
+	file->f_cred = get_cred(cred);
 
 	/* 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);
include/linux/checkpoint_hdr.h +1 -1
index 02f874e..1a4033c 100644
@@ -306,7 +306,7 @@ struct ckpt_hdr_file {
 	__u32 f_type;
 	__u32 f_mode;
 	__u32 f_flags;
-	__u32 _padding;
+	__s32 f_credref;
 	__u64 f_pos;
 	__u64 f_version;
 } __attribute__((aligned(8)));
Signature · 1 line
1.6.1
#12 lore raw

PATCH 9/10 cr: restore LSM credentials

In reply to a message not in the archive

Checkpoint and restore task and ipc struct ->security info. (files->f_security yet to be done).

LSM contexts (a string representation of obj->security) are checkpointed as shared objects before any object referencing it. The object's checkpoint header struct has a reference (h->sec_ref) to the shared object. A NULL ->security is indicated by h->sec_ref = -1.

At checkpoint time, for each obj->security to be checkpointed, the LSM will be asked (once) to convert it to a string, in memory which the checkpoint subsystem will kfree. At restart time, the LSM will first return some meaningful token given the checkpointed string. That token will be passed to per-object-type restore functions (task_restore_context(), shm_restore_security(), etc) where the LSM can determine based on the object type, the caller, and the token, whether to allow the object restore, and what value to actually assign to ->security. In smack, the token is the actual imported label. In SELinux, it is a temporary pointer to the sid which the checkpointed context referred to.

In smack, the checkpointed labels are used for both tasks and ipc objects so long as the task calling sys_restart() has CAP_MAC_ADMIN. Otherwise, if the checkpointed label is different from current_security(), -EPERM is returned.

The basics of SELinux support are there (enough to demonstrate working c/r with SELinux enforcing), but there will need to be new object permissions for restore, so the precise nature of those needs to be discussed. For instance, do we want to define process:restore and ipc_msg_msg:restore, in which case
allow root_t user_t:process restore
would mean that root_t may restart a task and label it user_t?

Since we are potentially skipping several allowed domain transitions (resulting in an illegal short-cut domain transition or type creation), I have a fear that the only sane way to proceed would be to have one all-powerful domain, checkpoint_restore_t, which can effectively transition to any domain it wants to by (ab)using the checkpoint image.

Or, perhaps we can define intermediate domains... So if we want user_t to be able to restart a server of type X_t, then we create a X_restore_t type, allow user_t to transition to it using a program which does sys_restart(), which in turn may transition to X_t?

Obviously this needs discussion.

Tomoyo has not been updated or tested. Given its path-based domain name model, I'm not sure what the tomoyo maintainers would prefer - that the restart program be reflected in the domain name, or that the original domain name be restored.

This is the first posting of this patch. There are testcases in git://git.sr71.net/~hallyn/cr_tests.git , in particular under (the slightly mis-named) cr_tests/userns/ directory. All pass fine with all LSMS (except Tomoyo, not tested).

---
 checkpoint/objhash.c           |   56 ++++++++++++
 include/linux/checkpoint_hdr.h |   15 +++
 include/linux/security.h       |  105 +++++++++++++++++++++
 ipc/checkpoint.c               |   19 +++--
 ipc/checkpoint_msg.c           |   30 ++++++-
 ipc/checkpoint_sem.c           |   12 +++-
 ipc/checkpoint_shm.c           |   12 +++-
 ipc/util.h                     |    3 +-
 kernel/cred.c                  |   29 ++++++-
 security/capability.c          |   47 ++++++++++
 security/security.c            |   39 ++++++++
 security/selinux/hooks.c       |  196 ++++++++++++++++++++++++++++++++++++++++
 security/smack/smack_lsm.c     |  135 +++++++++++++++++++++++++++
 13 files changed, 686 insertions(+), 12 deletions(-)
checkpoint/objhash.c +56 -0
index 84f003d..674b9b3 100644
@@ -20,6 +20,7 @@
 #include <linux/user_namespace.h>
 #include <linux/checkpoint.h>
 #include <linux/checkpoint_hdr.h>
+#include <linux/security.h>
 
 struct ckpt_obj;
 struct ckpt_obj_ops;
@@ -247,6 +248,52 @@ static int obj_groupinfo_users(void *ptr)
 	return atomic_read(&((struct group_info *) ptr)->usage);
 }
 
+/*
+ * checkpoint_string - checkpoint a shared string
+ * @ctx: checkpoint context
+ * @str: string to checkpoint
+ *
+ * If ptr has already been checkpointed, return the objref
+ * Else write it to checkpoint image and return the objref
+ * On error, return <0.
+ */
+#define MAX_STR_LEN 200
+static int checkpoint_security(struct ckpt_ctx *ctx, void *ptr)
+{
+	char *str;
+	int ret;
+	int len = 0;
+
+	str = security_context_to_str(ptr);
+	if (!str)
+		return 0;
+	if (IS_ERR(str))
+		return PTR_ERR(str);
+	len = strlen(str) + 1;
+	if (len > MAX_STR_LEN) {
+		printk(KERN_NOTICE "%s: security context too long\n",
+			__func__);
+		return -EINVAL;
+	}
+	ret = ckpt_write_obj_type(ctx, str, len, CKPT_HDR_SEC);
+	/* the LSM created a new string for us, now free it */
+	kfree(str);
+	return ret;
+}
+
+static void *restore_security(struct ckpt_ctx *ctx)
+{
+	struct ckpt_hdr_lsm *h;
+	void *security;
+
+	h = ckpt_read_buf_type(ctx, MAX_STR_LEN, CKPT_HDR_SEC);
+	if (IS_ERR(h))
+		return ERR_PTR(PTR_ERR(h));
+	security = security_context_from_str(h->str);
+	ckpt_hdr_put(ctx, h);
+	return security;
+}
+
 static struct ckpt_obj_ops ckpt_obj_ops[] = {
 	/* ignored object */
 	{
@@ -364,6 +411,15 @@ static struct ckpt_obj_ops ckpt_obj_ops[] = {
 		.checkpoint = checkpoint_groupinfo,
 		.restore = restore_groupinfo,
 	},
+	/* struct ckpt_sec */
+	{
+		.obj_name = "SECURITY",
+		.obj_type = CKPT_OBJ_SEC,
+		.ref_drop = obj_no_drop,
+		.ref_grab = obj_no_grab,
+		.checkpoint = checkpoint_security,
+		.restore = restore_security,
+	},
 };
 
 
include/linux/checkpoint_hdr.h +15 -0
index 1a4033c..a447b5a 100644
@@ -45,6 +45,7 @@ enum {
 	CKPT_HDR_BUFFER,
 	CKPT_HDR_STRING,
 	CKPT_HDR_OBJREF,
+	CKPT_HDR_SEC,
 
 	CKPT_HDR_TREE = 101,
 	CKPT_HDR_TASK,
@@ -114,6 +115,7 @@ enum obj_type {
 	CKPT_OBJ_CRED,
 	CKPT_OBJ_USER,
 	CKPT_OBJ_GROUPINFO,
+	CKPT_OBJ_SEC,
 	CKPT_OBJ_MAX
 };
 
@@ -181,6 +183,13 @@ struct ckpt_hdr_task {
 	__u32 task_comm_len;
 } __attribute__((aligned(8)));
 
+/* LSM security contexts (shared) */
+struct ckpt_hdr_lsm {
+	struct ckpt_hdr h;
+	/* followed by `len' characters */
+	char str[];
+} __attribute__((aligned(8)));
+
 /* Posix capabilities */
 struct ckpt_capabilities {
 	__u32 cap_i_0, cap_i_1; /* inheritable set */
@@ -204,6 +213,8 @@ struct ckpt_hdr_cred {
 	__s32 user_ref;
 	__s32 groupinfo_ref;
 	struct ckpt_capabilities cap_s;
+	__s32 sec_ref;
+	__u32 padding;
 } __attribute__((aligned(8)));
 
 struct ckpt_hdr_groupinfo {
@@ -418,6 +429,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 {
@@ -451,6 +464,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/security.h +105 -0

217 lines not on this page · raw message

ipc/checkpoint.c +12 -7
index bc77743..6da8ac8 100644
@@ -27,7 +27,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))
@@ -42,6 +43,13 @@ int checkpoint_fill_ipc_perms(struct ckpt_hdr_ipc_perms *h,
 	h->mode = perm->mode & S_IRWXUGO;
 	h->seq = perm->seq;
 
+	if (perm->security) {
+		h->sec_ref = checkpoint_obj(ctx, perm->security, CKPT_OBJ_SEC);
+		if (h->sec_ref < 0)
+			return h->sec_ref;
+	} else
+		h->sec_ref = -1;
+
 	return 0;
 }
 
@@ -169,13 +177,10 @@ int restore_load_ipc_perms(struct ckpt_hdr_ipc_perms *h,
 	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.
+	 * The checkpointed ->security value will be restored
+	 * (and verified) by our caller.
 	 */
+	perm->security = NULL;
 
 	return 0;
 }
ipc/checkpoint_msg.c +29 -1
index fb1a61e..025e33f 100644
@@ -18,6 +18,7 @@
 #include <linux/syscalls.h>
 #include <linux/nsproxy.h>
 #include <linux/ipc_namespace.h>
+#include <linux/security.h>
 
 #include "util.h"
 
@@ -36,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;
 
@@ -63,13 +64,20 @@ 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 = checkpoint_obj(ctx, msg->security, CKPT_OBJ_SEC);
+		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);
@@ -175,10 +183,19 @@ static int load_ipc_msg_hdr(struct ckpt_ctx *ctx,
 			    struct msg_queue *msq)
 {
 	int ret = 0;
+	void *security = NULL;;
 
 	ret = restore_load_ipc_perms(&h->perms, &msq->q_perm);
 	if (ret < 0)
 		return ret;
+	if (h->perms.sec_ref != -1) {
+		security = ckpt_obj_fetch(ctx, h->perms.sec_ref, CKPT_OBJ_SEC);
+		if (IS_ERR(security))
+			return PTR_ERR(security);
+	}
+	ret = security_msg_queue_restore(msq, security);
+	if (ret)
+		return ret;
 
 	ckpt_debug("msq: lspid %d lrpid %d qnum %lld qbytes %lld\n",
 		 h->q_lspid, h->q_lrpid, h->q_qnum, h->q_qbytes);
@@ -200,6 +217,7 @@ static struct msg_msg *restore_msg_contents_one(struct ckpt_ctx *ctx, int *clen)
 	struct ckpt_hdr_ipc_msg_msg *h;
 	struct msg_msg *msg = NULL;
 	struct msg_msgseg *seg, **pseg;
+	void *security = NULL;
 	int total, len;
 	int ret;
 
@@ -222,6 +240,16 @@ static struct msg_msg *restore_msg_contents_one(struct ckpt_ctx *ctx, int *clen)
 	}
 	msg->next = NULL;
 	pseg = &msg->next;
+	if (h->sec_ref != -1) {
+		security = ckpt_obj_fetch(ctx, h->sec_ref, CKPT_OBJ_SEC);
+		if (IS_ERR(security)) {
+			ret = PTR_ERR(security);
+			goto out;
+		}
+	}
+	ret = security_msg_msg_restore(msg, security);
+	if (ret)
+		goto out;
 
 	ret = _ckpt_read_buffer(ctx, (msg + 1), len);
 	if (ret < 0)
ipc/checkpoint_sem.c +11 -1
index e6934dc..cd76bcc 100644
@@ -18,6 +18,7 @@
 #include <linux/syscalls.h>
 #include <linux/nsproxy.h>
 #include <linux/ipc_namespace.h>
+#include <linux/security.h>
 
 #include <linux/msg.h>	/* needed for util.h that uses 'struct msg_msg' */
 #include "util.h"
@@ -37,7 +38,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;
 
@@ -112,10 +113,19 @@ static int load_ipc_sem_hdr(struct ckpt_ctx *ctx,
 			       struct sem_array *sem)
 {
 	int ret = 0;
+	void *security = NULL;
 
 	ret = restore_load_ipc_perms(&h->perms, &sem->sem_perm);
 	if (ret < 0)
 		return ret;
+	if (h->perms.sec_ref != -1) {
+		security = ckpt_obj_fetch(ctx, h->perms.sec_ref, CKPT_OBJ_SEC);
+		if (IS_ERR(security))
+			return PTR_ERR(security);
+	}
+	ret = security_sem_restore(sem, security);
+	if (ret)
+		return ret;
 
 	ckpt_debug("sem: nsems %u\n", h->sem_nsems);
 
ipc/checkpoint_shm.c +11 -1
index 0d8eb14..cf100fe 100644
@@ -22,6 +22,7 @@
 #include <linux/nsproxy.h>
 #include <linux/ipc_namespace.h>
 #include <linux/deferqueue.h>
+#include <linux/security.h>
 
 #include <linux/msg.h>	/* needed for util.h that uses 'struct msg_msg' */
 #include "util.h"
@@ -41,7 +42,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;
 
@@ -148,10 +149,19 @@ static int load_ipc_shm_hdr(struct ckpt_ctx *ctx,
 			    struct shmid_kernel *shp)
 {
 	int ret;
+	void *security = NULL;
 
 	ret = restore_load_ipc_perms(&h->perms, &shp->shm_perm);
 	if (ret < 0)
 		return ret;
+	if (h->perms.sec_ref != -1) {
+		security = ckpt_obj_fetch(ctx, h->perms.sec_ref, CKPT_OBJ_SEC);
+		if (IS_ERR(security))
+			return PTR_ERR(security);
+	}
+	ret = security_shm_restore(shp, security);
+	if (ret)
+		return ret;
 
 	ckpt_debug("shm: cprid %d lprid %d segsz %lld mlock %d\n",
 		 h->shm_cprid, h->shm_lprid, h->shm_segsz, h->mlock_uid);
ipc/util.h +2 -1
index 020de7b..5976308 100644
@@ -192,7 +192,8 @@ extern void freeary(struct ipc_namespace *, struct kern_ipc_perm *);
 extern void do_shm_rmid(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,
 				  struct kern_ipc_perm *perm);
kernel/cred.c +28 -1
index 6ef75a1..c47d175 100644
@@ -709,8 +709,9 @@ int cred_setfsgid(struct cred *new, gid_t gid, gid_t *old_fsgid)
 int checkpoint_write_cred(struct ckpt_ctx *ctx, const struct cred *cred)
 {
 	int ret;
-	int groupinfo_ref, user_ref;
+	int groupinfo_ref, user_ref, sec_ref = -1;
 	struct ckpt_hdr_cred *h;
+	void *security = NULL;
 
 	groupinfo_ref = checkpoint_obj(ctx, cred->group_info,
 					CKPT_OBJ_GROUPINFO);
@@ -719,6 +720,16 @@ int checkpoint_write_cred(struct ckpt_ctx *ctx, const struct cred *cred)
 	user_ref = checkpoint_obj(ctx, cred->user, CKPT_OBJ_USER);
 	if (user_ref < 0)
 		return user_ref;
+#ifdef CONFIG_SECURITY
+	/* should we checkpoint a 'lsm_na' field when !security ? */
+	security = cred->security;
+#endif
+
+	if (security) {
+		sec_ref = checkpoint_obj(ctx, security, CKPT_OBJ_SEC);
+		if (sec_ref < 0)
+			return sec_ref;
+	}
 
 	h = ckpt_hdr_get_type(ctx, sizeof(*h), CKPT_HDR_CRED);
 	if (!h)
@@ -738,6 +749,7 @@ int checkpoint_write_cred(struct ckpt_ctx *ctx, const struct cred *cred)
 
 	h->user_ref = user_ref;
 	h->groupinfo_ref = groupinfo_ref;
+	h->sec_ref = sec_ref;
 
 	ret = ckpt_write_obj(ctx, (struct ckpt_hdr *) h);
 	ckpt_hdr_put(ctx, h);
@@ -751,6 +763,7 @@ struct cred *restore_read_cred(struct ckpt_ctx *ctx)
 	struct ckpt_hdr_cred *h;
 	struct user_struct *user;
 	struct group_info *groupinfo;
+	void *security = NULL;
 	int ret = -EINVAL;
 	uid_t olduid;
 	gid_t oldgid;
@@ -774,6 +787,20 @@ struct cred *restore_read_cred(struct ckpt_ctx *ctx)
 	user = ckpt_obj_fetch(ctx, h->user_ref, CKPT_OBJ_USER);
 	if (IS_ERR(user))
 		goto err_putcred;
+	if (h->sec_ref != -1)
+		security = ckpt_obj_fetch(ctx, h->sec_ref, CKPT_OBJ_SEC);
+	if (IS_ERR(security))
+		goto err_putcred;
+
+#ifdef CONFIG_SECURITY
+	/*
+	 * Ask LSM to reset original task->security if allowed
+	 */
+	ret = security_task_restore_context(cred, security,
+					ctx->file->f_security);
+	if (ret)
+		goto err_putcred;
+#endif
 
 	/*
 	 * TODO: this check should  go into the common helper in
security/capability.c +47 -0

100 lines not on this page · raw message

security/security.c +39 -0
index 5284255..26e7989 100644
@@ -827,6 +827,11 @@ int security_msg_msg_alloc(struct msg_msg *msg)
 	return security_ops->msg_msg_alloc_security(msg);
 }
 
+int security_msg_msg_restore(struct msg_msg *msg, void *stored)
+{
+	return security_ops->msg_msg_restore_security(msg, stored);
+}
+
 void security_msg_msg_free(struct msg_msg *msg)
 {
 	security_ops->msg_msg_free_security(msg);
@@ -837,6 +842,11 @@ int security_msg_queue_alloc(struct msg_queue *msq)
 	return security_ops->msg_queue_alloc_security(msq);
 }
 
+int security_msg_queue_restore(struct msg_queue *msq, void *stored)
+{
+	return security_ops->msg_queue_restore_security(msq, stored);
+}
+
 void security_msg_queue_free(struct msg_queue *msq)
 {
 	security_ops->msg_queue_free_security(msq);
@@ -869,6 +879,11 @@ int security_shm_alloc(struct shmid_kernel *shp)
 	return security_ops->shm_alloc_security(shp);
 }
 
+int security_shm_restore(struct shmid_kernel *shp, void *stored)
+{
+	return security_ops->shm_restore_security(shp, stored);
+}
+
 void security_shm_free(struct shmid_kernel *shp)
 {
 	security_ops->shm_free_security(shp);
@@ -894,6 +909,11 @@ int security_sem_alloc(struct sem_array *sma)
 	return security_ops->sem_alloc_security(sma);
 }
 
+int security_sem_restore(struct sem_array *sma, void *stored)
+{
+	return security_ops->sem_restore_security(sma, stored);
+}
+
 void security_sem_free(struct sem_array *sma)
 {
 	security_ops->sem_free_security(sma);
@@ -962,6 +982,25 @@ void security_release_secctx(char *secdata, u32 seclen)
 }
 EXPORT_SYMBOL(security_release_secctx);
 
+char *security_context_to_str(void *security)
+{
+	return security_ops->context_to_str(security);
+}
+EXPORT_SYMBOL(security_context_to_str);
+
+void *security_context_from_str(char *str)
+{
+	return security_ops->context_from_str(str);
+}
+EXPORT_SYMBOL(security_context_from_str);
+
+int security_task_restore_context(struct cred *cred, void *stored,
+			void *f_security)
+{
+	return security_ops->task_restore_context(cred, stored, f_security);
+}
+EXPORT_SYMBOL(security_task_restore_context);
+
 #ifdef CONFIG_SECURITY_NETWORK
 
 int security_unix_stream_connect(struct socket *sock, struct socket *other,
security/selinux/hooks.c +196 -0

253 lines not on this page · raw message

security/smack/smack_lsm.c +135 -0

192 lines not on this page · raw message

Signature · 7 lines
1.6.1


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.

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

#14 lore raw

Re: [PATCH 09/10] cr: restore LSM credentials

Quoted 84 lines · Serge E. Hallyn

Checkpoint and restore task and ipc struct ->security info. (files->f_security yet to be done).

LSM contexts (a string representation of obj->security) are checkpointed as shared objects before any object referencing it. The object's checkpoint header struct has a reference (h->sec_ref) to the shared object. A NULL ->security is indicated by h->sec_ref = -1.

At checkpoint time, for each obj->security to be checkpointed, the LSM will be asked (once) to convert it to a string, in memory which the checkpoint subsystem will kfree. At restart time, the LSM will first return some meaningful token given the checkpointed string. That token will be passed to per-object-type restore functions (task_restore_context(), shm_restore_security(), etc) where the LSM can determine based on the object type, the caller, and the token, whether to allow the object restore, and what value to actually assign to ->security. In smack, the token is the actual imported label. In SELinux, it is a temporary pointer to the sid which the checkpointed context referred to.

In smack, the checkpointed labels are used for both tasks and ipc objects so long as the task calling sys_restart() has CAP_MAC_ADMIN. Otherwise, if the checkpointed label is different from current_security(), -EPERM is returned.

The basics of SELinux support are there (enough to demonstrate working c/r with SELinux enforcing), but there will need to be new object permissions for restore, so the precise nature of those needs to be discussed. For instance, do we want to define process:restore and ipc_msg_msg:restore, in which case
allow root_t user_t:process restore
would mean that root_t may restart a task and label it user_t?

Since we are potentially skipping several allowed domain transitions (resulting in an illegal short-cut domain transition or type creation), I have a fear that the only sane way to proceed would be to have one all-powerful domain, checkpoint_restore_t, which can effectively transition to any domain it wants to by (ab)using the checkpoint image.

Or, perhaps we can define intermediate domains... So if we want user_t to be able to restart a server of type X_t, then we create a X_restore_t type, allow user_t to transition to it using a program which does sys_restart(), which in turn may transition to X_t?

Obviously this needs discussion.

Tomoyo has not been updated or tested. Given its path-based domain name model, I'm not sure what the tomoyo maintainers would prefer - that the restart program be reflected in the domain name, or that the original domain name be restored.

This is the first posting of this patch. There are testcases in git://git.sr71.net/~hallyn/cr_tests.git , in particular under (the slightly mis-named) cr_tests/userns/ directory. All pass fine with all LSMS (except Tomoyo, not tested).

---
 checkpoint/objhash.c           |   56 ++++++++++++
 include/linux/checkpoint_hdr.h |   15 +++
 include/linux/security.h       |  105 +++++++++++++++++++++
 ipc/checkpoint.c               |   19 +++--
 ipc/checkpoint_msg.c           |   30 ++++++-
 ipc/checkpoint_sem.c           |   12 +++-
 ipc/checkpoint_shm.c           |   12 +++-
 ipc/util.h                     |    3 +-
 kernel/cred.c                  |   29 ++++++-
 security/capability.c          |   47 ++++++++++
 security/security.c            |   39 ++++++++
 security/selinux/hooks.c       |  196 ++++++++++++++++++++++++++++++++++++++++
 security/smack/smack_lsm.c     |  135 +++++++++++++++++++++++++++
 13 files changed, 686 insertions(+), 12 deletions(-)

...

security/smack/smack_lsm.c +0 -0
index 98b3195..dfc0f7a 100644

security/smack/smack_lsm.c static int smack_msg_msg_alloc_security(struct msg_msg *msg) · line 1616

Quoted 9 lines
security/smack/smack_lsm.c +5 -0
@@ -1608,6 +1608,32 @@ static int smack_msg_msg_alloc_security(struct msg_msg *msg)
 }
 
 /**
+ * smack_msg_msg_restore_security - Set the security blob for msg_msg
+ * @msg: the object
+ * @stored: the checkpointed label
+ *
+ * Returns 0
 

Comment ought to reflect the actual behavior.

security/smack/smack_lsm.c static int smack_msg_msg_alloc_security(struct msg_msg *msg)

Quoted 7 lines
security/smack/smack_lsm.c +6 -0
+ */
+static int smack_msg_msg_restore_security(struct msg_msg *msg,
+					void *stored)
+{
+	struct kern_ipc_perm *isp = &sma->sem_perm;
+	char *str = smk_import(stored, 0);
 

To be really nit-picky, I'd prefer a variable name that indicates it's a Smack label rather than just any old character string. Perhaps

    char *smack = smk_import(stored, 0);

security/smack/smack_lsm.c static int smack_msg_msg_alloc_security(struct msg_msg *msg)

Quoted 13 lines
security/smack/smack_lsm.c +12 -0
+
+	if (str == NULL)
+		return -EINVAL;
+
+	msg->security = current_security();
+	if (current_security() != str) {
+		if (!capable(CAP_MAC_ADMIN))
+			return -EPERM;
+		msg->security = str;
+	}
+	return 0;
+	return 0;
 

Returning once is sufficient.

Quoted 7 lines
security/smack/smack_lsm.c +3 -0
+}
+
+/**

* smack_msg_msg_free_security - Clear the security blob for msg_msg
* @msg: the object
*

security/smack/smack_lsm.c static int smack_shm_alloc_security(struct shmid_kernel *shp) · line 1678

Quoted 9 lines
security/smack/smack_lsm.c +5 -0
@@ -1644,6 +1670,30 @@ static int smack_shm_alloc_security(struct shmid_kernel *shp)
 }
 
 /**
+ * smack_shm_restore_security - retore the security blob for shm
+ * @shp: the object
+ * @stored: the checkpointed label
+ *
+ * Returns 0
 

Previous comment comment applies here as well.

Quoted 23 lines
security/smack/smack_lsm.c +19 -0
+ */
+static int smack_shm_restore_security(struct shmid_kernel *shp, void *stored)
+{
+	struct kern_ipc_perm *isp = &shp->shm_perm;
+	char *str = smk_import(stored, 0);
+
+	if (str == NULL)
+		return -EINVAL;
+
+	isp->security = current_security();
+	if (current_security() != str) {
+		if (!capable(CAP_MAC_ADMIN))
+			return -EPERM;
+		isp->security = str;
+	}
+	return 0;
+}
+
+/**
  * smack_shm_free_security - Clear the security blob for shm
  * @shp: the object

*

security/smack/smack_lsm.c static int smack_sem_alloc_security(struct sem_array *sma) · line 1811

Quoted 9 lines
security/smack/smack_lsm.c +5 -0
@@ -1753,6 +1803,31 @@ static int smack_sem_alloc_security(struct sem_array *sma)
 }
 
 /**
+ * smack_sem_restore_security - Set the security blob for sem
+ * @sma: the object
+ * @stored: the label stored in checkpoint image
+ *
+ * Returns 0
 

Or an error if the label is bad, as above.

Quoted 24 lines
security/smack/smack_lsm.c +20 -0
+ */
+static int smack_sem_restore_security(struct sem_array *sma,
+				void *stored)
+{
+	struct kern_ipc_perm *isp = &sma->sem_perm;
+	char *str = smk_import(stored, 0);
+
+	if (str == NULL)
+		return -EINVAL;
+
+	isp->security = current_security();
+	if (current_security() != str) {
+		if (!capable(CAP_MAC_ADMIN))
+			return -EPERM;
+		isp->security = str;
+	}
+	return 0;
+}
+
+/**
  * smack_sem_free_security - Clear the security blob for sem
  * @sma: the object

*

security/smack/smack_lsm.c static int smack_msg_queue_alloc_security(struct msg_queue *msq) · line 1940

Quoted 9 lines
security/smack/smack_lsm.c +5 -0
@@ -1857,6 +1932,31 @@ static int smack_msg_queue_alloc_security(struct msg_queue *msq)
 }
 
 /**
+ * smack_msg_restore_security - Set the security blob for msg
+ * @msq: the object
+ * @stored: the stored label
+ *
+ * Returns 0
 

And again ...

Quoted 96 lines
security/smack/smack_lsm.c +20 -0
+ */
+static int smack_msg_queue_restore_security(struct msg_queue *msq,
+					void *stored)
+{
+	struct kern_ipc_perm *kisp = &msq->q_perm;
+	char *str = smk_import(stored, 0);
+
+	if (str == NULL)
+		return -EINVAL;
+
+	kisp->security = current_security();
+	if (current_security() != str) {
+		if (!capable(CAP_MAC_ADMIN))
+			return -EPERM;
+		kisp->security = str;
+	}
+	return 0;
+}
+
+/**
  * smack_msg_free_security - Clear the security blob for msg
  * @msq: the object

*

security/smack/smack_lsm.c +35 -0
@@ -2823,6 +2923,33 @@ static void smack_release_secctx(char *secdata, u32 seclen)
 {
 }
 
+/* checkpoint/restore hooks */
+static char *smack_context_to_str(void *security)
+{
+	return kstrdup((char *)security, GFP_KERNEL);
+}
+
+static void *smack_context_from_str(char *str)
+{
+	char *newsmack = smk_import(str, 0);
+
+	if (newsmack == NULL)
+		return ERR_PTR(-EINVAL);
+
+	return newsmack;
+}
+
+static int smack_task_restore_context(struct cred *cred, void *stored,
+					void *f_security)
+{
+	if (cred->security != stored) {
+		if (!capable(CAP_MAC_ADMIN))
+			return -EPERM;
+		cred->security = stored;
+	}
+	return 0;
+}
+
 struct security_operations smack_ops = {
 	.name =				"smack",
 
@@ -2902,9 +3029,11 @@ struct security_operations smack_ops = {
 	.ipc_getsecid =			smack_ipc_getsecid,
 
 	.msg_msg_alloc_security = 	smack_msg_msg_alloc_security,
+	.msg_msg_restore_security = 	smack_msg_msg_restore_security,
 	.msg_msg_free_security = 	smack_msg_msg_free_security,
 
 	.msg_queue_alloc_security = 	smack_msg_queue_alloc_security,
+	.msg_queue_restore_security = 	smack_msg_queue_restore_security,
 	.msg_queue_free_security = 	smack_msg_queue_free_security,
 	.msg_queue_associate = 		smack_msg_queue_associate,
 	.msg_queue_msgctl = 		smack_msg_queue_msgctl,
@@ -2912,12 +3041,14 @@ struct security_operations smack_ops = {
 	.msg_queue_msgrcv = 		smack_msg_queue_msgrcv,
 
 	.shm_alloc_security = 		smack_shm_alloc_security,
+	.shm_restore_security = 	smack_shm_restore_security,
 	.shm_free_security = 		smack_shm_free_security,
 	.shm_associate = 		smack_shm_associate,
 	.shm_shmctl = 			smack_shm_shmctl,
 	.shm_shmat = 			smack_shm_shmat,
 
 	.sem_alloc_security = 		smack_sem_alloc_security,
+	.sem_restore_security = 	smack_sem_restore_security,
 	.sem_free_security = 		smack_sem_free_security,
 	.sem_associate = 		smack_sem_associate,
 	.sem_semctl = 			smack_sem_semctl,
@@ -2964,6 +3095,10 @@ struct security_operations smack_ops = {
 	.secid_to_secctx = 		smack_secid_to_secctx,
 	.secctx_to_secid = 		smack_secctx_to_secid,
 	.release_secctx = 		smack_release_secctx,
+
+	.context_to_str =		smack_context_to_str,
+	.context_from_str =		smack_context_from_str,
+	.task_restore_context =		smack_task_restore_context,
 };
 
 
#15 lore raw

Re: [PATCH 09/10] cr: restore LSM credentials

In reply to a message not in the archive
Quoted 9 lines · Serge E. Hallyn

Checkpoint and restore task and ipc struct ->security info. (files->f_security yet to be done).

LSM contexts (a string representation of obj->security) are checkpointed as shared objects before any object referencing it. The object's checkpoint header struct has a reference (h->sec_ref) to the shared object. A NULL ->security is indicated by h->sec_ref = -1.

Quoted 11 lines

At checkpoint time, for each obj->security to be checkpointed, the LSM will be asked (once) to convert it to a string, in memory which the checkpoint subsystem will kfree. At restart time, the LSM will first return some meaningful token given the checkpointed string. That token will be passed to per-object-type restore functions (task_restore_context(), shm_restore_security(), etc) where the LSM can determine based on the object type, the caller, and the token, whether to allow the object restore, and what value to actually assign to ->security. In smack, the token is the actual imported label. In SELinux, it is a temporary pointer to the sid which the checkpointed context referred to.

Possibly I misunderstand, but it appears that you have a single security_context_to_str() hook that tries to take an arbitrary ->security pointer for any object type. I don't believe that is safe, as each object type may have its own security structure.

There are already LSM hooks to obtain secids for objects (task, ipc, inode, sock), and to convert between secid and secctx strings for use by the audit subsystem and networking subsystem. Why can't you just use those hooks for getting the secids and then converting them to secctx strings later?

Quoted 5 lines

In smack, the checkpointed labels are used for both tasks and ipc objects so long as the task calling sys_restart() has CAP_MAC_ADMIN. Otherwise, if the checkpointed label is different from current_security(), -EPERM is returned.

Quoted 7 lines

The basics of SELinux support are there (enough to demonstrate working c/r with SELinux enforcing), but there will need to be new object permissions for restore, so the precise nature of those needs to be discussed. For instance, do we want to define process:restore and ipc_msg_msg:restore, in which case
allow root_t user_t:process restore
would mean that root_t may restart a task and label it user_t?

I think so, yes.

Quoted 7 lines

Since we are potentially skipping several allowed domain transitions (resulting in an illegal short-cut domain transition or type creation), I have a fear that the only sane way to proceed would be to have one all-powerful domain, checkpoint_restore_t, which can effectively transition to any domain it wants to by (ab)using the checkpoint image.

Quoted 5 lines

Or, perhaps we can define intermediate domains... So if we want user_t to be able to restart a server of type X_t, then we create a X_restore_t type, allow user_t to transition to it using a program which does sys_restart(), which in turn may transition to X_t?

Different domains will make sense for different use cases. As long as the mechanism doesn't prevent us from crafting more limited privilege restore domains in policy, it shouldn't be a problem.

Signature · 2 lines
Stephen Smalley
National Security Agency

A message that is not in the archive (sent off-list or not yet received): 1244642042.20265.143.camel-bi+AKbBUZKY6gyzm1THtWbp2dZbC/[email protected]

#17 lore raw

Re: [PATCH 09/10] cr: restore LSM credentials

Quoted 10 lines · Stephen Smalley
Quoted 9 lines · Serge E. Hallyn

Checkpoint and restore task and ipc struct ->security info. (files->f_security yet to be done).

LSM contexts (a string representation of obj->security) are checkpointed as shared objects before any object referencing it. The object's checkpoint header struct has a reference (h->sec_ref) to the shared object. A NULL ->security is indicated by h->sec_ref = -1.

Quoted 11 lines
Quoted 11 lines

At checkpoint time, for each obj->security to be checkpointed, the LSM will be asked (once) to convert it to a string, in memory which the checkpoint subsystem will kfree. At restart time, the LSM will first return some meaningful token given the checkpointed string. That token will be passed to per-object-type restore functions (task_restore_context(), shm_restore_security(), etc) where the LSM can determine based on the object type, the caller, and the token, whether to allow the object restore, and what value to actually assign to ->security. In smack, the token is the actual imported label. In SELinux, it is a temporary pointer to the sid which the checkpointed context referred to.

Thanks for taking a look.

Quoted 2 lines

Possibly I misunderstand, but it appears that you have a single security_context_to_str() hook that tries to take an arbitrary

Yikes, you're right. And I remember telling myself that wouldn't work - then apparently I ran into the next problem and forgot.

Quoted 2 lines

->security pointer for any object type. I don't believe that is safe, as each object type may have its own security structure.

Absolutely. Which begs the question why it was working for me :)

Quoted 5 lines

There are already LSM hooks to obtain secids for objects (task, ipc, inode, sock), and to convert between secid and secctx strings for use by the audit subsystem and networking subsystem. Why can't you just use those hooks for getting the secids and then converting them to secctx strings later?

I had taken a look at the *_secid() hooks, and think I misunderstood them. Using those makes sense; I'll make that change.

Quoted 13 lines
Quoted 5 lines

In smack, the checkpointed labels are used for both tasks and ipc objects so long as the task calling sys_restart() has CAP_MAC_ADMIN. Otherwise, if the checkpointed label is different from current_security(), -EPERM is returned.

Quoted 7 lines

The basics of SELinux support are there (enough to demonstrate working c/r with SELinux enforcing), but there will need to be new object permissions for restore, so the precise nature of those needs to be discussed. For instance, do we want to define process:restore and ipc_msg_msg:restore, in which case
allow root_t user_t:process restore
would mean that root_t may restart a task and label it user_t?

Quoted 1 line

I think so, yes.

Ok, I'll define those in the next set.

thanks,
-serge

#18 lore raw

PATCH 10/10 cr: lsm: restore file->f_security

In reply to a message not in the archive

file->f_cred is the cred of the task which opened it. file->f_security can be separately set by the LSM. Checkpoint the file->f_security, and at restart ask the LSM, using security_file_restore, based on the current task's context and the checkpointed f_security, which f_security to apply (or whether to refuse the restart altogether).

For Smack, accept the checkpointed label if the restarting task has CAP_MAC_ADMIN.

For SELinux, I currently ignore the checkpointed label and call file_alloc_security(). Do we want to have 'restore' permission for class file?

---
 checkpoint/files.c             |   33 +++++++++++++++++++++++++++++++++
 include/linux/checkpoint_hdr.h |    1 +
 include/linux/security.h       |   13 +++++++++++++
 security/capability.c          |    6 ++++++
 security/security.c            |    5 +++++
 security/selinux/hooks.c       |   11 +++++++++++
 security/smack/smack_lsm.c     |   26 +++++++++++++++++++++++++-
 7 files changed, 94 insertions(+), 1 deletions(-)
checkpoint/files.c +33 -0
index 5be7d1b..36c7f35 100644
@@ -19,6 +19,7 @@
 #include <linux/fsnotify.h>
 #include <linux/pipe_fs_i.h>
 #include <linux/syscalls.h>
+#include <linux/security.h>
 #include <linux/checkpoint.h>
 #include <linux/checkpoint_hdr.h>
 
@@ -155,6 +156,14 @@ int checkpoint_file_common(struct ckpt_ctx *ctx, struct file *file,
 	if (h->f_credref < 0)
 		return h->f_credref;
 
+#ifdef CONFIG_SECURITY
+	if (file->f_security) {
+		h->f_secref = checkpoint_obj(ctx, file->f_security, CKPT_OBJ_SEC);
+		if (h->f_secref < 0)
+			return h->f_secref;
+	} else
+		h->f_secref = -1;
+#endif
 	/* FIX: need also file->f_owner, etc */
 
 	return 0;
@@ -437,6 +446,26 @@ static int attach_file(struct file *file)
 	return fd;
 }
 
+#ifdef CONFIG_SECURITY
+int restore_file_security(struct ckpt_ctx *ctx, struct file *file,
+			   struct ckpt_hdr_file *h)
+{
+	void *security = NULL;
+
+	if (h->f_secref != -1)
+		security = ckpt_obj_fetch(ctx, h->f_secref, CKPT_OBJ_SEC);
+	if (IS_ERR(security))
+		return PTR_ERR(security);
+	return security_file_restore(file, security);
+}
+#else
+static inline int restore_file_security(struct ckpt_ctx *ctx,
+		struct file *file, struct ckpt_hdr_file *h)
+{
+	return 0;
+}
+#endif
+
 #define CKPT_SETFL_MASK  \
 	(O_APPEND | O_NONBLOCK | O_NDELAY | FASYNC | O_DIRECT | O_NOATIME)
 
@@ -455,6 +484,10 @@ int restore_file_common(struct ckpt_ctx *ctx, struct file *file,
 	put_cred(file->f_cred);
 	file->f_cred = get_cred(cred);
 
+	ret = restore_file_security(ctx, file, h);
+	if (ret < 0)
+		goto out;
+
 	/* 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)
include/linux/checkpoint_hdr.h +1 -0
index a447b5a..1722826 100644
@@ -320,6 +320,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 {
include/linux/security.h +13 -0
index 5625553..936a2a1 100644
@@ -554,6 +554,12 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *	created.
  *	@file contains the file structure to secure.
  *	Return 0 if the hook is successful and permission is granted.
+ * @file_restore_security:
+ *	Allocate and attach a security structure to the file->f_security field
+ *	during sys_restart().
+ *	@file contains the file structure to secure.
+ *	@stored contains the checkpointed context.
+ *	Return 0 if the hook is successful and permission is granted.
  * @file_free_security:
  *	Deallocate and free any security structures stored in file->f_security.
  *	@file contains the file structure being modified.
@@ -1494,6 +1500,7 @@ struct security_operations {
 
 	int (*file_permission) (struct file *file, int mask);
 	int (*file_alloc_security) (struct file *file);
+	int (*file_restore_security) (struct file *file, void *stored);
 	void (*file_free_security) (struct file *file);
 	int (*file_ioctl) (struct file *file, unsigned int cmd,
 			   unsigned long arg);
@@ -1761,6 +1768,7 @@ int security_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer
 void security_inode_getsecid(const struct inode *inode, u32 *secid);
 int security_file_permission(struct file *file, int mask);
 int security_file_alloc(struct file *file);
+int security_file_restore(struct file *file, void *stored);
 void security_file_free(struct file *file);
 int security_file_ioctl(struct file *file, unsigned int cmd, unsigned long arg);
 int security_file_mmap(struct file *file, unsigned long reqprot,
@@ -2250,6 +2258,11 @@ static inline int security_file_alloc(struct file *file)
 	return 0;
 }
 
+static inline int security_file_restore(struct file *file, void *stored)
+{
+	return 0;
+}
+
 static inline void security_file_free(struct file *file)
 { }
 
security/capability.c +6 -0
index 4e586a7..f0a3c65 100644
@@ -320,6 +320,11 @@ static int cap_file_alloc_security(struct file *file)
 	return 0;
 }
 
+static int cap_file_restore_security(struct file *file, void *stored)
+{
+	return 0;
+}
+
 static void cap_file_free_security(struct file *file)
 {
 }
@@ -976,6 +981,7 @@ void security_fixup_ops(struct security_operations *ops)
 #endif
 	set_to_cap_if_null(ops, file_permission);
 	set_to_cap_if_null(ops, file_alloc_security);
+	set_to_cap_if_null(ops, file_restore_security);
 	set_to_cap_if_null(ops, file_free_security);
 	set_to_cap_if_null(ops, file_ioctl);
 	set_to_cap_if_null(ops, file_mmap);
security/security.c +5 -0
index 26e7989..0006e9c 100644
@@ -628,6 +628,11 @@ int security_file_alloc(struct file *file)
 	return security_ops->file_alloc_security(file);
 }
 
+int security_file_restore(struct file *file, void *stored)
+{
+	return security_ops->file_restore_security(file, stored);
+}
+
 void security_file_free(struct file *file)
 {
 	security_ops->file_free_security(file);
security/selinux/hooks.c +11 -0
index ba24808..4b8c636 100644
@@ -2973,6 +2973,16 @@ static int selinux_file_alloc_security(struct file *file)
 	return file_alloc_security(file);
 }
 
+static int selinux_file_restore_security(struct file *file,
+				void *stored)
+{
+	/*
+	 * TODO - actually restore from 'stored' subject to authorization
+	 */
+	kfree(stored);
+	return file_alloc_security(file);
+}
+
 static void selinux_file_free_security(struct file *file)
 {
 	file_free_security(file);
@@ -5566,6 +5576,7 @@ static struct security_operations selinux_ops = {
 
 	.file_permission =		selinux_file_permission,
 	.file_alloc_security =		selinux_file_alloc_security,
+	.file_restore_security =	selinux_file_restore_security,
 	.file_free_security =		selinux_file_free_security,
 	.file_ioctl =			selinux_file_ioctl,
 	.file_mmap =			selinux_file_mmap,
security/smack/smack_lsm.c +25 -1
index dfc0f7a..7bcdfde 100644
@@ -831,6 +831,30 @@ static int smack_file_alloc_security(struct file *file)
 }
 
 /**
+ * smack_file_restore_security - assign a file security blob
+ * @file: the object
+ * @stored: the label stored in the checkpoint file
+ *
+ * Returns 0
+ */
+static int smack_file_restore_security(struct file *file, void *stored)
+{
+	char *str = smk_import(stored, 0);
+
+	if (str == NULL)
+		return -EINVAL;
+
+	file->f_security = current_security();
+	if (current_security() != str) {
+		if (!capable(CAP_MAC_ADMIN))
+			return -EPERM;
+		file->f_security = str;
+	}
+
+	return 0;
+}
+
+/**
  * smack_file_free_security - clear a file security blob
  * @file: the object
  *
@@ -1630,7 +1654,6 @@ static int smack_msg_msg_restore_security(struct msg_msg *msg,
 		msg->security = str;
 	}
 	return 0;
-	return 0;
 }
 
 /**
@@ -2996,6 +3019,7 @@ struct security_operations smack_ops = {
 
 	.file_permission = 		smack_file_permission,
 	.file_alloc_security = 		smack_file_alloc_security,
+	.file_restore_security =	smack_file_restore_security,
 	.file_free_security = 		smack_file_free_security,
 	.file_ioctl = 			smack_file_ioctl,
 	.file_lock = 			smack_file_lock,
Signature · 7 lines
1.6.1


--
This message was distributed to subscribers of the selinux mailing list.
If you no longer wish to subscribe, send mail to [email protected] with
the words "unsubscribe selinux" without quotes as the message.

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

#20 lore raw

Re: [PATCH 10/10] cr: lsm: restore file->f_security

Quoted 33 lines · Serge E. Hallyn

file->f_cred is the cred of the task which opened it. file->f_security can be separately set by the LSM. Checkpoint the file->f_security, and at restart ask the LSM, using security_file_restore, based on the current task's context and the checkpointed f_security, which f_security to apply (or whether to refuse the restart altogether).

For Smack, accept the checkpointed label if the restarting task has CAP_MAC_ADMIN.

For SELinux, I currently ignore the checkpointed label and call file_alloc_security(). Do we want to have 'restore' permission for class file?

---
 checkpoint/files.c             |   33 +++++++++++++++++++++++++++++++++
 include/linux/checkpoint_hdr.h |    1 +
 include/linux/security.h       |   13 +++++++++++++
 security/capability.c          |    6 ++++++
 security/security.c            |    5 +++++
 security/selinux/hooks.c       |   11 +++++++++++
 security/smack/smack_lsm.c     |   26 +++++++++++++++++++++++++-
 7 files changed, 94 insertions(+), 1 deletions(-)

...

security/smack/smack_lsm.c +0 -0
index dfc0f7a..7bcdfde 100644

security/smack/smack_lsm.c static int smack_file_alloc_security(struct file *file) · line 839

Quoted 9 lines
security/smack/smack_lsm.c +5 -0
@@ -831,6 +831,30 @@ static int smack_file_alloc_security(struct file *file)
 }
 
 /**
+ * smack_file_restore_security - assign a file security blob
+ * @file: the object
+ * @stored: the label stored in the checkpoint file
+ *
+ * Returns 0
 

Or -EINVAL if the label is not acceptable

Quoted 23 lines
security/smack/smack_lsm.c +19 -0
+ */
+static int smack_file_restore_security(struct file *file, void *stored)
+{
+	char *str = smk_import(stored, 0);
+
+	if (str == NULL)
+		return -EINVAL;
+
+	file->f_security = current_security();
+	if (current_security() != str) {
+		if (!capable(CAP_MAC_ADMIN))
+			return -EPERM;
+		file->f_security = str;
+	}
+
+	return 0;
+}
+
+/**
  * smack_file_free_security - clear a file security blob
  * @file: the object

*

security/smack/smack_lsm.c static int smack_msg_msg_restore_security(struct msg_msg *msg, · line 1657

Quoted 5 lines
security/smack/smack_lsm.c +0 -1
@@ -1630,7 +1654,6 @@ static int smack_msg_msg_restore_security(struct msg_msg *msg,
 		msg->security = str;
 	}
 	return 0;
-	return 0;
 

Looks like you caught that. Thank you

Quoted 12 lines
security/smack/smack_lsm.c +0 -0
 }
 

/**

security/smack/smack_lsm.c +1 -0
@@ -2996,6 +3019,7 @@ struct security_operations smack_ops = {
 
 	.file_permission = 		smack_file_permission,
 	.file_alloc_security = 		smack_file_alloc_security,
+	.file_restore_security =	smack_file_restore_security,
 	.file_free_security = 		smack_file_free_security,
 	.file_ioctl = 			smack_file_ioctl,
 	.file_lock = 			smack_file_lock,

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

#22 lore raw

Re: [PATCH 10/10] cr: lsm: restore file->f_security

Quoted 8 lines · Casey Schaufler

security/smack/smack_lsm.c static int smack_msg_msg_restore_security(struct msg_msg *msg, · line 1657

Quoted 6 lines
security/smack/smack_lsm.c +0 -1
@@ -1630,7 +1654,6 @@ static int smack_msg_msg_restore_security(struct msg_msg *msg,
 		msg->security = str;
 	}
 	return 0;
-	return 0;
 

Looks like you caught that. Thank you

Huh. No, I didn't :) I'm guessing that both the original problem and this accidental fix came about through my inexperience with resolving conflicts in git-rebase...

Thanks for taking a look, I will address all of your comments in the next posting.

For the next version I may split up the smack, selinux, and tomoyo hooks into separate patches from the core LSM patch (and nix the rather silly split of the security_file_restore hook) for easier review...

thanks,
-serge

#23 lore raw

Re: [PATCH 10/10] cr: lsm: restore file->f_security

In reply to a message not in the archive
Quoted 6 lines · Serge E. Hallyn

file->f_cred is the cred of the task which opened it. file->f_security can be separately set by the LSM. Checkpoint the file->f_security, and at restart ask the LSM, using security_file_restore, based on the current task's context and the checkpointed f_security, which f_security to apply (or whether to refuse the restart altogether).

Quoted 6 lines

For Smack, accept the checkpointed label if the restarting task has CAP_MAC_ADMIN.

For SELinux, I currently ignore the checkpointed label and call file_alloc_security(). Do we want to have 'restore' permission for class file?

Yes - otherwise we'll end up with a restarted process that may not be able to access its open files.

Signature · 2 lines
Stephen Smalley
National Security Agency