Skip to contentSkip to conversation

cr: lsm: restore LSM contexts for ipc objects

PATCH In review Serge E. Hallyn 6 participants 16 messages Jun 20, 2009 – Jun 25, 2009 1 message not in the archive

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

PATCH 1/1 cr: lsm: restore LSM contexts for ipc objects

Here is the next version of the patch implementing checkpoint and restore of LSM contexts. This is just handling IPC objects as a proof of concept. But actually, looking ahead and both files and tasks, I see that selinux stores several sids in the security structs. For instance, for tasks there is the current sid, exec sid, create sid, keycreate_sid, and sockcreate_sid. So I guess I'll have to ask the LSM for how many secids it wants to checkpoint, then checkpoint an array of contexts?

From 19669b07cdfef4d377f3f188e2421c4124e38708 Mon Sep 17 00:00:00 2001
From: Serge E. Hallyn <[email protected]>
Date: Wed, 17 Jun 2009 12:00:21 -0400
Subject: [PATCH 1/1] cr: lsm: restore LSM contexts for ipc objects

Introduce a cache of secids for checkpoint and restart. At checkpoint, it takes a secid, stores the corresponding context string, and stores the objref for later use. At restart, read the context from checkpoint image, ask the security module for a secid, and store the secid on the objhash.

The per-object security c/r code will be responsible for getting secid from void*security at checkpoint time, and converting secid to void*security at restore time.

The code to c/r contexts for IPC objects is also in this patch.

For Smack, assign the label of the process doing sys_restart() if !capable(CAP_MAC_ADMIN), otherwise use the checkpointed label.

For SELinux, define a new 'restore' permission for ipc objects. (A corresponding trival policy patch adding 'restore' to the common flask permissions for refpolicy is also needed). The caller of sys_restart() must have the class:restore permission to assign the checkpointed label, else restart will be refused.

---
 checkpoint/objhash.c                             |   10 ++
 checkpoint/sys.c                                 |   15 ++
 include/linux/checkpoint_hdr.h                   |   12 ++-
 include/linux/checkpoint_types.h                 |    7 +
 include/linux/security.h                         |   92 ++++++++++++
 ipc/checkpoint.c                                 |   20 ++-
 ipc/checkpoint_msg.c                             |   45 ++++++-
 ipc/checkpoint_sem.c                             |   18 +++-
 ipc/checkpoint_shm.c                             |   18 +++-
 ipc/util.h                                       |    3 +-
 security/capability.c                            |   38 +++++
 security/security.c                              |  169 ++++++++++++++++++++++
 security/selinux/hooks.c                         |   48 ++++++
 security/selinux/include/av_inherit.h            |    8 +-
 security/selinux/include/av_permissions.h        |   10 +-
 security/selinux/include/common_perm_to_string.h |    1 +
 security/smack/smack_lsm.c                       |   77 ++++++++++
 17 files changed, 571 insertions(+), 20 deletions(-)
checkpoint/objhash.c +10 -0
index b4bc2e4..c266375 100644
@@ -18,6 +18,7 @@
 #include <linux/sched.h>
 #include <linux/ipc_namespace.h>
 #include <linux/user_namespace.h>
+#include <linux/security.h>
 #include <linux/checkpoint.h>
 #include <linux/checkpoint_hdr.h>
 
@@ -365,6 +366,15 @@ static struct ckpt_obj_ops ckpt_obj_ops[] = {
 		.checkpoint = checkpoint_groupinfo,
 		.restore = restore_groupinfo,
 	},
+	/* LSM context */
+	{
+		.obj_name = "SECURITY",
+		.obj_type = CKPT_OBJ_SECURITY,
+		.ref_grab = obj_no_grab,
+		.ref_drop = obj_no_drop,
+		.checkpoint = checkpoint_security,
+		.restore = restore_security,
+	},
 };
 
 
checkpoint/sys.c +15 -0
index 38a5299..06a2c00 100644
@@ -20,6 +20,7 @@
 #include <linux/file.h>
 #include <linux/uaccess.h>
 #include <linux/capability.h>
+#include <linux/security.h>
 #include <linux/checkpoint.h>
 #include <linux/deferqueue.h>
 
@@ -188,6 +189,16 @@ static void task_arr_free(struct ckpt_ctx *ctx)
 	kfree(ctx->tasks_arr);
 }
 
+void free_secreflist(struct ckpt_ctx *ctx)
+{
+	struct sec_store *s, *p;
+
+	list_for_each_entry_safe(s, p, &ctx->secref_list, list) {
+		list_del(&s->list);
+		kfree(s);
+	}
+}
+
 static void ckpt_ctx_free(struct ckpt_ctx *ctx)
 {
 	int ret;
@@ -217,6 +228,7 @@ static void ckpt_ctx_free(struct ckpt_ctx *ctx)
 		put_task_struct(ctx->root_task);
 	if (ctx->root_freezer)
 		put_task_struct(ctx->root_freezer);
+	free_secreflist(ctx);
 
 	kfree(ctx->pids_arr);
 
@@ -233,6 +245,9 @@ static struct ckpt_ctx *ckpt_ctx_alloc(int fd, unsigned long uflags,
 	if (!ctx)
 		return ERR_PTR(-ENOMEM);
 
+	spin_lock_init(&ctx->secref_lock);
+	INIT_LIST_HEAD(&ctx->secref_list);
+
 	ctx->uflags = uflags;
 	ctx->kflags = kflags;
 	ctx->ktime_begin = ktime_get();
include/linux/checkpoint_hdr.h +11 -1
index e42e0db..e3fb9b3 100644
@@ -62,6 +62,7 @@ enum {
 	CKPT_HDR_USER,
 	CKPT_HDR_GROUPINFO,
 	CKPT_HDR_TASK_CREDS,
+	CKPT_HDR_SECURITY,
 
 	/* 201-299: reserved for arch-dependent */
 
@@ -114,6 +115,7 @@ enum obj_type {
 	CKPT_OBJ_CRED,
 	CKPT_OBJ_USER,
 	CKPT_OBJ_GROUPINFO,
+	CKPT_OBJ_SECURITY,
 	CKPT_OBJ_MAX
 };
 
@@ -192,6 +194,12 @@ struct ckpt_capabilities {
 	__u32 padding;
 } __attribute__((aligned(8)));
 
+/* LSM security contexts (shared) */
+struct ckpt_hdr_sec {
+	struct ckpt_hdr h;
+	char str[];
+} __attribute__((aligned(8)));
+
 struct ckpt_hdr_task_creds {
 	struct ckpt_hdr h;
 	__s32 cred_ref;
@@ -418,7 +426,7 @@ struct ckpt_hdr_ipc_perms {
 	__u32 cuid;
 	__u32 cgid;
 	__u32 mode;
-	__u32 _padding;
+	__s32 secref;
 	__u64 seq;
 } __attribute__((aligned(8)));
 
@@ -453,6 +461,8 @@ struct ckpt_hdr_ipc_msg_msg {
 	struct ckpt_hdr h;
 	__s32 m_type;
 	__u32 m_ts;
+	__s32 secref;
+	__u32 padding;
 } __attribute__((aligned(8)));
 
 struct ckpt_hdr_ipc_sem {
include/linux/checkpoint_types.h +7 -0
index 27fbe26..74c218a 100644
@@ -73,6 +73,13 @@ struct ckpt_ctx {
 	struct cred *realcred, *ecred;	/* tmp storage for cred at restart */
 
 	struct ckpt_stats stats;	/* statistics */
+
+	/*
+	 * next two form basis for a mini-cache of LSM contexts
+	 * turn it into a rbtree or hash
+	 */
+	spinlock_t secref_lock;
+	struct list_head secref_list;
 };
 
 #endif /* __KERNEL__ */
include/linux/security.h +92 -0

194 lines not on this page · raw message

ipc/checkpoint.c +13 -7
index 88996e2..b7641e2 100644
@@ -15,6 +15,7 @@
 #include <linux/msg.h>
 #include <linux/sched.h>
 #include <linux/ipc_namespace.h>
+#include <linux/security.h>
 #include <linux/checkpoint.h>
 #include <linux/checkpoint_hdr.h>
 
@@ -31,9 +32,12 @@ 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)
 {
+	int secid;
+
 	if (ipcperms(perm, S_IROTH))
 		return -EACCES;
 
@@ -46,6 +50,11 @@ int checkpoint_fill_ipc_perms(struct ckpt_hdr_ipc_perms *h,
 	h->mode = perm->mode & S_IRWXUGO;
 	h->seq = perm->seq;
 
+	security_ipc_getsecid(perm, &secid);
+	h->secref = checkpoint_security_getsecref(ctx, secid);
+	if (h->secref < 0)
+		return h->secref;
+
 	return 0;
 }
 
@@ -185,13 +194,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 +42 -3

91 lines not on this page · raw message

ipc/checkpoint_sem.c +17 -1
index 64d61ee..609750b 100644
@@ -17,6 +17,7 @@
 #include <linux/sched.h>
 #include <linux/syscalls.h>
 #include <linux/nsproxy.h>
+#include <linux/security.h>
 #include <linux/ipc_namespace.h>
 
 struct msg_msg;
@@ -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,11 +113,26 @@ static int load_ipc_sem_hdr(struct ckpt_ctx *ctx,
 			       struct sem_array *sem)
 {
 	int ret = 0;
+	int secid = 0;
 
 	ret = restore_load_ipc_perms(&h->perms, &sem->sem_perm);
 	if (ret < 0)
 		return ret;
 
+	if (h->perms.secref) {
+		struct sec_store *s;
+		s = ckpt_obj_fetch(ctx, h->perms.secref, CKPT_OBJ_SECURITY);
+		if (IS_ERR(s))
+			return PTR_ERR(s);
+		secid = s->secid;
+	}
+	ret = security_sem_alloc(sem);
+	if (ret)
+		return ret;
+	ret = security_sem_restore(sem, secid);
+	if (ret < 0)
+		return ret;
+
 	ckpt_debug("sem: nsems %u\n", h->sem_nsems);
 
 	sem->sem_otime = h->sem_otime;
ipc/checkpoint_shm.c +17 -1
index 41bacfb..a2a0e41 100644
@@ -21,6 +21,7 @@
 #include <linux/syscalls.h>
 #include <linux/nsproxy.h>
 #include <linux/ipc_namespace.h>
+#include <linux/security.h>
 #include <linux/deferqueue.h>
 
 #include <linux/msg.h>	/* needed for util.h that uses 'struct msg_msg' */
@@ -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,11 +149,26 @@ static int load_ipc_shm_hdr(struct ckpt_ctx *ctx,
 			    struct shmid_kernel *shp)
 {
 	int ret;
+	int secid = 0;
 
 	ret = restore_load_ipc_perms(&h->perms, &shp->shm_perm);
 	if (ret < 0)
 		return ret;
 
+	if (h->perms.secref) {
+		struct sec_store *s;
+		s = ckpt_obj_fetch(ctx, h->perms.secref, CKPT_OBJ_SECURITY);
+		if (IS_ERR(s))
+			return PTR_ERR(s);
+		secid = s->secid;
+	}
+	ret = security_shm_alloc(shp);
+	if (ret)
+		return ret;
+	ret = security_shm_restore(shp, secid);
+	if (ret < 0)
+		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 fa974eb..bed25bd 100644
@@ -199,7 +199,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);
security/capability.c +38 -0
index 21b6cea..d0d2e39 100644
@@ -494,6 +494,18 @@ static void cap_msg_msg_free_security(struct msg_msg *msg)
 {
 }
 
+static void cap_msg_msg_getsecid(struct msg_msg *msg, u32 *secid)
+{
+	*secid = 0;
+}
+
+static int cap_msg_msg_restore(struct msg_msg *msg, u32 secid)
+{
+	if (secid)
+		return -EINVAL;
+	return 0;
+}
+
 static int cap_msg_queue_alloc_security(struct msg_queue *msq)
 {
 	return 0;
@@ -525,6 +537,13 @@ static int cap_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
 	return 0;
 }
 
+static int cap_msg_queue_restore(struct msg_queue *msq, u32 secid)
+{
+	if (secid)
+		return -EINVAL;
+	return 0;
+}
+
 static int cap_shm_alloc_security(struct shmid_kernel *shp)
 {
 	return 0;
@@ -550,6 +569,13 @@ static int cap_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr,
 	return 0;
 }
 
+static int cap_shm_restore(struct shmid_kernel *shp, u32 secid)
+{
+	if (secid)
+		return -EINVAL;
+	return 0;
+}
+
 static int cap_sem_alloc_security(struct sem_array *sma)
 {
 	return 0;
@@ -575,6 +601,13 @@ static int cap_sem_semop(struct sem_array *sma, struct sembuf *sops,
 	return 0;
 }
 
+static int cap_sem_restore(struct sem_array *sma, u32 secid)
+{
+	if (secid)
+		return -EINVAL;
+	return 0;
+}
+
 #ifdef CONFIG_SECURITY_NETWORK
 static int cap_unix_stream_connect(struct socket *sock, struct socket *other,
 				   struct sock *newsk)
@@ -977,22 +1010,27 @@ void security_fixup_ops(struct security_operations *ops)
 	set_to_cap_if_null(ops, ipc_getsecid);
 	set_to_cap_if_null(ops, msg_msg_alloc_security);
 	set_to_cap_if_null(ops, msg_msg_free_security);
+	set_to_cap_if_null(ops, msg_msg_getsecid);
+	set_to_cap_if_null(ops, msg_msg_restore);
 	set_to_cap_if_null(ops, msg_queue_alloc_security);
 	set_to_cap_if_null(ops, msg_queue_free_security);
 	set_to_cap_if_null(ops, msg_queue_associate);
 	set_to_cap_if_null(ops, msg_queue_msgctl);
 	set_to_cap_if_null(ops, msg_queue_msgsnd);
 	set_to_cap_if_null(ops, msg_queue_msgrcv);
+	set_to_cap_if_null(ops, msg_queue_restore);
 	set_to_cap_if_null(ops, shm_alloc_security);
 	set_to_cap_if_null(ops, shm_free_security);
 	set_to_cap_if_null(ops, shm_associate);
 	set_to_cap_if_null(ops, shm_shmctl);
 	set_to_cap_if_null(ops, shm_shmat);
+	set_to_cap_if_null(ops, shm_restore);
 	set_to_cap_if_null(ops, sem_alloc_security);
 	set_to_cap_if_null(ops, sem_free_security);
 	set_to_cap_if_null(ops, sem_associate);
 	set_to_cap_if_null(ops, sem_semctl);
 	set_to_cap_if_null(ops, sem_semop);
+	set_to_cap_if_null(ops, sem_restore);
 	set_to_cap_if_null(ops, netlink_send);
 	set_to_cap_if_null(ops, netlink_recv);
 	set_to_cap_if_null(ops, d_instantiate);
security/security.c +169 -0

202 lines not on this page · raw message

security/selinux/hooks.c +48 -0

102 lines not on this page · raw message

security/selinux/include/av_inherit.h +4 -4
index 8377a4b..0d7689d 100644
@@ -15,10 +15,10 @@
    S_(SECCLASS_KEY_SOCKET, socket, 0x00400000UL)
    S_(SECCLASS_UNIX_STREAM_SOCKET, socket, 0x00400000UL)
    S_(SECCLASS_UNIX_DGRAM_SOCKET, socket, 0x00400000UL)
-   S_(SECCLASS_IPC, ipc, 0x00000200UL)
-   S_(SECCLASS_SEM, ipc, 0x00000200UL)
-   S_(SECCLASS_MSGQ, ipc, 0x00000200UL)
-   S_(SECCLASS_SHM, ipc, 0x00000200UL)
+   S_(SECCLASS_IPC, ipc, 0x00000400UL)
+   S_(SECCLASS_SEM, ipc, 0x00000400UL)
+   S_(SECCLASS_MSGQ, ipc, 0x00000400UL)
+   S_(SECCLASS_SHM, ipc, 0x00000400UL)
    S_(SECCLASS_NETLINK_ROUTE_SOCKET, socket, 0x00400000UL)
    S_(SECCLASS_NETLINK_FIREWALL_SOCKET, socket, 0x00400000UL)
    S_(SECCLASS_NETLINK_TCPDIAG_SOCKET, socket, 0x00400000UL)
security/selinux/include/av_permissions.h +8 -2
index d645192..3c3eba6 100644
@@ -47,6 +47,7 @@
 #define COMMON_IPC__ASSOCIATE                            0x00000040UL
 #define COMMON_IPC__UNIX_READ                            0x00000080UL
 #define COMMON_IPC__UNIX_WRITE                           0x00000100UL
+#define COMMON_IPC__RESTORE                              0x00000200UL
 #define FILESYSTEM__MOUNT                         0x00000001UL
 #define FILESYSTEM__REMOUNT                       0x00000002UL
 #define FILESYSTEM__UNMOUNT                       0x00000004UL
@@ -462,6 +463,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
@@ -471,6 +473,7 @@
 #define SEM__ASSOCIATE                            0x00000040UL
 #define SEM__UNIX_READ                            0x00000080UL
 #define SEM__UNIX_WRITE                           0x00000100UL
+#define SEM__RESTORE                              0x00000200UL
 #define MSGQ__CREATE                              0x00000001UL
 #define MSGQ__DESTROY                             0x00000002UL
 #define MSGQ__GETATTR                             0x00000004UL
@@ -480,9 +483,11 @@
 #define MSGQ__ASSOCIATE                           0x00000040UL
 #define MSGQ__UNIX_READ                           0x00000080UL
 #define MSGQ__UNIX_WRITE                          0x00000100UL
-#define MSGQ__ENQUEUE                             0x00000200UL
+#define MSGQ__RESTORE                             0x00000200UL
+#define MSGQ__ENQUEUE                             0x00000400UL
 #define MSG__SEND                                 0x00000001UL
 #define MSG__RECEIVE                              0x00000002UL
+#define MSG__RESTORE                              0x00000004UL
 #define SHM__CREATE                               0x00000001UL
 #define SHM__DESTROY                              0x00000002UL
 #define SHM__GETATTR                              0x00000004UL
@@ -492,7 +497,8 @@
 #define SHM__ASSOCIATE                            0x00000040UL
 #define SHM__UNIX_READ                            0x00000080UL
 #define SHM__UNIX_WRITE                           0x00000100UL
-#define SHM__LOCK                                 0x00000200UL
+#define SHM__RESTORE                              0x00000200UL
+#define SHM__LOCK                                 0x00000400UL
 #define SECURITY__COMPUTE_AV                      0x00000001UL
 #define SECURITY__COMPUTE_CREATE                  0x00000002UL
 #define SECURITY__COMPUTE_MEMBER                  0x00000004UL
security/selinux/include/common_perm_to_string.h +1 -0
index ce5b6e2..fb94053 100644
@@ -54,5 +54,6 @@ TB_(common_ipc_perm_to_string)
     S_("associate")
     S_("unix_read")
     S_("unix_write")
+    S_("restore")
 TE_(common_ipc_perm_to_string)
 
security/smack/smack_lsm.c +77 -0

125 lines not on this page · raw message

Signature · 1 line
1.6.1
maintainer
#1 lore raw
Quoted 9 lines · Serge E. Hallyn

Here is the next version of the patch implementing checkpoint and restore of LSM contexts. This is just handling IPC objects as a proof of concept. But actually, looking ahead and both files and tasks, I see that selinux stores several sids in the security structs. For instance, for tasks there is the current sid, exec sid, create sid, keycreate_sid, and sockcreate_sid. So I guess I'll have to ask the LSM for how many secids it wants to checkpoint, then checkpoint an array of contexts?

Can you please explain exactly what checkpoint/restart is?

Signature · 2 lines
James Morris
<[email protected]>
#2 lore raw
Quoted 12 lines · James Morris
Quoted 9 lines · Serge E. Hallyn

Here is the next version of the patch implementing checkpoint and restore of LSM contexts. This is just handling IPC objects as a proof of concept. But actually, looking ahead and both files and tasks, I see that selinux stores several sids in the security structs. For instance, for tasks there is the current sid, exec sid, create sid, keycreate_sid, and sockcreate_sid. So I guess I'll have to ask the LSM for how many secids it wants to checkpoint, then checkpoint an array of contexts?

Quoted 1 line

Can you please explain exactly what checkpoint/restart is?

Take a container or (it is still subject to debate whether to allow this) any process tree, freeze it, record the state of the tasks, all objects they own, and the filesystem. The result is a checkpoint image file for later use. Unfreeze, and either continue running or kill. Later, restart from the checkpoint image, which will create a new container containing all of the needed objects (IPC semaphores, open files, sockets, etc) and restart all tasks exactly where they left off.

While it seems very likely that in the end (when it hits upstream) we will require privilege to use restart at all, we are doing our best to design it so that it is safe for unprivileged users. That means that every object creation must be contingent on the authorization of the task calling sys_restart(). After all, it is a trivial matter to call sys_checkpoint() on your own vim process, edit the checkpoint file to change the filename to /etc/passwd and the process uid to 0, and then call sys_restart() on the result.

Since we don't want to talk about any 'trusted' user in SELinux at all, the same mindset required to support unprivileged restart for the DAC perms very much applies to c/r of SELinux state.

I'll add an explanation to the next version of the patch.

thanks,
-serge

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

#4 lore raw
Quoted 8 lines · Serge E. Hallyn

Here is the next version of the patch implementing checkpoint and restore of LSM contexts. This is just handling IPC objects as a proof of concept. But actually, looking ahead and both files and tasks, I see that selinux stores several sids in the security structs. For instance, for tasks there is the current sid, exec sid, create sid, keycreate_sid, and sockcreate_sid. So I guess I'll have to ask the LSM for how many secids it wants to checkpoint, then checkpoint an array of contexts?

You will need to support checkpointing multiple secids/contexts per object, but what about other state that might live in the security structs, e.g. flags fields, policy seqno, etc.

Quoted 6 lines
Quoted 1 line

From 19669b07cdfef4d377f3f188e2421c4124e38708 Mon Sep 17 00:00:00 2001

From: Serge E. Hallyn <[email protected]>
Date: Wed, 17 Jun 2009 12:00:21 -0400
Subject: [PATCH 1/1] cr: lsm: restore LSM contexts for ipc objects

Introduce a cache of secids for checkpoint and restart.

Not sure you need to cache them in the cr layer (vs. just using the mapping functions provided by the LSM hook interface, and letting the security module handle caching internally).

Quoted 30 lines

At checkpoint, it takes a secid, stores the corresponding context string, and stores the objref for later use. At restart, read the context from checkpoint image, ask the security module for a secid, and store the secid on the objhash.

The per-object security c/r code will be responsible for getting secid from void*security at checkpoint time, and converting secid to void*security at restore time.

The code to c/r contexts for IPC objects is also in this patch.

For Smack, assign the label of the process doing sys_restart() if !capable(CAP_MAC_ADMIN), otherwise use the checkpointed label.

For SELinux, define a new 'restore' permission for ipc objects. (A corresponding trival policy patch adding 'restore' to the common flask permissions for refpolicy is also needed). The caller of sys_restart() must have the class:restore permission to assign the checkpointed label, else restart will be refused.

include/linux/checkpoint_hdr.h +0 -0
index e42e0db..e3fb9b3 100644

include/linux/checkpoint_hdr.h struct ckpt_hdr_ipc_perms { · line 429

Quoted 5 lines
include/linux/checkpoint_hdr.h +1 -1
@@ -418,7 +426,7 @@ struct ckpt_hdr_ipc_perms {
 	__u32 cuid;
 	__u32 cgid;
 	__u32 mode;
-	__u32 _padding;
+	__s32 secref;

Why s32 vs u32? secids are u32 and 0 means they aren't supported by the security module.

Signature · 8 lines
Stephen Smalley
National Security Agency


--
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.
#5 lore raw
Quoted 9 lines · Stephen Smalley
Quoted 8 lines · Serge E. Hallyn

Here is the next version of the patch implementing checkpoint and restore of LSM contexts. This is just handling IPC objects as a proof of concept. But actually, looking ahead and both files and tasks, I see that selinux stores several sids in the security structs. For instance, for tasks there is the current sid, exec sid, create sid, keycreate_sid, and sockcreate_sid. So I guess I'll have to ask the LSM for how many secids it wants to checkpoint, then checkpoint an array of contexts?

Again thanks for taking a look, Stephen.

Quoted 3 lines

You will need to support checkpointing multiple secids/contexts per object, but what about other state that might live in the security structs, e.g. flags fields, policy seqno, etc.

I think the LSM should handle things like sb_flags and sclass automatically as the objects are restored. Allowing them to be specified in the checkpoint image only increases the number of ways in which a corrupted checkpoint image can mess with the kernel. (Note that at the moment the restart code doesn't address mounts and it's undecide whether that will be done manually in userspace, or done in the kernel by the restart code). As for seqno, see below.

Quoted 10 lines
Quoted 6 lines
Quoted 1 line

From 19669b07cdfef4d377f3f188e2421c4124e38708 Mon Sep 17 00:00:00 2001

From: Serge E. Hallyn <[email protected]>
Date: Wed, 17 Jun 2009 12:00:21 -0400
Subject: [PATCH 1/1] cr: lsm: restore LSM contexts for ipc objects

Introduce a cache of secids for checkpoint and restart.

Not sure you need to cache them in the cr layer (vs. just using the mapping functions provided by the LSM hook interface, and letting the security module handle caching internally).

Do I understand correctly that secids are supposed to be consistent across machines and reboots, but not across policy versions?

There are several ways we could handle this. One is to have security_checkpoint_object() spit out an arbitrary void* which describes the *full* security context, with the checkpoint/restart layer completely unaware about the meaning of the contents.

Another is to have security_checkpoint_header() output the policy version, and for each checkpointed object just write out an array of secids. If any file has a seqno which is not the same as the rest of the container's, then refuse the checkpoint?

A third, which is what I was doing here, is to write out textual context representations, and expect the LSM on _restore() to know of a single meaningful interpretation for the context_str. Maybe adding a security_checkpoint_header() at the top of the checkpoint file would help with that (so that in the general case, if policy version at restart is different from the checkpointed one, we refuse restart, assuming that we can't meaningfully intepret even system_u:object_r:user_file_t).

Quoted 25 lines
Quoted 24 lines

At checkpoint, it takes a secid, stores the corresponding context string, and stores the objref for later use. At restart, read the context from checkpoint image, ask the security module for a secid, and store the secid on the objhash.

The per-object security c/r code will be responsible for getting secid from void*security at checkpoint time, and converting secid to void*security at restore time.

The code to c/r contexts for IPC objects is also in this patch.

For Smack, assign the label of the process doing sys_restart() if !capable(CAP_MAC_ADMIN), otherwise use the checkpointed label.

For SELinux, define a new 'restore' permission for ipc objects. (A corresponding trival policy patch adding 'restore' to the common flask permissions for refpolicy is also needed). The caller of sys_restart() must have the class:restore permission to assign the checkpointed label, else restart will be refused.

Quoted 13 lines

include/linux/checkpoint_hdr.h struct ckpt_hdr_ipc_perms { · line 429

Quoted 10 lines
include/linux/checkpoint_hdr.h +1 -1
index e42e0db..e3fb9b3 100644
@@ -418,7 +426,7 @@ struct ckpt_hdr_ipc_perms {
 	__u32 cuid;
 	__u32 cgid;
 	__u32 mode;
-	__u32 _padding;
+	__s32 secref;

Why s32 vs u32? secids are u32 and 0 means they aren't supported by the security module.

The secref is a reference to an object in the checkpoint/restart object hashtable, not a secid. Those are signed, with <0 meaning error and 0 being a special case (in this case, 'not applicable')

If we write out the secids directly, which it sounds like you are advocating, and not the secid_to_secctx string, then we can store a u32 numsecs followed by __u32 secid[] which will have numsecs entries.

thanks,
-serge

#6 lore raw
Quoted 7 lines · Serge E. Hallyn
Quoted 3 lines · Stephen Smalley

Not sure you need to cache them in the cr layer (vs. just using the mapping functions provided by the LSM hook interface, and letting the security module handle caching internally).

Do I understand correctly that secids are supposed to be consistent across machines and reboots, but not across policy versions?

No, secids are temporal - they are dynamically allocated at runtime like file descriptors. You should only store security contexts in the images.

Quoted 9 lines

There are several ways we could handle this. One is to have security_checkpoint_object() spit out an arbitrary void* which describes the *full* security context, with the checkpoint/restart layer completely unaware about the meaning of the contents.

Another is to have security_checkpoint_header() output the policy version, and for each checkpointed object just write out an array of secids. If any file has a seqno which is not the same as the rest of the container's, then refuse the checkpoint?

No, I was referring to the seqno cached in the open file to determine whether we need to revalidate on read/write. I suppose resetting it to zero on restore won't affect behavior, just performance.

Quoted 3 lines

A third, which is what I was doing here, is to write out textual context representations, and expect the LSM on _restore() to know of a single meaningful interpretation for the context_str.

That's the right approach.

Quoted 45 lines

Maybe adding a security_checkpoint_header() at the top of the checkpoint file would help with that (so that in the general case, if policy version at restart is different from the checkpointed one, we refuse restart, assuming that we can't meaningfully intepret even system_u:object_r:user_file_t).

Quoted 25 lines
Quoted 24 lines

At checkpoint, it takes a secid, stores the corresponding context string, and stores the objref for later use. At restart, read the context from checkpoint image, ask the security module for a secid, and store the secid on the objhash.

The per-object security c/r code will be responsible for getting secid from void*security at checkpoint time, and converting secid to void*security at restore time.

The code to c/r contexts for IPC objects is also in this patch.

For Smack, assign the label of the process doing sys_restart() if !capable(CAP_MAC_ADMIN), otherwise use the checkpointed label.

For SELinux, define a new 'restore' permission for ipc objects. (A corresponding trival policy patch adding 'restore' to the common flask permissions for refpolicy is also needed). The caller of sys_restart() must have the class:restore permission to assign the checkpointed label, else restart will be refused.

Quoted 13 lines

include/linux/checkpoint_hdr.h struct ckpt_hdr_ipc_perms { · line 429

Quoted 10 lines
include/linux/checkpoint_hdr.h +1 -1
index e42e0db..e3fb9b3 100644
@@ -418,7 +426,7 @@ struct ckpt_hdr_ipc_perms {
 	__u32 cuid;
 	__u32 cgid;
 	__u32 mode;
-	__u32 _padding;
+	__s32 secref;

Why s32 vs u32? secids are u32 and 0 means they aren't supported by the security module.

Quoted 8 lines

The secref is a reference to an object in the checkpoint/restart object hashtable, not a secid. Those are signed, with <0 meaning error and 0 being a special case (in this case, 'not applicable')

If we write out the secids directly, which it sounds like you are advocating, and not the secid_to_secctx string, then we can store a u32 numsecs followed by __u32 secid[] which will have numsecs entries.

No, I just misunderstood what you meant by caching of the secids and by the use of secref - never mind.

Signature · 8 lines
Stephen Smalley
National Security Agency


--
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.
maintainer
#7 lore raw
Quoted 8 lines · Stephen Smalley
Quoted 6 lines · Serge E. Hallyn
Quoted 4 lines · Stephen Smalley

Not sure you need to cache them in the cr layer (vs. just using the mapping functions provided by the LSM hook interface, and letting the security module handle caching internally).

Quoted 8 lines
Quoted 3 lines

Do I understand correctly that secids are supposed to be consistent across machines and reboots, but not across policy versions?

No, secids are temporal - they are dynamically allocated at runtime like file descriptors. You should only store security contexts in the images.

Like he said. Smack would be happier if secid's went away, but there's too much left over from the era when SELinux was the only LSM for that to happen without crying and gnashing of teeth. A secid is good only for the current invocation of the current instance of the kernel.

#8 lore raw
In reply to Serge E. Hallyn
Quoted 4 lines · Serge E. Hallyn
ipc/checkpoint_msg.c +0 -0
index 51385b0..ca55339 100644

<snip>

Quoted 13 lines
ipc/checkpoint_msg.c +4 -0
@@ -175,11 +183,26 @@ static int load_ipc_msg_hdr(struct ckpt_ctx *ctx,
 			    struct msg_queue *msq)
 {
 	int ret = 0;
+	int secid = 0;
 
 	ret = restore_load_ipc_perms(&h->perms, &msq->q_perm);
 	if (ret < 0)
 		return ret;
 
+	if (h->perms.secref) {
+		struct sec_store *s;
+		s = ckpt_obj_fetch(ctx, h->perms.secref, CKPT_OBJ_SECURITY);

ipc/checkpoint_msg.c static int load_ipc_msg_hdr(struct ckpt_ctx *ctx, · line 204

Quoted 10 lines
ipc/checkpoint_msg.c +10 -0
+		if (IS_ERR(s))
+			return PTR_ERR(s);
+		secid = s->secid;
+	}
+	ret = security_msg_queue_alloc(msq);
+	if (ret)
+		return ret;
+	ret = security_msg_queue_restore(msq, secid);
+	if (ret < 0)
+		return ret;

I don't think you want to call security_msg_queue_alloc() here, as that both allocates the security struct and performs the create check. So I would just call the _restore() function, and let it internally call ipc_alloc_security() to allocate the struct but then apply its own distinct restore check. Likewise for the rest of them.

Also, where do we get to veto attempts to checkpoint the task in the first place? If ptrace, I think we'd want it treated as a PTRACE_MODE_ATTACH (also used for /proc/pid/mem) rather than just PTRACE_MODE_READ (reading other /proc/pid info).

Signature · 8 lines
Stephen Smalley
National Security Agency


--
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.
#9 lore raw
Quoted 27 lines · Stephen Smalley
Quoted 4 lines · Serge E. Hallyn
ipc/checkpoint_msg.c +0 -0
index 51385b0..ca55339 100644

<snip>

Quoted 21 lines
ipc/checkpoint_msg.c +12 -0
@@ -175,11 +183,26 @@ static int load_ipc_msg_hdr(struct ckpt_ctx *ctx,
 			    struct msg_queue *msq)
 {
 	int ret = 0;
+	int secid = 0;
 
 	ret = restore_load_ipc_perms(&h->perms, &msq->q_perm);
 	if (ret < 0)
 		return ret;
 
+	if (h->perms.secref) {
+		struct sec_store *s;
+		s = ckpt_obj_fetch(ctx, h->perms.secref, CKPT_OBJ_SECURITY);
+		if (IS_ERR(s))
+			return PTR_ERR(s);
+		secid = s->secid;
+	}
+	ret = security_msg_queue_alloc(msq);
+	if (ret)
+		return ret;
+	ret = security_msg_queue_restore(msq, secid);
Quoted 8 lines

ipc/checkpoint_msg.c static int load_ipc_msg_hdr(struct ckpt_ctx *ctx, · line 204

Quoted 2 lines
ipc/checkpoint_msg.c +2 -0
+	if (ret < 0)
+		return ret;

I don't think you want to call security_msg_queue_alloc() here, as that both allocates the security struct and performs the create check. So I would just call the _restore() function, and let it internally call ipc_alloc_security() to allocate the struct but then apply its own distinct restore check. Likewise for the rest of them.

Ok, will change that.

Quoted 4 lines

Also, where do we get to veto attempts to checkpoint the task in the first place? If ptrace, I think we'd want it treated as a PTRACE_MODE_ATTACH (also used for /proc/pid/mem) rather than just PTRACE_MODE_READ (reading other /proc/pid info).

The checkpointing of ipc objects goes through an ipcperms(perm, S_IROTH) check in ipc/checkpoint (at top of
http://git.ncl.cs.columbia.edu/?p=linux-cr.git;a=blob;f=ipc/checkpoint.c;h=88996e2b7abf328bd1b263400798ed5bd4924f48;hb=HEAD
)

But yes, for the task itself we check PTRACE_MODE_READ (line 280 in
http://git.ncl.cs.columbia.edu/?p=linux-cr.git;a=blob;f=checkpoint/checkpoint.c;h=a6dee4fb1085a47095f24443c48683a7fbc8ac59;hb=HEAD ) I had thought that PTRACE_MODE_ATTACH implied the permission to
actually modify the task. If it also can imply a "very invasive" read
then changing it certainly seems right.

thanks,
-serge

#10 lore raw
Quoted 37 lines · Serge E. Hallyn
Quoted 27 lines · Stephen Smalley
Quoted 4 lines · Serge E. Hallyn
ipc/checkpoint_msg.c +0 -0
index 51385b0..ca55339 100644

<snip>

Quoted 21 lines
ipc/checkpoint_msg.c +12 -0
@@ -175,11 +183,26 @@ static int load_ipc_msg_hdr(struct ckpt_ctx *ctx,
 			    struct msg_queue *msq)
 {
 	int ret = 0;
+	int secid = 0;
 
 	ret = restore_load_ipc_perms(&h->perms, &msq->q_perm);
 	if (ret < 0)
 		return ret;
 
+	if (h->perms.secref) {
+		struct sec_store *s;
+		s = ckpt_obj_fetch(ctx, h->perms.secref, CKPT_OBJ_SECURITY);
+		if (IS_ERR(s))
+			return PTR_ERR(s);
+		secid = s->secid;
+	}
+	ret = security_msg_queue_alloc(msq);
+	if (ret)
+		return ret;
+	ret = security_msg_queue_restore(msq, secid);
Quoted 8 lines

ipc/checkpoint_msg.c static int load_ipc_msg_hdr(struct ckpt_ctx *ctx, · line 204

Quoted 2 lines
ipc/checkpoint_msg.c +2 -0
+	if (ret < 0)
+		return ret;

I don't think you want to call security_msg_queue_alloc() here, as that both allocates the security struct and performs the create check. So I would just call the _restore() function, and let it internally call ipc_alloc_security() to allocate the struct but then apply its own distinct restore check. Likewise for the rest of them.

Quoted 1 line

Ok, will change that.

Hmm, but that means that if there is some new LSM which allocates memory in security_msg_queue_alloc(), but which does not define security_msg_queue_restore() (for some stupid reason), it'll end up causing a bug.

It's something we can certainly catch through code review, but do we want to set such a scenario up at all?

Speaking just for SELinux, the security_msg_queue_alloc() hook would return -EPERM only if the task calling sys_restart() wasn't allowed to create a msg queue with its own type, right? Is that something which is often disallowed?

I suppose we could have the default (cap_msg_queue_restore) call security_ops->msg_queue_alloc() - feels frail, but maybe it's ok...

thanks,
-serge

#11 lore raw
Quoted 45 lines · Serge E. Hallyn
Quoted 37 lines · Serge E. Hallyn
Quoted 27 lines · Stephen Smalley
Quoted 4 lines · Serge E. Hallyn
ipc/checkpoint_msg.c +0 -0
index 51385b0..ca55339 100644

<snip>

Quoted 21 lines
ipc/checkpoint_msg.c +12 -0
@@ -175,11 +183,26 @@ static int load_ipc_msg_hdr(struct ckpt_ctx *ctx,
 			    struct msg_queue *msq)
 {
 	int ret = 0;
+	int secid = 0;
 
 	ret = restore_load_ipc_perms(&h->perms, &msq->q_perm);
 	if (ret < 0)
 		return ret;
 
+	if (h->perms.secref) {
+		struct sec_store *s;
+		s = ckpt_obj_fetch(ctx, h->perms.secref, CKPT_OBJ_SECURITY);
+		if (IS_ERR(s))
+			return PTR_ERR(s);
+		secid = s->secid;
+	}
+	ret = security_msg_queue_alloc(msq);
+	if (ret)
+		return ret;
+	ret = security_msg_queue_restore(msq, secid);
Quoted 8 lines

ipc/checkpoint_msg.c static int load_ipc_msg_hdr(struct ckpt_ctx *ctx, · line 204

Quoted 2 lines
ipc/checkpoint_msg.c +2 -0
+	if (ret < 0)
+		return ret;

I don't think you want to call security_msg_queue_alloc() here, as that both allocates the security struct and performs the create check. So I would just call the _restore() function, and let it internally call ipc_alloc_security() to allocate the struct but then apply its own distinct restore check. Likewise for the rest of them.

Quoted 1 line

Ok, will change that.

Hmm, but that means that if there is some new LSM which allocates memory in security_msg_queue_alloc(), but which does not define security_msg_queue_restore() (for some stupid reason), it'll end up causing a bug.

Quoted 7 lines

It's something we can certainly catch through code review, but do we want to set such a scenario up at all?

Speaking just for SELinux, the security_msg_queue_alloc() hook would return -EPERM only if the task calling sys_restart() wasn't allowed to create a msg queue with its own type, right? Is that something which is often disallowed?

Certainly some program domains lack permission to create ipc objects. The ipc _alloc hooks are unusual in that they combine both allocation and create checking unlike the rest of the object alloc hooks. I think that was discussed at the time, but people didn't want two different hook calls at the same call site.

Quoted 2 lines

I suppose we could have the default (cap_msg_queue_restore) call security_ops->msg_queue_alloc() - feels frail, but maybe it's ok...

Signature · 2 lines
Stephen Smalley
National Security Agency
#12 lore raw
Quoted 54 lines · Stephen Smalley
Quoted 45 lines · Serge E. Hallyn
Quoted 37 lines · Serge E. Hallyn
Quoted 27 lines · Stephen Smalley
Quoted 4 lines · Serge E. Hallyn
ipc/checkpoint_msg.c +0 -0
index 51385b0..ca55339 100644

<snip>

Quoted 21 lines
ipc/checkpoint_msg.c +12 -0
@@ -175,11 +183,26 @@ static int load_ipc_msg_hdr(struct ckpt_ctx *ctx,
 			    struct msg_queue *msq)
 {
 	int ret = 0;
+	int secid = 0;
 
 	ret = restore_load_ipc_perms(&h->perms, &msq->q_perm);
 	if (ret < 0)
 		return ret;
 
+	if (h->perms.secref) {
+		struct sec_store *s;
+		s = ckpt_obj_fetch(ctx, h->perms.secref, CKPT_OBJ_SECURITY);
+		if (IS_ERR(s))
+			return PTR_ERR(s);
+		secid = s->secid;
+	}
+	ret = security_msg_queue_alloc(msq);
+	if (ret)
+		return ret;
+	ret = security_msg_queue_restore(msq, secid);
Quoted 8 lines

ipc/checkpoint_msg.c static int load_ipc_msg_hdr(struct ckpt_ctx *ctx, · line 204

Quoted 2 lines
ipc/checkpoint_msg.c +2 -0
+	if (ret < 0)
+		return ret;

I don't think you want to call security_msg_queue_alloc() here, as that both allocates the security struct and performs the create check. So I would just call the _restore() function, and let it internally call ipc_alloc_security() to allocate the struct but then apply its own distinct restore check. Likewise for the rest of them.

Quoted 1 line

Ok, will change that.

Hmm, but that means that if there is some new LSM which allocates memory in security_msg_queue_alloc(), but which does not define security_msg_queue_restore() (for some stupid reason), it'll end up causing a bug.

Quoted 7 lines

It's something we can certainly catch through code review, but do we want to set such a scenario up at all?

Speaking just for SELinux, the security_msg_queue_alloc() hook would return -EPERM only if the task calling sys_restart() wasn't allowed to create a msg queue with its own type, right? Is that something which is often disallowed?

Quoted 5 lines

Certainly some program domains lack permission to create ipc objects. The ipc _alloc hooks are unusual in that they combine both allocation and create checking unlike the rest of the object alloc hooks. I think that was discussed at the time, but people didn't want two different hook calls at the same call site.

Oh, no. I wasn't thinking right.

The objects are actually restored through calls to do_shmget() etc, so that security_xyz_alloc() already gets called.

So I think we'll just leave it as is right now, acknowledging that it might become problematic if we want to confine a restart_t domain to be able to restore but not alloc any ipcs. The actual ramifications of that still somewhat escape me, but I do prefer having the common helpers used whenever possible to recreate objects.

thanks,
-serge

#13 lore raw
Quoted 61 lines · Serge E. Hallyn
Quoted 54 lines · Stephen Smalley
Quoted 45 lines · Serge E. Hallyn
Quoted 37 lines · Serge E. Hallyn
Quoted 27 lines · Stephen Smalley
Quoted 4 lines · Serge E. Hallyn
ipc/checkpoint_msg.c +0 -0
index 51385b0..ca55339 100644

<snip>

Quoted 21 lines
ipc/checkpoint_msg.c +12 -0
@@ -175,11 +183,26 @@ static int load_ipc_msg_hdr(struct ckpt_ctx *ctx,
 			    struct msg_queue *msq)
 {
 	int ret = 0;
+	int secid = 0;
 
 	ret = restore_load_ipc_perms(&h->perms, &msq->q_perm);
 	if (ret < 0)
 		return ret;
 
+	if (h->perms.secref) {
+		struct sec_store *s;
+		s = ckpt_obj_fetch(ctx, h->perms.secref, CKPT_OBJ_SECURITY);
+		if (IS_ERR(s))
+			return PTR_ERR(s);
+		secid = s->secid;
+	}
+	ret = security_msg_queue_alloc(msq);
+	if (ret)
+		return ret;
+	ret = security_msg_queue_restore(msq, secid);
Quoted 8 lines

ipc/checkpoint_msg.c static int load_ipc_msg_hdr(struct ckpt_ctx *ctx, · line 204

Quoted 2 lines
ipc/checkpoint_msg.c +2 -0
+	if (ret < 0)
+		return ret;

I don't think you want to call security_msg_queue_alloc() here, as that both allocates the security struct and performs the create check. So I would just call the _restore() function, and let it internally call ipc_alloc_security() to allocate the struct but then apply its own distinct restore check. Likewise for the rest of them.

Quoted 1 line

Ok, will change that.

Hmm, but that means that if there is some new LSM which allocates memory in security_msg_queue_alloc(), but which does not define security_msg_queue_restore() (for some stupid reason), it'll end up causing a bug.

Quoted 7 lines

It's something we can certainly catch through code review, but do we want to set such a scenario up at all?

Speaking just for SELinux, the security_msg_queue_alloc() hook would return -EPERM only if the task calling sys_restart() wasn't allowed to create a msg queue with its own type, right? Is that something which is often disallowed?

Quoted 5 lines

Certainly some program domains lack permission to create ipc objects. The ipc _alloc hooks are unusual in that they combine both allocation and create checking unlike the rest of the object alloc hooks. I think that was discussed at the time, but people didn't want two different hook calls at the same call site.

Quoted 4 lines

Oh, no. I wasn't thinking right.

The objects are actually restored through calls to do_shmget() etc, so that security_xyz_alloc() already gets called.

Does this mean that the objects temporarily exist in the wrong security context and are accessible to other threads during the interval between creation and when they get "restored" to the right security context?

Quoted 5 lines

So I think we'll just leave it as is right now, acknowledging that it might become problematic if we want to confine a restart_t domain to be able to restore but not alloc any ipcs. The actual ramifications of that still somewhat escape me, but I do prefer having the common helpers used whenever possible to recreate objects.

Signature · 2 lines
Stephen Smalley
National Security Agency
#14 lore raw
Quoted 9 lines · Stephen Smalley
Quoted 4 lines · Serge E. Hallyn

Oh, no. I wasn't thinking right.

The objects are actually restored through calls to do_shmget() etc, so that security_xyz_alloc() already gets called.

Does this mean that the objects temporarily exist in the wrong security context and are accessible to other threads during the interval between creation and when they get "restored" to the right security context?

They get restored in a private IPC namespace so they aren't accessible to any live tasks. Also, the objects will be created using the default context for the program doing sys_restore(), running as app_restore_t or something, so presumably a policy could ensure that such temporary objects aren't readable by anyone else, just in case something goes wrong before the security_ipcxyz_restore(), right?

-serge

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

#15 lore raw
Quoted 11 lines · Serge E. Hallyn
Quoted 9 lines · Stephen Smalley
Quoted 4 lines · Serge E. Hallyn

Oh, no. I wasn't thinking right.

The objects are actually restored through calls to do_shmget() etc, so that security_xyz_alloc() already gets called.

Does this mean that the objects temporarily exist in the wrong security context and are accessible to other threads during the interval between creation and when they get "restored" to the right security context?

Quoted 6 lines

They get restored in a private IPC namespace so they aren't accessible to any live tasks. Also, the objects will be created using the default context for the program doing sys_restore(), running as app_restore_t or something, so presumably a policy could ensure that such temporary objects aren't readable by anyone else, just in case something goes wrong before the security_ipcxyz_restore(), right?

That could be confusing if the program ever needs to legitimately create any objects of its own for other purposes. But the private IPC namespace should be sufficient.

Signature · 2 lines
Stephen Smalley
National Security Agency
#16 lore raw
In reply to Serge E. Hallyn
Quoted 2 lines · Serge E. Hallyn
Quoted 1 line · Stephen Smalley

On Fri, 2009-06-19 at 20:32 -0500, Serge E. Hallyn wrote:

[...]

Quoted 10 lines
Quoted 4 lines

Also, where do we get to veto attempts to checkpoint the task in the first place? If ptrace, I think we'd want it treated as a PTRACE_MODE_ATTACH (also used for /proc/pid/mem) rather than just PTRACE_MODE_READ (reading other /proc/pid info).

The checkpointing of ipc objects goes through an ipcperms(perm, S_IROTH) check in ipc/checkpoint (at top of
http://git.ncl.cs.columbia.edu/?p=linux-cr.git;a=blob;f=ipc/checkpoint.c;h=88996e2b7abf328bd1b263400798ed5bd4924f48;hb=HEAD
)

Quoted 5 lines

But yes, for the task itself we check PTRACE_MODE_READ (line 280 in
http://git.ncl.cs.columbia.edu/?p=linux-cr.git;a=blob;f=checkpoint/checkpoint.c;h=a6dee4fb1085a47095f24443c48683a7fbc8ac59;hb=HEAD ) I had thought that PTRACE_MODE_ATTACH implied the permission to
actually modify the task. If it also can imply a "very invasive" read
then changing it certainly seems right.

Hmmm... I was unaware of this: http://lwn.net/Articles/282930/
So yes, probably need to change that.

Oren.