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

Serge E. Hallyn serue at us.ibm.com
Fri Jun 19 18:32:16 PDT 2009


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 <serue at us.ibm.com>
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.

Signed-off-by: Serge E. Hallyn <serue at us.ibm.com>
---
 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(-)

diff --git a/checkpoint/objhash.c b/checkpoint/objhash.c
index b4bc2e4..c266375 100644
--- a/checkpoint/objhash.c
+++ b/checkpoint/objhash.c
@@ -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,
+	},
 };
 
 
diff --git a/checkpoint/sys.c b/checkpoint/sys.c
index 38a5299..06a2c00 100644
--- a/checkpoint/sys.c
+++ b/checkpoint/sys.c
@@ -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();
diff --git a/include/linux/checkpoint_hdr.h b/include/linux/checkpoint_hdr.h
index e42e0db..e3fb9b3 100644
--- a/include/linux/checkpoint_hdr.h
+++ b/include/linux/checkpoint_hdr.h
@@ -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 {
diff --git a/include/linux/checkpoint_types.h b/include/linux/checkpoint_types.h
index 27fbe26..74c218a 100644
--- a/include/linux/checkpoint_types.h
+++ b/include/linux/checkpoint_types.h
@@ -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__ */
diff --git a/include/linux/security.h b/include/linux/security.h
index d5fd616..38f643c 100644
--- a/include/linux/security.h
+++ b/include/linux/security.h
@@ -1092,6 +1092,16 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  * @msg_msg_free_security:
  *	Deallocate the security structure for this message.
  *	@msg contains the message structure to be modified.
+ * @msg_msg_getsecid:
+ *	Get the secid associated with the msg_msg object.
+ *	@msg contains the message object
+ *	@secid contains a pointer to the location where result will be saved.
+ *	In case of failure, @secid will be set to zero.
+ * @msg_msg_restore:
+ *	Set security context on restored object
+ *	@msg contains the newly created msg_msg object
+ *	@secid contains the secid corresponding to the checkpointed context.
+ *	Return 0 if a proper label was set and permission is granted.
  *
  * Security hooks for System V IPC Message Queues
  *
@@ -1137,6 +1147,11 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *	@type contains the type of message requested.
  *	@mode contains the operational flags.
  *	Return 0 if permission is granted.
+ * @msg_queue_restore:
+ *	Set permission on a newly restored msg_queue
+ *	@msq contains the message queue being restored.
+ *	@secid is the secid corresponding to the checkpointed context.
+ *	Return 0 if an appropriate context was set and permission is granted.
  *
  * Security hooks for System V Shared Memory Segments
  *
@@ -1172,6 +1187,11 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *	@shmaddr contains the address to attach memory region to.
  *	@shmflg contains the operational flags.
  *	Return 0 if permission is granted.
+ * @shm_restore:
+ *	Set permission on a newly restored shm
+ *	@shm contains the shm being restored.
+ *	@secid is the secid corresponding to the checkpointed context.
+ *	Return 0 if an appropriate context was set and permission is granted.
  *
  * Security hooks for System V Semaphores
  *
@@ -1208,6 +1228,11 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
  *	@nsops contains the number of operations to perform.
  *	@alter contains the flag indicating whether changes are to be made.
  *	Return 0 if permission is granted.
+ * @sem_restore:
+ *	Set permission on a newly restored sem
+ *	@sem contains the sem being restored.
+ *	@secid is the secid corresponding to the checkpointed context.
+ *	Return 0 if an appropriate context was set and permission is granted.
  *
  * @ptrace_may_access:
  *	Check permission before allowing the current process to trace the
@@ -1499,6 +1524,8 @@ struct security_operations {
 
 	int (*msg_msg_alloc_security) (struct msg_msg *msg);
 	void (*msg_msg_free_security) (struct msg_msg *msg);
+	void (*msg_msg_getsecid) (struct msg_msg *msg, u32 *secid);
+	int (*msg_msg_restore) (struct msg_msg *msg, u32 secid);
 
 	int (*msg_queue_alloc_security) (struct msg_queue *msq);
 	void (*msg_queue_free_security) (struct msg_queue *msq);
@@ -1510,6 +1537,7 @@ struct security_operations {
 				 struct msg_msg *msg,
 				 struct task_struct *target,
 				 long type, int mode);
+	int (*msg_queue_restore) (struct msg_queue *msq, u32 secid);
 
 	int (*shm_alloc_security) (struct shmid_kernel *shp);
 	void (*shm_free_security) (struct shmid_kernel *shp);
@@ -1517,6 +1545,7 @@ struct security_operations {
 	int (*shm_shmctl) (struct shmid_kernel *shp, int cmd);
 	int (*shm_shmat) (struct shmid_kernel *shp,
 			  char __user *shmaddr, int shmflg);
+	int (*shm_restore) (struct shmid_kernel *shp, u32 secid);
 
 	int (*sem_alloc_security) (struct sem_array *sma);
 	void (*sem_free_security) (struct sem_array *sma);
@@ -1524,6 +1553,7 @@ struct security_operations {
 	int (*sem_semctl) (struct sem_array *sma, int cmd);
 	int (*sem_semop) (struct sem_array *sma,
 			  struct sembuf *sops, unsigned nsops, int alter);
+	int (*sem_restore) (struct sem_array *sma, u32 secid);
 
 	int (*netlink_send) (struct sock *sk, struct sk_buff *skb);
 	int (*netlink_recv) (struct sk_buff *skb, int cap);
@@ -1748,6 +1778,8 @@ int security_ipc_permission(struct kern_ipc_perm *ipcp, short flag);
 void security_ipc_getsecid(struct kern_ipc_perm *ipcp, u32 *secid);
 int security_msg_msg_alloc(struct msg_msg *msg);
 void security_msg_msg_free(struct msg_msg *msg);
+void security_msg_msg_getsecid(struct msg_msg *msg, u32 *secid);
+int security_msg_msg_restore(struct msg_msg *msg, u32 secid);
 int security_msg_queue_alloc(struct msg_queue *msq);
 void security_msg_queue_free(struct msg_queue *msq);
 int security_msg_queue_associate(struct msg_queue *msq, int msqflg);
@@ -1756,17 +1788,20 @@ int security_msg_queue_msgsnd(struct msg_queue *msq,
 			      struct msg_msg *msg, int msqflg);
 int security_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
 			      struct task_struct *target, long type, int mode);
+int security_msg_queue_restore(struct msg_queue *msq, u32 secid);
 int security_shm_alloc(struct shmid_kernel *shp);
 void security_shm_free(struct shmid_kernel *shp);
 int security_shm_associate(struct shmid_kernel *shp, int shmflg);
 int security_shm_shmctl(struct shmid_kernel *shp, int cmd);
 int security_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr, int shmflg);
+int security_shm_restore(struct shmid_kernel *shp, u32 secid);
 int security_sem_alloc(struct sem_array *sma);
 void security_sem_free(struct sem_array *sma);
 int security_sem_associate(struct sem_array *sma, int semflg);
 int security_sem_semctl(struct sem_array *sma, int cmd);
 int security_sem_semop(struct sem_array *sma, struct sembuf *sops,
 			unsigned nsops, int alter);
+int security_sem_restore(struct sem_array *sma, u32 secid);
 void security_d_instantiate(struct dentry *dentry, struct inode *inode);
 int security_getprocattr(struct task_struct *p, char *name, char **value);
 int security_setprocattr(struct task_struct *p, char *name, void *value, size_t size);
@@ -2393,6 +2428,18 @@ static inline int security_msg_msg_alloc(struct msg_msg *msg)
 	return 0;
 }
 
+static inline void security_msg_msg_getsecid(struct msg_msg *msg, u32 *secid)
+{
+	*secid = 0;
+}
+
+static inline int security_msg_msg_restore(struct msg_msg *msg, u32 secid)
+{
+	if (secid)
+		return -EINVAL;
+	return 0;
+}
+
 static inline void security_msg_msg_free(struct msg_msg *msg)
 { }
 
@@ -2429,6 +2476,14 @@ static inline int security_msg_queue_msgrcv(struct msg_queue *msq,
 	return 0;
 }
 
+static inline int security_msg_queue_restore(struct msg_queue *msq,
+						u32 secid)
+{
+	if (secid)
+		return -EINVAL;
+	return 0;
+}
+
 static inline int security_shm_alloc(struct shmid_kernel *shp)
 {
 	return 0;
@@ -2454,6 +2509,14 @@ static inline int security_shm_shmat(struct shmid_kernel *shp,
 	return 0;
 }
 
+static inline int security_shm_restore(struct shmid_kernel *shp,
+					u32 secid)
+{
+	if (secid)
+		return -EINVAL;
+	return 0;
+}
+
 static inline int security_sem_alloc(struct sem_array *sma)
 {
 	return 0;
@@ -2479,6 +2542,14 @@ static inline int security_sem_semop(struct sem_array *sma,
 	return 0;
 }
 
+static inline int security_sem_restore(struct sem_array *sma,
+					u32 secid)
+{
+	if (secid)
+		return -EINVAL;
+	return 0;
+}
+
 static inline void security_d_instantiate(struct dentry *dentry, struct inode *inode)
 { }
 
@@ -2975,7 +3046,28 @@ static inline char *alloc_secdata(void)
 
 static inline void free_secdata(void *secdata)
 { }
+
+#endif /* CONFIG_SECURITY */
+
+#ifdef CONFIG_CHECKPOINT
+struct sec_store {
+	int secid;  /* LSM secid */
+	int secref; /* objhash reference */
+	struct list_head list;
+};
+#ifdef CONFIG_SECURITY
+extern int checkpoint_security(struct ckpt_ctx *ctx, void *ptr);
+extern void *restore_security(struct ckpt_ctx *ctx);
+extern int checkpoint_security_getsecref(struct ckpt_ctx *ctx, int secid);
+#else /* CONFIG_SECURITY */
+#define checkpoint_security checkpoint_bad
+#define restore_security restore_bad
+static inline int checkpoint_security_getsecref(struct ckpt_ctx *ctx, int secid)
+{
+	return 0;
+}
 #endif /* CONFIG_SECURITY */
+#endif /* CONFIG_CHECKPOINT */
 
 #endif /* ! __LINUX_SECURITY_H */
 
diff --git a/ipc/checkpoint.c b/ipc/checkpoint.c
index 88996e2..b7641e2 100644
--- a/ipc/checkpoint.c
+++ b/ipc/checkpoint.c
@@ -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;
 }
diff --git a/ipc/checkpoint_msg.c b/ipc/checkpoint_msg.c
index 51385b0..ca55339 100644
--- a/ipc/checkpoint_msg.c
+++ b/ipc/checkpoint_msg.c
@@ -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>
 
 #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;
 
@@ -62,12 +63,19 @@ static int checkpoint_msg_contents(struct ckpt_ctx *ctx, struct msg_msg *msg)
 	struct ckpt_hdr_ipc_msg_msg *h;
 	struct msg_msgseg *seg;
 	int total, len;
-	int ret;
+	int ret, secid, secref;
+
+	security_msg_msg_getsecid(msg, &secid);
+	secref = checkpoint_security_getsecref(ctx, secid);
+	if (secref < 0)
+		return secref;
 
 	h = ckpt_hdr_get_type(ctx, sizeof(*h), CKPT_HDR_IPC_MSG_MSG);
 	if (!h)
 		return -ENOMEM;
 
+	h->secref = secref;
+
 	h->m_type = msg->m_type;
 	h->m_ts = msg->m_ts;
 
@@ -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);
+	if (ret < 0)
+		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);
 
@@ -201,7 +224,7 @@ static struct msg_msg *restore_msg_contents_one(struct ckpt_ctx *ctx, int *clen)
 	struct msg_msg *msg = NULL;
 	struct msg_msgseg *seg, **pseg;
 	int total, len;
-	int ret;
+	int ret, secid = 0;
 
 	h = ckpt_read_obj_type(ctx, sizeof(*h), CKPT_HDR_IPC_MSG_MSG);
 	if (IS_ERR(h))
@@ -245,6 +268,22 @@ static struct msg_msg *restore_msg_contents_one(struct ckpt_ctx *ctx, int *clen)
 		total -= len;
 	}
 
+	if (h->secref) {
+		struct sec_store *s;
+		s = ckpt_obj_fetch(ctx, h->secref, CKPT_OBJ_SECURITY);
+		if (IS_ERR(s)) {
+			ret = PTR_ERR(s);
+			goto out;
+		}
+		secid = s->secid;
+	}
+	ret = security_msg_msg_alloc(msg);
+	if (ret)
+		goto out;
+	ret = security_msg_msg_restore(msg, secid);
+	if (ret < 0)
+		goto out;
+
 	msg->m_type = h->m_type;
 	msg->m_ts = h->m_ts;
 	*clen = h->m_ts;
diff --git a/ipc/checkpoint_sem.c b/ipc/checkpoint_sem.c
index 64d61ee..609750b 100644
--- a/ipc/checkpoint_sem.c
+++ b/ipc/checkpoint_sem.c
@@ -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;
diff --git a/ipc/checkpoint_shm.c b/ipc/checkpoint_shm.c
index 41bacfb..a2a0e41 100644
--- a/ipc/checkpoint_shm.c
+++ b/ipc/checkpoint_shm.c
@@ -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);
 
diff --git a/ipc/util.h b/ipc/util.h
index fa974eb..bed25bd 100644
--- a/ipc/util.h
+++ b/ipc/util.h
@@ -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);
diff --git a/security/capability.c b/security/capability.c
index 21b6cea..d0d2e39 100644
--- a/security/capability.c
+++ b/security/capability.c
@@ -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);
diff --git a/security/security.c b/security/security.c
index 5284255..d737e0e 100644
--- a/security/security.c
+++ b/security/security.c
@@ -16,6 +16,7 @@
 #include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/security.h>
+#include <linux/checkpoint.h>
 
 /* Boot-time LSM user choice */
 static __initdata char chosen_lsm[SECURITY_NAME_MAX + 1];
@@ -832,6 +833,16 @@ void security_msg_msg_free(struct msg_msg *msg)
 	security_ops->msg_msg_free_security(msg);
 }
 
+void security_msg_msg_getsecid(struct msg_msg *msg, u32 *secid)
+{
+	security_ops->msg_msg_getsecid(msg, secid);
+}
+
+int security_msg_msg_restore(struct msg_msg *msg, u32 secid)
+{
+	return security_ops->msg_msg_restore(msg, secid);
+}
+
 int security_msg_queue_alloc(struct msg_queue *msq)
 {
 	return security_ops->msg_queue_alloc_security(msq);
@@ -864,6 +875,11 @@ int security_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
 	return security_ops->msg_queue_msgrcv(msq, msg, target, type, mode);
 }
 
+int security_msg_queue_restore(struct msg_queue *msq, u32 secid)
+{
+	return security_ops->msg_queue_restore(msq, secid);
+}
+
 int security_shm_alloc(struct shmid_kernel *shp)
 {
 	return security_ops->shm_alloc_security(shp);
@@ -889,6 +905,11 @@ int security_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr, int shmfl
 	return security_ops->shm_shmat(shp, shmaddr, shmflg);
 }
 
+int security_shm_restore(struct shmid_kernel *shp, u32 secid)
+{
+	return security_ops->shm_restore(shp, secid);
+}
+
 int security_sem_alloc(struct sem_array *sma)
 {
 	return security_ops->sem_alloc_security(sma);
@@ -915,6 +936,11 @@ int security_sem_semop(struct sem_array *sma, struct sembuf *sops,
 	return security_ops->sem_semop(sma, sops, nsops, alter);
 }
 
+int security_sem_restore(struct sem_array *sma, u32 secid)
+{
+	return security_ops->sem_restore(sma, secid);
+}
+
 void security_d_instantiate(struct dentry *dentry, struct inode *inode)
 {
 	if (unlikely(inode && IS_PRIVATE(inode)))
@@ -1247,3 +1273,146 @@ int security_audit_rule_match(u32 secid, u32 field, u32 op, void *lsmrule,
 }
 
 #endif /* CONFIG_AUDIT */
+
+#ifdef CONFIG_CHECKPOINT
+
+static int do_checkpoint_security(struct ckpt_ctx *ctx,
+				struct sec_store *s)
+{
+	char *str;
+	int ret, len;
+
+	ret = security_secid_to_secctx(s->secid, &str, &len);
+	if (ret)
+		return ret;
+	ret = ckpt_write_obj_type(ctx, str, len, CKPT_HDR_SECURITY);
+	security_release_secctx(str, len);
+	return ret;
+}
+
+int checkpoint_security(struct ckpt_ctx *ctx, void *ptr)
+{
+	return do_checkpoint_security(ctx, (struct sec_store *) ptr);
+}
+
+/*
+ * stupid ordered list insertion  Replace with rbtree or hash
+ * return 1 if the secid was already stored
+ * call with ctx->secref_lock held
+ */
+static int insert_secref(struct ckpt_ctx *ctx, struct sec_store *news)
+{
+	struct sec_store *last=NULL, *s;
+
+	if (list_empty(&ctx->secref_list)) {
+		list_add(&news->list, &ctx->secref_list);
+		return 0;
+	}
+
+	list_for_each_entry(s, &ctx->secref_list, list) {
+		if (s->secid == news->secid)
+			/* race */
+			return 1;
+		else if (s->secid < news->secid)
+			last = s;
+		else
+			break;
+	}
+	/*
+	 * if last is not null, insert after last.  Otherwise
+	 * this should be the first item
+	 */
+	if (last)
+		list_add(&news->list, &last->list);
+	else
+		list_add(&news->list, &ctx->secref_list);
+	return 0;
+}
+
+/* just need some sane value */
+#define MAX_STR_LEN 300
+static struct sec_store *do_restore_security(struct ckpt_ctx *ctx)
+{
+	struct ckpt_hdr_sec *h;
+	int id;
+	int ret, conflict;
+	struct sec_store *s;
+
+	h = ckpt_read_buf_type(ctx, MAX_STR_LEN, CKPT_HDR_SECURITY);
+	if (IS_ERR(h))
+		return ERR_PTR(PTR_ERR(h));
+	ret = security_secctx_to_secid(h->str, strlen(h->str)+1, &id);
+	ckpt_hdr_put(ctx, h);
+	if (ret < 0)
+		return ERR_PTR(ret);
+	s = kmalloc(sizeof(*s), GFP_KERNEL);
+	if (!s)
+		return ERR_PTR(-ENOMEM);
+	s->secid = id;
+	spin_lock(&ctx->secref_lock);
+	conflict = insert_secref(ctx, s);
+	spin_unlock(&ctx->secref_lock);
+	if (conflict) /* not possible */
+		return ERR_PTR(-EINVAL);
+	return s;
+}
+
+void *restore_security(struct ckpt_ctx *ctx)
+{
+	return (void *) do_restore_security(ctx);
+}
+
+/*
+ * if there's already a cached entry with secid, return
+ * its secref.  Return -1 if there is no such entry.  If
+ * LSMs are actually not supported, then a value of 0 may
+ * in fact be returned as the secref
+ */
+static int get_secref_from_secid(struct ckpt_ctx *ctx, int secid)
+{
+	int ret = -1;
+	struct sec_store *s;
+
+	spin_lock(&ctx->secref_lock);
+	list_for_each_entry(s, &ctx->secref_list, list)
+		if (s->secid == secid) {
+			ret = s->secref;
+			break;
+		}
+	spin_unlock(&ctx->secref_lock);
+	return ret;
+}
+
+/*
+ * get a objhash reference from a secid
+ * if already stored, return existing ref
+ * else checkpoint it and return the new ref
+ */
+int checkpoint_security_getsecref(struct ckpt_ctx *ctx, int secid)
+{
+	int ret, conflict=0, secref = 0;
+	struct sec_store *s;
+
+again:
+	ret = get_secref_from_secid(ctx, secid);
+	if (ret >= 0)
+		return ret;
+	BUG_ON(conflict!=0); /* a racer added it to list, but now it's gone? */
+	s = kzalloc(sizeof(*s), GFP_KERNEL);
+	if (!s)
+		return -ENOMEM;
+	s->secid = secid;
+	spin_lock(&ctx->secref_lock);
+	conflict = insert_secref(ctx, s);
+	if (conflict) {
+		spin_unlock(&ctx->secref_lock);
+		kfree(s);
+		goto again;
+	}
+	if (secid != 0)
+		secref = checkpoint_obj(ctx, s, CKPT_OBJ_SECURITY);
+	s->secref = secref;
+	spin_unlock(&ctx->secref_lock);
+	return secref;
+}
+#endif
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 2fcad7c..591f545 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -4675,6 +4675,19 @@ static void msg_msg_free_security(struct msg_msg *msg)
 	kfree(msec);
 }
 
+static int selinux_msg_msg_restore(struct msg_msg *msg, u32 secid)
+{
+	struct msg_security_struct *msec = msg->security;
+	u32 sid = current_sid();
+	int ret;
+
+	ret = avc_has_perm(sid, secid, SECCLASS_MSG, MSG__RESTORE, NULL);
+	if (ret)
+		return ret;
+	msec->sid = secid;
+	return 0;
+}
+
 static int ipc_has_perm(struct kern_ipc_perm *ipc_perms,
 			u32 perms)
 {
@@ -4700,6 +4713,12 @@ static void selinux_msg_msg_free_security(struct msg_msg *msg)
 	msg_msg_free_security(msg);
 }
 
+static void selinux_msg_msg_getsecid(struct msg_msg *msg, u32 *secid)
+{
+	struct msg_security_struct *msec = msg->security;
+	*secid = msec->sid;
+}
+
 /* message queue security operations */
 static int selinux_msg_queue_alloc_security(struct msg_queue *msq)
 {
@@ -4841,6 +4860,14 @@ static int selinux_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
 	return rc;
 }
 
+static int selinux_msg_queue_restore(struct msg_queue *msq, u32 secid)
+{
+	struct ipc_security_struct *isec = msq->q_perm.security;
+
+	isec->sid = secid;
+	return ipc_has_perm(&msq->q_perm, MSGQ__RESTORE);
+}
+
 /* Shared Memory security operations */
 static int selinux_shm_alloc_security(struct shmid_kernel *shp)
 {
@@ -4933,6 +4960,14 @@ static int selinux_shm_shmat(struct shmid_kernel *shp,
 	return ipc_has_perm(&shp->shm_perm, perms);
 }
 
+static int selinux_shm_restore(struct shmid_kernel *shp, u32 secid)
+{
+	struct ipc_security_struct *isec = shp->shm_perm.security;
+
+	isec->sid = secid;
+	return ipc_has_perm(&shp->shm_perm, SHM__RESTORE);
+}
+
 /* Semaphore security operations */
 static int selinux_sem_alloc_security(struct sem_array *sma)
 {
@@ -5034,6 +5069,14 @@ static int selinux_sem_semop(struct sem_array *sma,
 	return ipc_has_perm(&sma->sem_perm, perms);
 }
 
+static int selinux_sem_restore(struct sem_array *sma, u32 secid)
+{
+	struct ipc_security_struct *isec = sma->sem_perm.security;
+
+	isec->sid = secid;
+	return ipc_has_perm(&sma->sem_perm, SEM__RESTORE);
+}
+
 static int selinux_ipc_permission(struct kern_ipc_perm *ipcp, short flag)
 {
 	u32 av = 0;
@@ -5415,6 +5458,8 @@ static struct security_operations selinux_ops = {
 
 	.msg_msg_alloc_security =	selinux_msg_msg_alloc_security,
 	.msg_msg_free_security =	selinux_msg_msg_free_security,
+	.msg_msg_getsecid =		selinux_msg_msg_getsecid,
+	.msg_msg_restore =		selinux_msg_msg_restore,
 
 	.msg_queue_alloc_security =	selinux_msg_queue_alloc_security,
 	.msg_queue_free_security =	selinux_msg_queue_free_security,
@@ -5422,18 +5467,21 @@ static struct security_operations selinux_ops = {
 	.msg_queue_msgctl =		selinux_msg_queue_msgctl,
 	.msg_queue_msgsnd =		selinux_msg_queue_msgsnd,
 	.msg_queue_msgrcv =		selinux_msg_queue_msgrcv,
+	.msg_queue_restore =		selinux_msg_queue_restore,
 
 	.shm_alloc_security =		selinux_shm_alloc_security,
 	.shm_free_security =		selinux_shm_free_security,
 	.shm_associate =		selinux_shm_associate,
 	.shm_shmctl =			selinux_shm_shmctl,
 	.shm_shmat =			selinux_shm_shmat,
+	.shm_restore =			selinux_shm_restore,
 
 	.sem_alloc_security =		selinux_sem_alloc_security,
 	.sem_free_security =		selinux_sem_free_security,
 	.sem_associate =		selinux_sem_associate,
 	.sem_semctl =			selinux_sem_semctl,
 	.sem_semop =			selinux_sem_semop,
+	.sem_restore =			selinux_sem_restore,
 
 	.d_instantiate =		selinux_d_instantiate,
 
diff --git a/security/selinux/include/av_inherit.h b/security/selinux/include/av_inherit.h
index 8377a4b..0d7689d 100644
--- a/security/selinux/include/av_inherit.h
+++ b/security/selinux/include/av_inherit.h
@@ -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)
diff --git a/security/selinux/include/av_permissions.h b/security/selinux/include/av_permissions.h
index d645192..3c3eba6 100644
--- a/security/selinux/include/av_permissions.h
+++ b/security/selinux/include/av_permissions.h
@@ -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
diff --git a/security/selinux/include/common_perm_to_string.h b/security/selinux/include/common_perm_to_string.h
index ce5b6e2..fb94053 100644
--- a/security/selinux/include/common_perm_to_string.h
+++ b/security/selinux/include/common_perm_to_string.h
@@ -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)
 
diff --git a/security/smack/smack_lsm.c b/security/smack/smack_lsm.c
index 98b3195..070aeb7 100644
--- a/security/smack/smack_lsm.c
+++ b/security/smack/smack_lsm.c
@@ -1619,6 +1619,33 @@ static void smack_msg_msg_free_security(struct msg_msg *msg)
 }
 
 /**
+ * smack_msg_msg_getsecid - Extract smack security id
+ * @msg: the object
+ * @secid: where result will be saved
+ */
+static void smack_msg_msg_getsecid(struct msg_msg *msg, u32 *secid)
+{
+	char *smack = msg->security;
+
+	*secid = smack_to_secid(smack);
+}
+
+static int smack_msg_msg_restore(struct msg_msg *msg, u32 secid)
+{
+	char *smack = smack_from_secid(secid);
+
+	if (smack == NULL)
+		return -EINVAL;
+	if (current_security() != smack) {
+		if (!capable(CAP_MAC_ADMIN))
+			return -EPERM;
+		msg->security = smack;
+	} else
+		msg->security = current_security();
+	return 0;
+}
+
+/**
  * smack_of_shm - the smack pointer for the shm
  * @shp: the object
  *
@@ -1727,6 +1754,21 @@ static int smack_shm_shmat(struct shmid_kernel *shp, char __user *shmaddr,
 	return smk_curacc(ssp, may);
 }
 
+static int smack_shm_restore(struct shmid_kernel *shp, u32 secid)
+{
+	char *smack = smack_from_secid(secid);
+
+	if (smack == NULL)
+		return -EINVAL;
+	if (current_security() != smack) {
+		if (!capable(CAP_MAC_ADMIN))
+			return -EPERM;
+		shp->shm_perm.security = smack;
+	} else
+		shp->shm_perm.security = current_security();
+	return 0;
+}
+
 /**
  * smack_of_sem - the smack pointer for the sem
  * @sma: the object
@@ -1842,6 +1884,21 @@ static int smack_sem_semop(struct sem_array *sma, struct sembuf *sops,
 	return smk_curacc(ssp, MAY_READWRITE);
 }
 
+static int smack_sem_restore(struct sem_array *sma, u32 secid)
+{
+	char *smack = smack_from_secid(secid);
+
+	if (smack == NULL)
+		return -EINVAL;
+	if (current_security() != smack) {
+		if (!capable(CAP_MAC_ADMIN))
+			return -EPERM;
+		sma->sem_perm.security = smack;
+	} else
+		sma->sem_perm.security = current_security();
+	return 0;
+}
+
 /**
  * smack_msg_alloc_security - Set the security blob for msg
  * @msq: the object
@@ -1967,6 +2024,21 @@ static int smack_msg_queue_msgrcv(struct msg_queue *msq, struct msg_msg *msg,
 	return smk_curacc(msp, MAY_READWRITE);
 }
 
+static int smack_msg_queue_restore(struct msg_queue *msq, u32 secid)
+{
+	char *smack = smack_from_secid(secid);
+
+	if (smack == NULL)
+		return -EINVAL;
+	if (current_security() != smack) {
+		if (!capable(CAP_MAC_ADMIN))
+			return -EPERM;
+		msq->q_perm.security = smack;
+	} else
+		msq->q_perm.security = current_security();
+	return 0;
+}
+
 /**
  * smack_ipc_permission - Smack access for ipc_permission()
  * @ipp: the object permissions
@@ -2903,6 +2975,8 @@ struct security_operations smack_ops = {
 
 	.msg_msg_alloc_security = 	smack_msg_msg_alloc_security,
 	.msg_msg_free_security = 	smack_msg_msg_free_security,
+	.msg_msg_getsecid = 		smack_msg_msg_getsecid,
+	.msg_msg_restore = 		smack_msg_msg_restore,
 
 	.msg_queue_alloc_security = 	smack_msg_queue_alloc_security,
 	.msg_queue_free_security = 	smack_msg_queue_free_security,
@@ -2910,18 +2984,21 @@ struct security_operations smack_ops = {
 	.msg_queue_msgctl = 		smack_msg_queue_msgctl,
 	.msg_queue_msgsnd = 		smack_msg_queue_msgsnd,
 	.msg_queue_msgrcv = 		smack_msg_queue_msgrcv,
+	.msg_queue_restore = 		smack_msg_queue_restore,
 
 	.shm_alloc_security = 		smack_shm_alloc_security,
 	.shm_free_security = 		smack_shm_free_security,
 	.shm_associate = 		smack_shm_associate,
 	.shm_shmctl = 			smack_shm_shmctl,
 	.shm_shmat = 			smack_shm_shmat,
+	.shm_restore = 			smack_shm_restore,
 
 	.sem_alloc_security = 		smack_sem_alloc_security,
 	.sem_free_security = 		smack_sem_free_security,
 	.sem_associate = 		smack_sem_associate,
 	.sem_semctl = 			smack_sem_semctl,
 	.sem_semop = 			smack_sem_semop,
+	.sem_restore = 			smack_sem_restore,
 
 	.netlink_send =			cap_netlink_send,
 	.netlink_recv = 		cap_netlink_recv,
-- 
1.6.1

_______________________________________________
Containers mailing list
Containers at lists.linux-foundation.org
https://lists.linux-foundation.org/mailman/listinfo/containers




More information about the Devel mailing list