mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* patch 0/11] lsm stacking: intro
@ 2005-06-08 23:55 serue
  2005-06-08 23:56 ` [patch 1/11] lsm stacking: don't default to dummy_##hook serue
                   ` (10 more replies)
  0 siblings, 11 replies; 12+ messages in thread
From: serue @ 2005-06-08 23:55 UTC (permalink / raw)
  To: lkml; +Cc: Chris Wright, Stephen Smalley, James Morris

Hi,

The set of patches to follow introduces support for stacking LSMs.  I
am sending it out in the hopes of soliciting more widespread feedback
and testing.

The patches mainly do three things:

   1. Introduce the stacker LSM.
   2. Change the kernel object void * security fields to be hlists,
      and introduce an api for modules to share these.
   3. Modify SELinux to make use of stacker.

Motivation:

The purpose of these patches is to enable stacking multiple security
modules.  There are several cases where this would be very useful.  It
eases the testing of new modules with distro kernels, as it makes it
possible to stack new modules with selinux and capabilities -- for
instance if a user is running fedora.  Second, it enables running
selinux (or LIDS, etc) with integrity verification modules.  (Digsig is
an example of these, and within a few months hopefully the TPM-enabled
slim+evm modules, which verifies integrity of file contents and extended
attributes such as selinux contexts
(http://www.acsac.org/2004/workshop/David-Safford.pdf) will be released
for mainline inclusion).  Thirdly, there are systems where running
selinux is not practical for footprint reasons, and the security goals
are easily expressed as a very small module.  For instance, it might
be desirable to confine a web browser on a zaurus, or to implement a
site security policy on old hardware as per
http://mail.wirex.com/pipermail/linux-security-module/2005-May/6071.html

Performance impact of the actual stacker module is negligable.  The
security_{get,set,del,add}_value API does have a small performance
impact.  Please see
http://marc.theaimsgroup.com/?l=linux-security-module&m=111820455332752&w=2
and
http://marc.theaimsgroup.com/?l=linux-security-module&m=111824326500837&w=2
if interested in the performance results.  I am certainly interested in
ways to further speed up security_get_value.

thanks,
-serge

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 1/11] lsm stacking: don't default to dummy_##hook
  2005-06-08 23:55 patch 0/11] lsm stacking: intro serue
@ 2005-06-08 23:56 ` serue
  2005-06-08 23:57 ` [patch 2/11] lsm stacking: replace void* security with hlist serue
                   ` (9 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: serue @ 2005-06-08 23:56 UTC (permalink / raw)
  To: lkml; +Cc: Chris Wright, Stephen Smalley, James Morris

When stacking multiple LSMs, we do not want hooks which are undefined to
be substituted with the dummy_##hook.

Signed-off-by: Serge Hallyn <serue@us.ibm.com>
---
 security/security.c |   12 ++++++------
 1 files changed, 6 insertions(+), 6 deletions(-)

Index: linux-2.6.12-rc6/security/security.c
===================================================================
--- linux-2.6.12-rc6.orig/security/security.c
+++ linux-2.6.12-rc6/security/security.c
@@ -81,15 +81,15 @@ int __init security_init(void)
  */
 int register_security(struct security_operations *ops)
 {
+	if (security_ops != &dummy_security_ops)
+		return -EAGAIN;
+
 	if (verify(ops)) {
 		printk(KERN_DEBUG "%s could not verify "
 		       "security_operations structure.\n", __FUNCTION__);
 		return -EINVAL;
 	}
 
-	if (security_ops != &dummy_security_ops)
-		return -EAGAIN;
-
 	security_ops = ops;
 
 	return 0;
@@ -134,9 +134,9 @@ int unregister_security(struct security_
  */
 int mod_reg_security(const char *name, struct security_operations *ops)
 {
-	if (verify(ops)) {
-		printk(KERN_INFO "%s could not verify "
-		       "security operations.\n", __FUNCTION__);
+	if (!ops) {
+		printk(KERN_INFO "%s received NULL security operations",
+						       __FUNCTION__);
 		return -EINVAL;
 	}
 

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 2/11] lsm stacking: replace void* security with hlist
  2005-06-08 23:55 patch 0/11] lsm stacking: intro serue
  2005-06-08 23:56 ` [patch 1/11] lsm stacking: don't default to dummy_##hook serue
@ 2005-06-08 23:57 ` serue
  2005-06-08 23:58 ` [patch 3/11] lsm stacking: introduce security_*_value API serue
                   ` (8 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: serue @ 2005-06-08 23:57 UTC (permalink / raw)
  To: lkml; +Cc: Chris Wright, Stephen Smalley, James Morris

Replace kernel object ->security void*'s with hlists.  This will permit
multiple LSMs to each store information under one kernel object.

Signed-off-by: Serge Hallyn <serue@us.ibm.com>
---
 fs/compat.c             |    4 ++--
 fs/exec.c               |    4 ++--
 fs/inode.c              |    2 +-
 include/linux/binfmts.h |    2 +-
 include/linux/fs.h      |    8 ++++----
 include/linux/ipc.h     |    3 ++-
 include/linux/msg.h     |    2 +-
 include/linux/sched.h   |    2 +-
 include/net/sock.h      |    2 +-
 ipc/msg.c               |    2 +-
 ipc/msgutil.c           |    2 +-
 ipc/sem.c               |    2 +-
 ipc/shm.c               |    2 +-
 kernel/fork.c           |    2 +-
 14 files changed, 20 insertions(+), 19 deletions(-)

Index: linux-2.6.12-rc6/fs/compat.c
===================================================================
--- linux-2.6.12-rc6.orig/fs/compat.c
+++ linux-2.6.12-rc6/fs/compat.c
@@ -1519,6 +1519,7 @@ int compat_do_execve(char * filename,
 	bprm->file = file;
 	bprm->filename = filename;
 	bprm->interp = filename;
+	INIT_HLIST_HEAD(&bprm->security);
 	bprm->mm = mm_alloc();
 	retval = -ENOMEM;
 	if (!bprm->mm)
@@ -1575,8 +1576,7 @@ out:
 			__free_page(page);
 	}
 
-	if (bprm->security)
-		security_bprm_free(bprm);
+	security_bprm_free(bprm);
 
 out_mm:
 	if (bprm->mm)
Index: linux-2.6.12-rc6/fs/exec.c
===================================================================
--- linux-2.6.12-rc6.orig/fs/exec.c
+++ linux-2.6.12-rc6/fs/exec.c
@@ -1152,6 +1152,7 @@ int do_execve(char * filename,
 	bprm->file = file;
 	bprm->filename = filename;
 	bprm->interp = filename;
+	INIT_HLIST_HEAD(&bprm->security);
 	bprm->mm = mm_alloc();
 	retval = -ENOMEM;
 	if (!bprm->mm)
@@ -1210,8 +1211,7 @@ out:
 			__free_page(page);
 	}
 
-	if (bprm->security)
-		security_bprm_free(bprm);
+	security_bprm_free(bprm);
 
 out_mm:
 	if (bprm->mm)
Index: linux-2.6.12-rc6/fs/inode.c
===================================================================
--- linux-2.6.12-rc6.orig/fs/inode.c
+++ linux-2.6.12-rc6/fs/inode.c
@@ -132,7 +132,7 @@ static struct inode *alloc_inode(struct 
 		inode->i_bdev = NULL;
 		inode->i_cdev = NULL;
 		inode->i_rdev = 0;
-		inode->i_security = NULL;
+		INIT_HLIST_HEAD(&inode->i_security);
 		inode->dirtied_when = 0;
 		if (security_inode_alloc(inode)) {
 			if (inode->i_sb->s_op->destroy_inode)
Index: linux-2.6.12-rc6/include/linux/binfmts.h
===================================================================
--- linux-2.6.12-rc6.orig/include/linux/binfmts.h
+++ linux-2.6.12-rc6/include/linux/binfmts.h
@@ -29,7 +29,7 @@ struct linux_binprm{
 	struct file * file;
 	int e_uid, e_gid;
 	kernel_cap_t cap_inheritable, cap_permitted, cap_effective;
-	void *security;
+	struct hlist_head security;
 	int argc, envc;
 	char * filename;	/* Name of binary as seen by procps */
 	char * interp;		/* Name of the binary really executed. Most
Index: linux-2.6.12-rc6/include/linux/fs.h
===================================================================
--- linux-2.6.12-rc6.orig/include/linux/fs.h
+++ linux-2.6.12-rc6/include/linux/fs.h
@@ -477,7 +477,7 @@ struct inode {
 	unsigned int		i_flags;
 
 	atomic_t		i_writecount;
-	void			*i_security;
+	struct hlist_head	i_security;
 	union {
 		void		*generic_ip;
 	} u;
@@ -551,7 +551,7 @@ struct fown_struct {
 	rwlock_t lock;          /* protects pid, uid, euid fields */
 	int pid;		/* pid or -pgrp where SIGIO should be sent */
 	uid_t uid, euid;	/* uid/euid of process setting the owner */
-	void *security;
+	struct hlist_head security;
 	int signum;		/* posix.1b rt signal to be delivered on IO */
 };
 
@@ -589,7 +589,7 @@ struct file {
 
 	size_t			f_maxcount;
 	unsigned long		f_version;
-	void			*f_security;
+	struct hlist_head	f_security;
 
 	/* needed for tty driver, and maybe others */
 	void			*private_data;
@@ -775,7 +775,7 @@ struct super_block {
 	int			s_syncing;
 	int			s_need_sync_fs;
 	atomic_t		s_active;
-	void                    *s_security;
+ 	struct hlist_head	s_security;
 	struct xattr_handler	**s_xattr;
 
 	struct list_head	s_inodes;	/* all inodes */
Index: linux-2.6.12-rc6/include/linux/ipc.h
===================================================================
--- linux-2.6.12-rc6.orig/include/linux/ipc.h
+++ linux-2.6.12-rc6/include/linux/ipc.h
@@ -2,6 +2,7 @@
 #define _LINUX_IPC_H
 
 #include <linux/types.h>
+#include <linux/list.h>
 
 #define IPC_PRIVATE ((__kernel_key_t) 0)  
 
@@ -65,7 +66,7 @@ struct kern_ipc_perm
 	gid_t		cgid;
 	mode_t		mode; 
 	unsigned long	seq;
-	void		*security;
+	struct hlist_head security;
 };
 
 #endif /* __KERNEL__ */
Index: linux-2.6.12-rc6/include/linux/msg.h
===================================================================
--- linux-2.6.12-rc6.orig/include/linux/msg.h
+++ linux-2.6.12-rc6/include/linux/msg.h
@@ -70,7 +70,7 @@ struct msg_msg {
 	long  m_type;          
 	int m_ts;           /* message text size */
 	struct msg_msgseg* next;
-	void *security;
+	struct hlist_head security;
 	/* the actual message follows immediately */
 };
 
Index: linux-2.6.12-rc6/include/linux/sched.h
===================================================================
--- linux-2.6.12-rc6.orig/include/linux/sched.h
+++ linux-2.6.12-rc6/include/linux/sched.h
@@ -690,7 +690,7 @@ struct task_struct {
 	void *notifier_data;
 	sigset_t *notifier_mask;
 	
-	void *security;
+	struct hlist_head security;
 	struct audit_context *audit_context;
 	seccomp_t seccomp;
 
Index: linux-2.6.12-rc6/include/net/sock.h
===================================================================
--- linux-2.6.12-rc6.orig/include/net/sock.h
+++ linux-2.6.12-rc6/include/net/sock.h
@@ -240,7 +240,7 @@ struct sock {
 	struct sk_buff		*sk_send_head;
 	__u32			sk_sndmsg_off;
 	int			sk_write_pending;
-	void			*sk_security;
+	struct hlist_head	sk_security;
 	void			(*sk_state_change)(struct sock *sk);
 	void			(*sk_data_ready)(struct sock *sk, int bytes);
 	void			(*sk_write_space)(struct sock *sk);
Index: linux-2.6.12-rc6/ipc/msg.c
===================================================================
--- linux-2.6.12-rc6.orig/ipc/msg.c
+++ linux-2.6.12-rc6/ipc/msg.c
@@ -99,7 +99,7 @@ static int newque (key_t key, int msgflg
 	msq->q_perm.mode = (msgflg & S_IRWXUGO);
 	msq->q_perm.key = key;
 
-	msq->q_perm.security = NULL;
+	INIT_HLIST_HEAD(&msq->q_perm.security);
 	retval = security_msg_queue_alloc(msq);
 	if (retval) {
 		ipc_rcu_putref(msq);
Index: linux-2.6.12-rc6/ipc/msgutil.c
===================================================================
--- linux-2.6.12-rc6.orig/ipc/msgutil.c
+++ linux-2.6.12-rc6/ipc/msgutil.c
@@ -41,7 +41,7 @@ struct msg_msg *load_msg(const void __us
 		return ERR_PTR(-ENOMEM);
 
 	msg->next = NULL;
-	msg->security = NULL;
+	INIT_HLIST_HEAD(&msg->security);
 
 	if (copy_from_user(msg + 1, src, alen)) {
 		err = -EFAULT;
Index: linux-2.6.12-rc6/ipc/sem.c
===================================================================
--- linux-2.6.12-rc6.orig/ipc/sem.c
+++ linux-2.6.12-rc6/ipc/sem.c
@@ -178,7 +178,7 @@ static int newary (key_t key, int nsems,
 	sma->sem_perm.mode = (semflg & S_IRWXUGO);
 	sma->sem_perm.key = key;
 
-	sma->sem_perm.security = NULL;
+	INIT_HLIST_HEAD(&sma->sem_perm.security);
 	retval = security_sem_alloc(sma);
 	if (retval) {
 		ipc_rcu_putref(sma);
Index: linux-2.6.12-rc6/ipc/shm.c
===================================================================
--- linux-2.6.12-rc6.orig/ipc/shm.c
+++ linux-2.6.12-rc6/ipc/shm.c
@@ -199,7 +199,7 @@ static int newseg (key_t key, int shmflg
 	shp->shm_flags = (shmflg & S_IRWXUGO);
 	shp->mlock_user = NULL;
 
-	shp->shm_perm.security = NULL;
+	INIT_HLIST_HEAD(&shp->shm_perm.security);
 	error = security_shm_alloc(shp);
 	if (error) {
 		ipc_rcu_putref(shp);
Index: linux-2.6.12-rc6/kernel/fork.c
===================================================================
--- linux-2.6.12-rc6.orig/kernel/fork.c
+++ linux-2.6.12-rc6/kernel/fork.c
@@ -936,7 +936,7 @@ static task_t *copy_process(unsigned lon
 
 	p->lock_depth = -1;		/* -1 = no lock */
 	do_posix_clock_monotonic_gettime(&p->start_time);
-	p->security = NULL;
+	INIT_HLIST_HEAD(&p->security);
 	p->io_context = NULL;
 	p->io_wait = NULL;
 	p->audit_context = NULL;

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 3/11] lsm stacking: introduce security_*_value API
  2005-06-08 23:55 patch 0/11] lsm stacking: intro serue
  2005-06-08 23:56 ` [patch 1/11] lsm stacking: don't default to dummy_##hook serue
  2005-06-08 23:57 ` [patch 2/11] lsm stacking: replace void* security with hlist serue
@ 2005-06-08 23:58 ` serue
  2005-06-08 23:59 ` [patch 4/11] lsm stacking: stacker documentation serue
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: serue @ 2005-06-08 23:58 UTC (permalink / raw)
  To: lkml; +Cc: Chris Wright, Stephen Smalley, James Morris

Define the functions to be used by LSMs to add, retrieve, and remove
elements to the kernel object ->security hlists.

Signed-off-by: Serge Hallyn <serue@us.ibm.com>
---
 include/linux/security-stack.h |   51 +++++++++++++++++++++++++++
 include/linux/security.h       |   29 +++++++++++++++
 security/security.c            |   75 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 155 insertions(+)

Index: linux-2.6.12-rc6/include/linux/security-stack.h
===================================================================
--- /dev/null
+++ linux-2.6.12-rc6/include/linux/security-stack.h
@@ -0,0 +1,51 @@
+/*
+ * security-stack.h
+ *
+ * Contains function prototypes or inline definitions for the
+ * function which manipulate kernel object security annotations.
+ *
+ * If stacker is compiled in, then we use the full functions as
+ * defined in security/security.c.  Otherwise we use the #defines
+ * here.
+ */
+
+#ifdef CONFIG_SECURITY_STACKER
+extern struct security_list *security_get_value(struct hlist_head *head,
+			int security_id);
+
+extern struct security_list *security_set_value(struct hlist_head *head,
+			int security_id, struct security_list *obj_node);
+extern struct security_list *security_add_value(struct hlist_head *head,
+			int security_id, struct security_list *obj_node);
+extern struct security_list *security_del_value(struct hlist_head *head,
+			int security_id);
+#else
+static inline struct security_list *
+security_get_value(struct hlist_head *head, int security_id)
+{
+	struct hlist_node *tmp = head->first;
+	return tmp ? hlist_entry(tmp, struct security_list, list) : NULL;
+}
+
+static inline struct security_list *
+security_set_value(struct hlist_head *head, int security_id,
+	struct security_list *obj_node)
+{
+	head->first = &obj_node->list;
+}
+
+static inline struct security_list *
+security_add_value(struct hlist_head *head, int security_id,
+	struct security_list *obj_node)
+{
+	head->first = &obj_node->list;
+}
+
+static inline struct security_list *
+security_del_value(struct hlist_head *head, int security_id)
+{
+	struct hlist_node *tmp = head->first;
+	head->first = NULL;
+	return tmp ? hlist_entry(tmp, struct security_list, list) : NULL;
+}
+#endif
Index: linux-2.6.12-rc6/include/linux/security.h
===================================================================
--- linux-2.6.12-rc6.orig/include/linux/security.h
+++ linux-2.6.12-rc6/include/linux/security.h
@@ -34,6 +34,35 @@
 struct ctl_table;
 
 /*
+ * structure to be embedded at top of each LSM's security
+ * objects.
+ */
+struct security_list {
+	struct hlist_node list;
+	int security_id;
+};
+
+
+/*
+ * These #defines present more convenient interfaces to
+ * LSMs for using the security{g,d,s}et_value functions.
+ */
+#define security_get_value_type(head, id, type) ( { \
+	struct security_list *v = security_get_value(head, id); \
+	v ? hlist_entry(v, type, lsm_list) : NULL; } )
+
+#define security_set_value_type(head, id, value) \
+	security_set_value(head, id, &value->lsm_list);
+
+#define security_add_value_type(head, id, value) \
+	security_add_value(head, id, &value->lsm_list);
+
+#define security_del_value_type(head, id, type) ( { \
+	struct security_list *v; \
+	v = security_del_value(head, id); \
+	v ? hlist_entry(v, type, lsm_list) : NULL; } )
+
+/*
  * These functions are in security/capability.c and are used
  * as the default capabilities functions
  */
Index: linux-2.6.12-rc6/security/security.c
===================================================================
--- linux-2.6.12-rc6.orig/security/security.c
+++ linux-2.6.12-rc6/security/security.c
@@ -20,6 +20,81 @@
 
 #define SECURITY_FRAMEWORK_VERSION	"1.0.0"
 
+#ifdef CONFIG_SECURITY_STACKER
+fastcall struct security_list *
+security_get_value(struct hlist_head *head, int security_id)
+{
+	struct security_list *e, *ret = NULL;
+	struct hlist_node *tmp;
+
+	rcu_read_lock();
+	for (tmp = head->first; tmp;
+			 tmp = rcu_dereference(tmp->next)) {
+		e = hlist_entry(tmp, struct security_list, list);
+		if (e->security_id == security_id) {
+			ret = e;
+			goto out;
+		}
+	}
+
+out:
+	rcu_read_unlock();
+	return ret;
+}
+
+fastcall void
+security_set_value(struct hlist_head *head, int security_id,
+	struct security_list *obj_node)
+{
+
+	obj_node->security_id = security_id;
+	hlist_add_head(&obj_node->list, head);
+}
+
+static DEFINE_SPINLOCK(stacker_value_spinlock);
+
+fastcall void
+security_add_value(struct hlist_head *head, int security_id,
+	struct security_list *obj_node)
+{
+
+	spin_lock(&stacker_value_spinlock);
+	obj_node->security_id = security_id;
+	hlist_add_head_rcu(&obj_node->list, head);
+	spin_unlock(&stacker_value_spinlock);
+}
+
+/*
+ * XXX Serge: is it possible to add a security_del_value_locked(),
+ * which waits for a full rcu read cycle before returning an object
+ * to be deleted, so that it would be safe to use along with racing
+ * security_get_value()?
+ */
+
+/* No locking needed: only called during object_destroy */
+fastcall struct security_list *
+security_del_value(struct hlist_head *head, int security_id)
+{
+	struct security_list *e;
+	struct hlist_node *tmp;
+
+	for (tmp = head->first; tmp; tmp = tmp->next) {
+		e = hlist_entry(tmp, struct security_list, list);
+		if (e->security_id == security_id) {
+			hlist_del(&e->list);
+			return e;
+		}
+	}
+
+	return NULL;
+}
+
+EXPORT_SYMBOL_GPL(security_get_value);
+EXPORT_SYMBOL_GPL(security_set_value);
+EXPORT_SYMBOL_GPL(security_add_value);
+EXPORT_SYMBOL_GPL(security_del_value);
+#endif
+
 /* things that live in dummy.c */
 extern struct security_operations dummy_security_ops;
 extern void security_fixup_ops(struct security_operations *ops);

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 4/11] lsm stacking: stacker documentation
  2005-06-08 23:55 patch 0/11] lsm stacking: intro serue
                   ` (2 preceding siblings ...)
  2005-06-08 23:58 ` [patch 3/11] lsm stacking: introduce security_*_value API serue
@ 2005-06-08 23:59 ` serue
  2005-06-09  0:00 ` [patch 5/11] lsm stacking: actual stacker module serue
                   ` (6 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: serue @ 2005-06-08 23:59 UTC (permalink / raw)
  To: lkml; +Cc: Chris Wright, Stephen Smalley, James Morris

Add documentation about stacker and its usage.

Signed-off-by: Serge Hallyn <serue@us.ibm.com>
---
 Documentation/LSM-stacking.txt |  157 +++++++++++++++++++++++++++++++++++++++++
 1 files changed, 157 insertions(+)

Index: linux-2.6.12-rc6/Documentation/LSM-stacking.txt
===================================================================
--- /dev/null
+++ linux-2.6.12-rc6/Documentation/LSM-stacking.txt
@@ -0,0 +1,157 @@
+------------
+LSM stacking
+------------
+
+This document consists of two parts.  The first describes the stacker LSM.
+The second describes what is needed from an LSM in order to permit it to
+stack with other LSMs.
+
+--------------------------------------------------------
+stacker LSM - enable stacking multiple security modules.
+--------------------------------------------------------
+
+Stacker is compiled into the kernel.  Find the "Stacker" option under
+the Security submenu, and say 'Y'.  Now, any security modules which are
+loaded or compiled into the kernel will be managed by stacker.
+
+You may interact with stacker through its sysfs interface, located
+under /sys/stacker/.  This consists of the following files:
+
+/sys/stacker/lockdown:
+Once you write to this file, you will no longer be able to load
+LSMs.
+
+/sys/stacker/list_modules:
+Reading this file will show which LSMs are being stacked.
+
+/sys/stacker/stop_responding:
+Unregisters the /sys/stacker directory, so that you can no longer
+interact with stacker.
+
+/sys/stacker/unload:
+Disables the specified module.  The module will actually still be
+loaded, but will no longer be asked to mediate accesses or update
+security information.  It will still be consulted on kernel object
+deletions.  Please see further down why.
+
+---------------------------------------------
+Readying an LSM for stacking with other LSMs.
+---------------------------------------------
+
+LSM stacking is not a simple matter.  You must consider the behavior of
+all stacked LSMs very carefully, as well as certain subtle effects of
+the LSM implementation.  Please do not try to stack arbitrary modules!
+For instance, while SELinux and cap-stack should always be used
+together, SELinux cannot be combined with the original capability
+module.  The reason for this is that capability enforces that
+a process must have CAP_SYS_ADMIN when writing "security.*" extended
+attributes.  However selinux requires that non-CAP_SYS_ADMIN processes
+be able to write security.selinux attributes, instead enforcing its
+own permission check.  More subtle interactions are certainly
+imaginable, such as a first security module updating state on a kernel
+object such that a second security module denies or allows the action
+when it otherwise would not have.
+
+If you have any questions about the proper or actual behavior of
+modules, whether existing or ones to be written by yourself, a good
+place to engage in discussion is the lsm mailing list,
+linux-security-module@wirex.com.  Information about the mailing list can
+be found at lsm.immunix.org.
+
+For performance reasons, stacker currently does not permit unloading
+of stacked modules.  They may be disabled while loaded by using the
+/sys/stacker/unload file.  Stacker attempts to prevent the unloads by
+incrementing the usage count on the module's struct security_operations.
+
+If your module will be annotating security information to kernel
+objects, then you should use the provided API.  The functions intended
+for use by modules are defined in include/linux/security.h.  A
+good example of a user of these functions is the SELinux module.  The
+following describes the API usage.
+
+Assume you wish to annotate an instance of the following struct to the
+inode_struct:
+
+struct my_security_info {
+	int a;
+	struct list_head some_list;
+	spinlock_t lock;
+};
+
+At the top of the struct, you must add a struct security_list lsm_list,
+as follows:
+
+struct my_security_info {
++	struct security_list lsm_list;
+	int count;
+	struct list_head some_list;
+	spinlock_t lock;
+};
+
+This will add the information which the API will need to tell your
+information apart from that of other modules.  You also need to define a
+unique ID to distinguish information owned by your module.  Usually you
+can just "echo <module_name> | sha1sum" and use the first 8 digits.
+For instance, if
+#echo seclvl | sha1sum | awk --field-separator="" '{ print \
+$1$2$3$4$5$6$7$8 '}
+40e81e47
+
+then in your my_lsm.h, add
+#define MY_LSM_ID 0x40e81e47
+
+Do make sure that no other module happens to have the same ID.
+
+Now when the kernel object is created, you may use
+security_set_value_type to append the struct to the object's list of
+security information.  Note that you may ONLY use this while the kernel
+object is being created, ie during the security_<KERNEL_OBJECT>_alloc
+function.  Since you are appending my_security_info to the inode, you
+will do so during the security_inode_alloc() hook.  For instance,
+
+static inline int my_inode_alloc(struct inode *inode)
+{
+	struct my_security_info *my_data;
+
+	my_data = kmalloc(sizeof(struct my_security_info), GFP_KERNEL);
+	if (!my_data)
+		return -ENOMEM;
+	init_inode_data(my_data);
+
+	security_set_value_type(&inode->i_security, MY_LSM_ID, my_data);
+}
+
+If you need to append your information after the kernel object has been
+created, you may do so using security_add_value_type() hook.  However,
+for both performance and security reasons, it is preferable to compile
+your module into the kernel and always append your info while the object
+is created.
+
+To get your information back, you may use security_get_value_type.
+For instance,
+
+static inline int my_inode_create(struct inode *dir,
+				  struct dentry *dentry,
+				  int mode)
+{
+	struct my_security_info *my_data;
+
+	my_data = security_get_value_type(&dir->i_security,
+			MY_LSM_ID, struct my_security_info);
+	if (!my_data || my_data->count)
+		return -EPERM;
+	return 0;
+}
+
+Finally, data appended to kernel objects must (for now) be removed
+during the security_<KERNEL_OBJECT>_free() function only.  This is a
+limitation for performance reasons.  Allowing data to be freed anytime
+would only be needed if security modules could be unloaded, which would
+then require two additions to the locking scheme:  We would have to
+protect the object->security readers from data deletions, and likewise
+protect the actual security_operations structures from being unloaded
+while one of its member functions is executed.  It is possible that the
+latter is sufficiently taken care of by the module unloading logic.  The
+former would require waiting for a full rcu cycle between removing an
+element from the list, and actually deleting the element.  Additional
+locking (ie a refcount) would be up to the module itself.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 5/11] lsm stacking: actual stacker module
  2005-06-08 23:55 patch 0/11] lsm stacking: intro serue
                   ` (3 preceding siblings ...)
  2005-06-08 23:59 ` [patch 4/11] lsm stacking: stacker documentation serue
@ 2005-06-09  0:00 ` serue
  2005-06-09  0:00 ` [patch 6/11] lsm stacking: introduce stackable capabilities lsm serue
                   ` (5 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: serue @ 2005-06-09  0:00 UTC (permalink / raw)
  To: lkml; +Cc: Chris Wright, Stephen Smalley, James Morris

Adds the actual stacker LSM.

Signed-off-by: Serge Hallyn <serue@us.ibm.com>
---
 security/Kconfig   |    6 
 security/Makefile  |    1 
 security/stacker.c | 1455 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 1462 insertions(+)

Index: linux-2.6.12-rc2/security/Kconfig
===================================================================
--- linux-2.6.12-rc2.orig/security/Kconfig	2005-05-23 09:55:11.000000000 -0500
+++ linux-2.6.12-rc2/security/Kconfig	2005-05-23 15:25:45.000000000 -0500
@@ -87,5 +87,11 @@
 
 source security/selinux/Kconfig
 
+config SECURITY_STACKER
+	boolean "LSM Stacking"
+	depends on SECURITY
+	help
+	  Stack multiple LSMs.
+
 endmenu
 
Index: linux-2.6.12-rc2/security/Makefile
===================================================================
--- linux-2.6.12-rc2.orig/security/Makefile	2005-05-23 09:55:11.000000000 -0500
+++ linux-2.6.12-rc2/security/Makefile	2005-05-23 15:25:45.000000000 -0500
@@ -3,6 +3,7 @@
 #
 
 obj-$(CONFIG_KEYS)			+= keys/
+obj-$(CONFIG_SECURITY_STACKER)		+= stacker.o
 subdir-$(CONFIG_SECURITY_SELINUX)	+= selinux
 
 # if we don't select a security model, use the default capabilities
Index: linux-2.6.12-rc2/security/stacker.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.12-rc2/security/stacker.c	2005-05-23 15:25:39.000000000 -0500
@@ -0,0 +1,1455 @@
+/* "Stacker" Linux security module (LSM).
+ *
+ * Allows you to load (stack) multiple (additional) security modules.
+ *
+ * Copyright (C) 2002,2003,2004,2005 Serge E. Hallyn <serue@us.ibm.com>
+ * Copyright (C) 2002 David A. Wheeler <dwheeler@dwheeler.com>.
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/security.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/capability.h>
+#include <linux/rwsem.h>
+#include <linux/kobject.h>
+#include <linux/sysfs.h>
+#include <linux/netdevice.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <asm/system.h>
+
+/* A module entry keeps track of one of the stacked modules
+ * Note that module_operations is aggregated instead of being pointed to -
+ * it's one less allocation and one less pointer to follow. */
+
+struct module_entry {
+	struct list_head lsm_list;  /* list of active lsms */
+	struct list_head all_lsms; /* list of all lsms */
+	char *module_name;
+	int namelen;
+	struct security_operations module_operations;
+};
+static struct list_head stacked_modules;  /* list of stacked modules */
+static struct list_head all_modules;  /* list of all modules, including freed */
+
+static short sysfsfiles_registered;
+
+static spinlock_t stacker_lock;
+static int forbid_stacker_register;     /* = 0; if 1, can't register */
+
+
+/*
+ * Workarounds for the fact that get and setprocattr are used only by
+ * selinux.  (Maybe)
+ */
+static struct module_entry *selinux_module;
+
+/* Maximum number of characters in a stacked LSM module name */
+#define MAX_MODULE_NAME_LEN 128
+
+static int debug = 0;
+
+module_param(debug, bool, 0600);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
+#define MY_NAME "stacker"
+#define stacker_dbg(fmt, arg...)					\
+	do {							\
+		if (debug)					\
+			printk(KERN_DEBUG "%s: %s: " fmt ,	\
+				MY_NAME , __FUNCTION__ , 	\
+				## arg);			\
+	} while (0)
+
+/* Walk through the list of modules in stacked_modules
+ * and ask each (in turn) for their results, then return the
+ * results.  If more than one module reports an error, return
+ * the FIRST error code.
+ *
+ * We return as soon as an error is returned.
+ */
+
+#define stack_for_each_entry(pos, head, member)				\
+	for (pos = list_entry((head)->next, typeof(*pos), member);	\
+		&pos->member != (head);					\
+		pos = rcu_dereference(list_entry(pos->member.next, 	\
+				typeof(*pos), member)))
+
+/* to make this safe for module deletion, we would need to
+ * add a reference count to m as we had before
+ */
+#define RETURN_ERROR_IF_ANY_ERROR(BASE_FUNC, FUNC_WITH_ARGS) do { \
+	int result = 0; \
+	struct module_entry *m; \
+	rcu_read_lock(); \
+	stack_for_each_entry(m, &stacked_modules, lsm_list) { \
+		if (!m->module_operations.BASE_FUNC) \
+			continue; \
+		rcu_read_unlock(); \
+		result = m->module_operations.FUNC_WITH_ARGS; \
+		rcu_read_lock(); \
+		if (result) \
+			break; \
+	} \
+	rcu_read_unlock(); \
+	return result; \
+} while (0)
+
+/* Call all modules in stacked_modules' routine */
+#define CALL_ALL(BASE_FUNC, FUNC_WITH_ARGS) do { \
+	struct module_entry *m; \
+	rcu_read_lock(); \
+	stack_for_each_entry(m, &stacked_modules, lsm_list) { \
+		if (m->module_operations.BASE_FUNC) { \
+			rcu_read_unlock(); \
+			m->module_operations.FUNC_WITH_ARGS; \
+			rcu_read_lock(); \
+		} \
+	} \
+	rcu_read_unlock(); \
+} while (0)
+
+#define FREE_ALL(BASE_FREE,FREE_WITH_ARGS) do { \
+	struct module_entry *m; \
+	rcu_read_lock(); \
+	stack_for_each_entry(m, &stacked_modules, lsm_list ) { \
+		if (m->module_operations.BASE_FREE) { \
+			rcu_read_unlock(); \
+			m->module_operations.FREE_WITH_ARGS; \
+			rcu_read_lock(); \
+		} \
+	} \
+	rcu_read_unlock(); \
+} while (0)
+
+#define ALLOC_SECURITY(BASE_FUNC,FUNC_WITH_ARGS,BASE_FREE,FREE_WITH_ARGS) do { \
+	int result; \
+	struct module_entry *m, *m2; \
+	rcu_read_lock(); \
+	stack_for_each_entry(m, &stacked_modules, lsm_list) { \
+		if (!m->module_operations.BASE_FUNC) \
+			continue; \
+		rcu_read_unlock(); \
+		result = m->module_operations.FUNC_WITH_ARGS; \
+		rcu_read_lock(); \
+		if (result) \
+			goto bad; \
+	} \
+	rcu_read_unlock(); \
+	return 0; \
+bad: \
+	stack_for_each_entry(m2, &all_modules, all_lsms) { \
+		if (m == m2) \
+			break; \
+		if (!m2->module_operations.BASE_FREE) \
+			continue; \
+		rcu_read_unlock(); \
+		m2->module_operations.FREE_WITH_ARGS; \
+		rcu_read_lock(); \
+	} \
+	rcu_read_unlock(); \
+	return result; \
+} while (0)
+
+/*
+ * The list of functions for stacker_ops
+ */
+static int stacker_ptrace (struct task_struct *parent, struct task_struct *child)
+{
+	RETURN_ERROR_IF_ANY_ERROR(ptrace,ptrace(parent, child));
+}
+
+static int stacker_capget (struct task_struct *target, kernel_cap_t * effective,
+			 kernel_cap_t * inheritable, kernel_cap_t * permitted)
+{
+	RETURN_ERROR_IF_ANY_ERROR(capget,capget(target, effective, inheritable, permitted));
+}
+
+static int stacker_capset_check (struct task_struct *target,
+			       kernel_cap_t * effective,
+			       kernel_cap_t * inheritable,
+			       kernel_cap_t * permitted)
+{
+	RETURN_ERROR_IF_ANY_ERROR(capset_check,capset_check(target, effective, inheritable, permitted));
+}
+
+static void stacker_capset_set (struct task_struct *target,
+			      kernel_cap_t * effective,
+			      kernel_cap_t * inheritable,
+			      kernel_cap_t * permitted)
+{
+	CALL_ALL(capset_set,capset_set(target, effective, inheritable, permitted));
+}
+
+static int stacker_acct (struct file *file)
+{
+	RETURN_ERROR_IF_ANY_ERROR(acct,acct(file));
+}
+
+static int stacker_capable (struct task_struct *tsk, int cap)
+{
+	RETURN_ERROR_IF_ANY_ERROR(capable,capable(tsk,cap));
+}
+
+
+static int stacker_sysctl (struct ctl_table * table, int op)
+{
+	RETURN_ERROR_IF_ANY_ERROR(sysctl,sysctl(table, op));
+}
+
+static int stacker_quotactl (int cmds, int type, int id, struct super_block *sb)
+{
+	RETURN_ERROR_IF_ANY_ERROR(quotactl,quotactl(cmds,type,id,sb));
+}
+
+static int stacker_quota_on (struct dentry *dentry)
+{
+	RETURN_ERROR_IF_ANY_ERROR(quota_on,quota_on(dentry));
+}
+
+static int stacker_syslog (int type)
+{
+	RETURN_ERROR_IF_ANY_ERROR(syslog,syslog(type));
+}
+
+static int stacker_settime(struct timespec *ts, struct timezone *tz)
+{
+	RETURN_ERROR_IF_ANY_ERROR(settime,settime(ts,tz));
+}
+
+/*
+ * vm_enough_memory performs actual updates of vm state.  Most
+ * modules, including dummy, use the __vm_enough_memory helper
+ * to do this for them.
+ * This means we can't call more than one module's vm_enough.
+ * So we call the first module's, or if no modules are loaded,
+ * we call dummy_vm_enough_memory.
+ */
+static int stacker_vm_enough_memory(long pages)
+{
+	int result;
+	struct module_entry *m;
+
+	if (unlikely(list_empty(&stacked_modules)))
+		goto no_module_vmenough;
+
+	rcu_read_lock();
+	stack_for_each_entry(m, &stacked_modules, lsm_list) {
+		if (!m->module_operations.vm_enough_memory)
+			continue;
+		rcu_read_unlock();
+		result = m->module_operations.vm_enough_memory(pages);
+		return result;
+	}
+	rcu_read_unlock();
+
+no_module_vmenough:
+	result = __vm_enough_memory(pages, capable(CAP_SYS_ADMIN));
+	return result;
+}
+
+/*
+ * Each module may have it's own idea of how to set netlink perms.
+ * We use the intersection of all as the final alloted perms.
+ */
+static int stacker_netlink_send (struct sock *sk, struct sk_buff *skb)
+{
+	kernel_cap_t tmpcap = ~0;
+	int result = 0;
+	struct module_entry *m;
+
+	rcu_read_lock();
+	stack_for_each_entry(m, &stacked_modules, lsm_list) {
+		if (!m->module_operations.netlink_send)
+			continue;
+		NETLINK_CB(skb).eff_cap = ~0;
+		rcu_read_unlock();
+		result = m->module_operations.netlink_send(sk, skb);
+		rcu_read_lock();
+		tmpcap &= NETLINK_CB(skb).eff_cap;
+		if (result)
+			break;
+	}
+	rcu_read_unlock();
+
+	NETLINK_CB(skb).eff_cap = tmpcap;
+	return result;
+}
+
+
+static int stacker_netlink_recv (struct sk_buff *skb)
+{
+	RETURN_ERROR_IF_ANY_ERROR(netlink_recv,netlink_recv(skb));
+}
+
+static int stacker_bprm_alloc_security (struct linux_binprm *bprm)
+{
+	ALLOC_SECURITY(bprm_alloc_security,bprm_alloc_security(bprm),bprm_free_security,bprm_free_security(bprm));
+}
+
+static void stacker_bprm_free_security (struct linux_binprm *bprm)
+{
+	FREE_ALL(bprm_free_security,bprm_free_security(bprm));
+}
+
+static void stacker_bprm_apply_creds (struct linux_binprm *bprm, int unsafe)
+{
+	CALL_ALL(bprm_apply_creds,bprm_apply_creds(bprm, unsafe));
+}
+
+static void stacker_bprm_post_apply_creds (struct linux_binprm * bprm)
+{
+	CALL_ALL(bprm_post_apply_creds,bprm_post_apply_creds(bprm));
+}
+
+static int stacker_bprm_set_security (struct linux_binprm *bprm)
+{
+	RETURN_ERROR_IF_ANY_ERROR(bprm_set_security,bprm_set_security(bprm));
+}
+
+static int stacker_bprm_check_security (struct linux_binprm *bprm)
+{
+	RETURN_ERROR_IF_ANY_ERROR(bprm_check_security,bprm_check_security(bprm));
+}
+
+static int stacker_bprm_secureexec (struct linux_binprm *bprm)
+{
+	RETURN_ERROR_IF_ANY_ERROR(bprm_secureexec,bprm_secureexec(bprm));
+}
+
+static int stacker_sb_alloc_security (struct super_block *sb)
+{
+	ALLOC_SECURITY(sb_alloc_security,sb_alloc_security(sb),sb_free_security,sb_free_security(sb));
+}
+
+static void stacker_sb_free_security (struct super_block *sb)
+{
+	FREE_ALL(sb_free_security,sb_free_security(sb));
+}
+
+static int stacker_sb_copy_data (struct file_system_type *type,
+			void *orig, void *copy)
+{
+	RETURN_ERROR_IF_ANY_ERROR(sb_copy_data,sb_copy_data(type,orig,copy));
+}
+
+static int stacker_sb_kern_mount (struct super_block *sb, void *data)
+{
+	RETURN_ERROR_IF_ANY_ERROR(sb_kern_mount,sb_kern_mount(sb, data));
+}
+
+static int stacker_sb_statfs (struct super_block *sb)
+{
+	RETURN_ERROR_IF_ANY_ERROR(sb_statfs,sb_statfs(sb));
+}
+
+static int stacker_mount (char *dev_name, struct nameidata *nd, char *type,
+			unsigned long flags, void *data)
+{
+	RETURN_ERROR_IF_ANY_ERROR(sb_mount,sb_mount(dev_name, nd, type, flags, data));
+}
+
+static int stacker_check_sb (struct vfsmount *mnt, struct nameidata *nd)
+{
+	RETURN_ERROR_IF_ANY_ERROR(sb_check_sb,sb_check_sb(mnt, nd));
+}
+
+static int stacker_umount (struct vfsmount *mnt, int flags)
+{
+	RETURN_ERROR_IF_ANY_ERROR(sb_umount,sb_umount(mnt, flags));
+}
+
+static void stacker_umount_close (struct vfsmount *mnt)
+{
+	CALL_ALL(sb_umount_close,sb_umount_close(mnt));
+}
+
+static void stacker_umount_busy (struct vfsmount *mnt)
+{
+	CALL_ALL(sb_umount_busy,sb_umount_busy(mnt));
+}
+
+static void stacker_post_remount (struct vfsmount *mnt, unsigned long flags,
+				void *data)
+{
+	CALL_ALL(sb_post_remount,sb_post_remount(mnt, flags, data));
+}
+
+
+static void stacker_post_mountroot (void)
+{
+	CALL_ALL(sb_post_mountroot,sb_post_mountroot());
+}
+
+static void stacker_post_addmount (struct vfsmount *mnt, struct nameidata *nd)
+{
+	CALL_ALL(sb_post_addmount,sb_post_addmount(mnt, nd));
+}
+
+static int stacker_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd)
+{
+	RETURN_ERROR_IF_ANY_ERROR(sb_pivotroot,sb_pivotroot(old_nd, new_nd));
+}
+
+static void stacker_post_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd)
+{
+	CALL_ALL(sb_post_pivotroot,sb_post_pivotroot(old_nd, new_nd));
+}
+
+static int stacker_inode_alloc_security (struct inode *inode)
+{
+	ALLOC_SECURITY(inode_alloc_security,inode_alloc_security(inode),inode_free_security,inode_free_security(inode));
+}
+
+static void stacker_inode_free_security (struct inode *inode)
+{
+	FREE_ALL(inode_free_security,inode_free_security(inode));
+}
+
+static int stacker_inode_create (struct inode *inode, struct dentry *dentry,
+			       int mask)
+{
+	RETURN_ERROR_IF_ANY_ERROR(inode_create,inode_create(inode, dentry, mask));
+}
+
+static void stacker_inode_post_create (struct inode *inode,
+	    struct dentry *dentry, int mask)
+{
+	CALL_ALL(inode_post_create,inode_post_create(inode, dentry, mask));
+}
+
+static int stacker_inode_link (struct dentry *old_dentry, struct inode *inode,
+			     struct dentry *new_dentry)
+{
+	RETURN_ERROR_IF_ANY_ERROR(inode_link,inode_link(old_dentry, inode, new_dentry));
+}
+
+static void stacker_inode_post_link (struct dentry *old_dentry,
+				   struct inode *inode,
+				   struct dentry *new_dentry)
+{
+	CALL_ALL(inode_post_link,inode_post_link(old_dentry, inode, new_dentry));
+}
+
+static int stacker_inode_unlink (struct inode *inode, struct dentry *dentry)
+{
+	RETURN_ERROR_IF_ANY_ERROR(inode_unlink,inode_unlink(inode, dentry));
+}
+
+static int stacker_inode_symlink (struct inode *inode, struct dentry *dentry,
+				const char *name)
+{
+	RETURN_ERROR_IF_ANY_ERROR(inode_symlink,inode_symlink(inode, dentry, name));
+}
+
+static void stacker_inode_post_symlink (struct inode *inode,
+				      struct dentry *dentry, const char *name)
+{
+	CALL_ALL(inode_post_symlink,inode_post_symlink(inode, dentry, name));
+}
+
+static int stacker_inode_mkdir (struct inode *inode, struct dentry *dentry,
+			      int mask)
+{
+	RETURN_ERROR_IF_ANY_ERROR(inode_mkdir,inode_mkdir(inode, dentry, mask));
+}
+
+static void stacker_inode_post_mkdir (struct inode *inode,
+	    	struct dentry *dentry, int mask)
+{
+	CALL_ALL(inode_post_mkdir,inode_post_mkdir(inode, dentry, mask));
+}
+
+static int stacker_inode_rmdir (struct inode *inode, struct dentry *dentry)
+{
+	RETURN_ERROR_IF_ANY_ERROR(inode_rmdir,inode_rmdir(inode, dentry));
+}
+
+static int stacker_inode_mknod (struct inode *inode, struct dentry *dentry,
+			      int major, dev_t minor)
+{
+	RETURN_ERROR_IF_ANY_ERROR(inode_mknod,inode_mknod(inode, dentry, major, minor));
+}
+
+static void stacker_inode_post_mknod (struct inode *inode,
+	       	struct dentry *dentry, int major, dev_t minor)
+{
+	CALL_ALL(inode_post_mknod,inode_post_mknod(inode, dentry, major, minor));
+}
+
+static int stacker_inode_rename (struct inode *old_inode,
+			       struct dentry *old_dentry,
+			       struct inode *new_inode,
+			       struct dentry *new_dentry)
+{
+	RETURN_ERROR_IF_ANY_ERROR(inode_rename,inode_rename(old_inode, old_dentry,
+				  new_inode, new_dentry));
+}
+
+static void stacker_inode_post_rename (struct inode *old_inode,
+				     struct dentry *old_dentry,
+				     struct inode *new_inode,
+				     struct dentry *new_dentry)
+{
+	CALL_ALL(inode_post_rename,inode_post_rename(old_inode, old_dentry,
+				  new_inode, new_dentry));
+}
+
+static int stacker_inode_readlink (struct dentry *dentry)
+{
+	RETURN_ERROR_IF_ANY_ERROR(inode_readlink,inode_readlink(dentry));
+}
+
+static int stacker_inode_follow_link (struct dentry *dentry,
+				    struct nameidata *nameidata)
+{
+	RETURN_ERROR_IF_ANY_ERROR(inode_follow_link,inode_follow_link(dentry, nameidata));
+}
+
+static int stacker_inode_permission (struct inode *inode, int mask,
+		struct nameidata *nd)
+{
+	RETURN_ERROR_IF_ANY_ERROR(inode_permission,inode_permission(inode, mask, nd));
+}
+
+static int stacker_inode_setattr (struct dentry *dentry, struct iattr *iattr)
+{
+	RETURN_ERROR_IF_ANY_ERROR(inode_setattr,inode_setattr(dentry, iattr));
+}
+
+static int stacker_inode_getattr (struct vfsmount *mnt, struct dentry *dentry)
+{
+	RETURN_ERROR_IF_ANY_ERROR(inode_getattr,inode_getattr(mnt,dentry));
+}
+
+static void stacker_inode_delete (struct inode *ino)
+{
+	CALL_ALL(inode_delete,inode_delete(ino));
+}
+
+static int stacker_inode_setxattr (struct dentry *dentry, char *name,
+	        	void *value, size_t size, int flags)
+{
+	RETURN_ERROR_IF_ANY_ERROR(inode_setxattr,inode_setxattr(dentry,name,value,size,flags));
+}
+
+static void stacker_inode_post_setxattr (struct dentry *dentry, char *name, void *value,
+				       size_t size, int flags)
+{
+	CALL_ALL(inode_post_setxattr,inode_post_setxattr(dentry,name,value,size,flags));
+}
+
+static int stacker_inode_getxattr (struct dentry *dentry, char *name)
+{
+	RETURN_ERROR_IF_ANY_ERROR(inode_getxattr,inode_getxattr(dentry,name));
+}
+
+static int stacker_inode_listxattr (struct dentry *dentry)
+{
+	RETURN_ERROR_IF_ANY_ERROR(inode_listxattr,inode_listxattr(dentry));
+}
+
+static int stacker_inode_removexattr (struct dentry *dentry, char *name)
+{
+	RETURN_ERROR_IF_ANY_ERROR(inode_removexattr,inode_removexattr(dentry,name));
+}
+
+static int stacker_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size)
+{
+	RETURN_ERROR_IF_ANY_ERROR(inode_getsecurity,inode_getsecurity(inode,name,buffer,size));
+}
+
+static int stacker_inode_setsecurity(struct inode *inode, const char *name, const void *value, size_t size, int flags)
+{
+	RETURN_ERROR_IF_ANY_ERROR(inode_setsecurity,inode_setsecurity(inode,name,value,size,flags));
+}
+
+static int stacker_inode_listsecurity(struct inode *inode, char *buffer, size_t buffer_size)
+{
+	RETURN_ERROR_IF_ANY_ERROR(inode_listsecurity,inode_listsecurity(inode,buffer, buffer_size));
+}
+
+static int stacker_file_permission (struct file *file, int mask)
+{
+	RETURN_ERROR_IF_ANY_ERROR(file_permission,file_permission(file,mask));
+}
+
+static int stacker_file_alloc_security (struct file *file)
+{
+	ALLOC_SECURITY(file_alloc_security,file_alloc_security(file),file_free_security,file_free_security(file));
+}
+
+static void stacker_file_free_security (struct file *file)
+{
+	FREE_ALL(file_free_security,file_free_security(file));
+}
+
+static int stacker_file_ioctl (struct file *file, unsigned int command,
+			     unsigned long arg)
+{
+	RETURN_ERROR_IF_ANY_ERROR(file_ioctl,file_ioctl(file,command,arg));
+}
+
+static int stacker_file_mmap (struct file *file, unsigned long reqprot,
+			    unsigned long prot, unsigned long flags)
+{
+	RETURN_ERROR_IF_ANY_ERROR(file_mmap,file_mmap(file, reqprot, prot, flags));
+}
+
+static int stacker_file_mprotect (struct vm_area_struct *vma,
+	       	unsigned long reqprot, unsigned long prot)
+{
+	RETURN_ERROR_IF_ANY_ERROR(file_mprotect,file_mprotect(vma,reqprot,prot));
+}
+
+static int stacker_file_lock (struct file *file, unsigned int cmd)
+{
+	RETURN_ERROR_IF_ANY_ERROR(file_lock,file_lock(file,cmd));
+}
+
+static int stacker_file_fcntl (struct file *file, unsigned int cmd,
+			     unsigned long arg)
+{
+	RETURN_ERROR_IF_ANY_ERROR(file_fcntl,file_fcntl(file,cmd,arg));
+}
+
+static int stacker_file_set_fowner (struct file *file)
+{
+	RETURN_ERROR_IF_ANY_ERROR(file_set_fowner,file_set_fowner(file));
+}
+
+static int stacker_file_send_sigiotask (struct task_struct *tsk,
+				      struct fown_struct *fown, int sig)
+{
+	RETURN_ERROR_IF_ANY_ERROR(file_send_sigiotask,file_send_sigiotask(tsk,fown,sig));
+}
+
+static int stacker_file_receive (struct file *file)
+{
+	RETURN_ERROR_IF_ANY_ERROR(file_receive,file_receive(file));
+}
+
+static int stacker_task_create (unsigned long clone_flags)
+{
+	RETURN_ERROR_IF_ANY_ERROR(task_create,task_create(clone_flags));
+}
+
+static int stacker_task_alloc_security (struct task_struct *p)
+{
+	ALLOC_SECURITY(task_alloc_security,task_alloc_security(p),task_free_security,task_free_security(p));
+}
+
+static void stacker_task_free_security (struct task_struct *p)
+{
+	FREE_ALL(task_free_security,task_free_security(p));
+}
+
+static int stacker_task_setuid (uid_t id0, uid_t id1, uid_t id2, int flags)
+{
+	RETURN_ERROR_IF_ANY_ERROR(task_setuid,task_setuid(id0,id1,id2,flags));
+}
+
+static int stacker_task_post_setuid (uid_t id0, uid_t id1, uid_t id2, int flags)
+{
+	RETURN_ERROR_IF_ANY_ERROR(task_post_setuid,task_post_setuid(id0,id1,id2,flags));
+}
+
+static int stacker_task_setgid (gid_t id0, gid_t id1, gid_t id2, int flags)
+{
+	RETURN_ERROR_IF_ANY_ERROR(task_setgid,task_setgid(id0,id1,id2,flags));
+}
+
+static int stacker_task_setpgid (struct task_struct *p, pid_t pgid)
+{
+	RETURN_ERROR_IF_ANY_ERROR(task_setpgid,task_setpgid(p,pgid));
+}
+
+static int stacker_task_getpgid (struct task_struct *p)
+{
+	RETURN_ERROR_IF_ANY_ERROR(task_getpgid,task_getpgid(p));
+}
+
+static int stacker_task_getsid (struct task_struct *p)
+{
+	RETURN_ERROR_IF_ANY_ERROR(task_getsid,task_getsid(p));
+}
+
+static int stacker_task_setgroups (struct group_info *group_info)
+{
+	RETURN_ERROR_IF_ANY_ERROR(task_setgroups,task_setgroups(group_info));
+}
+
+static int stacker_task_setnice (struct task_struct *p, int nice)
+{
+	RETURN_ERROR_IF_ANY_ERROR(task_setnice,task_setnice(p,nice));
+}
+
+static int stacker_task_setrlimit (unsigned int resource, struct rlimit *new_rlim)
+{
+	RETURN_ERROR_IF_ANY_ERROR(task_setrlimit,task_setrlimit(resource,new_rlim));
+}
+
+static int stacker_task_setscheduler (struct task_struct *p, int policy,
+				    struct sched_param *lp)
+{
+	RETURN_ERROR_IF_ANY_ERROR(task_setscheduler,task_setscheduler(p,policy,lp));
+}
+
+static int stacker_task_getscheduler (struct task_struct *p)
+{
+	RETURN_ERROR_IF_ANY_ERROR(task_getscheduler,task_getscheduler(p));
+}
+
+static int stacker_task_wait (struct task_struct *p)
+{
+	RETURN_ERROR_IF_ANY_ERROR(task_wait,task_wait(p));
+}
+
+static int stacker_task_kill (struct task_struct *p, struct siginfo *info,
+			    int sig)
+{
+	RETURN_ERROR_IF_ANY_ERROR(task_kill,task_kill(p,info,sig));
+}
+
+static int stacker_task_prctl (int option, unsigned long arg2, unsigned long arg3,
+			     unsigned long arg4, unsigned long arg5)
+{
+	RETURN_ERROR_IF_ANY_ERROR(task_prctl,task_prctl(option,arg2,arg3,arg4,arg5));
+}
+
+static void stacker_task_reparent_to_init (struct task_struct *p)
+{
+	/* Note that the dummy version of this hook would call:
+	 *	p->euid = p->fsuid = 0; */
+
+	CALL_ALL(task_reparent_to_init,task_reparent_to_init(p));
+}
+
+static void stacker_task_to_inode(struct task_struct *p, struct inode *inode)
+{
+	CALL_ALL(task_to_inode,task_to_inode(p, inode));
+}
+
+#ifdef CONFIG_SECURITY_NETWORK
+static int stacker_socket_create (int family, int type, int protocol, int kern)
+{
+	RETURN_ERROR_IF_ANY_ERROR(socket_create,socket_create(family,type,protocol,kern));
+}
+
+static void stacker_socket_post_create (struct socket *sock, int family,
+	       			int type, int protocol, int kern)
+{
+	CALL_ALL(socket_post_create,socket_post_create(sock,family,type,protocol,kern));
+}
+
+static int stacker_socket_bind (struct socket *sock, struct sockaddr *address,
+			      int addrlen)
+{
+	RETURN_ERROR_IF_ANY_ERROR(socket_bind,socket_bind(sock,address,addrlen));
+}
+
+static int stacker_socket_connect (struct socket *sock,
+	       	struct sockaddr *address, int addrlen)
+{
+	RETURN_ERROR_IF_ANY_ERROR(socket_connect,socket_connect(sock,address,addrlen));
+}
+
+static int stacker_socket_listen (struct socket *sock, int backlog)
+{
+	RETURN_ERROR_IF_ANY_ERROR(socket_listen,socket_listen(sock,backlog));
+}
+
+static int stacker_socket_accept (struct socket *sock, struct socket *newsock)
+{
+	RETURN_ERROR_IF_ANY_ERROR(socket_accept,socket_accept(sock,newsock));
+}
+
+static void stacker_socket_post_accept (struct socket *sock,
+				      struct socket *newsock)
+{
+	CALL_ALL(socket_post_accept,socket_post_accept(sock,newsock));
+}
+
+static int stacker_socket_sendmsg (struct socket *sock, struct msghdr *msg,
+				 int size)
+{
+	RETURN_ERROR_IF_ANY_ERROR(socket_sendmsg,socket_sendmsg(sock,msg,size));
+}
+
+static int stacker_socket_recvmsg (struct socket *sock, struct msghdr *msg,
+				 int size, int flags)
+{
+	RETURN_ERROR_IF_ANY_ERROR(socket_recvmsg,socket_recvmsg(sock,msg,size,flags));
+}
+
+static int stacker_socket_getsockname (struct socket *sock)
+{
+	RETURN_ERROR_IF_ANY_ERROR(socket_getsockname,socket_getsockname(sock));
+}
+
+static int stacker_socket_getpeername (struct socket *sock)
+{
+	RETURN_ERROR_IF_ANY_ERROR(socket_getpeername,socket_getpeername(sock));
+}
+
+static int stacker_socket_setsockopt (struct socket *sock, int level, int optname)
+{
+	RETURN_ERROR_IF_ANY_ERROR(socket_setsockopt,socket_setsockopt(sock,level,optname));
+}
+
+static int stacker_socket_getsockopt (struct socket *sock, int level, int optname)
+{
+	RETURN_ERROR_IF_ANY_ERROR(socket_getsockopt,socket_getsockopt(sock,level,optname));
+}
+
+static int stacker_socket_shutdown (struct socket *sock, int how)
+{
+	RETURN_ERROR_IF_ANY_ERROR(socket_shutdown,socket_shutdown(sock,how));
+}
+
+static int stacker_socket_sock_rcv_skb (struct sock *sk, struct sk_buff *skb)
+{
+	RETURN_ERROR_IF_ANY_ERROR(socket_sock_rcv_skb,socket_sock_rcv_skb(sk,skb));
+}
+
+static int stacker_unix_stream_connect (struct socket *sock,
+			     struct socket *other, struct sock *newsk)
+{
+	RETURN_ERROR_IF_ANY_ERROR(unix_stream_connect,unix_stream_connect(sock,other,newsk));
+}
+
+static int stacker_unix_may_send (struct socket *sock,
+				       struct socket *other)
+{
+	RETURN_ERROR_IF_ANY_ERROR(unix_may_send,unix_may_send(sock,other));
+}
+
+static int stacker_socket_getpeersec(struct socket *sock,
+	char __user *optval, int __user *optlen, unsigned len)
+{
+	RETURN_ERROR_IF_ANY_ERROR(socket_getpeersec,socket_getpeersec(sock,optval,optlen,len));
+}
+
+static int stacker_sk_alloc_security(struct sock *sk, int family,
+			int priority)
+{
+	ALLOC_SECURITY(sk_alloc_security,sk_alloc_security(sk,family,priority),sk_free_security,sk_free_security(sk));
+}
+
+static void stacker_sk_free_security (struct sock *sk)
+{
+	FREE_ALL(sk_free_security,sk_free_security(sk));
+}
+
+#endif
+
+static int stacker_ipc_permission (struct kern_ipc_perm *ipcp, short flag)
+{
+	RETURN_ERROR_IF_ANY_ERROR(ipc_permission,ipc_permission(ipcp,flag));
+}
+
+static int stacker_msg_msg_alloc_security (struct msg_msg *msg)
+{
+	ALLOC_SECURITY(msg_msg_alloc_security,msg_msg_alloc_security(msg),msg_msg_free_security,msg_msg_free_security(msg));
+}
+
+static void stacker_msg_msg_free_security (struct msg_msg *msg)
+{
+	FREE_ALL(msg_msg_free_security,msg_msg_free_security(msg));
+}
+
+static int stacker_msg_queue_alloc_security (struct msg_queue *msq)
+{
+	ALLOC_SECURITY(msg_queue_alloc_security,msg_queue_alloc_security(msq),msg_queue_free_security,msg_queue_free_security(msq));
+}
+
+static void stacker_msg_queue_free_security (struct msg_queue *msq)
+{
+	FREE_ALL(msg_queue_free_security,msg_queue_free_security(msq));
+}
+
+static int stacker_msg_queue_associate (struct msg_queue *msq, int msqflg)
+{
+	RETURN_ERROR_IF_ANY_ERROR(msg_queue_associate,msg_queue_associate(msq,msqflg));
+}
+
+static int stacker_msg_queue_msgctl (struct msg_queue *msq, int cmd)
+{
+	RETURN_ERROR_IF_ANY_ERROR(msg_queue_msgctl,msg_queue_msgctl(msq,cmd));
+}
+
+static int stacker_msg_queue_msgsnd (struct msg_queue *msq, struct msg_msg *msg,
+				   int msgflg)
+{
+	RETURN_ERROR_IF_ANY_ERROR(msg_queue_msgsnd,msg_queue_msgsnd(msq,msg,msgflg));
+}
+
+static int stacker_msg_queue_msgrcv (struct msg_queue *msq, struct msg_msg *msg,
+				   struct task_struct *target, long type,
+				   int mode)
+{
+	RETURN_ERROR_IF_ANY_ERROR(msg_queue_msgrcv,msg_queue_msgrcv(msq,msg,target,type,mode));
+}
+
+static int stacker_shm_alloc_security (struct shmid_kernel *shp)
+{
+	ALLOC_SECURITY(shm_alloc_security,shm_alloc_security(shp),shm_free_security,shm_free_security(shp));
+}
+
+static void stacker_shm_free_security (struct shmid_kernel *shp)
+{
+	FREE_ALL(shm_free_security,shm_free_security(shp));
+}
+
+static int stacker_shm_associate (struct shmid_kernel *shp, int shmflg)
+{
+	RETURN_ERROR_IF_ANY_ERROR(shm_associate,shm_associate(shp,shmflg));
+}
+
+static int stacker_shm_shmctl (struct shmid_kernel *shp, int cmd)
+{
+	RETURN_ERROR_IF_ANY_ERROR(shm_shmctl,shm_shmctl(shp,cmd));
+}
+
+static int stacker_shm_shmat (struct shmid_kernel *shp, char *shmaddr,
+			    int shmflg)
+{
+	RETURN_ERROR_IF_ANY_ERROR(shm_shmat,shm_shmat(shp,shmaddr,shmflg));
+}
+
+static int stacker_sem_alloc_security (struct sem_array *sma)
+{
+	ALLOC_SECURITY(sem_alloc_security,sem_alloc_security(sma),sem_free_security,sem_free_security(sma));
+}
+
+static void stacker_sem_free_security (struct sem_array *sma)
+{
+	FREE_ALL(sem_free_security,sem_free_security(sma));
+}
+
+static int stacker_sem_associate (struct sem_array *sma, int semflg)
+{
+	RETURN_ERROR_IF_ANY_ERROR(sem_associate,sem_associate(sma,semflg));
+}
+
+static int stacker_sem_semctl (struct sem_array *sma, int cmd)
+{
+	RETURN_ERROR_IF_ANY_ERROR(sem_semctl,sem_semctl(sma,cmd));
+}
+
+static int stacker_sem_semop (struct sem_array *sma,
+			    struct sembuf *sops, unsigned nsops, int alter)
+{
+	RETURN_ERROR_IF_ANY_ERROR(sem_semop,sem_semop(sma,sops,nsops,alter));
+}
+
+static void stacker_d_instantiate (struct dentry *dentry, struct inode *inode)
+{
+	CALL_ALL(d_instantiate,d_instantiate(dentry,inode));
+}
+
+static int
+stacker_getprocattr(struct task_struct *p, char *name, void *value, size_t size)
+{
+	if (!selinux_module)
+		return -EINVAL;
+	if (!selinux_module->module_operations.getprocattr)
+		return -EINVAL;
+	return selinux_module->module_operations.getprocattr(p, name, value, size);
+}
+
+static int stacker_setprocattr(struct task_struct *p, char *name, void *value, size_t size)
+{
+
+	if (!selinux_module)
+		return -EINVAL;
+	if (!selinux_module->module_operations.setprocattr)
+		return -EINVAL;
+	return selinux_module->module_operations.setprocattr(p, name, value, size);
+}
+
+/*
+ * Add the stacked module (as specified by name and ops).
+ * If the module is not compiled in, the symbol_get at the end will
+ * prevent the the module from being unloaded.
+*/
+static int stacker_register (const char *name, struct security_operations *ops)
+{
+	char *new_module_name;
+	struct module_entry *new_module_entry;
+	int namelen = strnlen(name, MAX_MODULE_NAME_LEN);
+	int ret = 0;
+
+	spin_lock(&stacker_lock);
+
+	if (forbid_stacker_register) {
+		ret = -EINVAL;
+		goto out;
+	}
+
+	new_module_name = kmalloc(namelen+1, GFP_KERNEL);
+	new_module_entry = kmalloc(sizeof(struct module_entry), GFP_KERNEL);
+	if (!new_module_name || !new_module_entry) {
+		printk(KERN_WARNING
+			"%s: Failure registering module - out of memory\n",
+			__FUNCTION__);
+		ret = -ENOMEM;
+		goto out;
+	}
+
+	memset(new_module_entry, 0, sizeof(struct module_entry));
+	strncpy(new_module_name, name, namelen);
+	new_module_name[namelen] = '\0';
+	memcpy(&new_module_entry->module_operations, ops,
+			sizeof(struct security_operations));
+
+	new_module_entry->module_name = new_module_name;
+	new_module_entry->namelen = namelen;
+
+	INIT_LIST_HEAD(&new_module_entry->lsm_list);
+	INIT_LIST_HEAD(&new_module_entry->all_lsms);
+	list_add_tail(&new_module_entry->all_lsms, &all_modules);
+	list_add_tail(&new_module_entry->lsm_list, &stacked_modules);
+	if (strcmp(name, "selinux") == 0)
+		selinux_module = new_module_entry;
+
+	printk(KERN_INFO "%s: registered %s module\n", __FUNCTION__,
+		new_module_entry->module_name);
+
+	symbol_get(ops);
+
+out:
+	spin_unlock(&stacker_lock);
+	return ret;
+}
+
+static struct module_entry *
+find_active_lsm(const char *name, int len)
+{
+	struct module_entry *m, *ret = NULL;
+
+	rcu_read_lock();
+	stack_for_each_entry(m, &stacked_modules, lsm_list) {
+		if (m->namelen == len && !strncmp(m->module_name, name, len)) {
+			ret = m;
+			break;
+		}
+	}
+
+	rcu_read_unlock();
+	return ret;
+}
+
+/*
+ * Currently this version of stacker does not allow for module
+ * unregistering.
+ * Easy way to allow for this is using rcu ref counting like an older
+ * version of stacker did.
+ * Another way would be to force stacker_unregister to sleep between
+ * removing the module from all_modules and free_modules and unloading it.
+ */
+static int stacker_unregister (const char *name, struct security_operations *ops)
+{
+	return -EPERM;
+}
+
+static struct security_operations stacker_ops = {
+	.ptrace				= stacker_ptrace,
+	.capget				= stacker_capget,
+	.capset_check			= stacker_capset_check,
+	.capset_set			= stacker_capset_set,
+	.acct				= stacker_acct,
+	.sysctl				= stacker_sysctl,
+	.capable			= stacker_capable,
+	.quotactl			= stacker_quotactl,
+	.quota_on			= stacker_quota_on,
+	.syslog				= stacker_syslog,
+	.settime			= stacker_settime,
+	.vm_enough_memory		= stacker_vm_enough_memory,
+
+	.bprm_alloc_security		= stacker_bprm_alloc_security,
+	.bprm_free_security		= stacker_bprm_free_security,
+	.bprm_apply_creds		= stacker_bprm_apply_creds,
+	.bprm_post_apply_creds		= stacker_bprm_post_apply_creds,
+	.bprm_set_security		= stacker_bprm_set_security,
+	.bprm_check_security		= stacker_bprm_check_security,
+	.bprm_secureexec		= stacker_bprm_secureexec,
+
+	.sb_alloc_security		= stacker_sb_alloc_security,
+	.sb_free_security		= stacker_sb_free_security,
+	.sb_copy_data			= stacker_sb_copy_data,
+	.sb_kern_mount			= stacker_sb_kern_mount,
+	.sb_statfs			= stacker_sb_statfs,
+	.sb_mount			= stacker_mount,
+	.sb_check_sb			= stacker_check_sb,
+	.sb_umount			= stacker_umount,
+	.sb_umount_close		= stacker_umount_close,
+	.sb_umount_busy			= stacker_umount_busy,
+	.sb_post_remount		= stacker_post_remount,
+	.sb_post_mountroot		= stacker_post_mountroot,
+	.sb_post_addmount		= stacker_post_addmount,
+	.sb_pivotroot			= stacker_pivotroot,
+	.sb_post_pivotroot		= stacker_post_pivotroot,
+
+	.inode_alloc_security		= stacker_inode_alloc_security,
+	.inode_free_security		= stacker_inode_free_security,
+	.inode_create			= stacker_inode_create,
+	.inode_post_create		= stacker_inode_post_create,
+	.inode_link			= stacker_inode_link,
+	.inode_post_link		= stacker_inode_post_link,
+	.inode_unlink			= stacker_inode_unlink,
+	.inode_symlink			= stacker_inode_symlink,
+	.inode_post_symlink		= stacker_inode_post_symlink,
+	.inode_mkdir			= stacker_inode_mkdir,
+	.inode_post_mkdir		= stacker_inode_post_mkdir,
+	.inode_rmdir			= stacker_inode_rmdir,
+	.inode_mknod			= stacker_inode_mknod,
+	.inode_post_mknod		= stacker_inode_post_mknod,
+	.inode_rename			= stacker_inode_rename,
+	.inode_post_rename		= stacker_inode_post_rename,
+	.inode_readlink			= stacker_inode_readlink,
+	.inode_follow_link		= stacker_inode_follow_link,
+	.inode_permission		= stacker_inode_permission,
+
+	.inode_setattr			= stacker_inode_setattr,
+	.inode_getattr			= stacker_inode_getattr,
+	.inode_delete			= stacker_inode_delete,
+	.inode_setxattr			= stacker_inode_setxattr,
+	.inode_post_setxattr		= stacker_inode_post_setxattr,
+	.inode_getxattr			= stacker_inode_getxattr,
+	.inode_listxattr		= stacker_inode_listxattr,
+	.inode_removexattr		= stacker_inode_removexattr,
+	.inode_getsecurity		= stacker_inode_getsecurity,
+	.inode_setsecurity		= stacker_inode_setsecurity,
+	.inode_listsecurity		= stacker_inode_listsecurity,
+
+	.file_permission		= stacker_file_permission,
+	.file_alloc_security		= stacker_file_alloc_security,
+	.file_free_security		= stacker_file_free_security,
+	.file_ioctl			= stacker_file_ioctl,
+	.file_mmap			= stacker_file_mmap,
+	.file_mprotect			= stacker_file_mprotect,
+	.file_lock			= stacker_file_lock,
+	.file_fcntl			= stacker_file_fcntl,
+	.file_set_fowner		= stacker_file_set_fowner,
+	.file_send_sigiotask		= stacker_file_send_sigiotask,
+	.file_receive			= stacker_file_receive,
+
+	.task_create			= stacker_task_create,
+	.task_alloc_security		= stacker_task_alloc_security,
+	.task_free_security		= stacker_task_free_security,
+	.task_setuid			= stacker_task_setuid,
+	.task_post_setuid		= stacker_task_post_setuid,
+	.task_setgid			= stacker_task_setgid,
+	.task_setpgid			= stacker_task_setpgid,
+	.task_getpgid			= stacker_task_getpgid,
+	.task_getsid			= stacker_task_getsid,
+	.task_setgroups			= stacker_task_setgroups,
+	.task_setnice			= stacker_task_setnice,
+	.task_setrlimit			= stacker_task_setrlimit,
+	.task_setscheduler		= stacker_task_setscheduler,
+	.task_getscheduler		= stacker_task_getscheduler,
+	.task_kill			= stacker_task_kill,
+	.task_wait			= stacker_task_wait,
+	.task_prctl			= stacker_task_prctl,
+	.task_reparent_to_init		= stacker_task_reparent_to_init,
+	.task_to_inode			= stacker_task_to_inode,
+
+	.ipc_permission			= stacker_ipc_permission,
+
+	.msg_msg_alloc_security		= stacker_msg_msg_alloc_security,
+	.msg_msg_free_security		= stacker_msg_msg_free_security,
+	.msg_queue_alloc_security	= stacker_msg_queue_alloc_security,
+	.msg_queue_free_security	= stacker_msg_queue_free_security,
+	.msg_queue_associate		= stacker_msg_queue_associate,
+	.msg_queue_msgctl		= stacker_msg_queue_msgctl,
+	.msg_queue_msgsnd		= stacker_msg_queue_msgsnd,
+	.msg_queue_msgrcv		= stacker_msg_queue_msgrcv,
+	.shm_alloc_security		= stacker_shm_alloc_security,
+	.shm_free_security		= stacker_shm_free_security,
+	.shm_associate			= stacker_shm_associate,
+	.shm_shmctl			= stacker_shm_shmctl,
+	.shm_shmat			= stacker_shm_shmat,
+
+	.sem_alloc_security		= stacker_sem_alloc_security,
+	.sem_free_security		= stacker_sem_free_security,
+	.sem_associate			= stacker_sem_associate,
+	.sem_semctl			= stacker_sem_semctl,
+	.sem_semop			= stacker_sem_semop,
+
+	.netlink_send			= stacker_netlink_send,
+	.netlink_recv			= stacker_netlink_recv,
+
+	.register_security		= stacker_register,
+	.unregister_security		= stacker_unregister,
+
+	.d_instantiate			= stacker_d_instantiate,
+	.getprocattr			= stacker_getprocattr,
+	.setprocattr			= stacker_setprocattr,
+
+#ifdef CONFIG_SECURITY_NETWORK
+	.unix_stream_connect		= stacker_unix_stream_connect,
+	.unix_may_send			= stacker_unix_may_send,
+	.socket_create			= stacker_socket_create,
+	.socket_post_create		= stacker_socket_post_create,
+	.socket_bind			= stacker_socket_bind,
+	.socket_connect			= stacker_socket_connect,
+	.socket_listen			= stacker_socket_listen,
+	.socket_accept			= stacker_socket_accept,
+	.socket_post_accept		= stacker_socket_post_accept,
+	.socket_sendmsg			= stacker_socket_sendmsg,
+	.socket_recvmsg			= stacker_socket_recvmsg,
+	.socket_getsockname		= stacker_socket_getsockname,
+	.socket_getpeername		= stacker_socket_getpeername,
+	.socket_getsockopt		= stacker_socket_getsockopt,
+	.socket_setsockopt		= stacker_socket_setsockopt,
+	.socket_shutdown		= stacker_socket_shutdown,
+	.socket_sock_rcv_skb		= stacker_socket_sock_rcv_skb,
+	.socket_getpeersec		= stacker_socket_getpeersec,
+	.sk_alloc_security		= stacker_sk_alloc_security,
+	.sk_free_security		= stacker_sk_free_security,
+#endif
+};
+
+
+/*
+ * Functions to provide the sysfs interface
+ */
+
+/* A structure to pass into sysfs through kobjects */
+struct stacker_kobj {
+	struct list_head		slot_list;
+	struct kobject			kobj;
+};
+
+struct stacker_attribute {
+	struct attribute attr;
+	ssize_t (*show)(struct stacker_kobj *, char *);
+	ssize_t (*store)(struct stacker_kobj *, const char *, size_t);
+};
+
+/* variables to hold kobject/sysfs data */
+static struct subsystem stacker_subsys;
+
+static void unregister_sysfs_files(void);
+
+static ssize_t stacker_attr_store(struct kobject *kobj,
+		struct attribute *attr, const char *buf, size_t len)
+{
+	struct stacker_kobj *obj = container_of(kobj,
+			struct stacker_kobj, kobj);
+	struct stacker_attribute *attribute = container_of(attr,
+			struct stacker_attribute, attr);
+
+	return attribute->store ? attribute->store(obj, buf, len) : 0;
+}
+
+static ssize_t stacker_attr_show(struct kobject *kobj,
+		struct attribute *attr, char *buf)
+{
+	struct stacker_kobj *obj = container_of(kobj,
+			struct stacker_kobj, kobj);
+	struct stacker_attribute *attribute = container_of(attr,
+			struct stacker_attribute, attr);
+
+	return attribute->show ? attribute->show(obj, buf) : 0;
+}
+
+static struct sysfs_ops stacker_sysfs_ops = {
+	.show = stacker_attr_show,
+	.store = stacker_attr_store,
+};
+
+static struct kobj_type stacker_ktype = {
+	.sysfs_ops = &stacker_sysfs_ops
+};
+
+static decl_subsys(stacker, &stacker_ktype, NULL);
+
+/* Set lockdown */
+static ssize_t lockdown_read (struct stacker_kobj *obj, char *buff)
+{
+	return sprintf(buff, "%d", forbid_stacker_register);
+}
+
+static ssize_t lockdown_write (struct stacker_kobj *obj, const char *buff, size_t count)
+{
+	if (count>0)
+		forbid_stacker_register = 1;
+
+	return count;
+}
+
+static struct stacker_attribute stacker_attr_lockdown = {
+	.attr = {.name = "lockdown", .mode = S_IFREG | S_IRUGO | S_IWUSR},
+	.show = lockdown_read,
+	.store = lockdown_write
+};
+
+/* list modules */
+static ssize_t listmodules_read (struct stacker_kobj *obj, char *buff)
+{
+	ssize_t len = 0;
+	struct module_entry *m;
+
+	rcu_read_lock();
+	stack_for_each_entry(m, &stacked_modules, lsm_list) {
+		len += snprintf(buff+len, PAGE_SIZE - len, "%s\n",
+			m->module_name);
+	}
+	rcu_read_unlock();
+
+	return len;
+}
+
+static struct stacker_attribute stacker_attr_listmodules = {
+	.attr = {.name = "list_modules", .mode = S_IFREG | S_IRUGO | S_IWUSR},
+	.show = listmodules_read,
+};
+
+/* respond to a request to unload a module */
+static ssize_t stacker_unload_write (struct stacker_kobj *obj, const char *name,
+					size_t count)
+{
+	struct module_entry *m;
+	int len = strnlen(name, MAX_MODULE_NAME_LEN);
+	int ret = count;
+
+	if (!capable(CAP_SYS_ADMIN))
+		return -EPERM;
+
+	if (count <= 0)
+		return -EINVAL;
+
+	spin_lock(&stacker_lock);
+	m = find_active_lsm(name, len);
+
+	if (!m) {
+		printk(KERN_INFO "%s: could not find module %s.\n",
+			__FUNCTION__, name);
+		ret = -ENOENT;
+		goto out;
+	}
+
+	if (strcmp(m->module_name, "selinux") == 0)
+		selinux_module = NULL;
+	list_del_rcu(&m->lsm_list);
+
+out:
+	spin_unlock(&stacker_lock);
+
+	return ret;
+}
+
+static struct stacker_attribute stacker_attr_unload = {
+	.attr = {.name = "unload", .mode = S_IFREG | S_IRUGO | S_IWUSR},
+	.store = stacker_unload_write,
+};
+
+
+/* stop responding to sysfs */
+static ssize_t stop_responding_write (struct stacker_kobj *obj,
+					const char *buff, size_t count)
+{
+	if (count>0)
+		unregister_sysfs_files();
+	return count;
+}
+
+static struct stacker_attribute stacker_attr_stop_responding = {
+	.attr = {.name = "stop_responding", .mode = S_IFREG | S_IRUGO | S_IWUSR},
+	.store = stop_responding_write
+};
+
+static void unregister_sysfs_files(void)
+{
+	struct kobject *kobj;
+
+	if (!sysfsfiles_registered)
+		return;
+
+	kobj = &stacker_subsys.kset.kobj;
+	sysfs_remove_file(kobj, &stacker_attr_lockdown.attr);
+	sysfs_remove_file(kobj, &stacker_attr_listmodules.attr);
+	sysfs_remove_file(kobj, &stacker_attr_stop_responding.attr);
+	sysfs_remove_file(kobj, &stacker_attr_unload.attr);
+
+	sysfsfiles_registered = 0;
+}
+
+static int register_sysfs_files(void)
+{
+	int result;
+
+	result = subsystem_register(&stacker_subsys);
+	if (result) {
+		printk(KERN_WARNING
+			"Error (%d) registering stacker sysfs subsystem\n",
+			result);
+		return result;
+	}
+
+	sysfs_create_file(&stacker_subsys.kset.kobj,
+			&stacker_attr_lockdown.attr);
+	sysfs_create_file(&stacker_subsys.kset.kobj,
+			&stacker_attr_listmodules.attr);
+	sysfs_create_file(&stacker_subsys.kset.kobj,
+			&stacker_attr_unload.attr);
+	sysfsfiles_registered = 1;
+	stacker_dbg("sysfs files registered\n");
+	return 0;
+}
+
+module_init(register_sysfs_files);
+
+static int __init stacker_init (void)
+{
+	forbid_stacker_register = 0;
+	INIT_LIST_HEAD(&stacked_modules);
+	INIT_LIST_HEAD(&all_modules);
+	sysfsfiles_registered = 0;
+	spin_lock_init(&stacker_lock);
+
+	if (register_security (&stacker_ops)) {
+		/*
+		 * stacking stacker is just a stupid idea, so don't ask
+		 * the current module to load us.
+		 */
+		printk (KERN_WARNING "Failure registering stacker module "
+			"as primary security module.\n");
+		return -EINVAL;
+	}
+
+	printk(KERN_NOTICE "LSM stacker registered as the primary "
+			   "security module\n");
+	return 0;
+}
+
+static void __exit stacker_exit (void)
+{
+	/*
+	 * Since we have no return value, we can't just say no.
+	 * Should probably force all child modules to exit somehow...
+	 */
+
+	unregister_sysfs_files();
+	if (unregister_security (&stacker_ops))
+		printk(KERN_WARNING "Error unregistering LSM stacker.\n");
+	else
+		printk(KERN_WARNING "LSM stacker removed.\n");
+}
+
+security_initcall (stacker_init);
+module_exit (stacker_exit);
+
+MODULE_DESCRIPTION("LSM stacker - supports multiple simultaneous LSM modules");
+MODULE_AUTHOR("David A. Wheeler, Serge Hallyn");
+MODULE_LICENSE("GPL");

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 6/11] lsm stacking: introduce stackable capabilities lsm
  2005-06-08 23:55 patch 0/11] lsm stacking: intro serue
                   ` (4 preceding siblings ...)
  2005-06-09  0:00 ` [patch 5/11] lsm stacking: actual stacker module serue
@ 2005-06-09  0:00 ` serue
  2005-06-09  0:01 ` [patch 7/11] lsm stacking: selinux: update ->security structs serue
                   ` (4 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: serue @ 2005-06-09  0:00 UTC (permalink / raw)
  To: lkml; +Cc: Chris Wright, Stephen Smalley, James Morris

This patch adds a version of the capability module which is safe to
stack with SELinux.  It notably does not define the inode_setxattr
and inode_removexattr hooks, as these otherwise prevent selinux from
saving file types to disk.

Signed-off-by: Serge Hallyn <serue@us.ibm.com>
---
 security/Kconfig         |   21 +++++++++
 security/Makefile        |    1 
 security/cap_stack.c     |  101 +++++++++++++++++++++++++++++++++++++++++++++++
 security/selinux/Kconfig |    2 
 4 files changed, 124 insertions(+), 1 deletion(-)

Index: linux-2.6.12-rc6/security/Kconfig
===================================================================
--- linux-2.6.12-rc6.orig/security/Kconfig
+++ linux-2.6.12-rc6/security/Kconfig
@@ -56,10 +56,29 @@ config SECURITY_NETWORK
 config SECURITY_CAPABILITIES
 	tristate "Default Linux Capabilities"
 	depends on SECURITY
+	depends on SECURITY_SELINUX=n && SECURITY_CAP_STACK=n
 	help
-	  This enables the "default" Linux capabilities functionality.
+	  This enables the default Linux capabilities functionality.
+	  This module may not be used in conjunction with the stackable
+	  capabilities or SELinux modules.
+
 	  If you are unsure how to answer this question, answer Y.
 
+	  If you are using SELinux, answer N here and look at the
+	  Stackable Linux Capabilities instead.
+
+config SECURITY_CAP_STACK
+	tristate "Stackable Linux Capabilities"
+	depends on SECURITY
+	help
+	  This enables the "stackable" Linux capabilities functionality.
+
+	  If you are using SELinux, this option will be automatically
+	  enabled.
+	  
+	  If you are not using any other LSMs, answer N here and see above
+	  for the Default Linux Capabilities.
+
 config SECURITY_ROOTPLUG
 	tristate "Root Plug Support"
 	depends on USB && SECURITY
Index: linux-2.6.12-rc6/security/Makefile
===================================================================
--- linux-2.6.12-rc6.orig/security/Makefile
+++ linux-2.6.12-rc6/security/Makefile
@@ -16,5 +16,6 @@ obj-$(CONFIG_SECURITY)			+= security.o d
 # Must precede capability.o in order to stack properly.
 obj-$(CONFIG_SECURITY_SELINUX)		+= selinux/built-in.o
 obj-$(CONFIG_SECURITY_CAPABILITIES)	+= commoncap.o capability.o
+obj-$(CONFIG_SECURITY_CAP_STACK)	+= commoncap.o cap_stack.o
 obj-$(CONFIG_SECURITY_ROOTPLUG)		+= commoncap.o root_plug.o
 obj-$(CONFIG_SECURITY_SECLVL)		+= seclvl.o
Index: linux-2.6.12-rc6/security/cap_stack.c
===================================================================
--- /dev/null
+++ linux-2.6.12-rc6/security/cap_stack.c
@@ -0,0 +1,101 @@
+/*
+ *  Capabilities Linux Security Module
+ *
+ *	This program is free software; you can redistribute it and/or modify
+ *	it under the terms of the GNU General Public License as published by
+ *	the Free Software Foundation; either version 2 of the License, or
+ *	(at your option) any later version.
+ *
+ */
+
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/security.h>
+#include <linux/file.h>
+#include <linux/mm.h>
+#include <linux/mman.h>
+#include <linux/pagemap.h>
+#include <linux/swap.h>
+#include <linux/smp_lock.h>
+#include <linux/skbuff.h>
+#include <linux/netlink.h>
+#include <linux/ptrace.h>
+#include <linux/moduleparam.h>
+
+static struct security_operations capability_ops = {
+	.ptrace =			cap_ptrace,
+	.capget =			cap_capget,
+	.capset_check =			cap_capset_check,
+	.capset_set =			cap_capset_set,
+	.capable =			cap_capable,
+	.settime =			cap_settime,
+	.netlink_send =			cap_netlink_send,
+	.netlink_recv =			cap_netlink_recv,
+
+	.bprm_apply_creds =		cap_bprm_apply_creds,
+	.bprm_set_security =		cap_bprm_set_security,
+	.bprm_secureexec =		cap_bprm_secureexec,
+
+	.task_post_setuid =		cap_task_post_setuid,
+	.task_reparent_to_init =	cap_task_reparent_to_init,
+
+	.syslog =                       cap_syslog,
+
+	.vm_enough_memory =             cap_vm_enough_memory,
+};
+
+#define MY_NAME __stringify(KBUILD_MODNAME)
+
+/* flag to keep track of how we were registered */
+static int secondary;
+
+static int capability_disable;
+module_param_named(disable, capability_disable, int, 0);
+MODULE_PARM_DESC(disable, "To disable capabilities module set disable = 1");
+
+static int __init capability_init (void)
+{
+	if (capability_disable) {
+		printk(KERN_INFO "Capabilities disabled at initialization\n");
+		return 0;
+	}
+	/* register ourselves with the security framework */
+	if (register_security (&capability_ops)) {
+		/* try registering with primary module */
+		if (mod_reg_security (MY_NAME, &capability_ops)) {
+			printk (KERN_INFO "Failure registering capabilities "
+				"with primary security module.\n");
+			return -EINVAL;
+		}
+		secondary = 1;
+	}
+	printk (KERN_INFO "Capability LSM initialized%s\n",
+		secondary ? " as secondary" : "");
+	return 0;
+}
+
+static void __exit capability_exit (void)
+{
+	if (capability_disable)
+		return;
+	/* remove ourselves from the security framework */
+	if (secondary) {
+		if (mod_unreg_security (MY_NAME, &capability_ops))
+			printk (KERN_INFO "Failure unregistering capabilities "
+				"with primary module.\n");
+		return;
+	}
+
+	if (unregister_security (&capability_ops)) {
+		printk (KERN_INFO
+			"Failure unregistering capabilities with the kernel\n");
+	}
+}
+
+security_initcall (capability_init);
+module_exit (capability_exit);
+
+MODULE_DESCRIPTION("Standard Linux Capabilities Security Module");
+MODULE_LICENSE("GPL");
Index: linux-2.6.12-rc6/security/selinux/Kconfig
===================================================================
--- linux-2.6.12-rc6.orig/security/selinux/Kconfig
+++ linux-2.6.12-rc6/security/selinux/Kconfig
@@ -2,6 +2,8 @@ config SECURITY_SELINUX
 	bool "NSA SELinux Support"
 	depends on SECURITY && NET && INET
 	default n
+	select SECURITY_CAP_STACK
+	select SECURITY_STACKER
 	help
 	  This selects NSA Security-Enhanced Linux (SELinux).
 	  You will also need a policy configuration and a labeled filesystem.

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 7/11] lsm stacking: selinux: update ->security structs
  2005-06-08 23:55 patch 0/11] lsm stacking: intro serue
                   ` (5 preceding siblings ...)
  2005-06-09  0:00 ` [patch 6/11] lsm stacking: introduce stackable capabilities lsm serue
@ 2005-06-09  0:01 ` serue
  2005-06-09  0:02 ` [patch 8/11] lsm stacking: selinux: use security_*_value API serue
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: serue @ 2005-06-09  0:01 UTC (permalink / raw)
  To: lkml; +Cc: Chris Wright, Stephen Smalley, James Morris

Add the struct security_list lsm_list; to each structure which SELinux will be
appending to a kernel object.

Signed-off-by: Serge Hallyn <serue@us.ibm.com>
---
 security/selinux/include/objsec.h |   19 +++++++++++--------
 1 files changed, 11 insertions(+), 8 deletions(-)

Index: linux-2.6.12-rc2-stack/security/selinux/include/objsec.h
===================================================================
--- linux-2.6.12-rc2-stack.orig/security/selinux/include/objsec.h	2005-04-13 14:17:33.000000000 -0500
+++ linux-2.6.12-rc2-stack/security/selinux/include/objsec.h	2005-04-13 14:38:41.000000000 -0500
@@ -23,11 +23,14 @@
 #include <linux/fs.h>
 #include <linux/binfmts.h>
 #include <linux/in.h>
+#include <linux/security.h>
 #include "flask.h"
 #include "avc.h"
 
+#define SELINUX_LSM_ID 0xB65
+
 struct task_security_struct {
-        unsigned long magic;           /* magic number for this module */
+	struct security_list lsm_list; /* chained security objects */
 	struct task_struct *task;      /* back pointer to task object */
 	u32 osid;            /* SID prior to last execve */
 	u32 sid;             /* current SID */
@@ -37,7 +40,7 @@ struct task_security_struct {
 };
 
 struct inode_security_struct {
-	unsigned long magic;           /* magic number for this module */
+	struct security_list lsm_list; /* chained security objects */
         struct inode *inode;           /* back pointer to inode object */
 	struct list_head list;         /* list of inode_security_struct */
 	u32 task_sid;        /* SID of creating task */
@@ -49,14 +52,14 @@ struct inode_security_struct {
 };
 
 struct file_security_struct {
-	unsigned long magic;            /* magic number for this module */
+	struct security_list lsm_list; /* chained security objects */
 	struct file *file;              /* back pointer to file object */
 	u32 sid;              /* SID of open file description */
 	u32 fown_sid;         /* SID of file owner (for SIGIO) */
 };
 
 struct superblock_security_struct {
-	unsigned long magic;            /* magic number for this module */
+	struct security_list lsm_list; /* chained security objects */
 	struct super_block *sb;         /* back pointer to sb object */
 	struct list_head list;          /* list of superblock_security_struct */
 	u32 sid;              /* SID of file system */
@@ -70,20 +73,20 @@ struct superblock_security_struct {
 };
 
 struct msg_security_struct {
-        unsigned long magic;		/* magic number for this module */
+ 	struct security_list lsm_list; /* chained security objects */
 	struct msg_msg *msg;		/* back pointer */
 	u32 sid;              /* SID of message */
 };
 
 struct ipc_security_struct {
-        unsigned long magic;		/* magic number for this module */
+ 	struct security_list lsm_list; /* chained security objects */
 	struct kern_ipc_perm *ipc_perm; /* back pointer */
 	u16 sclass;	/* security class of this object */
 	u32 sid;              /* SID of IPC resource */
 };
 
 struct bprm_security_struct {
-	unsigned long magic;           /* magic number for this module */
+	struct security_list lsm_list; /* chained security objects */
 	struct linux_binprm *bprm;     /* back pointer to bprm object */
 	u32 sid;                       /* SID for transformed process */
 	unsigned char set;
@@ -102,7 +105,7 @@ struct netif_security_struct {
 };
 
 struct sk_security_struct {
-	unsigned long magic;		/* magic number for this module */
+	struct security_list lsm_list; /* chained security objects */
 	struct sock *sk;		/* back pointer to sk object */
 	u32 peer_sid;			/* SID of peer */
 };

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 8/11] lsm stacking: selinux: use security_*_value API
  2005-06-08 23:55 patch 0/11] lsm stacking: intro serue
                   ` (6 preceding siblings ...)
  2005-06-09  0:01 ` [patch 7/11] lsm stacking: selinux: update ->security structs serue
@ 2005-06-09  0:02 ` serue
  2005-06-09  0:02 ` [patch 9/11] lsm stacking: selinux: remove secondary support serue
                   ` (2 subsequent siblings)
  10 siblings, 0 replies; 12+ messages in thread
From: serue @ 2005-06-09  0:02 UTC (permalink / raw)
  To: lkml; +Cc: Chris Wright, Stephen Smalley, James Morris

Convert SELinux to use the security_*_value_type API for storing and using
information appended to kernel objects, instead of directly using the void*.

Signed-off-by: Serge Hallyn <serue@us.ibm.com>
---
 security/selinux/hooks.c     |  445 ++++++++++++++++++++++++++++---------------
 security/selinux/selinuxfs.c |   10 
 2 files changed, 299 insertions(+), 156 deletions(-)

Index: linux-2.6.12-rc6/security/selinux/hooks.c
===================================================================
--- linux-2.6.12-rc6.orig/security/selinux/hooks.c
+++ linux-2.6.12-rc6/security/selinux/hooks.c
@@ -26,6 +26,7 @@
 #include <linux/errno.h>
 #include <linux/sched.h>
 #include <linux/security.h>
+#include <linux/security-stack.h>
 #include <linux/xattr.h>
 #include <linux/capability.h>
 #include <linux/unistd.h>
@@ -126,30 +127,30 @@ static int task_alloc_security(struct ta
 		return -ENOMEM;
 
 	memset(tsec, 0, sizeof(struct task_security_struct));
-	tsec->magic = SELINUX_MAGIC;
 	tsec->task = task;
 	tsec->osid = tsec->sid = tsec->ptrace_sid = SECINITSID_UNLABELED;
-	task->security = tsec;
+	security_set_value_type(&task->security, SELINUX_LSM_ID, tsec);
 
 	return 0;
 }
 
 static void task_free_security(struct task_struct *task)
 {
-	struct task_security_struct *tsec = task->security;
-
-	if (!tsec || tsec->magic != SELINUX_MAGIC)
-		return;
+	struct task_security_struct *tsec;
+	
+	tsec = security_del_value_type(&task->security, SELINUX_LSM_ID,
+		struct task_security_struct);
 
-	task->security = NULL;
 	kfree(tsec);
 }
 
 static int inode_alloc_security(struct inode *inode)
 {
-	struct task_security_struct *tsec = current->security;
+	struct task_security_struct *tsec;
 	struct inode_security_struct *isec;
 
+	tsec = security_get_value_type(&current->security, SELINUX_LSM_ID,
+		struct task_security_struct);
 	isec = kmalloc(sizeof(struct inode_security_struct), GFP_KERNEL);
 	if (!isec)
 		return -ENOMEM;
@@ -157,68 +158,71 @@ static int inode_alloc_security(struct i
 	memset(isec, 0, sizeof(struct inode_security_struct));
 	init_MUTEX(&isec->sem);
 	INIT_LIST_HEAD(&isec->list);
-	isec->magic = SELINUX_MAGIC;
 	isec->inode = inode;
 	isec->sid = SECINITSID_UNLABELED;
 	isec->sclass = SECCLASS_FILE;
-	if (tsec && tsec->magic == SELINUX_MAGIC)
+	if (tsec)
 		isec->task_sid = tsec->sid;
 	else
 		isec->task_sid = SECINITSID_UNLABELED;
-	inode->i_security = isec;
+	security_set_value_type(&inode->i_security, SELINUX_LSM_ID, isec);
 
 	return 0;
 }
 
 static void inode_free_security(struct inode *inode)
 {
-	struct inode_security_struct *isec = inode->i_security;
-	struct superblock_security_struct *sbsec = inode->i_sb->s_security;
+	struct inode_security_struct *isec;
+	struct superblock_security_struct *sbsec;
 
-	if (!isec || isec->magic != SELINUX_MAGIC)
+	isec = security_del_value_type(&inode->i_security, SELINUX_LSM_ID,
+		struct inode_security_struct);
+	if (!isec)
 		return;
 
+	sbsec = security_get_value_type(&inode->i_sb->s_security,
+		SELINUX_LSM_ID, struct superblock_security_struct);
+
 	spin_lock(&sbsec->isec_lock);
 	if (!list_empty(&isec->list))
 		list_del_init(&isec->list);
 	spin_unlock(&sbsec->isec_lock);
 
-	inode->i_security = NULL;
 	kfree(isec);
 }
 
 static int file_alloc_security(struct file *file)
 {
-	struct task_security_struct *tsec = current->security;
+	struct task_security_struct *tsec;
 	struct file_security_struct *fsec;
 
+	tsec = security_get_value_type(&current->security, SELINUX_LSM_ID,
+		struct task_security_struct);
 	fsec = kmalloc(sizeof(struct file_security_struct), GFP_ATOMIC);
 	if (!fsec)
 		return -ENOMEM;
 
 	memset(fsec, 0, sizeof(struct file_security_struct));
-	fsec->magic = SELINUX_MAGIC;
 	fsec->file = file;
-	if (tsec && tsec->magic == SELINUX_MAGIC) {
+	if (tsec) {
 		fsec->sid = tsec->sid;
 		fsec->fown_sid = tsec->sid;
 	} else {
 		fsec->sid = SECINITSID_UNLABELED;
 		fsec->fown_sid = SECINITSID_UNLABELED;
 	}
-	file->f_security = fsec;
+	security_set_value_type(&file->f_security, SELINUX_LSM_ID, fsec);
 
 	return 0;
 }
 
 static void file_free_security(struct file *file)
 {
-	struct file_security_struct *fsec = file->f_security;
+	struct file_security_struct *fsec;
 
-	if (!fsec || fsec->magic != SELINUX_MAGIC)
-		return;
+	fsec = security_del_value_type(&file->f_security, SELINUX_LSM_ID,
+		struct file_security_struct);
 
-	file->f_security = NULL;
 	kfree(fsec);
 }
 
@@ -235,20 +239,21 @@ static int superblock_alloc_security(str
 	INIT_LIST_HEAD(&sbsec->list);
 	INIT_LIST_HEAD(&sbsec->isec_head);
 	spin_lock_init(&sbsec->isec_lock);
-	sbsec->magic = SELINUX_MAGIC;
 	sbsec->sb = sb;
 	sbsec->sid = SECINITSID_UNLABELED;
 	sbsec->def_sid = SECINITSID_FILE;
-	sb->s_security = sbsec;
+	security_set_value_type(&sb->s_security, SELINUX_LSM_ID, sbsec);
 
 	return 0;
 }
 
 static void superblock_free_security(struct super_block *sb)
 {
-	struct superblock_security_struct *sbsec = sb->s_security;
+	struct superblock_security_struct *sbsec;
 
-	if (!sbsec || sbsec->magic != SELINUX_MAGIC)
+	sbsec = security_del_value_type(&sb->s_security, SELINUX_LSM_ID,
+		struct superblock_security_struct);
+	if (!sbsec)
 		return;
 
 	spin_lock(&sb_security_lock);
@@ -256,7 +261,6 @@ static void superblock_free_security(str
 		list_del_init(&sbsec->list);
 	spin_unlock(&sb_security_lock);
 
-	sb->s_security = NULL;
 	kfree(sbsec);
 }
 
@@ -273,22 +277,23 @@ static int sk_alloc_security(struct sock
 		return -ENOMEM;
 
 	memset(ssec, 0, sizeof(*ssec));
-	ssec->magic = SELINUX_MAGIC;
 	ssec->sk = sk;
 	ssec->peer_sid = SECINITSID_UNLABELED;
-	sk->sk_security = ssec;
+	security_set_value_type(&sk->sk_security, SELINUX_LSM_ID, ssec);
 
 	return 0;
 }
 
 static void sk_free_security(struct sock *sk)
 {
-	struct sk_security_struct *ssec = sk->sk_security;
+	struct sk_security_struct *ssec;
 
-	if (sk->sk_family != PF_UNIX || ssec->magic != SELINUX_MAGIC)
+	if (sk->sk_family != PF_UNIX)
 		return;
 
-	sk->sk_security = NULL;
+	ssec = security_del_value_type(&sk->sk_security, SELINUX_LSM_ID,
+		struct sk_security_struct);
+
 	kfree(ssec);
 }
 #endif	/* CONFIG_SECURITY_NETWORK */
@@ -335,8 +340,13 @@ static int try_context_mount(struct supe
 	const char *name;
 	u32 sid;
 	int alloc = 0, rc = 0, seen = 0;
-	struct task_security_struct *tsec = current->security;
-	struct superblock_security_struct *sbsec = sb->s_security;
+	struct task_security_struct *tsec;
+	struct superblock_security_struct *sbsec;
+
+	tsec = security_get_value_type(&current->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+	sbsec = security_get_value_type(&sb->s_security, SELINUX_LSM_ID,
+		struct superblock_security_struct);
 
 	if (!data)
 		goto out;
@@ -502,11 +512,14 @@ out:
 
 static int superblock_doinit(struct super_block *sb, void *data)
 {
-	struct superblock_security_struct *sbsec = sb->s_security;
+	struct superblock_security_struct *sbsec;
 	struct dentry *root = sb->s_root;
 	struct inode *inode = root->d_inode;
 	int rc = 0;
 
+	sbsec = security_get_value_type(&sb->s_security, SELINUX_LSM_ID,
+		struct superblock_security_struct);
+
 	down(&sbsec->sem);
 	if (sbsec->initialized)
 		goto out;
@@ -731,7 +744,7 @@ static int selinux_proc_get_sid(struct p
 static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dentry)
 {
 	struct superblock_security_struct *sbsec = NULL;
-	struct inode_security_struct *isec = inode->i_security;
+	struct inode_security_struct *isec;
 	u32 sid;
 	struct dentry *dentry;
 #define INITCONTEXTLEN 255
@@ -740,6 +753,9 @@ static int inode_doinit_with_dentry(stru
 	int rc = 0;
 	int hold_sem = 0;
 
+	isec = security_get_value_type(&inode->i_security, SELINUX_LSM_ID,
+		struct inode_security_struct);
+
 	if (isec->initialized)
 		goto out;
 
@@ -748,7 +764,8 @@ static int inode_doinit_with_dentry(stru
 	if (isec->initialized)
 		goto out;
 
-	sbsec = inode->i_sb->s_security;
+	sbsec = security_get_value_type(&inode->i_sb->s_security,
+		SELINUX_LSM_ID, struct superblock_security_struct);
 	if (!sbsec->initialized) {
 		/* Defer initialization until selinux_complete_init,
 		   after the initial policy is loaded and the security
@@ -922,8 +939,10 @@ static int task_has_perm(struct task_str
 {
 	struct task_security_struct *tsec1, *tsec2;
 
-	tsec1 = tsk1->security;
-	tsec2 = tsk2->security;
+	tsec1 = security_get_value_type(&tsk1->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+	tsec2 = security_get_value_type(&tsk2->security, SELINUX_LSM_ID,
+		struct task_security_struct);
 	return avc_has_perm(tsec1->sid, tsec2->sid,
 			    SECCLASS_PROCESS, perms, NULL);
 }
@@ -935,7 +954,8 @@ static int task_has_capability(struct ta
 	struct task_security_struct *tsec;
 	struct avc_audit_data ad;
 
-	tsec = tsk->security;
+	tsec = security_get_value_type(&tsk->security, SELINUX_LSM_ID,
+		struct task_security_struct);
 
 	AVC_AUDIT_DATA_INIT(&ad,CAP);
 	ad.tsk = tsk;
@@ -951,7 +971,8 @@ static int task_has_system(struct task_s
 {
 	struct task_security_struct *tsec;
 
-	tsec = tsk->security;
+	tsec = security_get_value_type(&tsk->security, SELINUX_LSM_ID,
+		struct task_security_struct);
 
 	return avc_has_perm(tsec->sid, SECINITSID_KERNEL,
 			    SECCLASS_SYSTEM, perms, NULL);
@@ -969,8 +990,10 @@ static int inode_has_perm(struct task_st
 	struct inode_security_struct *isec;
 	struct avc_audit_data ad;
 
-	tsec = tsk->security;
-	isec = inode->i_security;
+	tsec = security_get_value_type(&tsk->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+	isec = security_get_value_type(&inode->i_security, SELINUX_LSM_ID,
+		struct inode_security_struct);
 
 	if (!adp) {
 		adp = &ad;
@@ -1009,14 +1032,19 @@ static inline int file_has_perm(struct t
 				struct file *file,
 				u32 av)
 {
-	struct task_security_struct *tsec = tsk->security;
-	struct file_security_struct *fsec = file->f_security;
+	struct task_security_struct *tsec;
+	struct file_security_struct *fsec;
 	struct vfsmount *mnt = file->f_vfsmnt;
 	struct dentry *dentry = file->f_dentry;
 	struct inode *inode = dentry->d_inode;
 	struct avc_audit_data ad;
 	int rc;
 
+	tsec = security_get_value_type(&tsk->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+	fsec = security_get_value_type(&file->f_security, SELINUX_LSM_ID,
+		struct file_security_struct);
+
 	AVC_AUDIT_DATA_INIT(&ad, FS);
 	ad.u.fs.mnt = mnt;
 	ad.u.fs.dentry = dentry;
@@ -1049,9 +1077,12 @@ static int may_create(struct inode *dir,
 	struct avc_audit_data ad;
 	int rc;
 
-	tsec = current->security;
-	dsec = dir->i_security;
-	sbsec = dir->i_sb->s_security;
+	tsec = security_get_value_type(&current->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+	dsec = security_get_value_type(&dir->i_security, SELINUX_LSM_ID,
+		struct inode_security_struct);
+	sbsec = security_get_value_type(&dir->i_sb->s_security, SELINUX_LSM_ID,
+		struct superblock_security_struct);
 
 	AVC_AUDIT_DATA_INIT(&ad, FS);
 	ad.u.fs.dentry = dentry;
@@ -1096,9 +1127,12 @@ static int may_link(struct inode *dir,
 	u32 av;
 	int rc;
 
-	tsec = current->security;
-	dsec = dir->i_security;
-	isec = dentry->d_inode->i_security;
+	tsec = security_get_value_type(&current->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+	dsec = security_get_value_type(&dir->i_security, SELINUX_LSM_ID,
+		struct inode_security_struct);
+	isec = security_get_value_type(&dentry->d_inode->i_security,
+		SELINUX_LSM_ID, struct inode_security_struct);
 
 	AVC_AUDIT_DATA_INIT(&ad, FS);
 	ad.u.fs.dentry = dentry;
@@ -1140,11 +1174,15 @@ static inline int may_rename(struct inod
 	int old_is_dir, new_is_dir;
 	int rc;
 
-	tsec = current->security;
-	old_dsec = old_dir->i_security;
-	old_isec = old_dentry->d_inode->i_security;
+	tsec = security_get_value_type(&current->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+	old_dsec = security_get_value_type(&old_dir->i_security, SELINUX_LSM_ID,
+		struct inode_security_struct);
+	old_isec = security_get_value_type(&old_dentry->d_inode->i_security,
+		SELINUX_LSM_ID, struct inode_security_struct);
 	old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
-	new_dsec = new_dir->i_security;
+	new_dsec = security_get_value_type(&new_dir->i_security, SELINUX_LSM_ID,
+		struct inode_security_struct);
 
 	AVC_AUDIT_DATA_INIT(&ad, FS);
 
@@ -1172,7 +1210,8 @@ static inline int may_rename(struct inod
 	if (rc)
 		return rc;
 	if (new_dentry->d_inode) {
-		new_isec = new_dentry->d_inode->i_security;
+		new_isec = security_get_value_type(&new_dentry->d_inode->i_security,
+			SELINUX_LSM_ID, struct inode_security_struct);
 		new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode);
 		rc = avc_has_perm(tsec->sid, new_isec->sid,
 				  new_isec->sclass,
@@ -1193,8 +1232,10 @@ static int superblock_has_perm(struct ta
 	struct task_security_struct *tsec;
 	struct superblock_security_struct *sbsec;
 
-	tsec = tsk->security;
-	sbsec = sb->s_security;
+	tsec = security_get_value_type(&tsk->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+	sbsec = security_get_value_type(&sb->s_security, SELINUX_LSM_ID,
+		struct superblock_security_struct);
 	return avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM,
 			    perms, ad);
 }
@@ -1247,8 +1288,13 @@ static inline u32 file_to_av(struct file
 /* Set an inode's SID to a specified value. */
 static int inode_security_set_sid(struct inode *inode, u32 sid)
 {
-	struct inode_security_struct *isec = inode->i_security;
-	struct superblock_security_struct *sbsec = inode->i_sb->s_security;
+	struct inode_security_struct *isec;
+	struct superblock_security_struct *sbsec;
+
+	isec = security_get_value_type(&inode->i_security, SELINUX_LSM_ID,
+		struct inode_security_struct);
+	sbsec = security_get_value_type(&inode->i_sb->s_security,
+		SELINUX_LSM_ID, struct superblock_security_struct);
 
 	if (!sbsec->initialized) {
 		/* Defer initialization to selinux_complete_init. */
@@ -1277,9 +1323,12 @@ static int post_create(struct inode *dir
 	unsigned int len;
 	int rc;
 
-	tsec = current->security;
-	dsec = dir->i_security;
-	sbsec = dir->i_sb->s_security;
+	tsec = security_get_value_type(&current->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+	dsec = security_get_value_type(&dir->i_security, SELINUX_LSM_ID,
+		struct inode_security_struct);
+	sbsec = security_get_value_type(&dir->i_sb->s_security, SELINUX_LSM_ID,
+		struct superblock_security_struct);
 
 	inode = dentry->d_inode;
 	if (!inode) {
@@ -1346,13 +1395,17 @@ static int post_create(struct inode *dir
 
 static int selinux_ptrace(struct task_struct *parent, struct task_struct *child)
 {
-	struct task_security_struct *psec = parent->security;
-	struct task_security_struct *csec = child->security;
+	struct task_security_struct *psec;
+	struct task_security_struct *csec;
 	int rc;
 
 	rc = secondary_ops->ptrace(parent,child);
 	if (rc)
 		return rc;
+	psec = security_get_value_type(&parent->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+	csec = security_get_value_type(&child->security, SELINUX_LSM_ID,
+		struct task_security_struct);
 
 	rc = task_has_perm(parent, child, PROCESS__PTRACE);
 	/* Save the SID of the tracing process for later use in apply_creds. */
@@ -1414,7 +1467,8 @@ static int selinux_sysctl(ctl_table *tab
 	if (rc)
 		return rc;
 
-	tsec = current->security;
+	tsec = security_get_value_type(&current->security, SELINUX_LSM_ID,
+		struct task_security_struct);
 
 	rc = selinux_proc_get_sid(table->de, (op == 001) ?
 	                          SECCLASS_DIR : SECCLASS_FILE, &tsid);
@@ -1549,12 +1603,11 @@ static int selinux_bprm_alloc_security(s
 		return -ENOMEM;
 
 	memset(bsec, 0, sizeof *bsec);
-	bsec->magic = SELINUX_MAGIC;
 	bsec->bprm = bprm;
 	bsec->sid = SECINITSID_UNLABELED;
 	bsec->set = 0;
 
-	bprm->security = bsec;
+	security_set_value_type(&bprm->security, SELINUX_LSM_ID, bsec);
 	return 0;
 }
 
@@ -1572,13 +1625,16 @@ static int selinux_bprm_set_security(str
 	if (rc)
 		return rc;
 
-	bsec = bprm->security;
+	bsec = security_get_value_type(&bprm->security, SELINUX_LSM_ID,
+		struct bprm_security_struct);
 
 	if (bsec->set)
 		return 0;
 
-	tsec = current->security;
-	isec = inode->i_security;
+	tsec = security_get_value_type(&current->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+	isec = security_get_value_type(&inode->i_security, SELINUX_LSM_ID,
+		struct inode_security_struct);
 
 	/* Default to the current task SID. */
 	bsec->sid = tsec->sid;
@@ -1641,9 +1697,11 @@ static int selinux_bprm_check_security (
 
 static int selinux_bprm_secureexec (struct linux_binprm *bprm)
 {
-	struct task_security_struct *tsec = current->security;
+	struct task_security_struct *tsec;
 	int atsecure = 0;
 
+	tsec = security_get_value_type(&current->security, SELINUX_LSM_ID,
+		struct task_security_struct);
 	if (tsec->osid != tsec->sid) {
 		/* Enable secure mode for SIDs transitions unless
 		   the noatsecure permission is granted between
@@ -1658,8 +1716,10 @@ static int selinux_bprm_secureexec (stru
 
 static void selinux_bprm_free_security(struct linux_binprm *bprm)
 {
-	struct bprm_security_struct *bsec = bprm->security;
-	bprm->security = NULL;
+	struct bprm_security_struct *bsec;
+	
+	bsec = security_del_value_type(&bprm->security, SELINUX_LSM_ID,
+			struct bprm_security_struct);
 	kfree(bsec);
 }
 
@@ -1757,9 +1817,10 @@ static void selinux_bprm_apply_creds(str
 
 	secondary_ops->bprm_apply_creds(bprm, unsafe);
 
-	tsec = current->security;
-
-	bsec = bprm->security;
+	tsec = security_get_value_type(&current->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+	bsec = security_get_value_type(&bprm->security, SELINUX_LSM_ID,
+		struct bprm_security_struct);
 	sid = bsec->sid;
 
 	tsec->osid = tsec->sid;
@@ -1802,8 +1863,10 @@ static void selinux_bprm_post_apply_cred
 	struct bprm_security_struct *bsec;
 	int rc, i;
 
-	tsec = current->security;
-	bsec = bprm->security;
+	tsec = security_get_value_type(&current->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+	bsec = security_get_value_type(&bprm->security, SELINUX_LSM_ID,
+		struct bprm_security_struct);
 
 	if (bsec->unsafe) {
 		force_sig_specific(SIGKILL, current);
@@ -2162,9 +2225,9 @@ static int selinux_inode_getattr(struct 
 
 static int selinux_inode_setxattr(struct dentry *dentry, char *name, void *value, size_t size, int flags)
 {
-	struct task_security_struct *tsec = current->security;
+	struct task_security_struct *tsec;
 	struct inode *inode = dentry->d_inode;
-	struct inode_security_struct *isec = inode->i_security;
+	struct inode_security_struct *isec;
 	struct superblock_security_struct *sbsec;
 	struct avc_audit_data ad;
 	u32 newsid;
@@ -2184,7 +2247,8 @@ static int selinux_inode_setxattr(struct
 		return dentry_has_perm(current, NULL, dentry, FILE__SETATTR);
 	}
 
-	sbsec = inode->i_sb->s_security;
+	sbsec = security_get_value_type(&inode->i_sb->s_security,
+		SELINUX_LSM_ID, struct superblock_security_struct);
 	if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
 		return -EOPNOTSUPP;
 
@@ -2194,6 +2258,10 @@ static int selinux_inode_setxattr(struct
 	AVC_AUDIT_DATA_INIT(&ad,FS);
 	ad.u.fs.dentry = dentry;
 
+	tsec = security_get_value_type(&current->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+	isec = security_get_value_type(&inode->i_security, SELINUX_LSM_ID,
+		struct inode_security_struct);
 	rc = avc_has_perm(tsec->sid, isec->sid, isec->sclass,
 			  FILE__RELABELFROM, &ad);
 	if (rc)
@@ -2224,10 +2292,13 @@ static void selinux_inode_post_setxattr(
                                         void *value, size_t size, int flags)
 {
 	struct inode *inode = dentry->d_inode;
-	struct inode_security_struct *isec = inode->i_security;
+	struct inode_security_struct *isec;
 	u32 newsid;
 	int rc;
 
+	isec = security_get_value_type(&inode->i_security, SELINUX_LSM_ID,
+		struct inode_security_struct);
+
 	if (strcmp(name, XATTR_NAME_SELINUX)) {
 		/* Not an attribute we recognize, so nothing to do. */
 		return;
@@ -2247,7 +2318,10 @@ static void selinux_inode_post_setxattr(
 static int selinux_inode_getxattr (struct dentry *dentry, char *name)
 {
 	struct inode *inode = dentry->d_inode;
-	struct superblock_security_struct *sbsec = inode->i_sb->s_security;
+	struct superblock_security_struct *sbsec;
+	
+	sbsec = security_get_value_type(&inode->i_sb->s_security,
+		SELINUX_LSM_ID, struct superblock_security_struct);
 
 	if (sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
 		return -EOPNOTSUPP;
@@ -2284,7 +2358,7 @@ static int selinux_inode_removexattr (st
 
 static int selinux_inode_getsecurity(struct inode *inode, const char *name, void *buffer, size_t size)
 {
-	struct inode_security_struct *isec = inode->i_security;
+	struct inode_security_struct *isec;
 	char *context;
 	unsigned len;
 	int rc;
@@ -2294,6 +2368,9 @@ static int selinux_inode_getsecurity(str
 	if (strcmp(name, XATTR_SELINUX_SUFFIX))
 		return -EOPNOTSUPP;
 
+	isec = security_get_value_type(&inode->i_security, SELINUX_LSM_ID,
+		struct inode_security_struct);
+
 	rc = security_sid_to_context(isec->sid, &context, &len);
 	if (rc)
 		return rc;
@@ -2314,13 +2391,16 @@ static int selinux_inode_getsecurity(str
 static int selinux_inode_setsecurity(struct inode *inode, const char *name,
                                      const void *value, size_t size, int flags)
 {
-	struct inode_security_struct *isec = inode->i_security;
+	struct inode_security_struct *isec;
 	u32 newsid;
 	int rc;
 
 	if (strcmp(name, XATTR_SELINUX_SUFFIX))
 		return -EOPNOTSUPP;
 
+	isec = security_get_value_type(&inode->i_security, SELINUX_LSM_ID,
+		struct inode_security_struct);
+
 	if (!value || !size)
 		return -EACCES;
 
@@ -2546,8 +2626,10 @@ static int selinux_file_set_fowner(struc
 	struct task_security_struct *tsec;
 	struct file_security_struct *fsec;
 
-	tsec = current->security;
-	fsec = file->f_security;
+	tsec = security_get_value_type(&current->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+	fsec = security_get_value_type(&file->f_security, SELINUX_LSM_ID,
+		struct file_security_struct);
 	fsec->fown_sid = tsec->sid;
 
 	return 0;
@@ -2564,8 +2646,10 @@ static int selinux_file_send_sigiotask(s
 	/* struct fown_struct is never outside the context of a struct file */
         file = (struct file *)((long)fown - offsetof(struct file,f_owner));
 
-	tsec = tsk->security;
-	fsec = file->f_security;
+	tsec = security_get_value_type(&tsk->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+	fsec = security_get_value_type(&file->f_security, SELINUX_LSM_ID,
+		struct file_security_struct);
 
 	if (!signum)
 		perm = signal_to_av(SIGIO); /* as per send_sigio_to_task */
@@ -2599,12 +2683,14 @@ static int selinux_task_alloc_security(s
 	struct task_security_struct *tsec1, *tsec2;
 	int rc;
 
-	tsec1 = current->security;
+	tsec1 = security_get_value_type(&current->security, SELINUX_LSM_ID,
+		struct task_security_struct);
 
 	rc = task_alloc_security(tsk);
 	if (rc)
 		return rc;
-	tsec2 = tsk->security;
+	tsec2 = security_get_value_type(&tsk->security, SELINUX_LSM_ID,
+		struct task_security_struct);
 
 	tsec2->osid = tsec1->osid;
 	tsec2->sid = tsec1->sid;
@@ -2757,7 +2843,8 @@ static void selinux_task_reparent_to_ini
 
 	secondary_ops->task_reparent_to_init(p);
 
-	tsec = p->security;
+	tsec = security_get_value_type(&p->security, SELINUX_LSM_ID,
+		struct task_security_struct);
 	tsec->osid = tsec->sid;
 	tsec->sid = SECINITSID_KERNEL;
 	return;
@@ -2766,8 +2853,13 @@ static void selinux_task_reparent_to_ini
 static void selinux_task_to_inode(struct task_struct *p,
 				  struct inode *inode)
 {
-	struct task_security_struct *tsec = p->security;
-	struct inode_security_struct *isec = inode->i_security;
+	struct task_security_struct *tsec;
+	struct inode_security_struct *isec;
+
+	tsec = security_get_value_type(&p->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+	isec = security_get_value_type(&inode->i_security, SELINUX_LSM_ID,
+		struct inode_security_struct);
 
 	isec->sid = tsec->sid;
 	isec->initialized = 1;
@@ -2935,8 +3027,10 @@ static int socket_has_perm(struct task_s
 	struct avc_audit_data ad;
 	int err = 0;
 
-	tsec = task->security;
-	isec = SOCK_INODE(sock)->i_security;
+	tsec = security_get_value_type(&task->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+	isec = security_get_value_type(&SOCK_INODE(sock)->i_security, SELINUX_LSM_ID,
+		struct inode_security_struct);
 
 	if (isec->sid == SECINITSID_KERNEL)
 		goto out;
@@ -2958,7 +3052,8 @@ static int selinux_socket_create(int fam
 	if (kern)
 		goto out;
 
-	tsec = current->security;
+	tsec = security_get_value_type(&current->security, SELINUX_LSM_ID,
+		struct task_security_struct);
 	err = avc_has_perm(tsec->sid, tsec->sid,
 			   socket_type_to_security_class(family, type,
 			   protocol), SOCKET__CREATE, NULL);
@@ -2973,9 +3068,11 @@ static void selinux_socket_post_create(s
 	struct inode_security_struct *isec;
 	struct task_security_struct *tsec;
 
-	isec = SOCK_INODE(sock)->i_security;
+	isec = security_get_value_type(&SOCK_INODE(sock)->i_security,
+		SELINUX_LSM_ID, struct inode_security_struct);
 
-	tsec = current->security;
+	tsec = security_get_value_type(&current->security, SELINUX_LSM_ID,
+		struct task_security_struct);
 	isec->sclass = socket_type_to_security_class(family, type, protocol);
 	isec->sid = kern ? SECINITSID_KERNEL : tsec->sid;
 	isec->initialized = 1;
@@ -3013,8 +3110,10 @@ static int selinux_socket_bind(struct so
 		struct sock *sk = sock->sk;
 		u32 sid, node_perm, addrlen;
 
-		tsec = current->security;
-		isec = SOCK_INODE(sock)->i_security;
+		tsec = security_get_value_type(&current->security,
+			SELINUX_LSM_ID, struct task_security_struct);
+		isec = security_get_value_type(&SOCK_INODE(sock)->i_security,
+			SELINUX_LSM_ID, struct inode_security_struct);
 
 		if (family == PF_INET) {
 			addr4 = (struct sockaddr_in *)address;
@@ -3092,7 +3191,8 @@ static int selinux_socket_connect(struct
 	/*
 	 * If a TCP socket, check name_connect permission for the port.
 	 */
-	isec = SOCK_INODE(sock)->i_security;
+	isec = security_get_value_type(&SOCK_INODE(sock)->i_security,
+		SELINUX_LSM_ID, struct inode_security_struct);
 	if (isec->sclass == SECCLASS_TCP_SOCKET) {
 		struct sock *sk = sock->sk;
 		struct avc_audit_data ad;
@@ -3146,9 +3246,11 @@ static int selinux_socket_accept(struct 
 	if (err)
 		return err;
 
-	newisec = SOCK_INODE(newsock)->i_security;
+	newisec = security_get_value_type(&SOCK_INODE(newsock)->i_security,
+		SELINUX_LSM_ID, struct inode_security_struct);
 
-	isec = SOCK_INODE(sock)->i_security;
+	isec = security_get_value_type(&SOCK_INODE(sock)->i_security,
+		SELINUX_LSM_ID, struct inode_security_struct);
 	newisec->sclass = isec->sclass;
 	newisec->sid = isec->sid;
 	newisec->initialized = 1;
@@ -3208,8 +3310,10 @@ static int selinux_socket_unix_stream_co
 	if (err)
 		return err;
 
-	isec = SOCK_INODE(sock)->i_security;
-	other_isec = SOCK_INODE(other)->i_security;
+	isec = security_get_value_type(&SOCK_INODE(sock)->i_security,
+		SELINUX_LSM_ID, struct inode_security_struct);
+	other_isec = security_get_value_type(&SOCK_INODE(other)->i_security,
+		SELINUX_LSM_ID, struct inode_security_struct);
 
 	AVC_AUDIT_DATA_INIT(&ad,NET);
 	ad.u.net.sk = other->sk;
@@ -3221,11 +3325,13 @@ static int selinux_socket_unix_stream_co
 		return err;
 
 	/* connecting socket */
-	ssec = sock->sk->sk_security;
+	ssec = security_get_value_type(&sock->sk->sk_security, SELINUX_LSM_ID,
+		struct sk_security_struct);
 	ssec->peer_sid = other_isec->sid;
 	
 	/* server child socket */
-	ssec = newsk->sk_security;
+	ssec = security_get_value_type(&newsk->sk_security, SELINUX_LSM_ID,
+		struct sk_security_struct);
 	ssec->peer_sid = isec->sid;
 	
 	return 0;
@@ -3239,8 +3345,10 @@ static int selinux_socket_unix_may_send(
 	struct avc_audit_data ad;
 	int err;
 
-	isec = SOCK_INODE(sock)->i_security;
-	other_isec = SOCK_INODE(other)->i_security;
+	isec = security_get_value_type(&SOCK_INODE(sock)->i_security,
+		SELINUX_LSM_ID, struct inode_security_struct);
+	other_isec = security_get_value_type(&SOCK_INODE(other)->i_security,
+		SELINUX_LSM_ID, struct inode_security_struct);
 
 	AVC_AUDIT_DATA_INIT(&ad,NET);
 	ad.u.net.sk = other->sk;
@@ -3280,7 +3388,8 @@ static int selinux_socket_sock_rcv_skb(s
  		inode = SOCK_INODE(sock);
  		if (inode) {
  			struct inode_security_struct *isec;
- 			isec = inode->i_security;
+			isec = security_get_value_type(&inode->i_security,
+				SELINUX_LSM_ID, struct inode_security_struct);
  			sock_sid = isec->sid;
  			sock_class = isec->sclass;
  		}
@@ -3363,13 +3472,15 @@ static int selinux_socket_getpeersec(str
 	struct sk_security_struct *ssec;
 	struct inode_security_struct *isec;
 
-	isec = SOCK_INODE(sock)->i_security;
+	isec = security_get_value_type(&SOCK_INODE(sock)->i_security,
+		SELINUX_LSM_ID, struct inode_security_struct);
 	if (isec->sclass != SECCLASS_UNIX_STREAM_SOCKET) {
 		err = -ENOPROTOOPT;
 		goto out;
 	}
 
-	ssec = sock->sk->sk_security;
+	ssec = security_get_value_type(&sock->sk->sk_security, SELINUX_LSM_ID,
+		struct sk_security_struct);
 	
 	err = security_sid_to_context(ssec->peer_sid, &scontext, &scontext_len);
 	if (err)
@@ -3408,7 +3519,10 @@ static int selinux_nlmsg_perm(struct soc
 	u32 perm;
 	struct nlmsghdr *nlh;
 	struct socket *sock = sk->sk_socket;
-	struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
+	struct inode_security_struct *isec;
+	
+	isec = security_get_value_type(&SOCK_INODE(sock)->i_security,
+		SELINUX_LSM_ID, struct inode_security_struct);
 	
 	if (skb->len < NLMSG_SPACE(0)) {
 		err = -EINVAL;
@@ -3474,7 +3588,8 @@ static unsigned int selinux_ip_postroute
 	if (err)
 		goto out;
 
-	isec = inode->i_security;
+	isec = security_get_value_type(&inode->i_security, SELINUX_LSM_ID,
+		struct inode_security_struct);
 	
 	switch (isec->sclass) {
 	case SECCLASS_UDP_SOCKET:
@@ -3584,7 +3699,8 @@ static int selinux_netlink_send(struct s
 	if (err)
 		return err;
 
-	tsec = current->security;
+	tsec = security_get_value_type(&current->security,
+		SELINUX_LSM_ID, struct task_security_struct);
 
 	avd.allowed = 0;
 	avc_has_perm_noaudit(tsec->sid, tsec->sid,
@@ -3608,15 +3724,17 @@ static int ipc_alloc_security(struct tas
 			      struct kern_ipc_perm *perm,
 			      u16 sclass)
 {
-	struct task_security_struct *tsec = task->security;
+	struct task_security_struct *tsec;
 	struct ipc_security_struct *isec;
 
+	tsec = security_get_value_type(&task->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+
 	isec = kmalloc(sizeof(struct ipc_security_struct), GFP_KERNEL);
 	if (!isec)
 		return -ENOMEM;
 
 	memset(isec, 0, sizeof(struct ipc_security_struct));
-	isec->magic = SELINUX_MAGIC;
 	isec->sclass = sclass;
 	isec->ipc_perm = perm;
 	if (tsec) {
@@ -3624,18 +3742,18 @@ static int ipc_alloc_security(struct tas
 	} else {
 		isec->sid = SECINITSID_UNLABELED;
 	}
-	perm->security = isec;
+	security_set_value_type(&perm->security, SELINUX_LSM_ID, isec);
 
 	return 0;
 }
 
 static void ipc_free_security(struct kern_ipc_perm *perm)
 {
-	struct ipc_security_struct *isec = perm->security;
-	if (!isec || isec->magic != SELINUX_MAGIC)
-		return;
+	struct ipc_security_struct *isec;
+	
+	isec = security_del_value_type(&perm->security, SELINUX_LSM_ID,
+		struct ipc_security_struct);
 
-	perm->security = NULL;
 	kfree(isec);
 }
 
@@ -3648,21 +3766,20 @@ static int msg_msg_alloc_security(struct
 		return -ENOMEM;
 
 	memset(msec, 0, sizeof(struct msg_security_struct));
-	msec->magic = SELINUX_MAGIC;
 	msec->msg = msg;
 	msec->sid = SECINITSID_UNLABELED;
-	msg->security = msec;
+	security_set_value_type(&msg->security, SELINUX_LSM_ID, msec);
 
 	return 0;
 }
 
 static void msg_msg_free_security(struct msg_msg *msg)
 {
-	struct msg_security_struct *msec = msg->security;
-	if (!msec || msec->magic != SELINUX_MAGIC)
-		return;
+	struct msg_security_struct *msec;
+	
+	msec = security_del_value_type(&msg->security, SELINUX_LSM_ID,
+		struct msg_security_struct);
 
-	msg->security = NULL;
 	kfree(msec);
 }
 
@@ -3673,8 +3790,10 @@ static int ipc_has_perm(struct kern_ipc_
 	struct ipc_security_struct *isec;
 	struct avc_audit_data ad;
 
-	tsec = current->security;
-	isec = ipc_perms->security;
+	tsec = security_get_value_type(&current->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+	isec = security_get_value_type(&ipc_perms->security, SELINUX_LSM_ID,
+		struct ipc_security_struct);
 
 	AVC_AUDIT_DATA_INIT(&ad, IPC);
 	ad.u.ipc_id = ipc_perms->key;
@@ -3704,8 +3823,10 @@ static int selinux_msg_queue_alloc_secur
 	if (rc)
 		return rc;
 
-	tsec = current->security;
-	isec = msq->q_perm.security;
+	tsec = security_get_value_type(&current->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+	isec = security_get_value_type(&msq->q_perm.security, SELINUX_LSM_ID,
+		struct ipc_security_struct);
 
 	AVC_AUDIT_DATA_INIT(&ad, IPC);
  	ad.u.ipc_id = msq->q_perm.key;
@@ -3730,8 +3851,10 @@ static int selinux_msg_queue_associate(s
 	struct ipc_security_struct *isec;
 	struct avc_audit_data ad;
 
-	tsec = current->security;
-	isec = msq->q_perm.security;
+	tsec = security_get_value_type(&current->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+	isec = security_get_value_type(&msq->q_perm.security, SELINUX_LSM_ID,
+		struct ipc_security_struct);
 
 	AVC_AUDIT_DATA_INIT(&ad, IPC);
 	ad.u.ipc_id = msq->q_perm.key;
@@ -3776,9 +3899,12 @@ static int selinux_msg_queue_msgsnd(stru
 	struct avc_audit_data ad;
 	int rc;
 
-	tsec = current->security;
-	isec = msq->q_perm.security;
-	msec = msg->security;
+	tsec = security_get_value_type(&current->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+	isec = security_get_value_type(&msq->q_perm.security, SELINUX_LSM_ID,
+		struct ipc_security_struct);
+	msec = security_get_value_type(&msg->security, SELINUX_LSM_ID,
+		struct msg_security_struct);
 
 	/*
 	 * First time through, need to assign label to the message
@@ -3824,9 +3950,12 @@ static int selinux_msg_queue_msgrcv(stru
 	struct avc_audit_data ad;
 	int rc;
 
-	tsec = target->security;
-	isec = msq->q_perm.security;
-	msec = msg->security;
+	tsec = security_get_value_type(&target->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+	isec = security_get_value_type(&msq->q_perm.security, SELINUX_LSM_ID,
+		struct ipc_security_struct);
+	msec = security_get_value_type(&msg->security, SELINUX_LSM_ID,
+		struct msg_security_struct);
 
 	AVC_AUDIT_DATA_INIT(&ad, IPC);
  	ad.u.ipc_id = msq->q_perm.key;
@@ -3851,8 +3980,10 @@ static int selinux_shm_alloc_security(st
 	if (rc)
 		return rc;
 
-	tsec = current->security;
-	isec = shp->shm_perm.security;
+	tsec = security_get_value_type(&current->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+	isec = security_get_value_type(&shp->shm_perm.security, SELINUX_LSM_ID,
+		struct ipc_security_struct);
 
 	AVC_AUDIT_DATA_INIT(&ad, IPC);
  	ad.u.ipc_id = shp->shm_perm.key;
@@ -3877,8 +4008,10 @@ static int selinux_shm_associate(struct 
 	struct ipc_security_struct *isec;
 	struct avc_audit_data ad;
 
-	tsec = current->security;
-	isec = shp->shm_perm.security;
+	tsec = security_get_value_type(&current->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+	isec = security_get_value_type(&shp->shm_perm.security, SELINUX_LSM_ID,
+		struct ipc_security_struct);
 
 	AVC_AUDIT_DATA_INIT(&ad, IPC);
 	ad.u.ipc_id = shp->shm_perm.key;
@@ -3950,8 +4083,10 @@ static int selinux_sem_alloc_security(st
 	if (rc)
 		return rc;
 
-	tsec = current->security;
-	isec = sma->sem_perm.security;
+	tsec = security_get_value_type(&current->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+	isec = security_get_value_type(&sma->sem_perm.security, SELINUX_LSM_ID,
+		struct ipc_security_struct);
 
 	AVC_AUDIT_DATA_INIT(&ad, IPC);
  	ad.u.ipc_id = sma->sem_perm.key;
@@ -3976,8 +4111,10 @@ static int selinux_sem_associate(struct 
 	struct ipc_security_struct *isec;
 	struct avc_audit_data ad;
 
-	tsec = current->security;
-	isec = sma->sem_perm.security;
+	tsec = security_get_value_type(&current->security, SELINUX_LSM_ID,
+		struct task_security_struct);
+	isec = security_get_value_type(&sma->sem_perm.security, SELINUX_LSM_ID,
+		struct ipc_security_struct);
 
 	AVC_AUDIT_DATA_INIT(&ad, IPC);
 	ad.u.ipc_id = sma->sem_perm.key;
@@ -4111,7 +4248,8 @@ static int selinux_getprocattr(struct ta
 	if (!size)
 		return -ERANGE;
 
-	tsec = p->security;
+	tsec = security_get_value_type(&p->security, SELINUX_LSM_ID,
+		struct task_security_struct);
 
 	if (!strcmp(name, "current"))
 		sid = tsec->sid;
@@ -4186,7 +4324,8 @@ static int selinux_setprocattr(struct ta
 	   operation.  See selinux_bprm_set_security for the execve
 	   checks and may_create for the file creation checks. The
 	   operation will then fail if the context is not permitted. */
-	tsec = p->security;
+	tsec = security_get_value_type(&p->security, SELINUX_LSM_ID,
+		struct task_security_struct);
 	if (!strcmp(name, "exec"))
 		tsec->exec_sid = sid;
 	else if (!strcmp(name, "fscreate"))
Index: linux-2.6.12-rc6/security/selinux/selinuxfs.c
===================================================================
--- linux-2.6.12-rc6.orig/security/selinux/selinuxfs.c
+++ linux-2.6.12-rc6/security/selinux/selinuxfs.c
@@ -18,6 +18,7 @@
 #include <linux/init.h>
 #include <linux/string.h>
 #include <linux/security.h>
+#include <linux/security-stack.h>
 #include <linux/major.h>
 #include <linux/seq_file.h>
 #include <linux/percpu.h>
@@ -59,7 +60,8 @@ static int task_has_security(struct task
 {
 	struct task_security_struct *tsec;
 
-	tsec = tsk->security;
+	tsec = security_get_value_type(&tsk->security, SELINUX_LSM_ID,
+			struct task_security_struct);
 	if (!tsec)
 		return -EACCES;
 
@@ -983,7 +985,8 @@ static int sel_make_bools(void)
 			ret = -ENAMETOOLONG;
 			goto err;
 		}
-		isec = (struct inode_security_struct*)inode->i_security;
+		isec = security_get_value_type(&inode->i_security,
+				SELINUX_LSM_ID, struct inode_security_struct);
 		if ((ret = security_genfs_sid("selinuxfs", page, SECCLASS_FILE, &sid)))
 			goto err;
 		isec->sid = sid;
@@ -1270,7 +1273,8 @@ static int sel_fill_super(struct super_b
 	inode = sel_make_inode(sb, S_IFCHR | S_IRUGO | S_IWUGO);
 	if (!inode)
 		goto out;
-	isec = (struct inode_security_struct*)inode->i_security;
+	isec = security_get_value_type(&inode->i_security, SELINUX_LSM_ID,
+			struct inode_security_struct);
 	isec->sid = SECINITSID_DEVNULL;
 	isec->sclass = SECCLASS_CHR_FILE;
 	isec->initialized = 1;

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 9/11] lsm stacking: selinux: remove secondary support
  2005-06-08 23:55 patch 0/11] lsm stacking: intro serue
                   ` (7 preceding siblings ...)
  2005-06-09  0:02 ` [patch 8/11] lsm stacking: selinux: use security_*_value API serue
@ 2005-06-09  0:02 ` serue
  2005-06-09  0:03 ` [patch 10/11] lsm stacking: hook completeness verification serue
  2005-06-09  0:04 ` [patch 11/11] lsm stacking: support sharing /proc/$$/attr/* serue
  10 siblings, 0 replies; 12+ messages in thread
From: serue @ 2005-06-09  0:02 UTC (permalink / raw)
  To: lkml; +Cc: Chris Wright, Stephen Smalley, James Morris

Remove the SELinux support for secondary modules.  This is no longer necessary
as SELinux can now be simply stacked with the cap-stack module.

Signed-off-by: Serge Hallyn <serue@us.ibm.com>
---
 security/selinux/hooks.c |  266 ++++++-----------------------------------------
 1 files changed, 34 insertions(+), 232 deletions(-)

Index: linux-2.6.12-rc6/security/selinux/hooks.c
===================================================================
--- linux-2.6.12-rc6.orig/security/selinux/hooks.c
+++ linux-2.6.12-rc6/security/selinux/hooks.c
@@ -80,6 +80,8 @@
 extern unsigned int policydb_loaded_version;
 extern int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm);
 
+static int secondary;  /* how were we registered? */
+
 #ifdef CONFIG_SECURITY_SELINUX_DEVELOP
 int selinux_enforcing = 0;
 
@@ -102,15 +104,6 @@ static int __init selinux_enabled_setup(
 __setup("selinux=", selinux_enabled_setup);
 #endif
 
-/* Original (dummy) security module. */
-static struct security_operations *original_ops = NULL;
-
-/* Minimal support for a secondary security module,
-   just to allow the use of the dummy or capability modules.
-   The owlsm module can alternatively be used as a secondary
-   module as long as CONFIG_OWLSM_FD is not enabled. */
-static struct security_operations *secondary_ops = NULL;
-
 /* Lists of inode and superblock security structures initialized
    before the policy was loaded. */
 static LIST_HEAD(superblock_security_head);
@@ -1399,9 +1392,6 @@ static int selinux_ptrace(struct task_st
 	struct task_security_struct *csec;
 	int rc;
 
-	rc = secondary_ops->ptrace(parent,child);
-	if (rc)
-		return rc;
 	psec = security_get_value_type(&parent->security, SELINUX_LSM_ID,
 		struct task_security_struct);
 	csec = security_get_value_type(&child->security, SELINUX_LSM_ID,
@@ -1417,41 +1407,17 @@ static int selinux_ptrace(struct task_st
 static int selinux_capget(struct task_struct *target, kernel_cap_t *effective,
                           kernel_cap_t *inheritable, kernel_cap_t *permitted)
 {
-	int error;
-
-	error = task_has_perm(current, target, PROCESS__GETCAP);
-	if (error)
-		return error;
-
-	return secondary_ops->capget(target, effective, inheritable, permitted);
+	return task_has_perm(current, target, PROCESS__GETCAP);
 }
 
 static int selinux_capset_check(struct task_struct *target, kernel_cap_t *effective,
                                 kernel_cap_t *inheritable, kernel_cap_t *permitted)
 {
-	int error;
-
-	error = secondary_ops->capset_check(target, effective, inheritable, permitted);
-	if (error)
-		return error;
-
 	return task_has_perm(current, target, PROCESS__SETCAP);
 }
 
-static void selinux_capset_set(struct task_struct *target, kernel_cap_t *effective,
-                               kernel_cap_t *inheritable, kernel_cap_t *permitted)
-{
-	secondary_ops->capset_set(target, effective, inheritable, permitted);
-}
-
 static int selinux_capable(struct task_struct *tsk, int cap)
 {
-	int rc;
-
-	rc = secondary_ops->capable(tsk, cap);
-	if (rc)
-		return rc;
-
 	return task_has_capability(tsk,cap);
 }
 
@@ -1463,10 +1429,6 @@ static int selinux_sysctl(ctl_table *tab
 	u32 tsid;
 	int rc;
 
-	rc = secondary_ops->sysctl(table, op);
-	if (rc)
-		return rc;
-
 	tsec = security_get_value_type(&current->security, SELINUX_LSM_ID,
 		struct task_security_struct);
 
@@ -1534,11 +1496,7 @@ static int selinux_quota_on(struct dentr
 
 static int selinux_syslog(int type)
 {
-	int rc;
-
-	rc = secondary_ops->syslog(type);
-	if (rc)
-		return rc;
+	int rc = 0;
 
 	switch (type) {
 		case 3:         /* Read last kernel messages */
@@ -1562,36 +1520,6 @@ static int selinux_syslog(int type)
 	return rc;
 }
 
-/*
- * Check that a process has enough memory to allocate a new virtual
- * mapping. 0 means there is enough memory for the allocation to
- * succeed and -ENOMEM implies there is not.
- *
- * Note that secondary_ops->capable and task_has_perm_noaudit return 0
- * if the capability is granted, but __vm_enough_memory requires 1 if
- * the capability is granted.
- *
- * Do not audit the selinux permission check, as this is applied to all
- * processes that allocate mappings.
- */
-static int selinux_vm_enough_memory(long pages)
-{
-	int rc, cap_sys_admin = 0;
-	struct task_security_struct *tsec = current->security;
-
-	rc = secondary_ops->capable(current, CAP_SYS_ADMIN);
-	if (rc == 0)
-		rc = avc_has_perm_noaudit(tsec->sid, tsec->sid,
-					SECCLASS_CAPABILITY,
-					CAP_TO_MASK(CAP_SYS_ADMIN),
-					NULL);
-
-	if (rc == 0)
-		cap_sys_admin = 1;
-
-	return __vm_enough_memory(pages, cap_sys_admin);
-}
-
 /* binprm security operations */
 
 static int selinux_bprm_alloc_security(struct linux_binprm *bprm)
@@ -1621,10 +1549,6 @@ static int selinux_bprm_set_security(str
 	struct avc_audit_data ad;
 	int rc;
 
-	rc = secondary_ops->bprm_set_security(bprm);
-	if (rc)
-		return rc;
-
 	bsec = security_get_value_type(&bprm->security, SELINUX_LSM_ID,
 		struct bprm_security_struct);
 
@@ -1689,12 +1613,6 @@ static int selinux_bprm_set_security(str
 	return 0;
 }
 
-static int selinux_bprm_check_security (struct linux_binprm *bprm)
-{
-	return secondary_ops->bprm_check_security(bprm);
-}
-
-
 static int selinux_bprm_secureexec (struct linux_binprm *bprm)
 {
 	struct task_security_struct *tsec;
@@ -1711,7 +1629,7 @@ static int selinux_bprm_secureexec (stru
 					 PROCESS__NOATSECURE, NULL);
 	}
 
-	return (atsecure || secondary_ops->bprm_secureexec(bprm));
+	return atsecure;
 }
 
 static void selinux_bprm_free_security(struct linux_binprm *bprm)
@@ -1815,8 +1733,6 @@ static void selinux_bprm_apply_creds(str
 	u32 sid;
 	int rc;
 
-	secondary_ops->bprm_apply_creds(bprm, unsafe);
-
 	tsec = security_get_value_type(&current->security, SELINUX_LSM_ID,
 		struct task_security_struct);
 	bsec = security_get_value_type(&bprm->security, SELINUX_LSM_ID,
@@ -2041,12 +1957,6 @@ static int selinux_mount(char * dev_name
                          unsigned long flags,
                          void * data)
 {
-	int rc;
-
-	rc = secondary_ops->sb_mount(dev_name, nd, type, flags, data);
-	if (rc)
-		return rc;
-
 	if (flags & MS_REMOUNT)
 		return superblock_has_perm(current, nd->mnt->mnt_sb,
 		                           FILESYSTEM__REMOUNT, NULL);
@@ -2057,12 +1967,6 @@ static int selinux_mount(char * dev_name
 
 static int selinux_umount(struct vfsmount *mnt, int flags)
 {
-	int rc;
-
-	rc = secondary_ops->sb_umount(mnt, flags);
-	if (rc)
-		return rc;
-
 	return superblock_has_perm(current,mnt->mnt_sb,
 	                           FILESYSTEM__UNMOUNT,NULL);
 }
@@ -2091,11 +1995,6 @@ static void selinux_inode_post_create(st
 
 static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
 {
-	int rc;
-
-	rc = secondary_ops->inode_link(old_dentry,dir,new_dentry);
-	if (rc)
-		return rc;
 	return may_link(dir, old_dentry, MAY_LINK);
 }
 
@@ -2106,11 +2005,6 @@ static void selinux_inode_post_link(stru
 
 static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
 {
-	int rc;
-
-	rc = secondary_ops->inode_unlink(dir, dentry);
-	if (rc)
-		return rc;
 	return may_link(dir, dentry, MAY_UNLINK);
 }
 
@@ -2141,12 +2035,6 @@ static int selinux_inode_rmdir(struct in
 
 static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
 {
-	int rc;
-
-	rc = secondary_ops->inode_mknod(dir, dentry, mode, dev);
-	if (rc)
-		return rc;
-
 	return may_create(dir, dentry, inode_mode_to_security_class(mode));
 }
 
@@ -2174,23 +2062,12 @@ static int selinux_inode_readlink(struct
 
 static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
 {
-	int rc;
-
-	rc = secondary_ops->inode_follow_link(dentry,nameidata);
-	if (rc)
-		return rc;
 	return dentry_has_perm(current, NULL, dentry, FILE__READ);
 }
 
 static int selinux_inode_permission(struct inode *inode, int mask,
 				    struct nameidata *nd)
 {
-	int rc;
-
-	rc = secondary_ops->inode_permission(inode, mask, nd);
-	if (rc)
-		return rc;
-
 	if (!mask) {
 		/* No permission to check.  Existence test. */
 		return 0;
@@ -2202,12 +2079,6 @@ static int selinux_inode_permission(stru
 
 static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
 {
-	int rc;
-
-	rc = secondary_ops->inode_setattr(dentry, iattr);
-	if (rc)
-		return rc;
-
 	if (iattr->ia_valid & ATTR_FORCE)
 		return 0;
 
@@ -2529,12 +2400,6 @@ static int file_map_prot_check(struct fi
 static int selinux_file_mmap(struct file *file, unsigned long reqprot,
 			     unsigned long prot, unsigned long flags)
 {
-	int rc;
-
-	rc = secondary_ops->file_mmap(file, reqprot, prot, flags);
-	if (rc)
-		return rc;
-
 	if (selinux_checkreqprot)
 		prot = reqprot;
 
@@ -2546,12 +2411,6 @@ static int selinux_file_mprotect(struct 
 				 unsigned long reqprot,
 				 unsigned long prot)
 {
-	int rc;
-
-	rc = secondary_ops->file_mprotect(vma, reqprot, prot);
-	if (rc)
-		return rc;
-
 	if (selinux_checkreqprot)
 		prot = reqprot;
 
@@ -2669,12 +2528,6 @@ static int selinux_file_receive(struct f
 
 static int selinux_task_create(unsigned long clone_flags)
 {
-	int rc;
-
-	rc = secondary_ops->task_create(clone_flags);
-	if (rc)
-		return rc;
-
 	return task_has_perm(current, current, PROCESS__FORK);
 }
 
@@ -2723,11 +2576,6 @@ static int selinux_task_setuid(uid_t id0
 	return 0;
 }
 
-static int selinux_task_post_setuid(uid_t id0, uid_t id1, uid_t id2, int flags)
-{
-	return secondary_ops->task_post_setuid(id0,id1,id2,flags);
-}
-
 static int selinux_task_setgid(gid_t id0, gid_t id1, gid_t id2, int flags)
 {
 	/* See the comment for setuid above. */
@@ -2757,24 +2605,12 @@ static int selinux_task_setgroups(struct
 
 static int selinux_task_setnice(struct task_struct *p, int nice)
 {
-	int rc;
-
-	rc = secondary_ops->task_setnice(p, nice);
-	if (rc)
-		return rc;
-
 	return task_has_perm(current,p, PROCESS__SETSCHED);
 }
 
 static int selinux_task_setrlimit(unsigned int resource, struct rlimit *new_rlim)
 {
 	struct rlimit *old_rlim = current->signal->rlim + resource;
-	int rc;
-
-	rc = secondary_ops->task_setrlimit(resource, new_rlim);
-	if (rc)
-		return rc;
-
 	/* Control the ability to change the hard limit (whether
 	   lowering or raising it), so that the hard limit can
 	   later be used as a safe reset point for the soft limit
@@ -2798,11 +2634,6 @@ static int selinux_task_getscheduler(str
 static int selinux_task_kill(struct task_struct *p, struct siginfo *info, int sig)
 {
 	u32 perm;
-	int rc;
-
-	rc = secondary_ops->task_kill(p, info, sig);
-	if (rc)
-		return rc;
 
 	if (info && ((unsigned long)info == 1 ||
 	             (unsigned long)info == 2 || SI_FROMKERNEL(info)))
@@ -2841,8 +2672,6 @@ static void selinux_task_reparent_to_ini
 {
   	struct task_security_struct *tsec;
 
-	secondary_ops->task_reparent_to_init(p);
-
 	tsec = security_get_value_type(&p->security, SELINUX_LSM_ID,
 		struct task_security_struct);
 	tsec->osid = tsec->sid;
@@ -3306,10 +3135,6 @@ static int selinux_socket_unix_stream_co
 	struct avc_audit_data ad;
 	int err;
 
-	err = secondary_ops->unix_stream_connect(sock, other, newsk);
-	if (err)
-		return err;
-
 	isec = security_get_value_type(&SOCK_INODE(sock)->i_security,
 		SELINUX_LSM_ID, struct inode_security_struct);
 	other_isec = security_get_value_type(&SOCK_INODE(other)->i_security,
@@ -3693,11 +3518,7 @@ static int selinux_netlink_send(struct s
 {
 	struct task_security_struct *tsec;
 	struct av_decision avd;
-	int err;
-
-	err = secondary_ops->netlink_send(sk, skb);
-	if (err)
-		return err;
+	int err = 0;
 
 	tsec = security_get_value_type(&current->security,
 		SELINUX_LSM_ID, struct task_security_struct);
@@ -3713,13 +3534,6 @@ static int selinux_netlink_send(struct s
 	return err;
 }
 
-static int selinux_netlink_recv(struct sk_buff *skb)
-{
-	if (!cap_raised(NETLINK_CB(skb).eff_cap, CAP_NET_ADMIN))
-		return -EPERM;
-	return 0;
-}
-
 static int ipc_alloc_security(struct task_struct *task,
 			      struct kern_ipc_perm *perm,
 			      u16 sclass)
@@ -4057,11 +3871,6 @@ static int selinux_shm_shmat(struct shmi
 			     char __user *shmaddr, int shmflg)
 {
 	u32 perms;
-	int rc;
-
-	rc = secondary_ops->shm_shmat(shp, shmaddr, shmflg);
-	if (rc)
-		return rc;
 
 	if (shmflg & SHM_RDONLY)
 		perms = SHM__READ;
@@ -4197,32 +4006,12 @@ static int selinux_ipc_permission(struct
 /* module stacking operations */
 static int selinux_register_security (const char *name, struct security_operations *ops)
 {
-	if (secondary_ops != original_ops) {
-		printk(KERN_INFO "%s:  There is already a secondary security "
-		       "module registered.\n", __FUNCTION__);
-		return -EINVAL;
- 	}
-
-	secondary_ops = ops;
-
-	printk(KERN_INFO "%s:  Registering secondary module %s\n",
-	       __FUNCTION__,
-	       name);
-
-	return 0;
+	return -EINVAL;
 }
 
 static int selinux_unregister_security (const char *name, struct security_operations *ops)
 {
-	if (ops != secondary_ops) {
-		printk (KERN_INFO "%s:  trying to unregister a security module "
-		        "that is not registered.\n", __FUNCTION__);
-		return -EINVAL;
-	}
-
-	secondary_ops = original_ops;
-
-	return 0;
+	return -EINVAL;
 }
 
 static void selinux_d_instantiate (struct dentry *dentry, struct inode *inode)
@@ -4385,23 +4174,19 @@ static struct security_operations selinu
 	.ptrace =			selinux_ptrace,
 	.capget =			selinux_capget,
 	.capset_check =			selinux_capset_check,
-	.capset_set =			selinux_capset_set,
 	.sysctl =			selinux_sysctl,
 	.capable =			selinux_capable,
 	.quotactl =			selinux_quotactl,
 	.quota_on =			selinux_quota_on,
 	.syslog =			selinux_syslog,
-	.vm_enough_memory =		selinux_vm_enough_memory,
 
 	.netlink_send =			selinux_netlink_send,
-        .netlink_recv =			selinux_netlink_recv,
 
 	.bprm_alloc_security =		selinux_bprm_alloc_security,
 	.bprm_free_security =		selinux_bprm_free_security,
 	.bprm_apply_creds =		selinux_bprm_apply_creds,
 	.bprm_post_apply_creds =	selinux_bprm_post_apply_creds,
 	.bprm_set_security =		selinux_bprm_set_security,
-	.bprm_check_security =		selinux_bprm_check_security,
 	.bprm_secureexec =		selinux_bprm_secureexec,
 
 	.sb_alloc_security =		selinux_sb_alloc_security,
@@ -4458,7 +4243,6 @@ static struct security_operations selinu
 	.task_alloc_security =		selinux_task_alloc_security,
 	.task_free_security =		selinux_task_free_security,
 	.task_setuid =			selinux_task_setuid,
-	.task_post_setuid =		selinux_task_post_setuid,
 	.task_setgid =			selinux_task_setgid,
 	.task_setpgid =			selinux_task_setpgid,
 	.task_getpgid =			selinux_task_getpgid,
@@ -4530,10 +4314,12 @@ static struct security_operations selinu
 #endif
 };
 
+#define MY_NAME "selinux"
 static __init int selinux_init(void)
 {
 	struct task_security_struct *tsec;
 
+	secondary = 0;
 	if (!selinux_enabled) {
 		printk(KERN_INFO "SELinux:  Disabled at boot.\n");
 		return 0;
@@ -4544,22 +4330,30 @@ static __init int selinux_init(void)
 	/* Set the security state for the initial task. */
 	if (task_alloc_security(current))
 		panic("SELinux:  Failed to initialize initial task.\n");
-	tsec = current->security;
+	tsec = security_get_value_type(&current->security, SELINUX_LSM_ID,
+		struct task_security_struct);
 	tsec->osid = tsec->sid = SECINITSID_KERNEL;
 
 	avc_init();
 
-	original_ops = secondary_ops = security_ops;
-	if (!secondary_ops)
-		panic ("SELinux: No initial security operations\n");
-	if (register_security (&selinux_ops))
-		panic("SELinux: Unable to register with kernel.\n");
+	if (register_security (&selinux_ops)) {
+		if (mod_reg_security( MY_NAME, &selinux_ops)) {
+			printk(KERN_ERR "%s: Failed to register with primary LSM.\n",
+				__FUNCTION__);
+			panic("SELinux: Unable to register with kernel.\n");
+		} else {
+			printk(KERN_ERR "%s: registered with primary LSM.\n",
+				__FUNCTION__);
+		}
+		secondary = 1;
+	}
 
 	if (selinux_enforcing) {
 		printk(KERN_INFO "SELinux:  Starting in enforcing mode\n");
 	} else {
 		printk(KERN_INFO "SELinux:  Starting in permissive mode\n");
 	}
+
 	return 0;
 }
 
@@ -4669,6 +4463,7 @@ int selinux_disable(void)
 {
 	extern void exit_sel_fs(void);
 	static int selinux_disabled = 0;
+	int ret;
 
 	if (ss_initialized) {
 		/* Not permitted after initial policy load. */
@@ -4684,8 +4479,15 @@ int selinux_disable(void)
 
 	selinux_disabled = 1;
 
-	/* Reset security_ops to the secondary module, dummy or capability. */
-	security_ops = secondary_ops;
+	if (secondary)
+		ret = mod_unreg_security(MY_NAME, &selinux_ops);
+	else
+		ret = unregister_security(&selinux_ops);
+
+	if (ret)
+		printk(KERN_INFO "Failure unregistering selinux.\n");
+	else
+		printk(KERN_INFO "Unregistered selinux.\n");
 
 	/* Unregister netfilter hooks. */
 	selinux_nf_ip_exit();

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 10/11] lsm stacking: hook completeness verification
  2005-06-08 23:55 patch 0/11] lsm stacking: intro serue
                   ` (8 preceding siblings ...)
  2005-06-09  0:02 ` [patch 9/11] lsm stacking: selinux: remove secondary support serue
@ 2005-06-09  0:03 ` serue
  2005-06-09  0:04 ` [patch 11/11] lsm stacking: support sharing /proc/$$/attr/* serue
  10 siblings, 0 replies; 12+ messages in thread
From: serue @ 2005-06-09  0:03 UTC (permalink / raw)
  To: lkml; +Cc: Chris Wright, Stephen Smalley, James Morris

Add a script to check whether all security_operations hooks are defined
in both dummy_security_ops (through security_fixup_ops) and in stacker_ops.
Also adds a note in security.h to remind developers that all hooks must
be defined in these two modules, and to verify this using the
lsm_verify_hooks.sh script.

Signed-off-by: Serge Hallyn <serue@us.ibm.com>
---
 include/linux/security.h    |    4 ++++
 scripts/lsm_verify_hooks.sh |   44 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 48 insertions(+)

Index: linux-2.6.12-rc2/include/linux/security.h
===================================================================
--- linux-2.6.12-rc2.orig/include/linux/security.h	2005-05-23 15:01:00.000000000 -0500
+++ linux-2.6.12-rc2/include/linux/security.h	2005-05-23 15:01:43.000000000 -0500
@@ -121,6 +121,10 @@
 /**
  * struct security_operations - main security structure
  *
+ * When adding functions to this structure, please add them to
+ * dummy.c and stacker.c, and run linux/scripts/lsm_verify_hooks.sh
+ * to verify their inclusion in these modules.
+ *
  * Security hooks for program execution operations.
  *
  * @bprm_alloc_security:
Index: linux-2.6.12-rc2/scripts/lsm_verify_hooks.sh
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.12-rc2/scripts/lsm_verify_hooks.sh	2005-05-23 15:01:43.000000000 -0500
@@ -0,0 +1,44 @@
+#!/bin/sh
+
+# Author: Serge E. Hallyn <serue@us.ibm.com>
+
+# Checks that both the dummy and stacker modules define all the
+# security hooks.
+
+# This probably should be done in perl
+
+# Copyright (C) 2002,2003,2004,2005 Serge E. Hallyn <serue@us.ibm.com>
+# Copyright (C) 2002 David A. Wheeler <dwheeler@dwheeler.com>.
+#  This program is free software; you can redistribute it and/or modify
+#  it under the terms of the GNU General Public License as published by
+#  the Free Software Foundation; either version 2 of the License, or
+#  (at your option) any later version.
+
+# Grab the relevant pieces of text
+sed -n '/^void security_fixup_ops /,/}/p' dummy.c > dummy.out
+sed -n '/^static struct security_operations/,/}/p' stacker.c > stack.out
+../scripts/Lindent -o tmpsec.h ../include/linux/security.h
+sed -n '/^struct security_operations {/,/}/p' tmpsec.h > sech.out
+rm tmpsec.h
+
+# Get a list of functions in security.h
+cat sech.out | sed -n '/\t[a-z]/p' | sed -e 's/^\t[a-z]* (\*\([^)]*\).*$/\1/' > sech.out
+
+# check dummy.c
+for line in `cat sech.out`; do
+	grep $line dummy.out > /dev/null 2>&1
+	if [ $? -ne 0 ]; then
+		echo "WARNING: $line missing from dummy module!"
+	fi
+done
+
+# check stacker.c
+for line in `cat sech.out`; do
+	grep $line stack.out > /dev/null 2>&1
+	if [ $? -ne 0 ]; then
+		echo "WARNING: $line missing from stacker module!"
+	fi
+done
+
+rm sech.out stack.out dummy.out
+echo "LSM hook verification done."

^ permalink raw reply	[flat|nested] 12+ messages in thread

* [patch 11/11] lsm stacking: support sharing /proc/$$/attr/*
  2005-06-08 23:55 patch 0/11] lsm stacking: intro serue
                   ` (9 preceding siblings ...)
  2005-06-09  0:03 ` [patch 10/11] lsm stacking: hook completeness verification serue
@ 2005-06-09  0:04 ` serue
  10 siblings, 0 replies; 12+ messages in thread
From: serue @ 2005-06-09  0:04 UTC (permalink / raw)
  To: lkml; +Cc: Chris Wright, Stephen Smalley, James Morris

This patch enables sharing of the /proc/<pid>/attr files.  Input and
output now takes the form of
	"whatever_data_is_expected (module_name)"
For writes, the data section (minus " (module_name)") is sent to the
module identified as "module_name".  For reads, stacker appends the
" (module_name)" to whatever modules send.  If any module returns
an error other than -EINVAL, that error and no data is returned.

If data is written to a procattr file without " (module_name)"
the data is sent to the selinux module.

Signed-off-by: Serge Hallyn <serue@us.ibm.com>
---
 security/stacker.c |  125 ++++++++++++++++++++++++++++++++++++++++++-----------
 1 files changed, 100 insertions(+), 25 deletions(-)

Index: linux-2.6.12-rc2-stack/security/stacker.c
===================================================================
--- linux-2.6.12-rc2-stack.orig/security/stacker.c	2005-05-25 16:01:52.000000000 -0500
+++ linux-2.6.12-rc2-stack/security/stacker.c	2005-05-31 15:52:49.000000000 -0500
@@ -956,24 +956,116 @@ static void stacker_d_instantiate (struc
 	CALL_ALL(d_instantiate,d_instantiate(dentry,inode));
 }
 
+/*
+ * Query all LSMs.
+ * If all return EINVAL, we return EINVAL.  If any returns any other
+ * error, then we return that error.  Otherwise, we concatenate all
+ * modules' results.
+ */
 static int
 stacker_getprocattr(struct task_struct *p, char *name, void *value, size_t size)
 {
-	if (!selinux_module)
-		return -EINVAL;
-	if (!selinux_module->module_operations.getprocattr)
+	struct module_entry *m;
+	int len = 0, ret;
+	int found_noneinval = 0;
+
+
+	if (list_empty(&stacked_modules))
 		return -EINVAL;
-	return selinux_module->module_operations.getprocattr(p, name, value, size);
+
+	rcu_read_lock();
+	stack_for_each_entry(m, &stacked_modules, lsm_list) {
+		if (!m->module_operations.getprocattr)
+			continue;
+		rcu_read_unlock();
+		ret = m->module_operations.getprocattr(p, name,
+					value+len, size-len);
+		rcu_read_lock();
+		if (ret == -EINVAL)
+			continue;
+		found_noneinval = 1;
+		if (ret < 0) {
+			memset(value, 0, len);
+			len = ret;
+			break;
+		}
+		if (ret == 0)
+			continue;
+		len += ret;
+		if (len+m->namelen+4 < size) {
+			char *v = value;
+			if (v[len-1]=='\n')
+				len--;
+			len += sprintf(value+len, " (%s)\n", m->module_name);
+		}
+	}
+	rcu_read_unlock();
+
+	return found_noneinval ? len : -EINVAL;
+}
+
+static struct module_entry *
+find_active_lsm(const char *name, int len)
+{
+	struct module_entry *m, *ret = NULL;
+
+	rcu_read_lock();
+	stack_for_each_entry(m, &stacked_modules, lsm_list) {
+		if (m->namelen == len && !strncmp(m->module_name, name, len)) {
+			ret = m;
+			break;
+		}
+	}
+
+	rcu_read_unlock();
+	return ret;
 }
 
-static int stacker_setprocattr(struct task_struct *p, char *name, void *value, size_t size)
+/*
+ * We assume input will be either
+ * "data" - in which case it goes to selinux, or
+ * "data (mod_name)" in which case the data goes to module mod_name.
+ */
+static int
+stacker_setprocattr(struct task_struct *p, char *name, void *value, size_t size)
 {
+	struct module_entry *callm = selinux_module;
+	char *realv = (char *)value;
+	size_t dsize = size;
+	int loc = 0, end_data = size;
 
-	if (!selinux_module)
+	if (list_empty(&stacked_modules))
 		return -EINVAL;
-	if (!selinux_module->module_operations.setprocattr)
+
+	if (dsize && realv[dsize-1] == '\n')
+		dsize--;
+
+	if (!dsize || realv[dsize-1]!=')')
+		goto call;
+
+	dsize--;
+	loc = dsize-1;
+	while (loc && realv[loc]!='(')
+		loc--;
+	if (!loc)
+		goto call;
+
+	callm = find_active_lsm(realv+loc+1, dsize-loc-1);
+	if (!callm)
+		goto call;
+
+
+	loc--;
+	while (loc && realv[loc]==' ')
+		loc--;
+
+	end_data = loc+1;
+call:
+	if (!callm || !callm->module_operations.setprocattr)
 		return -EINVAL;
-	return selinux_module->module_operations.setprocattr(p, name, value, size);
+
+	return callm->module_operations.setprocattr(p, name, value, end_data) +
+			(size-end_data);
 }
 
 /*
@@ -1031,23 +1123,6 @@ out:
 	return ret;
 }
 
-static struct module_entry *
-find_active_lsm(const char *name, int len)
-{
-	struct module_entry *m, *ret = NULL;
-
-	rcu_read_lock();
-	stack_for_each_entry(m, &stacked_modules, lsm_list) {
-		if (m->namelen == len && !strncmp(m->module_name, name, len)) {
-			ret = m;
-			break;
-		}
-	}
-
-	rcu_read_unlock();
-	return ret;
-}
-
 /*
  * Currently this version of stacker does not allow for module
  * unregistering.

^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2005-06-09  1:03 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-06-08 23:55 patch 0/11] lsm stacking: intro serue
2005-06-08 23:56 ` [patch 1/11] lsm stacking: don't default to dummy_##hook serue
2005-06-08 23:57 ` [patch 2/11] lsm stacking: replace void* security with hlist serue
2005-06-08 23:58 ` [patch 3/11] lsm stacking: introduce security_*_value API serue
2005-06-08 23:59 ` [patch 4/11] lsm stacking: stacker documentation serue
2005-06-09  0:00 ` [patch 5/11] lsm stacking: actual stacker module serue
2005-06-09  0:00 ` [patch 6/11] lsm stacking: introduce stackable capabilities lsm serue
2005-06-09  0:01 ` [patch 7/11] lsm stacking: selinux: update ->security structs serue
2005-06-09  0:02 ` [patch 8/11] lsm stacking: selinux: use security_*_value API serue
2005-06-09  0:02 ` [patch 9/11] lsm stacking: selinux: remove secondary support serue
2005-06-09  0:03 ` [patch 10/11] lsm stacking: hook completeness verification serue
2005-06-09  0:04 ` [patch 11/11] lsm stacking: support sharing /proc/$$/attr/* serue

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®