linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [patch 0/12] lsm stacking v0.2: intro
@ 2005-06-30 19:44 serue
  2005-06-30 19:48 ` [patch 1/12] lsm stacking v0.2: don't default to dummy_##hook serue
                   ` (11 more replies)
  0 siblings, 12 replies; 57+ messages in thread
From: serue @ 2005-06-30 19:44 UTC (permalink / raw)
  To: lkml
  Cc: Chris Wright, Stephen Smalley, James Morris, Andrew Morton,
	Michael Halcrow, David Safford, Reiner Sailer, Gerrit Huizenga,
	emily

Hi,

The set of patches to follow introduces support for stacking LSMs.
This is its second posting to lkml.  I am sending it out in the hopes of
soliciting feedback and testing, with the obvious eventual goal of
mainline adoption.

The patches mainly do the following:

   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.
   4. Modify seclvl to use 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] 57+ messages in thread

* [patch 1/12] lsm stacking v0.2: don't default to dummy_##hook
  2005-06-30 19:44 [patch 0/12] lsm stacking v0.2: intro serue
@ 2005-06-30 19:48 ` serue
  2005-06-30 19:48 ` [patch 2/12] lsm stacking v0.2: replace void* security with hlist serue
                   ` (10 subsequent siblings)
  11 siblings, 0 replies; 57+ messages in thread
From: serue @ 2005-06-30 19:48 UTC (permalink / raw)
  To: lkml
  Cc: Chris Wright, Stephen Smalley, James Morris, Andrew Morton,
	Michael Halcrow, David Safford, Reiner Sailer, Gerrit Huizenga

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.c |   12 ++++++------
 1 files changed, 6 insertions(+), 6 deletions(-)

Index: linux-2.6.13-rc1/security/security.c
===================================================================
--- linux-2.6.13-rc1.orig/security/security.c	2005-06-30 14:02:59.000000000 -0500
+++ linux-2.6.13-rc1/security/security.c	2005-06-30 14:03:54.000000000 -0500
@@ -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] 57+ messages in thread

* [patch 2/12] lsm stacking v0.2: replace void* security with hlist
  2005-06-30 19:44 [patch 0/12] lsm stacking v0.2: intro serue
  2005-06-30 19:48 ` [patch 1/12] lsm stacking v0.2: don't default to dummy_##hook serue
@ 2005-06-30 19:48 ` serue
  2005-06-30 19:49 ` [patch 3/12] lsm stacking v0.2: introduce security_*_value API serue
                   ` (9 subsequent siblings)
  11 siblings, 0 replies; 57+ messages in thread
From: serue @ 2005-06-30 19:48 UTC (permalink / raw)
  To: lkml
  Cc: Chris Wright, Stephen Smalley, James Morris, Andrew Morton,
	Michael Halcrow, David Safford, Reiner Sailer, Gerrit Huizenga

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.13-rc1/fs/compat.c
===================================================================
--- linux-2.6.13-rc1.orig/fs/compat.c	2005-06-30 14:03:11.000000000 -0500
+++ linux-2.6.13-rc1/fs/compat.c	2005-06-30 14:04:03.000000000 -0500
@@ -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.13-rc1/fs/exec.c
===================================================================
--- linux-2.6.13-rc1.orig/fs/exec.c	2005-06-30 14:03:41.000000000 -0500
+++ linux-2.6.13-rc1/fs/exec.c	2005-06-30 14:04:03.000000000 -0500
@@ -1154,6 +1154,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)
@@ -1212,8 +1213,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.13-rc1/fs/inode.c
===================================================================
--- linux-2.6.13-rc1.orig/fs/inode.c	2005-06-30 14:03:41.000000000 -0500
+++ linux-2.6.13-rc1/fs/inode.c	2005-06-30 14:04:03.000000000 -0500
@@ -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.13-rc1/include/linux/binfmts.h
===================================================================
--- linux-2.6.13-rc1.orig/include/linux/binfmts.h	2005-06-30 14:03:42.000000000 -0500
+++ linux-2.6.13-rc1/include/linux/binfmts.h	2005-06-30 14:04:03.000000000 -0500
@@ -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.13-rc1/include/linux/fs.h
===================================================================
--- linux-2.6.13-rc1.orig/include/linux/fs.h	2005-06-30 14:03:42.000000000 -0500
+++ linux-2.6.13-rc1/include/linux/fs.h	2005-06-30 14:04:03.000000000 -0500
@@ -480,7 +480,7 @@ struct inode {
 	unsigned int		i_flags;
 
 	atomic_t		i_writecount;
-	void			*i_security;
+	struct hlist_head	i_security;
 	union {
 		void		*generic_ip;
 	} u;
@@ -554,7 +554,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 */
 };
 
@@ -591,7 +591,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;
@@ -778,7 +778,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.13-rc1/include/linux/ipc.h
===================================================================
--- linux-2.6.13-rc1.orig/include/linux/ipc.h	2004-12-24 15:33:48.000000000 -0600
+++ linux-2.6.13-rc1/include/linux/ipc.h	2005-06-30 14:04:03.000000000 -0500
@@ -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.13-rc1/include/linux/msg.h
===================================================================
--- linux-2.6.13-rc1.orig/include/linux/msg.h	2004-12-24 15:34:57.000000000 -0600
+++ linux-2.6.13-rc1/include/linux/msg.h	2005-06-30 14:04:03.000000000 -0500
@@ -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.13-rc1/include/linux/sched.h
===================================================================
--- linux-2.6.13-rc1.orig/include/linux/sched.h	2005-06-30 14:03:42.000000000 -0500
+++ linux-2.6.13-rc1/include/linux/sched.h	2005-06-30 14:04:03.000000000 -0500
@@ -717,7 +717,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.13-rc1/include/net/sock.h
===================================================================
--- linux-2.6.13-rc1.orig/include/net/sock.h	2005-06-30 14:03:42.000000000 -0500
+++ linux-2.6.13-rc1/include/net/sock.h	2005-06-30 14:04:03.000000000 -0500
@@ -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.13-rc1/ipc/msg.c
===================================================================
--- linux-2.6.13-rc1.orig/ipc/msg.c	2005-06-30 14:03:13.000000000 -0500
+++ linux-2.6.13-rc1/ipc/msg.c	2005-06-30 14:04:03.000000000 -0500
@@ -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.13-rc1/ipc/msgutil.c
===================================================================
--- linux-2.6.13-rc1.orig/ipc/msgutil.c	2004-12-24 15:34:44.000000000 -0600
+++ linux-2.6.13-rc1/ipc/msgutil.c	2005-06-30 14:04:03.000000000 -0500
@@ -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.13-rc1/ipc/sem.c
===================================================================
--- linux-2.6.13-rc1.orig/ipc/sem.c	2005-06-30 14:03:42.000000000 -0500
+++ linux-2.6.13-rc1/ipc/sem.c	2005-06-30 14:04:03.000000000 -0500
@@ -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.13-rc1/ipc/shm.c
===================================================================
--- linux-2.6.13-rc1.orig/ipc/shm.c	2005-06-30 14:03:13.000000000 -0500
+++ linux-2.6.13-rc1/ipc/shm.c	2005-06-30 14:04:03.000000000 -0500
@@ -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.13-rc1/kernel/fork.c
===================================================================
--- linux-2.6.13-rc1.orig/kernel/fork.c	2005-06-30 14:03:42.000000000 -0500
+++ linux-2.6.13-rc1/kernel/fork.c	2005-06-30 14:04:03.000000000 -0500
@@ -939,7 +939,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] 57+ messages in thread

* [patch 3/12] lsm stacking v0.2: introduce security_*_value API
  2005-06-30 19:44 [patch 0/12] lsm stacking v0.2: intro serue
  2005-06-30 19:48 ` [patch 1/12] lsm stacking v0.2: don't default to dummy_##hook serue
  2005-06-30 19:48 ` [patch 2/12] lsm stacking v0.2: replace void* security with hlist serue
@ 2005-06-30 19:49 ` serue
  2005-06-30 19:49 ` [patch 4/12] lsm stacking v0.2: stacker documentation serue
                   ` (8 subsequent siblings)
  11 siblings, 0 replies; 57+ messages in thread
From: serue @ 2005-06-30 19:49 UTC (permalink / raw)
  To: lkml
  Cc: Chris Wright, Stephen Smalley, James Morris, Andrew Morton,
	Michael Halcrow, David Safford, Reiner Sailer, Gerrit Huizenga

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.13-rc1/include/linux/security-stack.h
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.13-rc1/include/linux/security-stack.h	2005-06-30 14:11:36.000000000 -0500
@@ -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.13-rc1/include/linux/security.h
===================================================================
--- linux-2.6.13-rc1.orig/include/linux/security.h	2005-06-30 14:03:13.000000000 -0500
+++ linux-2.6.13-rc1/include/linux/security.h	2005-06-30 14:11:36.000000000 -0500
@@ -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.13-rc1/security/security.c
===================================================================
--- linux-2.6.13-rc1.orig/security/security.c	2005-06-30 14:03:54.000000000 -0500
+++ linux-2.6.13-rc1/security/security.c	2005-06-30 14:11:36.000000000 -0500
@@ -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] 57+ messages in thread

* [patch 4/12] lsm stacking v0.2: stacker documentation
  2005-06-30 19:44 [patch 0/12] lsm stacking v0.2: intro serue
                   ` (2 preceding siblings ...)
  2005-06-30 19:49 ` [patch 3/12] lsm stacking v0.2: introduce security_*_value API serue
@ 2005-06-30 19:49 ` serue
  2005-06-30 19:50 ` [patch 5/12] lsm stacking v0.2: actual stacker module serue
                   ` (7 subsequent siblings)
  11 siblings, 0 replies; 57+ messages in thread
From: serue @ 2005-06-30 19:49 UTC (permalink / raw)
  To: lkml
  Cc: Chris Wright, Stephen Smalley, James Morris, Andrew Morton,
	Michael Halcrow, David Safford, Reiner Sailer, Gerrit Huizenga,
	emily

Add documentation about stacker and its usage.

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

Index: linux-2.6.13-rc1/Documentation/LSM-stacking.txt
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.13-rc1/Documentation/LSM-stacking.txt	2005-06-30 14:11:39.000000000 -0500
@@ -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] 57+ messages in thread

* [patch 5/12] lsm stacking v0.2: actual stacker module
  2005-06-30 19:44 [patch 0/12] lsm stacking v0.2: intro serue
                   ` (3 preceding siblings ...)
  2005-06-30 19:49 ` [patch 4/12] lsm stacking v0.2: stacker documentation serue
@ 2005-06-30 19:50 ` serue
  2005-07-01  2:32   ` James Morris
                     ` (3 more replies)
  2005-06-30 19:51 ` [patch 6/12] lsm stacking v0.2: stackable capability lsm serue
                   ` (6 subsequent siblings)
  11 siblings, 4 replies; 57+ messages in thread
From: serue @ 2005-06-30 19:50 UTC (permalink / raw)
  To: lkml
  Cc: Chris Wright, Stephen Smalley, James Morris, Andrew Morton,
	Michael Halcrow, David Safford, Reiner Sailer, Gerrit Huizenga

Adds the actual stacker LSM.

Changelog:
	1. Stack the dummy LSM by default whenever no other modules are
	loaded.

	2. When no modules are stacked which define security_vm_enough,
	use stacker_capable() rather than capable() so that
	PF_SUPERPRIV does not get automatically set.

	3. Register the stop_responding sysfs file which unregisters
	stacker's sysfs files to prevent LSMs being unloaded from now on.

	Thanks to Tony Jones for pointing the first two errors.

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

Index: linux-2.6.13-rc1/security/Kconfig
===================================================================
--- linux-2.6.13-rc1.orig/security/Kconfig	2005-06-30 15:32:15.000000000 -0500
+++ linux-2.6.13-rc1/security/Kconfig	2005-06-30 18:22:13.000000000 -0500
@@ -87,5 +87,11 @@ config SECURITY_SECLVL
 
 source security/selinux/Kconfig
 
+config SECURITY_STACKER
+	boolean "LSM Stacking"
+	depends on SECURITY
+	help
+	  Stack multiple LSMs.
+
 endmenu
 
Index: linux-2.6.13-rc1/security/Makefile
===================================================================
--- linux-2.6.13-rc1.orig/security/Makefile	2005-06-30 15:32:15.000000000 -0500
+++ linux-2.6.13-rc1/security/Makefile	2005-06-30 18:22:13.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.13-rc1/security/stacker.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.13-rc1/security/stacker.c	2005-06-30 18:28:37.000000000 -0500
@@ -0,0 +1,1495 @@
+/* "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;
+
+/*
+ * when !modules_registered, the default_module, defined
+ * below, will be stacked
+ */
+static short modules_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;
+static struct module_entry default_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;
+	int cap_sys_admin = 0;
+
+	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:
+	if (stacker_capable(current, CAP_SYS_ADMIN) == 0)
+		cap_sys_admin = 1;
+	result = __vm_enough_memory(pages, 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);
+
+	rcu_read_lock();
+	if (!modules_registered) {
+		modules_registered++;
+		list_del_rcu(&default_module.lsm_list);
+	}
+	list_add_tail_rcu(&new_module_entry->all_lsms, &all_modules);
+	list_add_tail_rcu(&new_module_entry->lsm_list, &stacked_modules);
+	if (strcmp(name, "selinux") == 0)
+		selinux_module = new_module_entry;
+	rcu_read_unlock();
+
+	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;
+
+	if (!modules_registered)
+		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;
+
+	rcu_read_lock();
+	list_del_rcu(&m->lsm_list);
+	if (list_empty(&stacked_modules)) {
+		INIT_LIST_HEAD(&default_module.lsm_list);
+		list_add_tail_rcu(&default_module.lsm_list, &stacked_modules);
+		modules_registered = 0;
+	}
+	rcu_read_unlock();
+
+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_stop_responding.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);
+
+extern struct security_operations dummy_security_ops;
+#define DEFAULT_MODULE_NAME "dummy"
+
+static int __init stacker_init (void)
+{
+	forbid_stacker_register = 0;
+	sysfsfiles_registered = 0;
+
+	INIT_LIST_HEAD(&stacked_modules);
+	INIT_LIST_HEAD(&all_modules);
+	spin_lock_init(&stacker_lock);
+	default_module.module_name = DEFAULT_MODULE_NAME;
+	default_module.namelen = strlen(DEFAULT_MODULE_NAME);
+	memcpy(&default_module.module_operations, &dummy_security_ops,
+			sizeof(struct security_operations));
+	INIT_LIST_HEAD(&default_module.lsm_list);
+	list_add_tail(&default_module.lsm_list, &stacked_modules);
+
+	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] 57+ messages in thread

* [patch 6/12] lsm stacking v0.2: stackable capability lsm
  2005-06-30 19:44 [patch 0/12] lsm stacking v0.2: intro serue
                   ` (4 preceding siblings ...)
  2005-06-30 19:50 ` [patch 5/12] lsm stacking v0.2: actual stacker module serue
@ 2005-06-30 19:51 ` serue
  2005-06-30 19:52 ` [patch 7/12] lsm stacking v0.2: selinux: update security structs serue
                   ` (5 subsequent siblings)
  11 siblings, 0 replies; 57+ messages in thread
From: serue @ 2005-06-30 19:51 UTC (permalink / raw)
  To: lkml
  Cc: Chris Wright, Stephen Smalley, James Morris, Andrew Morton,
	Michael Halcrow, David Safford, Reiner Sailer, Gerrit Huizenga

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>
---
 Kconfig         |   21 +++++++++++
 Makefile        |    1 
 cap_stack.c     |  101 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 selinux/Kconfig |    2 +
 4 files changed, 124 insertions(+), 1 deletion(-)

Index: linux-2.6.13-rc1/security/Kconfig
===================================================================
--- linux-2.6.13-rc1.orig/security/Kconfig	2005-06-30 15:32:43.000000000 -0500
+++ linux-2.6.13-rc1/security/Kconfig	2005-06-30 15:33:43.000000000 -0500
@@ -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.13-rc1/security/Makefile
===================================================================
--- linux-2.6.13-rc1.orig/security/Makefile	2005-06-30 15:32:43.000000000 -0500
+++ linux-2.6.13-rc1/security/Makefile	2005-06-30 15:32:47.000000000 -0500
@@ -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.13-rc1/security/cap_stack.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.13-rc1/security/cap_stack.c	2005-06-30 15:32:47.000000000 -0500
@@ -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.13-rc1/security/selinux/Kconfig
===================================================================
--- linux-2.6.13-rc1.orig/security/selinux/Kconfig	2005-06-30 14:15:01.000000000 -0500
+++ linux-2.6.13-rc1/security/selinux/Kconfig	2005-06-30 15:32:47.000000000 -0500
@@ -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] 57+ messages in thread

* [patch 7/12] lsm stacking v0.2: selinux: update security structs
  2005-06-30 19:44 [patch 0/12] lsm stacking v0.2: intro serue
                   ` (5 preceding siblings ...)
  2005-06-30 19:51 ` [patch 6/12] lsm stacking v0.2: stackable capability lsm serue
@ 2005-06-30 19:52 ` serue
  2005-06-30 19:53 ` [patch 8/12] lsm stacking v0.2: selinux: use security_*_value API serue
                   ` (4 subsequent siblings)
  11 siblings, 0 replies; 57+ messages in thread
From: serue @ 2005-06-30 19:52 UTC (permalink / raw)
  To: lkml
  Cc: Chris Wright, Stephen Smalley, James Morris, Andrew Morton,
	Michael Halcrow, David Safford, Reiner Sailer, Gerrit Huizenga

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>
---
 objsec.h |   19 +++++++++++--------
 1 files changed, 11 insertions(+), 8 deletions(-)

Index: linux-2.6.13-rc1/security/selinux/include/objsec.h
===================================================================
--- linux-2.6.13-rc1.orig/security/selinux/include/objsec.h	2005-06-30 15:32:49.000000000 -0500
+++ linux-2.6.13-rc1/security/selinux/include/objsec.h	2005-06-30 15:33:47.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] 57+ messages in thread

* [patch 8/12] lsm stacking v0.2: selinux: use security_*_value API
  2005-06-30 19:44 [patch 0/12] lsm stacking v0.2: intro serue
                   ` (6 preceding siblings ...)
  2005-06-30 19:52 ` [patch 7/12] lsm stacking v0.2: selinux: update security structs serue
@ 2005-06-30 19:53 ` serue
  2005-06-30 19:53 ` [patch 9/12] lsm stacking v0.2: selinux: remove secondary support serue
                   ` (3 subsequent siblings)
  11 siblings, 0 replies; 57+ messages in thread
From: serue @ 2005-06-30 19:53 UTC (permalink / raw)
  To: lkml
  Cc: Chris Wright, Stephen Smalley, James Morris, Andrew Morton,
	Michael Halcrow, David Safford, Reiner Sailer, Gerrit Huizenga

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>
---
 hooks.c     |  446 +++++++++++++++++++++++++++++++++++++++---------------------
 selinuxfs.c |   10 -
 2 files changed, 300 insertions(+), 156 deletions(-)

Index: linux-2.6.13-rc1/security/selinux/hooks.c
===================================================================
--- linux-2.6.13-rc1.orig/security/selinux/hooks.c	2005-06-30 14:15:01.000000000 -0500
+++ linux-2.6.13-rc1/security/selinux/hooks.c	2005-06-30 16:02:02.000000000 -0500
@@ -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,11 @@ static int selinux_bprm_secureexec (stru
 
 static void selinux_bprm_free_security(struct linux_binprm *bprm)
 {
-	kfree(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);
 }
 
 extern struct vfsmount *selinuxfs_mount;
@@ -1756,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;
@@ -1801,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 +2226,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 +2248,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 +2259,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 +2293,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 +2319,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 +2359,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 +2369,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 +2392,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;
 
@@ -2567,8 +2648,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;
@@ -2585,8 +2668,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 */
@@ -2620,12 +2705,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;
@@ -2778,7 +2865,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;
@@ -2787,8 +2875,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;
@@ -2956,8 +3049,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;
@@ -2979,7 +3074,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);
@@ -2994,9 +3090,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;
@@ -3034,8 +3132,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;
@@ -3113,7 +3213,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;
@@ -3167,9 +3268,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;
@@ -3229,8 +3332,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;
@@ -3242,11 +3347,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;
@@ -3260,8 +3367,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;
@@ -3301,7 +3410,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;
  		}
@@ -3384,13 +3494,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)
@@ -3429,7 +3541,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;
@@ -3495,7 +3610,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:
@@ -3605,7 +3721,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,
@@ -3629,15 +3746,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) {
@@ -3645,18 +3764,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);
 }
 
@@ -3669,21 +3788,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);
 }
 
@@ -3694,8 +3812,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;
@@ -3725,8 +3845,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;
@@ -3751,8 +3873,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;
@@ -3797,9 +3921,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
@@ -3845,9 +3972,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;
@@ -3872,8 +4002,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;
@@ -3898,8 +4030,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;
@@ -3971,8 +4105,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;
@@ -3997,8 +4133,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;
@@ -4132,7 +4270,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;
@@ -4207,7 +4346,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.13-rc1/security/selinux/selinuxfs.c
===================================================================
--- linux-2.6.13-rc1.orig/security/selinux/selinuxfs.c	2005-06-30 14:15:01.000000000 -0500
+++ linux-2.6.13-rc1/security/selinux/selinuxfs.c	2005-06-30 15:34:03.000000000 -0500
@@ -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;
 
@@ -982,7 +984,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;
@@ -1267,7 +1270,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] 57+ messages in thread

* [patch 9/12] lsm stacking v0.2: selinux: remove secondary support
  2005-06-30 19:44 [patch 0/12] lsm stacking v0.2: intro serue
                   ` (7 preceding siblings ...)
  2005-06-30 19:53 ` [patch 8/12] lsm stacking v0.2: selinux: use security_*_value API serue
@ 2005-06-30 19:53 ` serue
  2005-06-30 19:54 ` [patch 10/12] lsm stacking v0.2: hook completeness verification serue
                   ` (2 subsequent siblings)
  11 siblings, 0 replies; 57+ messages in thread
From: serue @ 2005-06-30 19:53 UTC (permalink / raw)
  To: lkml
  Cc: Chris Wright, Stephen Smalley, James Morris, Andrew Morton,
	Michael Halcrow, David Safford, Reiner Sailer, Gerrit Huizenga

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>
---
 hooks.c |  266 ++++++++--------------------------------------------------------
 1 files changed, 35 insertions(+), 231 deletions(-)

Index: linux-2.6.13-rc1/security/selinux/hooks.c
===================================================================
--- linux-2.6.13-rc1.orig/security/selinux/hooks.c	2005-06-30 16:02:02.000000000 -0500
+++ linux-2.6.13-rc1/security/selinux/hooks.c	2005-06-30 16:05:34.000000000 -0500
@@ -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,
@@ -2042,12 +1958,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);
@@ -2058,12 +1968,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);
 }
@@ -2092,11 +1996,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);
 }
 
@@ -2107,11 +2006,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);
 }
 
@@ -2142,12 +2036,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));
 }
 
@@ -2175,23 +2063,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;
@@ -2203,12 +2080,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;
 
@@ -2530,12 +2401,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;
 
@@ -2549,10 +2414,6 @@ static int selinux_file_mprotect(struct 
 {
 	int rc;
 
-	rc = secondary_ops->file_mprotect(vma, reqprot, prot);
-	if (rc)
-		return rc;
-
 	if (selinux_checkreqprot)
 		prot = reqprot;
 
@@ -2575,7 +2436,7 @@ static int selinux_file_mprotect(struct 
 		 * check ability to execute the possibly modified content.
 		 * This typically should only occur for text relocations.
 		 */
-		int rc = file_has_perm(current, vma->vm_file, FILE__EXECMOD);
+		rc = file_has_perm(current, vma->vm_file, FILE__EXECMOD);
 		if (rc)
 			return rc;
 	}
@@ -2691,12 +2552,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);
 }
 
@@ -2745,11 +2600,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. */
@@ -2779,24 +2629,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
@@ -2820,11 +2658,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)))
@@ -2863,8 +2696,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;
@@ -3328,10 +3159,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,
@@ -3715,11 +3542,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);
@@ -3735,13 +3558,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)
@@ -4079,11 +3895,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;
@@ -4219,32 +4030,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)
@@ -4407,23 +4198,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,
@@ -4480,7 +4267,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,
@@ -4552,10 +4338,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;
@@ -4566,22 +4354,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;
 }
 
@@ -4691,6 +4487,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. */
@@ -4706,8 +4503,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] 57+ messages in thread

* [patch 10/12] lsm stacking v0.2: hook completeness verification
  2005-06-30 19:44 [patch 0/12] lsm stacking v0.2: intro serue
                   ` (8 preceding siblings ...)
  2005-06-30 19:53 ` [patch 9/12] lsm stacking v0.2: selinux: remove secondary support serue
@ 2005-06-30 19:54 ` serue
  2005-06-30 19:55 ` [patch 11/12] lsm stacking v0.2: /proc/$$/attr/ sharing serue
  2005-06-30 19:55 ` [patch 12/12] lsm stacking v0.2: update seclvl for stacking serue
  11 siblings, 0 replies; 57+ messages in thread
From: serue @ 2005-06-30 19:54 UTC (permalink / raw)
  To: lkml
  Cc: Chris Wright, Stephen Smalley, James Morris, Andrew Morton,
	Michael Halcrow, David Safford, Reiner Sailer, Gerrit Huizenga

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.13-rc1/include/linux/security.h
===================================================================
--- linux-2.6.13-rc1.orig/include/linux/security.h	2005-06-30 14:15:01.000000000 -0500
+++ linux-2.6.13-rc1/include/linux/security.h	2005-06-30 15:40:16.000000000 -0500
@@ -121,6 +121,10 @@ struct swap_info_struct;
 /**
  * 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.13-rc1/scripts/lsm_verify_hooks.sh
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6.13-rc1/scripts/lsm_verify_hooks.sh	2005-06-30 15:40:16.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] 57+ messages in thread

* [patch 11/12] lsm stacking v0.2: /proc/$$/attr/ sharing
  2005-06-30 19:44 [patch 0/12] lsm stacking v0.2: intro serue
                   ` (9 preceding siblings ...)
  2005-06-30 19:54 ` [patch 10/12] lsm stacking v0.2: hook completeness verification serue
@ 2005-06-30 19:55 ` serue
  2005-06-30 19:55 ` [patch 12/12] lsm stacking v0.2: update seclvl for stacking serue
  11 siblings, 0 replies; 57+ messages in thread
From: serue @ 2005-06-30 19:55 UTC (permalink / raw)
  To: lkml
  Cc: Chris Wright, Stephen Smalley, James Morris, Andrew Morton,
	Michael Halcrow, David Safford, Reiner Sailer, Gerrit Huizenga

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>
---
 stacker.c |  125 +++++++++++++++++++++++++++++++++++++++++++++++++-------------
 1 files changed, 100 insertions(+), 25 deletions(-)

Index: linux-2.6.13-rc1/security/stacker.c
===================================================================
--- linux-2.6.13-rc1.orig/security/stacker.c	2005-06-30 15:32:43.000000000 -0500
+++ linux-2.6.13-rc1/security/stacker.c	2005-06-30 15:40:19.000000000 -0500
@@ -966,24 +966,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);
 }
 
 /*
@@ -1048,23 +1140,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] 57+ messages in thread

* [patch 12/12] lsm stacking v0.2: update seclvl for stacking
  2005-06-30 19:44 [patch 0/12] lsm stacking v0.2: intro serue
                   ` (10 preceding siblings ...)
  2005-06-30 19:55 ` [patch 11/12] lsm stacking v0.2: /proc/$$/attr/ sharing serue
@ 2005-06-30 19:55 ` serue
  11 siblings, 0 replies; 57+ messages in thread
From: serue @ 2005-06-30 19:55 UTC (permalink / raw)
  To: lkml
  Cc: Chris Wright, Stephen Smalley, James Morris, Andrew Morton,
	Michael Halcrow, David Safford, Reiner Sailer, Gerrit Huizenga

Add stacking support to the seclvl module.

Signed-off-by: Serge Hallyn <serue@us.ibm.com>
---
 seclvl.c |  101 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------
 1 files changed, 91 insertions(+), 10 deletions(-)

Index: linux-2.6.13-rc1/security/seclvl.c
===================================================================
--- linux-2.6.13-rc1.orig/security/seclvl.c	2005-06-30 18:22:12.000000000 -0500
+++ linux-2.6.13-rc1/security/seclvl.c	2005-06-30 18:32:38.000000000 -0500
@@ -21,6 +21,7 @@
 #include <linux/kernel.h>
 #include <linux/init.h>
 #include <linux/security.h>
+#include <linux/security-stack.h>
 #include <linux/netlink.h>
 #include <linux/fs.h>
 #include <linux/namei.h>
@@ -35,6 +36,7 @@
 #include <linux/sysfs.h>
 
 #define SHA1_DIGEST_SIZE 20
+#define SECLVL_LSM_ID 0xF45
 
 /**
  * Module parameter that defines the initial secure level.
@@ -485,12 +487,39 @@ static int seclvl_settime(struct timespe
 	return 0;
 }
 
+/*
+ * A structure which is stored with the inode when a process
+ * has a unmounted block device open for writing.
+ */
+struct seclvl_i_sec {
+	struct security_list lsm_list;
+	struct task_struct *task;
+	spinlock_t spinlock;
+};
+
+static void seclvl_inode_free(struct inode *inode)
+{
+	struct seclvl_i_sec *isec;
+
+	isec = security_del_value_type(&inode->i_security, SECLVL_LSM_ID,
+				struct seclvl_i_sec);
+	if (isec) {
+		if (isec->task == current)
+			isec->task = NULL;
+		kfree(isec);
+	}
+}
+
 /* claim the blockdev to exclude mounters, release on file close */
-static int seclvl_bd_claim(struct inode *inode)
+static int seclvl_bd_claim(struct inode *inode, struct seclvl_i_sec *isec)
 {
 	int holder;
 	struct block_device *bdev = NULL;
 	dev_t dev = inode->i_rdev;
+
+	if (isec->task && isec->task != current)
+		return -EPERM;
+
 	bdev = open_by_devnum(dev, FMODE_WRITE);
 	if (bdev) {
 		if (bd_claim(bdev, &holder)) {
@@ -498,7 +527,7 @@ static int seclvl_bd_claim(struct inode 
 			return -EPERM;
 		}
 		/* claimed, mark it to release on close */
-		inode->i_security = current;
+		isec->task = current;
 	}
 	return 0;
 }
@@ -506,16 +535,59 @@ static int seclvl_bd_claim(struct inode 
 /* release the blockdev if you claimed it */
 static void seclvl_bd_release(struct inode *inode)
 {
-	if (inode && S_ISBLK(inode->i_mode) && inode->i_security == current) {
-		struct block_device *bdev = inode->i_bdev;
-		if (bdev) {
-			bd_release(bdev);
-			blkdev_put(bdev);
-			inode->i_security = NULL;
-		}
+	struct seclvl_i_sec *isec;
+
+	if (inode && S_ISBLK(inode->i_mode)) {
+		isec = security_get_value_type(&inode->i_security,
+				SECLVL_LSM_ID, struct seclvl_i_sec);
+		if (!isec)
+			return;
+		spin_lock(&isec->spinlock);
+		if (isec->task == current) {
+			struct block_device *bdev = inode->i_bdev;
+			if (bdev) {
+				bd_release(bdev);
+				blkdev_put(bdev);
+				isec->task = NULL;
+			}
+ 		}
+		spin_unlock(&isec->spinlock);
 	}
 }
 
+static DEFINE_SPINLOCK(seclvl_new_isec_lock);
+
+/**
+ * Either returns the existing inode isec, or creates a new
+ * isec, places it on the inode->i_security list, and returns
+ * it.
+ * On error, return NULL.
+ */
+static struct seclvl_i_sec *
+seclvl_inode_get_or_alloc(struct inode *inode)
+{
+	struct seclvl_i_sec *isec;
+
+	isec = security_get_value_type(&inode->i_security,
+			SECLVL_LSM_ID, struct seclvl_i_sec);
+	if (isec)
+		return isec;
+	spin_lock(&seclvl_new_isec_lock);
+	isec = security_get_value_type(&inode->i_security,
+			SECLVL_LSM_ID, struct seclvl_i_sec);
+	if (isec)
+		goto out;
+	isec = kmalloc(sizeof(struct seclvl_i_sec), GFP_KERNEL);
+	if (!isec)
+		goto out;
+	spin_lock_init(&isec->spinlock);
+	security_add_value_type(&inode->i_security, SECLVL_LSM_ID, isec);
+
+out:
+	spin_unlock(&seclvl_new_isec_lock);
+	return isec;
+}
+
 /**
  * Security for writes to block devices is regulated by this seclvl
  * function.  Deny all writes to block devices in seclvl 2.  In
@@ -524,6 +596,8 @@ static void seclvl_bd_release(struct ino
 static int
 seclvl_inode_permission(struct inode *inode, int mask, struct nameidata *nd)
 {
+	struct seclvl_i_sec *isec;
+
 	if (current->pid != 1 && S_ISBLK(inode->i_mode) && (mask & MAY_WRITE)) {
 		switch (seclvl) {
 		case 2:
@@ -531,13 +605,19 @@ seclvl_inode_permission(struct inode *in
 				      "denied in secure level [%d]\n", seclvl);
 			return -EPERM;
 		case 1:
-			if (seclvl_bd_claim(inode)) {
+			isec = seclvl_inode_get_or_alloc(inode);
+			if (!isec)
+				return -ENOMEM;
+			spin_lock(&isec->spinlock);
+			if (seclvl_bd_claim(inode, isec)) {
 				seclvl_printk(1, KERN_WARNING,
 					      "Write to mounted block device "
 					      "denied in secure level [%d]\n",
 					      seclvl);
+				spin_unlock(&isec->spinlock);
 				return -EPERM;
 			}
+			spin_unlock(&isec->spinlock);
 		}
 	}
 	return 0;
@@ -595,6 +675,7 @@ static struct security_operations seclvl
 	.capable = seclvl_capable,
 	.inode_permission = seclvl_inode_permission,
 	.inode_setattr = seclvl_inode_setattr,
+	.inode_free_security = seclvl_inode_free,
 	.file_free_security = seclvl_file_free_security,
 	.settime = seclvl_settime,
 	.sb_umount = seclvl_umount,

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

* Re: [patch 5/12] lsm stacking v0.2: actual stacker module
  2005-06-30 19:50 ` [patch 5/12] lsm stacking v0.2: actual stacker module serue
@ 2005-07-01  2:32   ` James Morris
  2005-07-01 19:24     ` serge
  2005-07-01 20:35   ` Greg KH
                     ` (2 subsequent siblings)
  3 siblings, 1 reply; 57+ messages in thread
From: James Morris @ 2005-07-01  2:32 UTC (permalink / raw)
  To: serue
  Cc: lkml, Chris Wright, Stephen Smalley, Andrew Morton,
	Michael Halcrow, David Safford, Reiner Sailer, Gerrit Huizenga

On Thu, 30 Jun 2005 serue@us.ibm.com wrote:

> +/* 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;
> +}
> +

As far as I'm aware, sysfs nodes are supposed to contain one entity per 
file.  Not sure what the alternative here is, though.


- James
-- 
James Morris
<jmorris@redhat.com>



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

* Re: [patch 5/12] lsm stacking v0.2: actual stacker module
  2005-07-01  2:32   ` James Morris
@ 2005-07-01 19:24     ` serge
  0 siblings, 0 replies; 57+ messages in thread
From: serge @ 2005-07-01 19:24 UTC (permalink / raw)
  To: greg, James Morris
  Cc: lkml, Chris Wright, Stephen Smalley, Andrew Morton,
	Michael Halcrow, David Safford, Reiner Sailer, Gerrit Huizenga

Quoting James Morris (jmorris@redhat.com):
> On Thu, 30 Jun 2005 serue@us.ibm.com wrote:
> 
> > +/* 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;
> > +}
> > +
> 
> As far as I'm aware, sysfs nodes are supposed to contain one entity per 
> file.  Not sure what the alternative here is, though.

Thanks James, good point.

Documentation/filesystems/sysfs.txt seems a little soft on the issue,
saying it's "preferable".  So just to make sure:

Greg, should stacker be using its own filesystem?  There are 4
files:

	stop_responding: takes one input ("1")
	unload: takes one string
	lockdown: takes one input ("1")
	list_modules: outputs a list of strings, ie
		selinux
		cap_stack
	under a patched fedora kernel.

thanks,
-serge

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

* Re: [patch 5/12] lsm stacking v0.2: actual stacker module
  2005-06-30 19:50 ` [patch 5/12] lsm stacking v0.2: actual stacker module serue
  2005-07-01  2:32   ` James Morris
@ 2005-07-01 20:35   ` Greg KH
  2005-07-03  0:24     ` serge
  2005-07-04  3:18   ` [patch 5/12] lsm stacking v0.2: actual stacker module Tony Jones
  2005-07-11 14:40   ` Stephen Smalley
  3 siblings, 1 reply; 57+ messages in thread
From: Greg KH @ 2005-07-01 20:35 UTC (permalink / raw)
  To: serue
  Cc: lkml, Chris Wright, Stephen Smalley, James Morris, Andrew Morton,
	Michael Halcrow, David Safford, Reiner Sailer, Gerrit Huizenga

On Thu, Jun 30, 2005 at 02:50:43PM -0500, serue@us.ibm.com wrote:
> +/* variables to hold kobject/sysfs data */
> +static struct subsystem stacker_subsys;

Use decl_subsys please.

And yes, James is right, only value per sysfs file is allowed.

> +	result = subsystem_register(&stacker_subsys);

Why are you putting this at the root of sysfs.  It should go in
/sys/kernel/security/ right?  Please put it there.

> +	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_stop_responding.attr);
> +	sysfs_create_file(&stacker_subsys.kset.kobj,
> +			&stacker_attr_unload.attr);

Hm, I think those functions return error values, you might want to check
them...

> +	sysfsfiles_registered = 1;

Why?  You know if this works or not, otherwise you would have failed
here.

> +	printk(KERN_NOTICE "LSM stacker registered as the primary "
> +			   "security module\n");

And everyone really wants to see this in their logs?

> +	if (unregister_security (&stacker_ops))
> +		printk(KERN_WARNING "Error unregistering LSM stacker.\n");
> +	else
> +		printk(KERN_WARNING "LSM stacker removed.\n");

Same here as above...

thanks,

greg k-h

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

* Re: [patch 5/12] lsm stacking v0.2: actual stacker module
  2005-07-01 20:35   ` Greg KH
@ 2005-07-03  0:24     ` serge
  2005-07-03 18:25       ` Tony Jones
  0 siblings, 1 reply; 57+ messages in thread
From: serge @ 2005-07-03  0:24 UTC (permalink / raw)
  To: Greg KH
  Cc: serue, lkml, Chris Wright, Stephen Smalley, James Morris,
	Andrew Morton, Michael Halcrow, David Safford, Reiner Sailer,
	Gerrit Huizenga

Thanks for all your comments.

Quoting Greg KH (greg@kroah.com):
> On Thu, Jun 30, 2005 at 02:50:43PM -0500, serue@us.ibm.com wrote:
> > +/* variables to hold kobject/sysfs data */
> > +static struct subsystem stacker_subsys;
> 
> Use decl_subsys please.
> 
> And yes, James is right, only value per sysfs file is allowed.

Hmm, I could instead have one file per loaded LSM, which could
obviate the need for the stacker/unload file, but that would make
it more work for a user to find the ordering of the LSMs.  I wonder
how much that would matter.

I'll implement your other changes, and consider switching to a
stackerfs (versus changing the content presentation under sysfs).

thanks,
-serge

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

* Re: [patch 5/12] lsm stacking v0.2: actual stacker module
  2005-07-03  0:24     ` serge
@ 2005-07-03 18:25       ` Tony Jones
  2005-07-03 18:53         ` James Morris
  0 siblings, 1 reply; 57+ messages in thread
From: Tony Jones @ 2005-07-03 18:25 UTC (permalink / raw)
  To: serge
  Cc: Greg KH, serue, lkml, Chris Wright, Stephen Smalley,
	James Morris, Andrew Morton, Michael Halcrow, David Safford,
	Reiner Sailer, Gerrit Huizenga

On Sat, Jul 02, 2005 at 07:24:41PM -0500, serge@hallyn.com wrote:
> Hmm, I could instead have one file per loaded LSM, which could
> obviate the need for the stacker/unload file, but that would make
> it more work for a user to find the ordering of the LSMs.  I wonder
> how much that would matter.
> 
> I'll implement your other changes, and consider switching to a
> stackerfs (versus changing the content presentation under sysfs).

I'd prefer each file (per loaded LSM) when read returned it's ordering
position, even though it's much clumsier than your current implementation.

There just isn't enough content to justify a stacker specific filesystem IMHO.

Tony

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

* Re: [patch 5/12] lsm stacking v0.2: actual stacker module
  2005-07-03 18:25       ` Tony Jones
@ 2005-07-03 18:53         ` James Morris
  2005-07-03 19:09           ` Tony Jones
  2005-07-03 20:44           ` [PATCH] securityfs Greg KH
  0 siblings, 2 replies; 57+ messages in thread
From: James Morris @ 2005-07-03 18:53 UTC (permalink / raw)
  To: Tony Jones
  Cc: serge, Greg KH, serue, lkml, Chris Wright, Stephen Smalley,
	Andrew Morton, Michael Halcrow, David Safford, Reiner Sailer,
	Gerrit Huizenga

On Sun, 3 Jul 2005, Tony Jones wrote:

> There just isn't enough content to justify a stacker specific filesystem IMHO.

It might be worth thinking about a more general securityfs as part of LSM,
to be used by stacker and LSM modules.  SELinux could use this instead of
managing its own selinuxfs.


- James
-- 
James Morris
<jmorris@redhat.com>



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

* Re: [patch 5/12] lsm stacking v0.2: actual stacker module
  2005-07-03 18:53         ` James Morris
@ 2005-07-03 19:09           ` Tony Jones
  2005-07-03 20:44           ` [PATCH] securityfs Greg KH
  1 sibling, 0 replies; 57+ messages in thread
From: Tony Jones @ 2005-07-03 19:09 UTC (permalink / raw)
  To: James Morris
  Cc: Tony Jones, serge, Greg KH, serue, lkml, Chris Wright,
	Stephen Smalley, Andrew Morton, Michael Halcrow, David Safford,
	Reiner Sailer, Gerrit Huizenga

On Sun, Jul 03, 2005 at 02:53:17PM -0400, James Morris wrote:

> It might be worth thinking about a more general securityfs as part of LSM,
> to be used by stacker and LSM modules.  SELinux could use this instead of
> managing its own selinuxfs.

Good idea.   In the case of stacked modules each with a custom fs, having them
be part of a common hierarchy makes a lot of sense.

I'm assuming you are advocating for adding LSM support to provide some level 
of consistency in presentation rather than it _just_ being a new mount point
for every module to live under?

Take the discussion to the LSM list?

Thanks!

Tony

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

* [PATCH] securityfs
  2005-07-03 18:53         ` James Morris
  2005-07-03 19:09           ` Tony Jones
@ 2005-07-03 20:44           ` Greg KH
  2005-07-04 12:39             ` serge
                               ` (3 more replies)
  1 sibling, 4 replies; 57+ messages in thread
From: Greg KH @ 2005-07-03 20:44 UTC (permalink / raw)
  To: James Morris
  Cc: Tony Jones, serge, serue, lkml, Chris Wright, Stephen Smalley,
	Andrew Morton, Michael Halcrow, David Safford, Reiner Sailer,
	Gerrit Huizenga

On Sun, Jul 03, 2005 at 02:53:17PM -0400, James Morris wrote:
> On Sun, 3 Jul 2005, Tony Jones wrote:
> 
> > There just isn't enough content to justify a stacker specific filesystem IMHO.
> 
> It might be worth thinking about a more general securityfs as part of LSM,
> to be used by stacker and LSM modules.  SELinux could use this instead of
> managing its own selinuxfs.

Good idea.  Here's a patch to do just that (compile tested only...)

Comments?

thanks,

greg k-h


 include/linux/security.h |    5 
 security/Makefile        |    2 
 security/inode.c         |  336 +++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 342 insertions(+), 1 deletion(-)

Index: gregkh-2.6/security/Makefile
===================================================================
--- gregkh-2.6.orig/security/Makefile	2005-06-17 12:48:29.000000000 -0700
+++ gregkh-2.6/security/Makefile	2005-07-03 13:26:39.000000000 -0700
@@ -11,7 +11,7 @@
 endif
 
 # Object file lists
-obj-$(CONFIG_SECURITY)			+= security.o dummy.o
+obj-$(CONFIG_SECURITY)			+= security.o dummy.o inode.o
 # 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
Index: gregkh-2.6/security/inode.c
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ gregkh-2.6/security/inode.c	2005-07-03 13:41:43.000000000 -0700
@@ -0,0 +1,336 @@
+/*
+ *  inode.c - part of securityfs
+ *
+ *  Copyright (C) 2004 Greg Kroah-Hartman <greg@kroah.com>
+ *  Copyright (C) 2004 IBM Inc.
+ *
+ *	This program is free software; you can redistribute it and/or
+ *	modify it under the terms of the GNU General Public License version
+ *	2 as published by the Free Software Foundation.
+ *
+ */
+
+/* #define DEBUG */
+#include <linux/config.h>
+#include <linux/module.h>
+#include <linux/fs.h>
+#include <linux/mount.h>
+#include <linux/pagemap.h>
+#include <linux/init.h>
+#include <linux/namei.h>
+#include <linux/security.h>
+
+#define SECURITYFS_MAGIC	0x73636673
+
+static struct vfsmount *mount;
+static int mount_count;
+
+static ssize_t default_read_file(struct file *file, char __user *buf,
+				 size_t count, loff_t *ppos)
+{
+	return 0;
+}
+
+static ssize_t default_write_file(struct file *file, const char __user *buf,
+				   size_t count, loff_t *ppos)
+{
+	return count;
+}
+
+static int default_open(struct inode *inode, struct file *file)
+{
+	if (inode->u.generic_ip)
+		file->private_data = inode->u.generic_ip;
+
+	return 0;
+}
+
+static struct file_operations default_file_ops = {
+	.read =		default_read_file,
+	.write =	default_write_file,
+	.open =		default_open,
+};
+
+static struct inode *get_inode(struct super_block *sb, int mode, dev_t dev)
+{
+	struct inode *inode = new_inode(sb);
+
+	if (inode) {
+		inode->i_mode = mode;
+		inode->i_uid = 0;
+		inode->i_gid = 0;
+		inode->i_blksize = PAGE_CACHE_SIZE;
+		inode->i_blocks = 0;
+		inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME;
+		switch (mode & S_IFMT) {
+		default:
+			init_special_inode(inode, mode, dev);
+			break;
+		case S_IFREG:
+			inode->i_fop = &default_file_ops;
+			break;
+		case S_IFDIR:
+			inode->i_op = &simple_dir_inode_operations;
+			inode->i_fop = &simple_dir_operations;
+
+			/* directory inodes start off with i_nlink == 2 (for "." entry) */
+			inode->i_nlink++;
+			break;
+		}
+	}
+	return inode;
+}
+
+/* SMP-safe */
+static int mknod(struct inode *dir, struct dentry *dentry,
+			 int mode, dev_t dev)
+{
+	struct inode *inode = get_inode(dir->i_sb, mode, dev);
+	int error = -EPERM;
+
+	if (dentry->d_inode)
+		return -EEXIST;
+
+	if (inode) {
+		d_instantiate(dentry, inode);
+		dget(dentry);
+		error = 0;
+	}
+	return error;
+}
+
+static int mkdir(struct inode *dir, struct dentry *dentry, int mode)
+{
+	int res;
+
+	mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR;
+	res = mknod(dir, dentry, mode, 0);
+	if (!res)
+		dir->i_nlink++;
+	return res;
+}
+
+static int create(struct inode *dir, struct dentry *dentry, int mode)
+{
+	mode = (mode & S_IALLUGO) | S_IFREG;
+	return mknod(dir, dentry, mode, 0);
+}
+
+static inline int positive(struct dentry *dentry)
+{
+	return dentry->d_inode && !d_unhashed(dentry);
+}
+
+static int fill_super(struct super_block *sb, void *data, int silent)
+{
+	static struct tree_descr files[] = {{""}};
+
+	return simple_fill_super(sb, SECURITYFS_MAGIC, files);
+}
+
+static struct super_block *get_sb(struct file_system_type *fs_type,
+				        int flags, const char *dev_name,
+					void *data)
+{
+	return get_sb_single(fs_type, flags, data, fill_super);
+}
+
+static struct file_system_type fs_type = {
+	.owner =	THIS_MODULE,
+	.name =		"securityfs",
+	.get_sb =	get_sb,
+	.kill_sb =	kill_litter_super,
+};
+
+static int create_by_name(const char *name, mode_t mode,
+			  struct dentry *parent,
+			  struct dentry **dentry)
+{
+	int error = 0;
+
+	/* If the parent is not specified, we create it in the root.
+	 * We need the root dentry to do this, which is in the super
+	 * block. A pointer to that is in the struct vfsmount that we
+	 * have around.
+	 */
+	if (!parent ) {
+		if (mount && mount->mnt_sb) {
+			parent = mount->mnt_sb->s_root;
+		}
+	}
+	if (!parent) {
+		pr_debug("securityfs: Ah! can not find a parent!\n");
+		return -EFAULT;
+	}
+
+	*dentry = NULL;
+	down(&parent->d_inode->i_sem);
+	*dentry = lookup_one_len(name, parent, strlen(name));
+	if (!IS_ERR(dentry)) {
+		if ((mode & S_IFMT) == S_IFDIR)
+			error = mkdir(parent->d_inode, *dentry, mode);
+		else
+			error = create(parent->d_inode, *dentry, mode);
+	} else
+		error = PTR_ERR(dentry);
+	up(&parent->d_inode->i_sem);
+
+	return error;
+}
+
+/**
+ * securityfs_create_file - create a file in the securityfs filesystem
+ *
+ * @name: a pointer to a string containing the name of the file to create.
+ * @mode: the permission that the file should have
+ * @parent: a pointer to the parent dentry for this file.  This should be a
+ *          directory dentry if set.  If this paramater is NULL, then the
+ *          file will be created in the root of the securityfs filesystem.
+ * @data: a pointer to something that the caller will want to get to later
+ *        on.  The inode.u.generic_ip pointer will point to this value on
+ *        the open() call.
+ * @fops: a pointer to a struct file_operations that should be used for
+ *        this file.
+ *
+ * This is the basic "create a file" function for securityfs.  It allows for a
+ * wide range of flexibility in createing a file, or a directory (if you
+ * want to create a directory, the securityfs_create_dir() function is
+ * recommended to be used instead.)
+ *
+ * This function will return a pointer to a dentry if it succeeds.  This
+ * pointer must be passed to the securityfs_remove() function when the file is
+ * to be removed (no automatic cleanup happens if your module is unloaded,
+ * you are responsible here.)  If an error occurs, NULL will be returned.
+ *
+ * If securityfs is not enabled in the kernel, the value -ENODEV will be
+ * returned.  It is not wise to check for this value, but rather, check for
+ * NULL or !NULL instead as to eliminate the need for #ifdef in the calling
+ * code.
+ */
+struct dentry *securityfs_create_file(const char *name, mode_t mode,
+				   struct dentry *parent, void *data,
+				   struct file_operations *fops)
+{
+	struct dentry *dentry = NULL;
+	int error;
+
+	pr_debug("securityfs: creating file '%s'\n",name);
+
+	error = simple_pin_fs("securityfs", &mount, &mount_count);
+	if (error)
+		goto exit;
+
+	error = create_by_name(name, mode, parent, &dentry);
+	if (error) {
+		dentry = NULL;
+		goto exit;
+	}
+
+	if (dentry->d_inode) {
+		if (data)
+			dentry->d_inode->u.generic_ip = data;
+		if (fops)
+			dentry->d_inode->i_fop = fops;
+	}
+exit:
+	return dentry;
+}
+EXPORT_SYMBOL_GPL(securityfs_create_file);
+
+/**
+ * securityfs_create_dir - create a directory in the securityfs filesystem
+ *
+ * @name: a pointer to a string containing the name of the directory to
+ *        create.
+ * @parent: a pointer to the parent dentry for this file.  This should be a
+ *          directory dentry if set.  If this paramater is NULL, then the
+ *          directory will be created in the root of the securityfs filesystem.
+ *
+ * This function creates a directory in securityfs with the given name.
+ *
+ * This function will return a pointer to a dentry if it succeeds.  This
+ * pointer must be passed to the securityfs_remove() function when the file is
+ * to be removed (no automatic cleanup happens if your module is unloaded,
+ * you are responsible here.)  If an error occurs, NULL will be returned.
+ *
+ * If securityfs is not enabled in the kernel, the value -ENODEV will be
+ * returned.  It is not wise to check for this value, but rather, check for
+ * NULL or !NULL instead as to eliminate the need for #ifdef in the calling
+ * code.
+ */
+struct dentry *securityfs_create_dir(const char *name, struct dentry *parent)
+{
+	return securityfs_create_file(name,
+				      S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
+				      parent, NULL, NULL);
+}
+EXPORT_SYMBOL_GPL(securityfs_create_dir);
+
+/**
+ * securityfs_remove - removes a file or directory from the securityfs filesystem
+ *
+ * @dentry: a pointer to a the dentry of the file or directory to be
+ *          removed.
+ *
+ * This function removes a file or directory in securityfs that was previously
+ * created with a call to another securityfs function (like
+ * securityfs_create_file() or variants thereof.)
+ *
+ * This function is required to be called in order for the file to be
+ * removed, no automatic cleanup of files will happen when a module is
+ * removed, you are responsible here.
+ */
+void securityfs_remove(struct dentry *dentry)
+{
+	struct dentry *parent;
+
+	if (!dentry)
+		return;
+
+	parent = dentry->d_parent;
+	if (!parent || !parent->d_inode)
+		return;
+
+	down(&parent->d_inode->i_sem);
+	if (positive(dentry)) {
+		if (dentry->d_inode) {
+			if (S_ISDIR(dentry->d_inode->i_mode))
+				simple_rmdir(parent->d_inode, dentry);
+			else
+				simple_unlink(parent->d_inode, dentry);
+		dput(dentry);
+		}
+	}
+	up(&parent->d_inode->i_sem);
+	simple_release_fs(&mount, &mount_count);
+}
+EXPORT_SYMBOL_GPL(securityfs_remove);
+
+static decl_subsys(security, NULL, NULL);
+
+static int __init securityfs_init(void)
+{
+	int retval;
+
+	kset_set_kset_s(&security_subsys, kernel_subsys);
+	retval = subsystem_register(&security_subsys);
+	if (retval)
+		return retval;
+
+	retval = register_filesystem(&fs_type);
+	if (retval)
+		subsystem_unregister(&security_subsys);
+	return retval;
+}
+
+static void __exit securityfs_exit(void)
+{
+	simple_release_fs(&mount, &mount_count);
+	unregister_filesystem(&fs_type);
+	subsystem_unregister(&security_subsys);
+}
+
+core_initcall(securityfs_init);
+module_exit(securityfs_exit);
+MODULE_LICENSE("GPL");
+
Index: gregkh-2.6/include/linux/security.h
===================================================================
--- gregkh-2.6.orig/include/linux/security.h	2005-06-17 12:48:29.000000000 -0700
+++ gregkh-2.6/include/linux/security.h	2005-07-03 13:37:52.000000000 -0700
@@ -1983,6 +1983,11 @@
 extern int unregister_security	(struct security_operations *ops);
 extern int mod_reg_security	(const char *name, struct security_operations *ops);
 extern int mod_unreg_security	(const char *name, struct security_operations *ops);
+extern struct dentry *securityfs_create_file(const char *name, mode_t mode,
+					     struct dentry *parent, void *data,
+					     struct file_operations *fops);
+extern struct dentry *securityfs_create_dir(const char *name, struct dentry *parent);
+extern void securityfs_remove(struct dentry *dentry);
 
 
 #else /* CONFIG_SECURITY */

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

* Re: [patch 5/12] lsm stacking v0.2: actual stacker module
  2005-06-30 19:50 ` [patch 5/12] lsm stacking v0.2: actual stacker module serue
  2005-07-01  2:32   ` James Morris
  2005-07-01 20:35   ` Greg KH
@ 2005-07-04  3:18   ` Tony Jones
  2005-07-04 11:51     ` serge
  2005-07-08 21:43     ` serue
  2005-07-11 14:40   ` Stephen Smalley
  3 siblings, 2 replies; 57+ messages in thread
From: Tony Jones @ 2005-07-04  3:18 UTC (permalink / raw)
  To: serue; +Cc: lkml

[-- Attachment #1: Type: text/plain, Size: 1107 bytes --]

Hey Serge,

I don't think your symbol_get() is doing what you think it is ;-)

> + * 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)
> +{
 ...
> +	symbol_get(ops);
> +
> +out:
> +	spin_unlock(&stacker_lock);
> +	return ret;
> +}


Seemed useful to be able to view which modules had been unloaded.
Easier to maintain them on their own list than to compute the difference
of <stacked_modules> and <all_modules>.  Patch attached, not sure if you
are cool with reusing the 'unload' file.

> +static struct stacker_attribute stacker_attr_unload = {
> +	.attr = {.name = "unload", .mode = S_IFREG | S_IRUGO | S_IWUSR},
> +	.store = stacker_unload_write,
> +};


Apart from this, looks good.  I ran it against our regression tests using
AppArmor (SubDomain) composed with Capability and everything was functionally
as expected.   I still need to run it through our SMP stress tests.

Thanks

Tony

[-- Attachment #2: stacker_v2.diff --]
[-- Type: text/plain, Size: 1579 bytes --]

--- stacker.c.orig	2005-07-03 19:57:21.000000000 -0700
+++ stacker.c	2005-07-03 19:55:40.000000000 -0700
@@ -39,6 +39,7 @@
 	struct security_operations module_operations;
 };
 static struct list_head stacked_modules;  /* list of stacked modules */
+static struct list_head unloaded_modules; /* list of unloaded modules */
 static struct list_head all_modules;  /* list of all modules, including freed */
 
 static short sysfsfiles_registered;
@@ -1439,6 +1440,7 @@
 
 	rcu_read_lock();
 	list_del_rcu(&m->lsm_list);
+	list_add_tail_rcu(&m->lsm_list, &unloaded_modules);
 	if (list_empty(&stacked_modules)) {
 		INIT_LIST_HEAD(&default_module.lsm_list);
 		list_add_tail_rcu(&default_module.lsm_list, &stacked_modules);
@@ -1452,9 +1454,26 @@
 	return ret;
 }
 
+/* list unloaded modules */
+static ssize_t stacker_unload_read (struct stacker_kobj *obj, char *buff)
+{
+	ssize_t len = 0;
+	struct module_entry *m;
+
+	rcu_read_lock();
+	stack_for_each_entry(m, &unloaded_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_unload = {
 	.attr = {.name = "unload", .mode = S_IFREG | S_IRUGO | S_IWUSR},
 	.store = stacker_unload_write,
+	.show =  stacker_unload_read,
 };
 
 
@@ -1525,6 +1544,7 @@
 
 	INIT_LIST_HEAD(&stacked_modules);
 	INIT_LIST_HEAD(&all_modules);
+	INIT_LIST_HEAD(&unloaded_modules);
 	spin_lock_init(&stacker_lock);
 	default_module.module_name = DEFAULT_MODULE_NAME;
 	default_module.namelen = strlen(DEFAULT_MODULE_NAME);

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

* Re: [patch 5/12] lsm stacking v0.2: actual stacker module
  2005-07-04  3:18   ` [patch 5/12] lsm stacking v0.2: actual stacker module Tony Jones
@ 2005-07-04 11:51     ` serge
  2005-07-04 19:37       ` Tony Jones
  2005-07-08 21:43     ` serue
  1 sibling, 1 reply; 57+ messages in thread
From: serge @ 2005-07-04 11:51 UTC (permalink / raw)
  To: Tony Jones; +Cc: lkml

Quoting Tony Jones (tonyj@suse.de):
> Hey Serge,
> 
> I don't think your symbol_get() is doing what you think it is ;-)

Hmm, I wonder whether something changed.  It shouldn't be possible to
rmmod module b if module a has done a symbol_get on it...  This may mean
more stringent locking will be required after all to support unloading.
That, or a rmmod lsm hook.

> > + * 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)
> > +{
>  ...
> > +	symbol_get(ops);
> > +
> > +out:
> > +	spin_unlock(&stacker_lock);
> > +	return ret;
> > +}
> 
> 
> Seemed useful to be able to view which modules had been unloaded.
> Easier to maintain them on their own list than to compute the difference
> of <stacked_modules> and <all_modules>.  Patch attached, not sure if you
> are cool with reusing the 'unload' file.

No, that's good, thanks.  Though I guess "unloading" of this type won't
be needed if true module deletion has to be supported.

> Apart from this, looks good.  I ran it against our regression tests using
> AppArmor (SubDomain) composed with Capability and everything was functionally
> as expected.   I still need to run it through our SMP stress tests.

Excellent :)

thanks,
-serge

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

* Re: [PATCH] securityfs
  2005-07-03 20:44           ` [PATCH] securityfs Greg KH
@ 2005-07-04 12:39             ` serge
  2005-07-04 15:53             ` serge
                               ` (2 subsequent siblings)
  3 siblings, 0 replies; 57+ messages in thread
From: serge @ 2005-07-04 12:39 UTC (permalink / raw)
  To: Greg KH
  Cc: James Morris, Tony Jones, serue, lkml, Chris Wright,
	Stephen Smalley, Andrew Morton, Michael Halcrow, David Safford,
	Reiner Sailer, Gerrit Huizenga

Quoting Greg KH (greg@kroah.com):
> On Sun, Jul 03, 2005 at 02:53:17PM -0400, James Morris wrote:
> > On Sun, 3 Jul 2005, Tony Jones wrote:
> > 
> > > There just isn't enough content to justify a stacker specific filesystem IMHO.
> > 
> > It might be worth thinking about a more general securityfs as part of LSM,
> > to be used by stacker and LSM modules.  SELinux could use this instead of
> > managing its own selinuxfs.
> 
> Good idea.  Here's a patch to do just that (compile tested only...)

Having all the security relevant stuff under one place has been
something we've wanted to do for awhile :)  Thanks, Greg!

All my good machines are down right now, so compiling is slow, but I'm
attempting to convert seclvl to use securityfs.  So far the resulting
code is quite nice.  I'll hopefully send something out tomorrow.

thanks,
-serge

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

* Re: [PATCH] securityfs
  2005-07-03 20:44           ` [PATCH] securityfs Greg KH
  2005-07-04 12:39             ` serge
@ 2005-07-04 15:53             ` serge
  2005-07-05  6:07               ` Greg KH
  2005-07-06  6:52             ` James Morris
  2005-07-06 22:08             ` serue
  3 siblings, 1 reply; 57+ messages in thread
From: serge @ 2005-07-04 15:53 UTC (permalink / raw)
  To: Greg KH
  Cc: James Morris, Tony Jones, lkml, Chris Wright, Stephen Smalley,
	Andrew Morton, Michael Halcrow, David Safford, Reiner Sailer,
	Gerrit Huizenga

Quoting Greg KH (greg@kroah.com):
> On Sun, Jul 03, 2005 at 02:53:17PM -0400, James Morris wrote:
> > On Sun, 3 Jul 2005, Tony Jones wrote:
> > 
> > > There just isn't enough content to justify a stacker specific filesystem IMHO.
> > 
> > It might be worth thinking about a more general securityfs as part of LSM,
> > to be used by stacker and LSM modules.  SELinux could use this instead of
> > managing its own selinuxfs.
> 
> Good idea.  Here's a patch to do just that (compile tested only...)
> 
> Comments?

Tested without a hitch.

In addition, the attached patch converts seclvl to use the securityfs.
Also tested without any problems.  (Only meant as proof of concept:
Mike, you'll probably want to at least add the passwd_read_file
function back in, I assume?)

thanks,
-serge

--
seclvl.c |  226
+++++++++++++++++++++++++++------------------------------------
 1 files changed, 99 insertions(+), 127 deletions(-)

Signed-off-by: Serge Hallyn <serue@us.ibm.com>

Index: linux-2.6.13-rc1/security/seclvl.c
===================================================================
--- linux-2.6.13-rc1.orig/security/seclvl.c	2005-07-02 21:49:34.000000000 -0500
+++ linux-2.6.13-rc1/security/seclvl.c	2005-07-04 07:58:15.000000000 -0500
@@ -119,69 +119,6 @@
 	} while (0)
 
 /**
- * kobject stuff
- */
-
-struct subsystem seclvl_subsys;
-
-struct seclvl_obj {
-	char *name;
-	struct list_head slot_list;
-	struct kobject kobj;
-};
-
-/**
- * There is a seclvl_attribute struct for each file in sysfs.
- *
- * In our case, we have one of these structs for "passwd" and another
- * for "seclvl".
- */
-struct seclvl_attribute {
-	struct attribute attr;
-	ssize_t(*show) (struct seclvl_obj *, char *);
-	ssize_t(*store) (struct seclvl_obj *, const char *, size_t);
-};
-
-/**
- * When this function is called, one of the files in sysfs is being
- * written to.  attribute->store is a function pointer to whatever the
- * struct seclvl_attribute store function pointer points to.  It is
- * unique for "passwd" and "seclvl".
- */
-static ssize_t
-seclvl_attr_store(struct kobject *kobj,
-		  struct attribute *attr, const char *buf, size_t len)
-{
-	struct seclvl_obj *obj = container_of(kobj, struct seclvl_obj, kobj);
-	struct seclvl_attribute *attribute =
-	    container_of(attr, struct seclvl_attribute, attr);
-	return attribute->store ? attribute->store(obj, buf, len) : -EIO;
-}
-
-static ssize_t
-seclvl_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
-{
-	struct seclvl_obj *obj = container_of(kobj, struct seclvl_obj, kobj);
-	struct seclvl_attribute *attribute =
-	    container_of(attr, struct seclvl_attribute, attr);
-	return attribute->show ? attribute->show(obj, buf) : -EIO;
-}
-
-/**
- * Callback function pointers for show and store
- */
-static struct sysfs_ops seclvlfs_sysfs_ops = {
-	.show = seclvl_attr_show,
-	.store = seclvl_attr_store,
-};
-
-static struct kobj_type seclvl_ktype = {
-	.sysfs_ops = &seclvlfs_sysfs_ops
-};
-
-decl_subsys(seclvl, &seclvl_ktype, NULL);
-
-/**
  * The actual security level.  Ranges between -1 and 2 inclusive.
  */
 static int seclvl;
@@ -216,9 +153,15 @@
  * Called whenever the user reads the sysfs handle to this kernel
  * object
  */
-static ssize_t seclvl_read_file(struct seclvl_obj *obj, char *buff)
+#define TMPBUFLEN 12
+static ssize_t seclvl_read_file(struct file *filp, char __user *buf,
+					size_t count, loff_t *ppos)
 {
-	return snprintf(buff, PAGE_SIZE, "%d\n", seclvl);
+	char tmpbuf[TMPBUFLEN];
+	ssize_t length;
+
+	length = scnprintf(tmpbuf, TMPBUFLEN, "%d", seclvl);
+	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
 }
 
 /**
@@ -253,57 +196,58 @@
  * object (seclvl/seclvl).  It expects a single-digit number.
  */
 static ssize_t
-seclvl_write_file(struct seclvl_obj *obj, const char *buff, size_t count)
+seclvl_write_file(struct file * file, const char __user * buf,
+			      size_t count, loff_t *ppos)
 {
-	unsigned long val;
-	if (count > 2 || (count == 2 && buff[1] != '\n')) {
-		seclvl_printk(1, KERN_WARNING, "Invalid value passed to "
-			      "seclvl: [%s]\n", buff);
+	int val;
+	int err;
+	char *page;
+
+	if (count > 2)
 		return -EINVAL;
+	if (*ppos != 0)
+		return -EINVAL;
+
+	page = (char *) get_zeroed_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+
+	if (copy_from_user(page, buf, count)) {
+		err = -EFAULT;
+		goto out;
+	}
+
+	if (sscanf(page, "%d", &val) != 1) {
+		err = -EINVAL;
+		goto out;
 	}
-	val = buff[0] - 48;
+
 	if (seclvl_sanity(val)) {
 		seclvl_printk(1, KERN_WARNING, "Illegal secure level "
 			      "requested: [%d]\n", (int)val);
-		return -EPERM;
+		err = -EINVAL;
+		goto out;
 	}
+	err = count;
 	if (do_seclvl_advance(val)) {
 		seclvl_printk(0, KERN_ERR, "Failure advancing security level "
-			      "to %lu\n", val);
+			      "to %d\n", val);
+		err = -EINVAL;
 	}
-	return count;
+
+out:
+	free_page((unsigned long)page);
+	return err;
 }
 
-/* Generate sysfs_attr_seclvl */
-static struct seclvl_attribute sysfs_attr_seclvl =
-__ATTR(seclvl, (S_IFREG | S_IRUGO | S_IWUSR), seclvl_read_file,
-       seclvl_write_file);
+static struct file_operations seclvl_file_ops = {
+	.read = seclvl_read_file,
+	.write = seclvl_write_file,
+};
 
 static unsigned char hashedPassword[SHA1_DIGEST_SIZE];
 
 /**
- * Called whenever the user reads the sysfs passwd handle.
- */
-static ssize_t seclvl_read_passwd(struct seclvl_obj *obj, char *buff)
-{
-	/* So just how good *is* your password? :-) */
-	char tmp[3];
-	int i = 0;
-	buff[0] = '\0';
-	if (hideHash) {
-		/* Security through obscurity */
-		return 0;
-	}
-	while (i < SHA1_DIGEST_SIZE) {
-		snprintf(tmp, 3, "%02x", hashedPassword[i]);
-		strncat(buff, tmp, 2);
-		i++;
-	}
-	strcat(buff, "\n");
-	return ((SHA1_DIGEST_SIZE * 2) + 1);
-}
-
-/**
  * Converts a block of plaintext of into its SHA1 hashed value.
  *
  * It would be nice if crypto had a wrapper to do this for us linear
@@ -347,12 +291,15 @@
  * object.  It hashes the password and compares the hashed results.
  */
 static ssize_t
-seclvl_write_passwd(struct seclvl_obj *obj, const char *buff, size_t count)
+passwd_write_file(struct file * file, const char __user * buf,
+				size_t count, loff_t *ppos)
 {
 	int i;
 	unsigned char tmp[SHA1_DIGEST_SIZE];
+	char *page;
 	int rc;
 	int len;
+
 	if (!*passwd && !*sha1_passwd) {
 		seclvl_printk(0, KERN_ERR, "Attempt to password-unlock the "
 			      "seclvl module, but neither a plain text "
@@ -363,13 +310,26 @@
 			      "maintainer about this event.\n");
 		return -EINVAL;
 	}
-	len = strlen(buff);
+
+	if (count < 0 || count >= PAGE_SIZE)
+		return -ENOMEM;
+	if (*ppos != 0) {
+		return -EINVAL;
+	}
+	page = (char *)get_zeroed_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+	len = -EFAULT;
+	if (copy_from_user(page, buf, count))
+		goto out;
+	
+	len = strlen(page);
 	/* ``echo "secret" > seclvl/passwd'' includes a newline */
-	if (buff[len - 1] == '\n') {
+	if (page[len - 1] == '\n') {
 		len--;
 	}
 	/* Hash the password, then compare the hashed values */
-	if ((rc = plaintext_to_sha1(tmp, buff, len))) {
+	if ((rc = plaintext_to_sha1(tmp, page, len))) {
 		seclvl_printk(0, KERN_ERR, "Error hashing password: rc = "
 			      "[%d]\n", rc);
 		return rc;
@@ -382,13 +342,16 @@
 	seclvl_printk(0, KERN_INFO,
 		      "Password accepted; seclvl reduced to 0.\n");
 	seclvl = 0;
-	return count;
+	len = count;
+
+out:
+	free_page((unsigned long)page);
+	return len;
 }
 
-/* Generate sysfs_attr_passwd */
-static struct seclvl_attribute sysfs_attr_passwd =
-__ATTR(passwd, (S_IFREG | S_IRUGO | S_IWUSR), seclvl_read_passwd,
-       seclvl_write_passwd);
+static struct file_operations passwd_file_ops = {
+	.write = passwd_write_file,
+};
 
 /**
  * Explicitely disallow ptrace'ing the init process.
@@ -647,22 +610,34 @@
 }
 
 /**
- * Sysfs registrations
+ * securityfs registrations
  */
-static int doSysfsRegistrations(void)
+struct dentry *dir_ino, *seclvl_ino, *passwd_ino;
+
+static int seclvlfs_register(void)
 {
-	int rc = 0;
-	if ((rc = subsystem_register(&seclvl_subsys))) {
-		seclvl_printk(0, KERN_WARNING,
-			      "Error [%d] registering seclvl subsystem\n", rc);
-		return rc;
-	}
-	sysfs_create_file(&seclvl_subsys.kset.kobj, &sysfs_attr_seclvl.attr);
+	dir_ino = securityfs_create_dir("seclvl", NULL);
+	if (!dir_ino)
+		return -EFAULT;
+
+	seclvl_ino = securityfs_create_file("seclvl", S_IRUGO | S_IWUSR,
+				dir_ino, NULL, &seclvl_file_ops);
+	if (!seclvl_ino)
+		goto out_deldir;
 	if (*passwd || *sha1_passwd) {
-		sysfs_create_file(&seclvl_subsys.kset.kobj,
-				  &sysfs_attr_passwd.attr);
+		passwd_ino = securityfs_create_file("passwd", S_IRUGO | S_IWUSR,
+				dir_ino, NULL, &passwd_file_ops);
+		if (!passwd_ino)
+			goto out_delf;
 	}
 	return 0;
+
+out_deldir:
+	securityfs_remove(dir_ino);
+out_delf:
+	securityfs_remove(seclvl_ino);
+
+	return -EFAULT;
 }
 
 /**
@@ -677,8 +652,6 @@
 		rc = -EINVAL;
 		goto exit;
 	}
-	sysfs_attr_seclvl.attr.owner = THIS_MODULE;
-	sysfs_attr_passwd.attr.owner = THIS_MODULE;
 	if (initlvl < -1 || initlvl > 2) {
 		seclvl_printk(0, KERN_ERR, "Error: bad initial securelevel "
 			      "[%d].\n", initlvl);
@@ -706,7 +679,7 @@
 		}		/* if primary module registered */
 		secondary = 1;
 	}			/* if we registered ourselves with the security framework */
-	if ((rc = doSysfsRegistrations())) {
+	if ((rc = seclvlfs_register())) {
 		seclvl_printk(0, KERN_ERR, "Error registering with sysfs\n");
 		goto exit;
 	}
@@ -724,12 +697,11 @@
  */
 static void __exit seclvl_exit(void)
 {
-	sysfs_remove_file(&seclvl_subsys.kset.kobj, &sysfs_attr_seclvl.attr);
+	securityfs_remove(seclvl_ino);
 	if (*passwd || *sha1_passwd) {
-		sysfs_remove_file(&seclvl_subsys.kset.kobj,
-				  &sysfs_attr_passwd.attr);
+		securityfs_remove(passwd_ino);
 	}
-	subsystem_unregister(&seclvl_subsys);
+	securityfs_remove(dir_ino);
 	if (secondary == 1) {
 		mod_unreg_security(MY_NAME, &seclvl_ops);
 	} else if (unregister_security(&seclvl_ops)) {

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

* Re: [patch 5/12] lsm stacking v0.2: actual stacker module
  2005-07-04 11:51     ` serge
@ 2005-07-04 19:37       ` Tony Jones
  2005-07-04 20:06         ` serge
  0 siblings, 1 reply; 57+ messages in thread
From: Tony Jones @ 2005-07-04 19:37 UTC (permalink / raw)
  To: serge; +Cc: lkml

On Mon, Jul 04, 2005 at 06:51:35AM -0500, serge@hallyn.com wrote:

> > I don't think your symbol_get() is doing what you think it is ;-)

> Hmm, I wonder whether something changed.  It shouldn't be possible to
> rmmod module b if module a has done a symbol_get on it...  

Are you thinking of resolve_symbol rather than get_symbol?

You are calling __symbol_get("ops").

Maybe (/probably :-)) I'm totally misunderstanding what you are doing but:

a) I would have thought you would need to call symbol_get on the name the
   caller was passing, i.e symbol_get(capability_security_ops)
b) The module registering these ops would need to EXPORT_SYMBOL this name.
c) mod->state is MODULE_STATE_COMING right before the call to mod->init
   in sys_init_module which causes any symbol_gets() to return 0 (not that
   you actually care about the return value, only it's side effect)
d) I don't see anything in this code path that would incr a ref on the 
   registering module as a side effect of returning the sym.

> more stringent locking will be required after all to support unloading.
> That, or a rmmod lsm hook.

Yep.  I was able to rmmod subdomain and capability, the former with unpleasant
results.

Tony

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

* Re: [patch 5/12] lsm stacking v0.2: actual stacker module
  2005-07-04 19:37       ` Tony Jones
@ 2005-07-04 20:06         ` serge
  2005-07-04 20:41           ` Tony Jones
  0 siblings, 1 reply; 57+ messages in thread
From: serge @ 2005-07-04 20:06 UTC (permalink / raw)
  To: Tony Jones; +Cc: lkml

Quoting Tony Jones (tonyj@suse.de):
> On Mon, Jul 04, 2005 at 06:51:35AM -0500, serge@hallyn.com wrote:
> 
> > > I don't think your symbol_get() is doing what you think it is ;-)
> 
> > Hmm, I wonder whether something changed.  It shouldn't be possible to
> > rmmod module b if module a has done a symbol_get on it...  
> 
> Are you thinking of resolve_symbol rather than get_symbol?
> 
> You are calling __symbol_get("ops").
> 
> Maybe (/probably :-)) I'm totally misunderstanding what you are doing but:
> a) I would have thought you would need to call symbol_get on the name the
>    caller was passing, i.e symbol_get(capability_security_ops)
> b) The module registering these ops would need to EXPORT_SYMBOL this name.
> c) mod->state is MODULE_STATE_COMING right before the call to mod->init
>    in sys_init_module which causes any symbol_gets() to return 0 (not that
>    you actually care about the return value, only it's side effect)
> d) I don't see anything in this code path that would incr a ref on the 
>    registering module as a side effect of returning the sym.

__symbol_get should eventually call try_module_get, which increments the
use count, right?

But I'm completely misusing symbol_get - as you say, that is supposed
to be "symbol_name", not a pointer to the symbol.

Any suggestions on a good way to do what I wanted to do?  Frankly a
new LSM hook seems the cleanest solution.  Or, I could ramp up the
locking and permit module deletion, probably at a bit of performance
cost.  Or I could just count on modules doing a symbol_get on
themselves?

thanks,
-serge

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

* Re: [patch 5/12] lsm stacking v0.2: actual stacker module
  2005-07-04 20:06         ` serge
@ 2005-07-04 20:41           ` Tony Jones
  2005-07-05 18:17             ` serge
  0 siblings, 1 reply; 57+ messages in thread
From: Tony Jones @ 2005-07-04 20:41 UTC (permalink / raw)
  To: serge; +Cc: Tony Jones, lkml

On Mon, Jul 04, 2005 at 03:06:46PM -0500, serge@hallyn.com wrote:

> > You are calling __symbol_get("ops").
> > 
> > Maybe (/probably :-)) I'm totally misunderstanding what you are doing but:
> > a) I would have thought you would need to call symbol_get on the name the
> >    caller was passing, i.e symbol_get(capability_security_ops)
> > b) The module registering these ops would need to EXPORT_SYMBOL this name.
> > c) mod->state is MODULE_STATE_COMING right before the call to mod->init
> >    in sys_init_module which causes any symbol_gets() to return 0 (not that
> >    you actually care about the return value, only it's side effect)
> > d) I don't see anything in this code path that would incr a ref on the 
> >    registering module as a side effect of returning the sym.
> 
> __symbol_get should eventually call try_module_get, which increments the
> use count, right?

Duh, I missed the call to try_module_get,  probably because it's right
below the 'if (mod && mod->state == MODULE_STATE_COMING) return 0;' :-)
in strong_try_module_get (2.6.13-rc1)

mod->state is MODULE_STATE_COMING until after mod->init returns and since
you are calling __symbol_get indirectly from the modules init routine,
bammo.

> Any suggestions on a good way to do what I wanted to do?  Frankly a
> new LSM hook seems the cleanest solution.  Or, I could ramp up the
> locking and permit module deletion, probably at a bit of performance
> cost.  Or I could just count on modules doing a symbol_get on
> themselves?

I think any symbol_get is problematic given the above. I was thinking
you could wrap mod_reg_security but it would still need to be called from
within the modules init fn.

I'm going to have to give it some thought, but a new rmmod hook does seem
a good solution off the top of my head.

Tony

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

* Re: [PATCH] securityfs
  2005-07-04 15:53             ` serge
@ 2005-07-05  6:07               ` Greg KH
  2005-07-06 12:25                 ` serge
  0 siblings, 1 reply; 57+ messages in thread
From: Greg KH @ 2005-07-05  6:07 UTC (permalink / raw)
  To: serge
  Cc: James Morris, Tony Jones, lkml, Chris Wright, Stephen Smalley,
	Andrew Morton, Michael Halcrow, David Safford, Reiner Sailer,
	Gerrit Huizenga

On Mon, Jul 04, 2005 at 10:53:21AM -0500, serge@hallyn.com wrote:
> > On Sun, Jul 03, 2005 at 02:53:17PM -0400, James Morris wrote:
> > > On Sun, 3 Jul 2005, Tony Jones wrote:
> > > 
> > > > There just isn't enough content to justify a stacker specific filesystem IMHO.
> > > 
> > > It might be worth thinking about a more general securityfs as part of LSM,
> > > to be used by stacker and LSM modules.  SELinux could use this instead of
> > > managing its own selinuxfs.
> > 
> > Good idea.  Here's a patch to do just that (compile tested only...)
> > 
> > Comments?
> 
> Tested without a hitch.

Thanks for testing.

> In addition, the attached patch converts seclvl to use the securityfs.
> Also tested without any problems.  (Only meant as proof of concept:
> Mike, you'll probably want to at least add the passwd_read_file
> function back in, I assume?)
> 
> --
> seclvl.c |  226 > +++++++++++++++++++++++++++------------------------------------
>  1 files changed, 99 insertions(+), 127 deletions(-)

Nice, glad to see this makes your code smaller and simpler.  Although I
think it could be made even smaller if you use the default read and
write file type functions in libfs (look at the debugfs wrappers of them
for u8, u16, etc, for examples of how to use them.)

thanks,

greg k-h

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

* Re: [patch 5/12] lsm stacking v0.2: actual stacker module
  2005-07-04 20:41           ` Tony Jones
@ 2005-07-05 18:17             ` serge
  0 siblings, 0 replies; 57+ messages in thread
From: serge @ 2005-07-05 18:17 UTC (permalink / raw)
  To: Tony Jones; +Cc: lkml

Quoting Tony Jones (tonyj@immunix.com):
> I'm going to have to give it some thought, but a new rmmod hook does seem
> a good solution off the top of my head.

In reponse to some prodding by Tony, here is a summary of the current
locking scheme in stacker, sprinkled with some notes about one way lsm
removal could be supported.

This will likely be added to the Documentation/stacker.txt file.

thanks,
-serge

The following describes the locking used by the lsm stacker as of
July 1, 2005:

Things which require locking include:

	1. module list
	2. per-kernel-object security lists

The module list is protected as follows:

	Walking the list is done under a partial rcu_read_lock.  In
	particular, we cannot hold the rcu_read_lock while calling a
	module_entry->lsm_hook(), as these are very likely to sleep.
	Therefore we call rcu_read_lock() only when we rcu_dereference
	module_entry->next.

	module_entries are not to be deleted.  By using the
	stacker_unload() function, they may be removed from the
	stacked_modules list.  The forward pointer is not changed, so
	that any stacker hook which is currently on module_entry
	can safely and correctly dereference module_entry->next.
	The module_entry remains on the all_modules list, which is
	used when kernel objects are freed.  In this way, any memory
	allocated by module_entry can still be freed.

	In the past, module deletion was supported in this scheme as
	follows: we added a reference count to the module_entry,
	which was incremented (under the rcu_read_lock) whenever a
	stacker hook was going to execute module_entry->lsm_hook().
	Module deletion was then done from a call_rcu().  If the
	refcount was not null after an rcu cycle, the del_func could
	delete the module.  Otherwise, it decremented the usage count,
	so that when the stacker hook returned from lsm_hook() it would
	find the refcount at 1, and delete the module.

	Re-enabling module deletion in this way should have a performance
	impact, and would require all modules to delete all their
	allocated kernel memory during module_exit().

The kernel object security lists are protected as follows:

	The security_set_value and security_del_value are only to
	be called during security_alloc_object and security_del_object,
	respectively.  Since these are automatically safe from
	concurrent accesses, no locking is required here.

	The security_add_value() function is protected from concurrent
	access using the stacker_value_spinlock.  security_get_value()
	is protected from security_add_value() using rcu.

	To allow module deletion, it would be desirable for modules
	to be able to delete kernel object security entries at any
	time.  This should be safe to do using RCU.  Modules would use
	security_unlink_value(), which would use hlist_del_rcu() to free
	the value, and LSMs would have to use call_rcu() to free the
	data in order to protect racing security_get_value()s.  This
	would happen as follows:

	1. security_unlink_value() would basically be security_del_value
	protected using the stacker_value_spinlock().
	2. An LSM would delete a value using:

		my_struct = security_unlink_value_type(&inode->i_security,
				MY_LSM_ID, struct my_struct);
		< do any necessary freeing of LSM data>
		security_free_value_type(my_struct);
	3. security_free_value_type would use call_rcu to kfree my_struct.

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

* Re: [PATCH] securityfs
  2005-07-03 20:44           ` [PATCH] securityfs Greg KH
  2005-07-04 12:39             ` serge
  2005-07-04 15:53             ` serge
@ 2005-07-06  6:52             ` James Morris
  2005-07-06  7:04               ` Greg KH
  2005-07-06 12:29               ` Stephen Smalley
  2005-07-06 22:08             ` serue
  3 siblings, 2 replies; 57+ messages in thread
From: James Morris @ 2005-07-06  6:52 UTC (permalink / raw)
  To: Greg KH
  Cc: Tony Jones, serge, serue, lkml, Chris Wright, Stephen Smalley,
	Andrew Morton, Michael Halcrow, David Safford, Reiner Sailer,
	Gerrit Huizenga

On Sun, 3 Jul 2005, Greg KH wrote:

> Good idea.  Here's a patch to do just that (compile tested only...)
> 
> Comments?

Looks promising so far.

I'm currently porting selinuxfs funtionality to securityfs, although I'm
not sure if we'll be ok during early initialization.  selinuxfs is
currently kern_mounted via an initcall.  We may need an initcall
kern_mount() of securityfs before SELinux kicks in.

Stephen: opinions on this?

Otherwise, it looks like it'll allow SELinux to drop some code.  Generally 
it will mean that other LSM components won't have to create their own 
filesystems, and their subdirectories will be hanging off /security (or 
wherever selinuxfs is mounted), rather than scattered across /

Some of the SELinux code may be useful as part of securityfs later, as 
well.


> +struct dentry *securityfs_create_file(const char *name, mode_t mode,
> +				   struct dentry *parent, void *data,
> +				   struct file_operations *fops)
> +{
> +	struct dentry *dentry = NULL;
> +	int error;
> +
> +	pr_debug("securityfs: creating file '%s'\n",name);
> +
> +	error = simple_pin_fs("securityfs", &mount, &mount_count);
> +	if (error)
> +		goto exit;
> +
> +	error = create_by_name(name, mode, parent, &dentry);
> +	if (error) {
> +		dentry = NULL;
> +		goto exit;
> +	}
> +
> +	if (dentry->d_inode) {
> +		if (data)
> +			dentry->d_inode->u.generic_ip = data;
> +		if (fops)
> +			dentry->d_inode->i_fop = fops;
> +	}
> +exit:
> +	return dentry;
> +}
> +EXPORT_SYMBOL_GPL(securityfs_create_file);

How about having all API functions which return a pointer be converted to 
use ERR_PTR() ?

This will allow errors to be propagated to the calling code.


- James
-- 
James Morris
<jmorris@redhat.com>



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

* Re: [PATCH] securityfs
  2005-07-06  6:52             ` James Morris
@ 2005-07-06  7:04               ` Greg KH
  2005-07-06 12:29               ` Stephen Smalley
  1 sibling, 0 replies; 57+ messages in thread
From: Greg KH @ 2005-07-06  7:04 UTC (permalink / raw)
  To: James Morris
  Cc: Tony Jones, serge, serue, lkml, Chris Wright, Stephen Smalley,
	Andrew Morton, Michael Halcrow, David Safford, Reiner Sailer,
	Gerrit Huizenga

On Wed, Jul 06, 2005 at 02:52:47AM -0400, James Morris wrote:
> On Sun, 3 Jul 2005, Greg KH wrote:
> 
> > Good idea.  Here's a patch to do just that (compile tested only...)
> > 
> > Comments?
> 
> Looks promising so far.
> 
> I'm currently porting selinuxfs funtionality to securityfs, although I'm
> not sure if we'll be ok during early initialization.  selinuxfs is
> currently kern_mounted via an initcall.  We may need an initcall
> kern_mount() of securityfs before SELinux kicks in.

Sure, I don't mind moving this if needed.

> Otherwise, it looks like it'll allow SELinux to drop some code.  Generally 
> it will mean that other LSM components won't have to create their own 
> filesystems, and their subdirectories will be hanging off /security (or 
> wherever selinuxfs is mounted), rather than scattered across /

The code creates /sys/kernel/security as a mount point for securityfs.
This will make the LSB people happy that every LSM does not create a new
fs in / :)

> Some of the SELinux code may be useful as part of securityfs later, as 
> well.

That would be fine.

> How about having all API functions which return a pointer be converted to 
> use ERR_PTR() ?
> 
> This will allow errors to be propagated to the calling code.

Good point, will change that.

thanks,

greg k-h

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

* Re: [PATCH] securityfs
  2005-07-05  6:07               ` Greg KH
@ 2005-07-06 12:25                 ` serge
  0 siblings, 0 replies; 57+ messages in thread
From: serge @ 2005-07-06 12:25 UTC (permalink / raw)
  To: Greg KH
  Cc: James Morris, Tony Jones, lkml, Chris Wright, Stephen Smalley,
	Andrew Morton, Michael Halcrow, David Safford, Reiner Sailer,
	Gerrit Huizenga

Quoting Greg KH (greg@kroah.com):
> Nice, glad to see this makes your code smaller and simpler.  Although I
> think it could be made even smaller if you use the default read and
> write file type functions in libfs (look at the debugfs wrappers of them
> for u8, u16, etc, for examples of how to use them.)

Hmm, I looked around at libfs and debugfs yesterday...  it seems that
the simple_attr_read as used by fops_u8 would have been great for
seclvl - except that -1 is a valid input for seclvl  :)

A more specialized per-type API in security/security.c in the line of
debugfs/file.c might be good,simple_attr_read as used by fops_u8 would
have been great for
seclvl - except that -1 is a valid input for seclvl  :)

The general type of API provided by debugfs/file.c might be useful in
security/security.c, though, provided that the securityfs_create_int()
and friends also took a function pointer to an update() or validate()
function.  I'll try to do something like that later today or tomorrow.

thanks,
-serge

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

* Re: [PATCH] securityfs
  2005-07-06  6:52             ` James Morris
  2005-07-06  7:04               ` Greg KH
@ 2005-07-06 12:29               ` Stephen Smalley
  2005-07-06 15:35                 ` James Morris
  1 sibling, 1 reply; 57+ messages in thread
From: Stephen Smalley @ 2005-07-06 12:29 UTC (permalink / raw)
  To: James Morris
  Cc: Greg KH, Tony Jones, serge, serue, lkml, Chris Wright,
	Andrew Morton, Michael Halcrow, David Safford, Reiner Sailer,
	Gerrit Huizenga

On Wed, 2005-07-06 at 02:52 -0400, James Morris wrote:
> On Sun, 3 Jul 2005, Greg KH wrote:
> 
> > Good idea.  Here's a patch to do just that (compile tested only...)
> > 
> > Comments?
> 
> Looks promising so far.
> 
> I'm currently porting selinuxfs funtionality to securityfs, although I'm
> not sure if we'll be ok during early initialization.  selinuxfs is
> currently kern_mounted via an initcall.  We may need an initcall
> kern_mount() of securityfs before SELinux kicks in.
> 
> Stephen: opinions on this?

The reason for creating a kernel mount of selinuxfs at that point is so
that the selinuxfs_mount vfsmount and selinux_null dentry are available
for flush_unauthorized_files to use.

> Otherwise, it looks like it'll allow SELinux to drop some code.  Generally 
> it will mean that other LSM components won't have to create their own 
> filesystems, and their subdirectories will be hanging off /security (or 
> wherever selinuxfs is mounted), rather than scattered across /
> 
> Some of the SELinux code may be useful as part of securityfs later, as 
> well.

We need to be able to assign specific security labels to specific inodes
in selinuxfs, particularly for the booleans, but ideally for any of
them.

Userspace compatibility is obviously a concern for such a change.
libselinux determines where selinuxfs is mounted during library
initialization by checking /proc/mounts for selinuxfs, and rc.sysinit
does likewise.  /sbin/init performs the initial mount of selinuxfs prior
to initial policy load.  Further, the existence of selinuxfs
in /proc/filesystems is used as a test of whether SELinux was enabled in
the kernel (e.g. is_selinux_enabled in libselinux).

I'm not sure such a change is worthwhile for SELinux; large amount of
disruption for little real gain.

-- 
Stephen Smalley
National Security Agency


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

* Re: [PATCH] securityfs
  2005-07-06 12:29               ` Stephen Smalley
@ 2005-07-06 15:35                 ` James Morris
  2005-07-06 16:06                   ` Stephen Smalley
  0 siblings, 1 reply; 57+ messages in thread
From: James Morris @ 2005-07-06 15:35 UTC (permalink / raw)
  To: Stephen Smalley
  Cc: Greg KH, Tony Jones, serge, serue, lkml, Chris Wright,
	Andrew Morton, Michael Halcrow, David Safford, Reiner Sailer,
	Gerrit Huizenga

On Wed, 6 Jul 2005, Stephen Smalley wrote:

> > Stephen: opinions on this?
> 
> The reason for creating a kernel mount of selinuxfs at that point is so
> that the selinuxfs_mount vfsmount and selinux_null dentry are available
> for flush_unauthorized_files to use.

When exactly is this needed?  The securityfs mountpoint will be available 
via a core_initcall, after which we can initialize the selinux subtree.

> Userspace compatibility is obviously a concern for such a change.
> libselinux determines where selinuxfs is mounted during library
> initialization by checking /proc/mounts for selinuxfs, and rc.sysinit
> does likewise.
>
>  /sbin/init performs the initial mount of selinuxfs prior
> to initial policy load.

With securityfs, we'd have /sys/kernel/security/selinux configured during 
kernel initialization.

> Further, the existence of selinuxfs
> in /proc/filesystems is used as a test of whether SELinux was enabled in
> the kernel (e.g. is_selinux_enabled in libselinux).

Could be a simple change to look for the presence of
/sys/kernel/security/selinux

> I'm not sure such a change is worthwhile for SELinux; large amount of
> disruption for little real gain.

I think it should reduce and simplify the SELinux kernel code, with less
filesystems in the kernel, consolidating several potential projects into
the same security filesystem.


- James
-- 
James Morris
<jmorris@redhat.com>



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

* Re: [PATCH] securityfs
  2005-07-06 15:35                 ` James Morris
@ 2005-07-06 16:06                   ` Stephen Smalley
  2005-07-06 16:16                     ` Greg KH
  2005-07-06 18:01                     ` Chris Wright
  0 siblings, 2 replies; 57+ messages in thread
From: Stephen Smalley @ 2005-07-06 16:06 UTC (permalink / raw)
  To: James Morris
  Cc: Greg KH, Tony Jones, serge, serue, lkml, Chris Wright,
	Andrew Morton, Michael Halcrow, David Safford, Reiner Sailer,
	Gerrit Huizenga

On Wed, 2005-07-06 at 11:35 -0400, James Morris wrote:
> When exactly is this needed?  The securityfs mountpoint will be available 
> via a core_initcall, after which we can initialize the selinux subtree.

As long as it occurs prior to initial policy load, so that should be
fine.

> With securityfs, we'd have /sys/kernel/security/selinux configured during 
> kernel initialization.

It still has to be mounted by userspace, right?  So /sbin/init still
needs to know to mount securityfs, and where the selinux nodes live
under it, so you are still talking about changing it (and libselinux and
rc.sysinit), and risking compatibility breakage for existing systems
when they update their kernels.

> Could be a simple change to look for the presence of
> /sys/kernel/security/selinux

Slightly different.  That would correspond to checking for the presence
of selinuxfs in /proc/mounts (i.e. has it been mounted), vs. the current
check of selinuxfs in /proc/filesystems (i.e. has it been registered).
The latter allows testing whether SELinux is enabled at all in the
kernel, regardless of whether selinuxfs has been mounted in the process'
namespace.  In practice, the difference likely only matters for init and
you can deal with distinction there.  But again, this requires code
change to libselinux, /sbin/init, and rc.sysinit at least, with
coordinated update with the kernel.  Certainly possible, but experience
suggests it isn't likely to go smoothly.

> I think it should reduce and simplify the SELinux kernel code, with less
> filesystems in the kernel, consolidating several potential projects into
> the same security filesystem.

If there are several such projects in the first place...

-- 
Stephen Smalley
National Security Agency


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

* Re: [PATCH] securityfs
  2005-07-06 16:06                   ` Stephen Smalley
@ 2005-07-06 16:16                     ` Greg KH
  2005-07-06 18:01                     ` Chris Wright
  1 sibling, 0 replies; 57+ messages in thread
From: Greg KH @ 2005-07-06 16:16 UTC (permalink / raw)
  To: Stephen Smalley
  Cc: James Morris, Tony Jones, serge, serue, lkml, Chris Wright,
	Andrew Morton, Michael Halcrow, David Safford, Reiner Sailer,
	Gerrit Huizenga

On Wed, Jul 06, 2005 at 12:06:40PM -0400, Stephen Smalley wrote:
> > I think it should reduce and simplify the SELinux kernel code, with less
> > filesystems in the kernel, consolidating several potential projects into
> > the same security filesystem.
> 
> If there are several such projects in the first place...

Serge has already posted a patch converting the sysfs usage over to it,
and I know the subdomain people are going to also use this code, for
when they submit their patches to mainline (they are currently working
on it, honestly, I've seen them doing it...)

thanks,

greg k-h

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

* Re: [PATCH] securityfs
  2005-07-06 16:06                   ` Stephen Smalley
  2005-07-06 16:16                     ` Greg KH
@ 2005-07-06 18:01                     ` Chris Wright
  1 sibling, 0 replies; 57+ messages in thread
From: Chris Wright @ 2005-07-06 18:01 UTC (permalink / raw)
  To: Stephen Smalley
  Cc: James Morris, Greg KH, Tony Jones, serge, serue, lkml,
	Chris Wright, Andrew Morton, Michael Halcrow, David Safford,
	Reiner Sailer, Gerrit Huizenga

* Stephen Smalley (sds@epoch.ncsc.mil) wrote:
> It still has to be mounted by userspace, right?  So /sbin/init still
> needs to know to mount securityfs, and where the selinux nodes live
> under it, so you are still talking about changing it (and libselinux and
> rc.sysinit), and risking compatibility breakage for existing systems
> when they update their kernels.

initrd, and proper dependency during kernel upgrade?

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

* Re: [PATCH] securityfs
  2005-07-03 20:44           ` [PATCH] securityfs Greg KH
                               ` (2 preceding siblings ...)
  2005-07-06  6:52             ` James Morris
@ 2005-07-06 22:08             ` serue
  2005-07-06 22:22               ` Greg KH
  3 siblings, 1 reply; 57+ messages in thread
From: serue @ 2005-07-06 22:08 UTC (permalink / raw)
  To: Greg KH
  Cc: James Morris, Tony Jones, serge, serue, lkml, Chris Wright,
	Stephen Smalley, Andrew Morton, Michael Halcrow, David Safford,
	Reiner Sailer, Gerrit Huizenga

Quoting Greg KH (greg@kroah.com):
> think it could be made even smaller if you use the default read and
> write file type functions in libfs (look at the debugfs wrappers of them
> for u8, u16, etc, for examples of how to use them.)

The attached patch cleans up the securelevel code for the seclvl file.
Is this a reasonable way to go about this?  Or is there a better way to
do this?  Should these be in libfs instead?  Really I guess it would
only take very minor changes to the _attr code in libfs to forego the
need for these functions in security/inode.c.  It's mainly allowing
signed arguments, and a return value from the __set function.

But if this is ok, then it should be quick to come up with the same kind 
of thing for string arguments, so that all files for both stacker and 
seclvl should be very simple to code.

thanks,
-serge

Signed-off-by: Serge Hallyn <serue@us.ibm.com>
--
 include/linux/security.h |   24 ++++++++++
 security/inode.c         |  110 +++++++++++++++++++++++++++++++++++++++++++++++
 security/seclvl.c        |   84 +++--------------------------------
 3 files changed, 143 insertions(+), 75 deletions(-)

Index: linux-2.6.13-rc1/security/inode.c
===================================================================
--- linux-2.6.13-rc1.orig/security/inode.c	2005-07-06 19:05:38.000000000 -0500
+++ linux-2.6.13-rc1/security/inode.c	2005-07-06 19:37:16.000000000 -0500
@@ -330,6 +330,116 @@ static void __exit securityfs_exit(void)
 	subsystem_unregister(&security_subsys);
 }
 
+/* mostly copied from fs/libfs.c:simple_attr */
+struct secfs_int_attr {
+	int (*get)(void *);
+	int (*set)(void *, int);
+	char get_buf[24];	/* enough to store an int and "\n\0" */
+	char set_buf[24];
+	void *data;
+	const char *fmt;	/* format for read operation */
+	struct semaphore sem;	/* protects access to these buffers */
+};
+
+int open_file_int(struct inode *inode, struct file *file,
+		     int (*get)(void *), int (*set)(void *, int),
+		     const char *fmt)
+{
+	struct secfs_int_attr *attr;
+
+	attr = kmalloc(sizeof(*attr), GFP_KERNEL);
+	if (!attr)
+		return -ENOMEM;
+
+	attr->get = get;
+	attr->set = set;
+	attr->data = inode->u.generic_ip;
+	attr->fmt = fmt;
+	init_MUTEX(&attr->sem);
+
+	file->private_data = attr;
+
+	return nonseekable_open(inode, file);
+}
+
+int close_file_int(struct inode *inode, struct file *file)
+{
+	kfree(file->private_data);
+	return 0;
+}
+
+ssize_t read_file_int(struct file *file, char __user *user_buf,
+			      size_t count, loff_t *ppos)
+{
+	struct secfs_int_attr *attr;
+	size_t size;
+	ssize_t ret;
+
+	attr = file->private_data;
+
+	if (!attr->get)
+		return -EACCES;
+
+	down(&attr->sem);
+	if (*ppos) /* continued read */
+		size = strlen(attr->get_buf);
+	else	  /* first read */
+		size = scnprintf(attr->get_buf, sizeof(attr->get_buf),
+				 attr->fmt,
+				 (unsigned long long)attr->get(attr->data));
+
+	ret = simple_read_from_buffer(user_buf, count, ppos, attr->get_buf, size);
+	up(&attr->sem);
+	return ret;
+}
+
+ssize_t write_file_int(struct file *file, const char __user *user_buf,
+			       size_t count, loff_t *ppos)
+{
+	struct secfs_int_attr *attr;
+	int val;
+	size_t size;
+	ssize_t ret;
+
+	attr = file->private_data;
+
+	if (!attr->set)
+		return -EACCES;
+
+	down(&attr->sem);
+	ret = -EFAULT;
+	size = min(sizeof(attr->set_buf) - 1, count);
+	if (copy_from_user(attr->set_buf, user_buf, size))
+		goto out;
+
+	attr->set_buf[size] = '\0';
+	val = simple_strtol(attr->set_buf, NULL, 0);
+	ret = attr->set(attr->data, val);
+	if (ret)
+		goto out;
+	ret = count; /* claim we got the whole input */
+out:
+	up(&attr->sem);
+	return ret;
+}
+
+void secfs_int_set(void *data, int val)
+{
+	*(int *)data = val;
+}
+
+int secfs_int_get(void *data)
+{
+	return *(int *)data;
+}
+
+EXPORT_SYMBOL_GPL(read_file_int);
+EXPORT_SYMBOL_GPL(close_file_int);
+EXPORT_SYMBOL_GPL(open_file_int);
+EXPORT_SYMBOL_GPL(write_file_int);
+EXPORT_SYMBOL_GPL(secfs_int_set);
+EXPORT_SYMBOL_GPL(secfs_int_get);
+
 core_initcall(securityfs_init);
 module_exit(securityfs_exit);
 MODULE_LICENSE("GPL");
Index: linux-2.6.13-rc1/include/linux/security.h
===================================================================
--- linux-2.6.13-rc1.orig/include/linux/security.h	2005-07-06 19:05:38.000000000 -0500
+++ linux-2.6.13-rc1/include/linux/security.h	2005-07-06 19:30:27.000000000 -0500
@@ -1977,6 +1977,30 @@ static inline int security_netlink_recv(
 	return security_ops->netlink_recv(skb);
 }
 
+#define SECFS_DEFINE_INT_FILE(__fops, __get, __set, __fmt)		\
+static int __fops ## _open(struct inode *inode, struct file *file)	\
+{									\
+	return open_file_int(inode, file, __get, __set, __fmt);		\
+}									\
+static struct file_operations __fops = {				\
+	.owner	 = THIS_MODULE,						\
+	.open	 = __fops ## _open,					\
+	.release = close_file_int,					\
+	.read	 = read_file_int,					\
+	.write	 = write_file_int,					\
+};
+
+int open_file_int(struct inode *inode, struct file *file,
+		     int (*get)(void *), int (*set)(void *, int),
+		     const char *fmt);
+int close_file_int(struct inode *inode, struct file *file);
+ssize_t read_file_int(struct file *file, char __user *user_buf,
+			      size_t count, loff_t *ppos);
+ssize_t write_file_int(struct file *file, const char __user *user_buf,
+			       size_t count, loff_t *ppos);
+void secfs_int_set(void *data, int val);
+int secfs_int_get(void *data);
+
 /* prototypes */
 extern int security_init	(void);
 extern int register_security	(struct security_operations *ops);
Index: linux-2.6.13-rc1/security/seclvl.c
===================================================================
--- linux-2.6.13-rc1.orig/security/seclvl.c	2005-07-06 19:05:38.000000000 -0500
+++ linux-2.6.13-rc1/security/seclvl.c	2005-07-06 19:33:01.000000000 -0500
@@ -150,33 +150,19 @@ static int seclvl_sanity(int reqlvl)
 }
 
 /**
- * Called whenever the user reads the sysfs handle to this kernel
- * object
- */
-#define TMPBUFLEN 12
-static ssize_t seclvl_read_file(struct file *filp, char __user *buf,
-					size_t count, loff_t *ppos)
-{
-	char tmpbuf[TMPBUFLEN];
-	ssize_t length;
-
-	length = scnprintf(tmpbuf, TMPBUFLEN, "%d", seclvl);
-	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
-}
-
-/**
  * security level advancement rules:
  *   Valid levels are -1 through 2, inclusive.
  *   From -1, stuck.  [ in case compiled into kernel ]
  *   From 0 or above, can only increment.
  */
-static int do_seclvl_advance(int newlvl)
+static int do_seclvl_advance(void *data, int newlvl)
 {
-	if (newlvl <= seclvl) {
-		seclvl_printk(1, KERN_WARNING, "Cannot advance to seclvl "
-			      "[%d]\n", newlvl);
-		return -EINVAL;
-	}
+	int ret;
+	
+	ret = seclvl_sanity(newlvl);
+	if (ret)
+		return ret;
+
 	if (newlvl > 2) {
 		seclvl_printk(1, KERN_WARNING, "Cannot advance to seclvl "
 			      "[%d]\n", newlvl);
@@ -191,59 +177,7 @@ static int do_seclvl_advance(int newlvl)
 	return 0;
 }
 
-/**
- * Called whenever the user writes to the sysfs handle to this kernel
- * object (seclvl/seclvl).  It expects a single-digit number.
- */
-static ssize_t
-seclvl_write_file(struct file * file, const char __user * buf,
-			      size_t count, loff_t *ppos)
-{
-	int val;
-	int err;
-	char *page;
-
-	if (count > 2)
-		return -EINVAL;
-	if (*ppos != 0)
-		return -EINVAL;
-
-	page = (char *) get_zeroed_page(GFP_KERNEL);
-	if (!page)
-		return -ENOMEM;
-
-	if (copy_from_user(page, buf, count)) {
-		err = -EFAULT;
-		goto out;
-	}
-
-	if (sscanf(page, "%d", &val) != 1) {
-		err = -EINVAL;
-		goto out;
-	}
-
-	if (seclvl_sanity(val)) {
-		seclvl_printk(1, KERN_WARNING, "Illegal secure level "
-			      "requested: [%d]\n", (int)val);
-		err = -EINVAL;
-		goto out;
-	}
-	err = count;
-	if (do_seclvl_advance(val)) {
-		seclvl_printk(0, KERN_ERR, "Failure advancing security level "
-			      "to %d\n", val);
-		err = -EINVAL;
-	}
-
-out:
-	free_page((unsigned long)page);
-	return err;
-}
-
-static struct file_operations seclvl_file_ops = {
-	.read = seclvl_read_file,
-	.write = seclvl_write_file,
-};
+SECFS_DEFINE_INT_FILE(seclvl_file_ops,secfs_int_get,do_seclvl_advance,"%d\n");
 
 static unsigned char hashedPassword[SHA1_DIGEST_SIZE];
 
@@ -621,7 +555,7 @@ static int seclvlfs_register(void)
 		return -EFAULT;
 
 	seclvl_ino = securityfs_create_file("seclvl", S_IRUGO | S_IWUSR,
-				dir_ino, NULL, &seclvl_file_ops);
+				dir_ino, &seclvl, &seclvl_file_ops);
 	if (!seclvl_ino)
 		goto out_deldir;
 	if (*passwd || *sha1_passwd) {

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

* Re: [PATCH] securityfs
  2005-07-06 22:08             ` serue
@ 2005-07-06 22:22               ` Greg KH
  2005-07-06 23:32                 ` serge
  2005-07-07 17:30                 ` serge
  0 siblings, 2 replies; 57+ messages in thread
From: Greg KH @ 2005-07-06 22:22 UTC (permalink / raw)
  To: serue
  Cc: James Morris, Tony Jones, serge, lkml, Chris Wright,
	Stephen Smalley, Andrew Morton, Michael Halcrow, David Safford,
	Reiner Sailer, Gerrit Huizenga

On Wed, Jul 06, 2005 at 05:08:35PM -0500, serue@us.ibm.com wrote:
> Quoting Greg KH (greg@kroah.com):
> > think it could be made even smaller if you use the default read and
> > write file type functions in libfs (look at the debugfs wrappers of them
> > for u8, u16, etc, for examples of how to use them.)
> 
> The attached patch cleans up the securelevel code for the seclvl file.
> Is this a reasonable way to go about this?

No.

> Or is there a better way to do this?

Look at how debugfs uses the libfs code.  We should not need to add
these handlers to securityfs.

thanks,

greg k-h

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

* Re: [PATCH] securityfs
  2005-07-06 22:22               ` Greg KH
@ 2005-07-06 23:32                 ` serge
  2005-07-07 17:30                 ` serge
  1 sibling, 0 replies; 57+ messages in thread
From: serge @ 2005-07-06 23:32 UTC (permalink / raw)
  To: Greg KH
  Cc: serue, James Morris, Tony Jones, lkml, Chris Wright,
	Stephen Smalley, Andrew Morton, Michael Halcrow, David Safford,
	Reiner Sailer, Gerrit Huizenga

Quoting Greg KH (greg@kroah.com):
> > Or is there a better way to do this?
> 
> Look at how debugfs uses the libfs code.  We should not need to add
> these handlers to securityfs.

Ah, ok, thanks.  I think I've got it - will send out a new patch tomorrow.

thanks,
-serge

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

* Re: [PATCH] securityfs
  2005-07-06 22:22               ` Greg KH
  2005-07-06 23:32                 ` serge
@ 2005-07-07 17:30                 ` serge
  2005-07-07 17:48                   ` Greg KH
  1 sibling, 1 reply; 57+ messages in thread
From: serge @ 2005-07-07 17:30 UTC (permalink / raw)
  To: Greg KH
  Cc: serue, James Morris, Tony Jones, lkml, Chris Wright,
	Stephen Smalley, Andrew Morton, Michael Halcrow, David Safford,
	Reiner Sailer, Gerrit Huizenga

Quoting Greg KH (greg@kroah.com):
> On Wed, Jul 06, 2005 at 05:08:35PM -0500, serue@us.ibm.com wrote:
> > Quoting Greg KH (greg@kroah.com):
> > > think it could be made even smaller if you use the default read and
> > > write file type functions in libfs (look at the debugfs wrappers of them
> > > for u8, u16, etc, for examples of how to use them.)
> > 
> > The attached patch cleans up the securelevel code for the seclvl file.
> > Is this a reasonable way to go about this?
> 
> No.
> 
> > Or is there a better way to do this?
> 
> Look at how debugfs uses the libfs code.  We should not need to add
> these handlers to securityfs.

Unfortunately the simple_attr code from libfs really doesn't seem to be
usable for int args.  However the below patch follows some of the
examples in debugfs and comes out cleaner than my original patch.

This patch against seclvl moves the filesystem interface from sysfs to
the securityfs proposed by Greg KH.

thanks,
-serge

Signed-off-by: Serge Hallyn <serue@us.ibm.com>
--
 seclvl.c |  251 +++++++++++++++++++++++----------------------------------------
 1 files changed, 93 insertions(+), 158 deletions(-)

Index: linux-2.6.13-rc1/security/seclvl.c
===================================================================
--- linux-2.6.13-rc1.orig/security/seclvl.c	2005-07-07 15:33:45.000000000 -0500
+++ linux-2.6.13-rc1/security/seclvl.c	2005-07-07 15:34:33.000000000 -0500
@@ -119,69 +119,6 @@ MODULE_PARM_DESC(hideHash, "When set to 
 	} while (0)
 
 /**
- * kobject stuff
- */
-
-struct subsystem seclvl_subsys;
-
-struct seclvl_obj {
-	char *name;
-	struct list_head slot_list;
-	struct kobject kobj;
-};
-
-/**
- * There is a seclvl_attribute struct for each file in sysfs.
- *
- * In our case, we have one of these structs for "passwd" and another
- * for "seclvl".
- */
-struct seclvl_attribute {
-	struct attribute attr;
-	ssize_t(*show) (struct seclvl_obj *, char *);
-	ssize_t(*store) (struct seclvl_obj *, const char *, size_t);
-};
-
-/**
- * When this function is called, one of the files in sysfs is being
- * written to.  attribute->store is a function pointer to whatever the
- * struct seclvl_attribute store function pointer points to.  It is
- * unique for "passwd" and "seclvl".
- */
-static ssize_t
-seclvl_attr_store(struct kobject *kobj,
-		  struct attribute *attr, const char *buf, size_t len)
-{
-	struct seclvl_obj *obj = container_of(kobj, struct seclvl_obj, kobj);
-	struct seclvl_attribute *attribute =
-	    container_of(attr, struct seclvl_attribute, attr);
-	return attribute->store ? attribute->store(obj, buf, len) : -EIO;
-}
-
-static ssize_t
-seclvl_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
-{
-	struct seclvl_obj *obj = container_of(kobj, struct seclvl_obj, kobj);
-	struct seclvl_attribute *attribute =
-	    container_of(attr, struct seclvl_attribute, attr);
-	return attribute->show ? attribute->show(obj, buf) : -EIO;
-}
-
-/**
- * Callback function pointers for show and store
- */
-static struct sysfs_ops seclvlfs_sysfs_ops = {
-	.show = seclvl_attr_show,
-	.store = seclvl_attr_store,
-};
-
-static struct kobj_type seclvl_ktype = {
-	.sysfs_ops = &seclvlfs_sysfs_ops
-};
-
-decl_subsys(seclvl, &seclvl_ktype, NULL);
-
-/**
  * The actual security level.  Ranges between -1 and 2 inclusive.
  */
 static int seclvl;
@@ -194,6 +131,11 @@ static int secondary;
 /**
  * Verifies that the requested secure level is valid, given the current
  * secure level.
+ *
+ * security level advancement rules:
+ *   Valid levels are -1 through 2, inclusive.
+ *   From -1, stuck.  [ in case compiled into kernel ]
+ *   From 0 or above, can only increment.
  */
 static int seclvl_sanity(int reqlvl)
 {
@@ -202,6 +144,11 @@ static int seclvl_sanity(int reqlvl)
 			      "range: [%d]\n", reqlvl);
 		return -EINVAL;
 	}
+	if (seclvl == -1) {
+		seclvl_printk(1, KERN_WARNING, "Not allowed to switch from "
+			      "seclvl [%d]\n", seclvl);
+		return -EPERM;
+	}
 	if ((seclvl == 0) && (reqlvl == -1))
 		return 0;
 	if (reqlvl < seclvl) {
@@ -216,36 +163,15 @@ static int seclvl_sanity(int reqlvl)
  * Called whenever the user reads the sysfs handle to this kernel
  * object
  */
-static ssize_t seclvl_read_file(struct seclvl_obj *obj, char *buff)
+#define TMPBUFLEN 12
+static ssize_t seclvl_read_file(struct file *filp, char __user *buf,
+					size_t count, loff_t *ppos)
 {
-	return snprintf(buff, PAGE_SIZE, "%d\n", seclvl);
-}
+	char tmpbuf[TMPBUFLEN];
+	ssize_t length;
 
-/**
- * security level advancement rules:
- *   Valid levels are -1 through 2, inclusive.
- *   From -1, stuck.  [ in case compiled into kernel ]
- *   From 0 or above, can only increment.
- */
-static int do_seclvl_advance(int newlvl)
-{
-	if (newlvl <= seclvl) {
-		seclvl_printk(1, KERN_WARNING, "Cannot advance to seclvl "
-			      "[%d]\n", newlvl);
-		return -EINVAL;
-	}
-	if (newlvl > 2) {
-		seclvl_printk(1, KERN_WARNING, "Cannot advance to seclvl "
-			      "[%d]\n", newlvl);
-		return -EINVAL;
-	}
-	if (seclvl == -1) {
-		seclvl_printk(1, KERN_WARNING, "Not allowed to advance to "
-			      "seclvl [%d]\n", seclvl);
-		return -EPERM;
-	}
-	seclvl = newlvl;
-	return 0;
+	length = scnprintf(tmpbuf, TMPBUFLEN, "%d\n", seclvl);
+	return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
 }
 
 /**
@@ -253,57 +179,38 @@ static int do_seclvl_advance(int newlvl)
  * object (seclvl/seclvl).  It expects a single-digit number.
  */
 static ssize_t
-seclvl_write_file(struct seclvl_obj *obj, const char *buff, size_t count)
+seclvl_write_file(struct file * file, const char __user * user_buf,
+			      size_t count, loff_t *ppos)
 {
-	unsigned long val;
-	if (count > 2 || (count == 2 && buff[1] != '\n')) {
-		seclvl_printk(1, KERN_WARNING, "Invalid value passed to "
-			      "seclvl: [%s]\n", buff);
+	int newlvl;
+	int buf_size;
+	char buf[32];
+
+	buf_size = min(count, (sizeof(buf)-1));
+	if (copy_from_user(buf, user_buf, buf_size))
+		return -EFAULT;
+
+	if (sscanf(buf, "%d\n", &newlvl) != 1)
 		return -EINVAL;
-	}
-	val = buff[0] - 48;
-	if (seclvl_sanity(val)) {
+
+	if (seclvl_sanity(newlvl)) {
 		seclvl_printk(1, KERN_WARNING, "Illegal secure level "
-			      "requested: [%d]\n", (int)val);
-		return -EPERM;
-	}
-	if (do_seclvl_advance(val)) {
-		seclvl_printk(0, KERN_ERR, "Failure advancing security level "
-			      "to %lu\n", val);
+			      "requested: [%d]\n", newlvl);
+		return -EINVAL;
 	}
+
+	seclvl = newlvl;
 	return count;
 }
 
-/* Generate sysfs_attr_seclvl */
-static struct seclvl_attribute sysfs_attr_seclvl =
-__ATTR(seclvl, (S_IFREG | S_IRUGO | S_IWUSR), seclvl_read_file,
-       seclvl_write_file);
+static struct file_operations seclvl_file_ops = {
+	.read = seclvl_read_file,
+	.write = seclvl_write_file,
+};
 
 static unsigned char hashedPassword[SHA1_DIGEST_SIZE];
 
 /**
- * Called whenever the user reads the sysfs passwd handle.
- */
-static ssize_t seclvl_read_passwd(struct seclvl_obj *obj, char *buff)
-{
-	/* So just how good *is* your password? :-) */
-	char tmp[3];
-	int i = 0;
-	buff[0] = '\0';
-	if (hideHash) {
-		/* Security through obscurity */
-		return 0;
-	}
-	while (i < SHA1_DIGEST_SIZE) {
-		snprintf(tmp, 3, "%02x", hashedPassword[i]);
-		strncat(buff, tmp, 2);
-		i++;
-	}
-	strcat(buff, "\n");
-	return ((SHA1_DIGEST_SIZE * 2) + 1);
-}
-
-/**
  * Converts a block of plaintext of into its SHA1 hashed value.
  *
  * It would be nice if crypto had a wrapper to do this for us linear
@@ -347,12 +254,15 @@ plaintext_to_sha1(unsigned char *hash, c
  * object.  It hashes the password and compares the hashed results.
  */
 static ssize_t
-seclvl_write_passwd(struct seclvl_obj *obj, const char *buff, size_t count)
+passwd_write_file(struct file * file, const char __user * buf,
+				size_t count, loff_t *ppos)
 {
 	int i;
 	unsigned char tmp[SHA1_DIGEST_SIZE];
+	char *page;
 	int rc;
 	int len;
+
 	if (!*passwd && !*sha1_passwd) {
 		seclvl_printk(0, KERN_ERR, "Attempt to password-unlock the "
 			      "seclvl module, but neither a plain text "
@@ -363,13 +273,26 @@ seclvl_write_passwd(struct seclvl_obj *o
 			      "maintainer about this event.\n");
 		return -EINVAL;
 	}
-	len = strlen(buff);
+
+	if (count < 0 || count >= PAGE_SIZE)
+		return -ENOMEM;
+	if (*ppos != 0) {
+		return -EINVAL;
+	}
+	page = (char *)get_zeroed_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+	len = -EFAULT;
+	if (copy_from_user(page, buf, count))
+		goto out;
+	
+	len = strlen(page);
 	/* ``echo "secret" > seclvl/passwd'' includes a newline */
-	if (buff[len - 1] == '\n') {
+	if (page[len - 1] == '\n') {
 		len--;
 	}
 	/* Hash the password, then compare the hashed values */
-	if ((rc = plaintext_to_sha1(tmp, buff, len))) {
+	if ((rc = plaintext_to_sha1(tmp, page, len))) {
 		seclvl_printk(0, KERN_ERR, "Error hashing password: rc = "
 			      "[%d]\n", rc);
 		return rc;
@@ -382,13 +305,16 @@ seclvl_write_passwd(struct seclvl_obj *o
 	seclvl_printk(0, KERN_INFO,
 		      "Password accepted; seclvl reduced to 0.\n");
 	seclvl = 0;
-	return count;
+	len = count;
+
+out:
+	free_page((unsigned long)page);
+	return len;
 }
 
-/* Generate sysfs_attr_passwd */
-static struct seclvl_attribute sysfs_attr_passwd =
-__ATTR(passwd, (S_IFREG | S_IRUGO | S_IWUSR), seclvl_read_passwd,
-       seclvl_write_passwd);
+static struct file_operations passwd_file_ops = {
+	.write = passwd_write_file,
+};
 
 /**
  * Explicitely disallow ptrace'ing the init process.
@@ -647,22 +573,34 @@ static int processPassword(void)
 }
 
 /**
- * Sysfs registrations
+ * securityfs registrations
  */
-static int doSysfsRegistrations(void)
+struct dentry *dir_ino, *seclvl_ino, *passwd_ino;
+
+static int seclvlfs_register(void)
 {
-	int rc = 0;
-	if ((rc = subsystem_register(&seclvl_subsys))) {
-		seclvl_printk(0, KERN_WARNING,
-			      "Error [%d] registering seclvl subsystem\n", rc);
-		return rc;
-	}
-	sysfs_create_file(&seclvl_subsys.kset.kobj, &sysfs_attr_seclvl.attr);
+	dir_ino = securityfs_create_dir("seclvl", NULL);
+	if (!dir_ino)
+		return -EFAULT;
+
+	seclvl_ino = securityfs_create_file("seclvl", S_IRUGO | S_IWUSR,
+				dir_ino, NULL, &seclvl_file_ops);
+	if (!seclvl_ino)
+		goto out_deldir;
 	if (*passwd || *sha1_passwd) {
-		sysfs_create_file(&seclvl_subsys.kset.kobj,
-				  &sysfs_attr_passwd.attr);
+		passwd_ino = securityfs_create_file("passwd", S_IRUGO | S_IWUSR,
+				dir_ino, NULL, &passwd_file_ops);
+		if (!passwd_ino)
+			goto out_delf;
 	}
 	return 0;
+
+out_deldir:
+	securityfs_remove(dir_ino);
+out_delf:
+	securityfs_remove(seclvl_ino);
+
+	return -EFAULT;
 }
 
 /**
@@ -677,8 +615,6 @@ static int __init seclvl_init(void)
 		rc = -EINVAL;
 		goto exit;
 	}
-	sysfs_attr_seclvl.attr.owner = THIS_MODULE;
-	sysfs_attr_passwd.attr.owner = THIS_MODULE;
 	if (initlvl < -1 || initlvl > 2) {
 		seclvl_printk(0, KERN_ERR, "Error: bad initial securelevel "
 			      "[%d].\n", initlvl);
@@ -706,7 +642,7 @@ static int __init seclvl_init(void)
 		}		/* if primary module registered */
 		secondary = 1;
 	}			/* if we registered ourselves with the security framework */
-	if ((rc = doSysfsRegistrations())) {
+	if ((rc = seclvlfs_register())) {
 		seclvl_printk(0, KERN_ERR, "Error registering with sysfs\n");
 		goto exit;
 	}
@@ -724,12 +660,11 @@ static int __init seclvl_init(void)
  */
 static void __exit seclvl_exit(void)
 {
-	sysfs_remove_file(&seclvl_subsys.kset.kobj, &sysfs_attr_seclvl.attr);
+	securityfs_remove(seclvl_ino);
 	if (*passwd || *sha1_passwd) {
-		sysfs_remove_file(&seclvl_subsys.kset.kobj,
-				  &sysfs_attr_passwd.attr);
+		securityfs_remove(passwd_ino);
 	}
-	subsystem_unregister(&seclvl_subsys);
+	securityfs_remove(dir_ino);
 	if (secondary == 1) {
 		mod_unreg_security(MY_NAME, &seclvl_ops);
 	} else if (unregister_security(&seclvl_ops)) {

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

* Re: [PATCH] securityfs
  2005-07-07 17:30                 ` serge
@ 2005-07-07 17:48                   ` Greg KH
  2005-07-07 18:27                     ` serue
  0 siblings, 1 reply; 57+ messages in thread
From: Greg KH @ 2005-07-07 17:48 UTC (permalink / raw)
  To: serge
  Cc: serue, James Morris, Tony Jones, lkml, Chris Wright,
	Stephen Smalley, Andrew Morton, Michael Halcrow, David Safford,
	Reiner Sailer, Gerrit Huizenga

On Thu, Jul 07, 2005 at 12:30:35PM -0500, serge@hallyn.com wrote:
> Quoting Greg KH (greg@kroah.com):
> > On Wed, Jul 06, 2005 at 05:08:35PM -0500, serue@us.ibm.com wrote:
> > > Quoting Greg KH (greg@kroah.com):
> > > > think it could be made even smaller if you use the default read and
> > > > write file type functions in libfs (look at the debugfs wrappers of them
> > > > for u8, u16, etc, for examples of how to use them.)
> > > 
> > > The attached patch cleans up the securelevel code for the seclvl file.
> > > Is this a reasonable way to go about this?
> > 
> > No.
> > 
> > > Or is there a better way to do this?
> > 
> > Look at how debugfs uses the libfs code.  We should not need to add
> > these handlers to securityfs.
> 
> Unfortunately the simple_attr code from libfs really doesn't seem to be
> usable for int args.

Why not?  You want a negative number?  Just cast the u64 to a signed int
then.  Will that not work?  If not we can tweak the libfs interface to
work properly for you.

> However the below patch follows some of the
> examples in debugfs and comes out cleaner than my original patch.

That is nicer.  But I think you can get it smaller with the libfs stuff
:)

thanks,

greg k-h

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

* Re: [PATCH] securityfs
  2005-07-07 17:48                   ` Greg KH
@ 2005-07-07 18:27                     ` serue
  2005-07-07 22:46                       ` serge
  0 siblings, 1 reply; 57+ messages in thread
From: serue @ 2005-07-07 18:27 UTC (permalink / raw)
  To: Greg KH
  Cc: serge, serue, James Morris, Tony Jones, lkml, Chris Wright,
	Stephen Smalley, Andrew Morton, Michael Halcrow, David Safford,
	Reiner Sailer, Gerrit Huizenga

Quoting Greg KH (greg@kroah.com):
> > Unfortunately the simple_attr code from libfs really doesn't seem to be
> > usable for int args.
> 
> Why not?  You want a negative number?  Just cast the u64 to a signed int
> then.  Will that not work?  If not we can tweak the libfs interface to
> work properly for you.

Hmm, I ran into two problems:
	1, the __simple_attr_check_format seems to complain about a "%d"
	format.
	2, when I try just doing the typecasting, I get an oops...

The patch below is my attempt.  The oops follows, but I'll look at it
some more tomorrow.  It seems like it has to be something obvious...


Jul  7 18:14:42 serge-hv4 kernel:  Oops: Kernel access of bad area, sig: 11 [#2]
Jul  7 18:14:42 serge-hv4 kernel: SMP NR_CPUS=128 NUMA PSERIES LPAR 
Jul  7 18:14:42 serge-hv4 kernel: Modules linked in: seclvl ipv6 sg binfmt_misc dm_mod
Jul  7 18:14:42 serge-hv4 kernel: NIP: D00000000002F1DC XER: 20000001 LR: C0000000000E3A58 CTR: D00000000002F1DC
Jul  7 18:14:42 serge-hv4 kernel: REGS: c00000004256f9c0 TRAP: 0300   Not tainted  (2.6.13-rc1-seclvl)
Jul  7 18:14:42 serge-hv4 kernel: MSR: 8000000000009032 EE: 1 PR: 0 FP: 0 ME: 1 IR/DR: 11 CR: 24040482
Jul  7 18:14:42 serge-hv4 kernel: DAR: 0000000000000000 DSISR: 0000000040000000
Jul  7 18:14:42 serge-hv4 kernel: TASK: c000000043858030[4707] 'cat' THREAD: c00000004256c000 CPU: 3
Jul  7 18:14:42 serge-hv4 kernel: GPR00: D00000000002F1DC C00000004256FC40 D000000000040888 0000000000000000 
Jul  7 18:14:42 serge-hv4 kernel: GPR04: 0000000010015858 0000000000001000 C00000004256FE08 0000000000001000 
Jul  7 18:14:42 serge-hv4 kernel: GPR08: 0000000010015858 D0000000000387B8 C000000000538D78 D00000000002F1E4 
Jul  7 18:14:42 serge-hv4 kernel: GPR12: 0000000000000000 C000000000435400 00000000100F3458 0000000000000001 
Jul  7 18:14:42 serge-hv4 kernel: GPR16: 0000000000001000 00000000FFFFFFFF 0000000000000000 0000000000000000 
Jul  7 18:14:42 serge-hv4 kernel: GPR20: 0000000010015858 00000000FFEF4D14 0000000000000002 0000000000000000 
Jul  7 18:14:42 serge-hv4 kernel: GPR24: 0000000044222442 0000000000001000 0000000010015858 C00000004256FE08 
Jul  7 18:14:42 serge-hv4 kernel: GPR28: C000000047C00F10 C000000047C00F50 C0000000004AC920 C000000047C00F00 
Jul  7 18:14:42 serge-hv4 kernel: NIP [d00000000002f1dc] .seclvl_int_get+0x0/0x8 [seclvl]
Jul  7 18:14:42 serge-hv4 kernel: LR [c0000000000e3a58] .simple_attr_read+0xb8/0x168
Jul  7 18:14:42 serge-hv4 kernel: Call Trace:
Jul  7 18:14:42 serge-hv4 kernel: [c00000004256fc40] [000000000ffca938] 0xffca938 (unreliable)
Jul  7 18:14:42 serge-hv4 kernel: [c00000004256fcf0] [c0000000000b13bc] .vfs_read+0x1c0/0x1c8
Jul  7 18:14:42 serge-hv4 kernel: [c00000004256fd90] [c0000000000b1740] .sys_read+0x4c/0x90
Jul  7 18:14:42 serge-hv4 kernel: [c00000004256fe30] [c00000000000d600] syscall_exit+0x0/0x18
Jul  7 18:14:42 serge-hv4 kernel: Instruction dump:
Jul  7 18:14:42 serge-hv4 kernel: e93e8008 ebbe8060 ebe90000 e81d0000 7c00f850 2ba003e8 409dfe94 e8be8058 
Jul  7 18:14:42 serge-hv4 kernel: e87e8068 e89e8020 38c0ffff 4bffff94 <e8630000> 4e800020 7c0802a6 fbc1fff0 

thanks,
-serge

Index: linux-2.6.13-rc1/include/linux/fs.h
===================================================================
--- linux-2.6.13-rc1.orig/include/linux/fs.h	2005-07-07 15:10:22.000000000 -0500
+++ linux-2.6.13-rc1/include/linux/fs.h	2005-07-07 17:59:54.000000000 -0500
@@ -1717,7 +1717,6 @@ static inline void simple_transaction_se
 #define DEFINE_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt)		\
 static int __fops ## _open(struct inode *inode, struct file *file)	\
 {									\
-	__simple_attr_check_format(__fmt, 0ull);			\
 	return simple_attr_open(inode, file, __get, __set, __fmt);	\
 }									\
 static struct file_operations __fops = {				\
Index: linux-2.6.13-rc1/security/seclvl.c
===================================================================
--- linux-2.6.13-rc1.orig/security/seclvl.c	2005-07-07 15:33:45.000000000 -0500
+++ linux-2.6.13-rc1/security/seclvl.c	2005-07-07 18:16:11.000000000 -0500
@@ -119,69 +119,6 @@ MODULE_PARM_DESC(hideHash, "When set to 
 	} while (0)
 
 /**
- * kobject stuff
- */
-
-struct subsystem seclvl_subsys;
-
-struct seclvl_obj {
-	char *name;
-	struct list_head slot_list;
-	struct kobject kobj;
-};
-
-/**
- * There is a seclvl_attribute struct for each file in sysfs.
- *
- * In our case, we have one of these structs for "passwd" and another
- * for "seclvl".
- */
-struct seclvl_attribute {
-	struct attribute attr;
-	ssize_t(*show) (struct seclvl_obj *, char *);
-	ssize_t(*store) (struct seclvl_obj *, const char *, size_t);
-};
-
-/**
- * When this function is called, one of the files in sysfs is being
- * written to.  attribute->store is a function pointer to whatever the
- * struct seclvl_attribute store function pointer points to.  It is
- * unique for "passwd" and "seclvl".
- */
-static ssize_t
-seclvl_attr_store(struct kobject *kobj,
-		  struct attribute *attr, const char *buf, size_t len)
-{
-	struct seclvl_obj *obj = container_of(kobj, struct seclvl_obj, kobj);
-	struct seclvl_attribute *attribute =
-	    container_of(attr, struct seclvl_attribute, attr);
-	return attribute->store ? attribute->store(obj, buf, len) : -EIO;
-}
-
-static ssize_t
-seclvl_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
-{
-	struct seclvl_obj *obj = container_of(kobj, struct seclvl_obj, kobj);
-	struct seclvl_attribute *attribute =
-	    container_of(attr, struct seclvl_attribute, attr);
-	return attribute->show ? attribute->show(obj, buf) : -EIO;
-}
-
-/**
- * Callback function pointers for show and store
- */
-static struct sysfs_ops seclvlfs_sysfs_ops = {
-	.show = seclvl_attr_show,
-	.store = seclvl_attr_store,
-};
-
-static struct kobj_type seclvl_ktype = {
-	.sysfs_ops = &seclvlfs_sysfs_ops
-};
-
-decl_subsys(seclvl, &seclvl_ktype, NULL);
-
-/**
  * The actual security level.  Ranges between -1 and 2 inclusive.
  */
 static int seclvl;
@@ -213,97 +150,44 @@ static int seclvl_sanity(int reqlvl)
 }
 
 /**
- * Called whenever the user reads the sysfs handle to this kernel
- * object
- */
-static ssize_t seclvl_read_file(struct seclvl_obj *obj, char *buff)
-{
-	return snprintf(buff, PAGE_SIZE, "%d\n", seclvl);
-}
-
-/**
  * security level advancement rules:
  *   Valid levels are -1 through 2, inclusive.
  *   From -1, stuck.  [ in case compiled into kernel ]
  *   From 0 or above, can only increment.
  */
-static int do_seclvl_advance(int newlvl)
+static void do_seclvl_advance(void *data, u64 val)
 {
-	if (newlvl <= seclvl) {
-		seclvl_printk(1, KERN_WARNING, "Cannot advance to seclvl "
-			      "[%d]\n", newlvl);
-		return -EINVAL;
-	}
+	int ret;
+	int newlvl = (int)val;
+
+	ret = seclvl_sanity(newlvl);
+	if (ret)
+		return;
+
 	if (newlvl > 2) {
 		seclvl_printk(1, KERN_WARNING, "Cannot advance to seclvl "
 			      "[%d]\n", newlvl);
-		return -EINVAL;
+		return;
 	}
 	if (seclvl == -1) {
 		seclvl_printk(1, KERN_WARNING, "Not allowed to advance to "
 			      "seclvl [%d]\n", seclvl);
-		return -EPERM;
+		return;
 	}
-	seclvl = newlvl;
-	return 0;
+	seclvl = newlvl;  /* would it be more "correct" to set *data? */
+	return;
 }
 
-/**
- * Called whenever the user writes to the sysfs handle to this kernel
- * object (seclvl/seclvl).  It expects a single-digit number.
- */
-static ssize_t
-seclvl_write_file(struct seclvl_obj *obj, const char *buff, size_t count)
+static u64 seclvl_int_get(void *data)
 {
-	unsigned long val;
-	if (count > 2 || (count == 2 && buff[1] != '\n')) {
-		seclvl_printk(1, KERN_WARNING, "Invalid value passed to "
-			      "seclvl: [%s]\n", buff);
-		return -EINVAL;
-	}
-	val = buff[0] - 48;
-	if (seclvl_sanity(val)) {
-		seclvl_printk(1, KERN_WARNING, "Illegal secure level "
-			      "requested: [%d]\n", (int)val);
-		return -EPERM;
-	}
-	if (do_seclvl_advance(val)) {
-		seclvl_printk(0, KERN_ERR, "Failure advancing security level "
-			      "to %lu\n", val);
-	}
-	return count;
+	return *(int *)data;
 }
 
-/* Generate sysfs_attr_seclvl */
-static struct seclvl_attribute sysfs_attr_seclvl =
-__ATTR(seclvl, (S_IFREG | S_IRUGO | S_IWUSR), seclvl_read_file,
-       seclvl_write_file);
+DEFINE_SIMPLE_ATTRIBUTE(seclvl_file_ops, seclvl_int_get, do_seclvl_advance, "%d\n");
 
 static unsigned char hashedPassword[SHA1_DIGEST_SIZE];
 
 /**
- * Called whenever the user reads the sysfs passwd handle.
- */
-static ssize_t seclvl_read_passwd(struct seclvl_obj *obj, char *buff)
-{
-	/* So just how good *is* your password? :-) */
-	char tmp[3];
-	int i = 0;
-	buff[0] = '\0';
-	if (hideHash) {
-		/* Security through obscurity */
-		return 0;
-	}
-	while (i < SHA1_DIGEST_SIZE) {
-		snprintf(tmp, 3, "%02x", hashedPassword[i]);
-		strncat(buff, tmp, 2);
-		i++;
-	}
-	strcat(buff, "\n");
-	return ((SHA1_DIGEST_SIZE * 2) + 1);
-}
-
-/**
  * Converts a block of plaintext of into its SHA1 hashed value.
  *
  * It would be nice if crypto had a wrapper to do this for us linear
@@ -347,12 +231,15 @@ plaintext_to_sha1(unsigned char *hash, c
  * object.  It hashes the password and compares the hashed results.
  */
 static ssize_t
-seclvl_write_passwd(struct seclvl_obj *obj, const char *buff, size_t count)
+passwd_write_file(struct file * file, const char __user * buf,
+				size_t count, loff_t *ppos)
 {
 	int i;
 	unsigned char tmp[SHA1_DIGEST_SIZE];
+	char *page;
 	int rc;
 	int len;
+
 	if (!*passwd && !*sha1_passwd) {
 		seclvl_printk(0, KERN_ERR, "Attempt to password-unlock the "
 			      "seclvl module, but neither a plain text "
@@ -363,13 +250,26 @@ seclvl_write_passwd(struct seclvl_obj *o
 			      "maintainer about this event.\n");
 		return -EINVAL;
 	}
-	len = strlen(buff);
+
+	if (count < 0 || count >= PAGE_SIZE)
+		return -ENOMEM;
+	if (*ppos != 0) {
+		return -EINVAL;
+	}
+	page = (char *)get_zeroed_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+	len = -EFAULT;
+	if (copy_from_user(page, buf, count))
+		goto out;
+	
+	len = strlen(page);
 	/* ``echo "secret" > seclvl/passwd'' includes a newline */
-	if (buff[len - 1] == '\n') {
+	if (page[len - 1] == '\n') {
 		len--;
 	}
 	/* Hash the password, then compare the hashed values */
-	if ((rc = plaintext_to_sha1(tmp, buff, len))) {
+	if ((rc = plaintext_to_sha1(tmp, page, len))) {
 		seclvl_printk(0, KERN_ERR, "Error hashing password: rc = "
 			      "[%d]\n", rc);
 		return rc;
@@ -382,13 +282,16 @@ seclvl_write_passwd(struct seclvl_obj *o
 	seclvl_printk(0, KERN_INFO,
 		      "Password accepted; seclvl reduced to 0.\n");
 	seclvl = 0;
-	return count;
+	len = count;
+
+out:
+	free_page((unsigned long)page);
+	return len;
 }
 
-/* Generate sysfs_attr_passwd */
-static struct seclvl_attribute sysfs_attr_passwd =
-__ATTR(passwd, (S_IFREG | S_IRUGO | S_IWUSR), seclvl_read_passwd,
-       seclvl_write_passwd);
+static struct file_operations passwd_file_ops = {
+	.write = passwd_write_file,
+};
 
 /**
  * Explicitely disallow ptrace'ing the init process.
@@ -647,22 +550,34 @@ static int processPassword(void)
 }
 
 /**
- * Sysfs registrations
+ * securityfs registrations
  */
-static int doSysfsRegistrations(void)
+struct dentry *dir_ino, *seclvl_ino, *passwd_ino;
+
+static int seclvlfs_register(void)
 {
-	int rc = 0;
-	if ((rc = subsystem_register(&seclvl_subsys))) {
-		seclvl_printk(0, KERN_WARNING,
-			      "Error [%d] registering seclvl subsystem\n", rc);
-		return rc;
-	}
-	sysfs_create_file(&seclvl_subsys.kset.kobj, &sysfs_attr_seclvl.attr);
+	dir_ino = securityfs_create_dir("seclvl", NULL);
+	if (!dir_ino)
+		return -EFAULT;
+
+	seclvl_ino = securityfs_create_file("seclvl", S_IRUGO | S_IWUSR,
+				dir_ino, NULL, &seclvl_file_ops);
+	if (!seclvl_ino)
+		goto out_deldir;
 	if (*passwd || *sha1_passwd) {
-		sysfs_create_file(&seclvl_subsys.kset.kobj,
-				  &sysfs_attr_passwd.attr);
+		passwd_ino = securityfs_create_file("passwd", S_IRUGO | S_IWUSR,
+				dir_ino, NULL, &passwd_file_ops);
+		if (!passwd_ino)
+			goto out_delf;
 	}
 	return 0;
+
+out_deldir:
+	securityfs_remove(dir_ino);
+out_delf:
+	securityfs_remove(seclvl_ino);
+
+	return -EFAULT;
 }
 
 /**
@@ -677,8 +592,6 @@ static int __init seclvl_init(void)
 		rc = -EINVAL;
 		goto exit;
 	}
-	sysfs_attr_seclvl.attr.owner = THIS_MODULE;
-	sysfs_attr_passwd.attr.owner = THIS_MODULE;
 	if (initlvl < -1 || initlvl > 2) {
 		seclvl_printk(0, KERN_ERR, "Error: bad initial securelevel "
 			      "[%d].\n", initlvl);
@@ -706,7 +619,7 @@ static int __init seclvl_init(void)
 		}		/* if primary module registered */
 		secondary = 1;
 	}			/* if we registered ourselves with the security framework */
-	if ((rc = doSysfsRegistrations())) {
+	if ((rc = seclvlfs_register())) {
 		seclvl_printk(0, KERN_ERR, "Error registering with sysfs\n");
 		goto exit;
 	}
@@ -724,12 +637,11 @@ static int __init seclvl_init(void)
  */
 static void __exit seclvl_exit(void)
 {
-	sysfs_remove_file(&seclvl_subsys.kset.kobj, &sysfs_attr_seclvl.attr);
+	securityfs_remove(seclvl_ino);
 	if (*passwd || *sha1_passwd) {
-		sysfs_remove_file(&seclvl_subsys.kset.kobj,
-				  &sysfs_attr_passwd.attr);
+		securityfs_remove(passwd_ino);
 	}
-	subsystem_unregister(&seclvl_subsys);
+	securityfs_remove(dir_ino);
 	if (secondary == 1) {
 		mod_unreg_security(MY_NAME, &seclvl_ops);
 	} else if (unregister_security(&seclvl_ops)) {

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

* Re: [PATCH] securityfs
  2005-07-07 18:27                     ` serue
@ 2005-07-07 22:46                       ` serge
  2005-07-07 23:06                         ` Greg KH
  0 siblings, 1 reply; 57+ messages in thread
From: serge @ 2005-07-07 22:46 UTC (permalink / raw)
  To: serue
  Cc: Greg KH, James Morris, Tony Jones, lkml, Chris Wright,
	Stephen Smalley, Andrew Morton, Michael Halcrow, David Safford,
	Reiner Sailer, Gerrit Huizenga

Quoting serue@us.ibm.com (serue@us.ibm.com):
> Quoting Greg KH (greg@kroah.com):
> > > Unfortunately the simple_attr code from libfs really doesn't seem to be
> > > usable for int args.
> > 
> > Why not?  You want a negative number?  Just cast the u64 to a signed int
> > then.  Will that not work?  If not we can tweak the libfs interface to
> > work properly for you.
> 
> Hmm, I ran into two problems:
> 	1, the __simple_attr_check_format seems to complain about a "%d"
> 	format.
> 	2, when I try just doing the typecasting, I get an oops...

Uh, never mind...

please don't look at that patch :)

With the obvious fix, that does in fact work (patch appended).  The
__simple_attr_check_format problem remains however.  I assume we don't
really want to just take it out, though, like this patch does?  The
error I get without the fs.h patch is:

security/seclvl.c: In function `seclvl_file_ops_open':
security/seclvl.c:186: warning: int format, different type arg (arg 2)

thanks,
-serge
--
 include/linux/fs.h |    1 
 security/seclvl.c  |  228 ++++++++++++++++-------------------------------------
 2 files changed, 70 insertions(+), 159 deletions(-)

Index: linux-2.6.13-rc1/include/linux/fs.h
===================================================================
--- linux-2.6.13-rc1.orig/include/linux/fs.h	2005-07-07 15:10:22.000000000 -0500
+++ linux-2.6.13-rc1/include/linux/fs.h	2005-07-07 17:59:54.000000000 -0500
@@ -1717,7 +1717,6 @@ static inline void simple_transaction_se
 #define DEFINE_SIMPLE_ATTRIBUTE(__fops, __get, __set, __fmt)		\
 static int __fops ## _open(struct inode *inode, struct file *file)	\
 {									\
-	__simple_attr_check_format(__fmt, 0ull);			\
 	return simple_attr_open(inode, file, __get, __set, __fmt);	\
 }									\
 static struct file_operations __fops = {				\
Index: linux-2.6.13-rc1/security/seclvl.c
===================================================================
--- linux-2.6.13-rc1.orig/security/seclvl.c	2005-07-07 15:33:45.000000000 -0500
+++ linux-2.6.13-rc1/security/seclvl.c	2005-07-07 22:30:45.000000000 -0500
@@ -119,69 +119,6 @@ MODULE_PARM_DESC(hideHash, "When set to 
 	} while (0)
 
 /**
- * kobject stuff
- */
-
-struct subsystem seclvl_subsys;
-
-struct seclvl_obj {
-	char *name;
-	struct list_head slot_list;
-	struct kobject kobj;
-};
-
-/**
- * There is a seclvl_attribute struct for each file in sysfs.
- *
- * In our case, we have one of these structs for "passwd" and another
- * for "seclvl".
- */
-struct seclvl_attribute {
-	struct attribute attr;
-	ssize_t(*show) (struct seclvl_obj *, char *);
-	ssize_t(*store) (struct seclvl_obj *, const char *, size_t);
-};
-
-/**
- * When this function is called, one of the files in sysfs is being
- * written to.  attribute->store is a function pointer to whatever the
- * struct seclvl_attribute store function pointer points to.  It is
- * unique for "passwd" and "seclvl".
- */
-static ssize_t
-seclvl_attr_store(struct kobject *kobj,
-		  struct attribute *attr, const char *buf, size_t len)
-{
-	struct seclvl_obj *obj = container_of(kobj, struct seclvl_obj, kobj);
-	struct seclvl_attribute *attribute =
-	    container_of(attr, struct seclvl_attribute, attr);
-	return attribute->store ? attribute->store(obj, buf, len) : -EIO;
-}
-
-static ssize_t
-seclvl_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
-{
-	struct seclvl_obj *obj = container_of(kobj, struct seclvl_obj, kobj);
-	struct seclvl_attribute *attribute =
-	    container_of(attr, struct seclvl_attribute, attr);
-	return attribute->show ? attribute->show(obj, buf) : -EIO;
-}
-
-/**
- * Callback function pointers for show and store
- */
-static struct sysfs_ops seclvlfs_sysfs_ops = {
-	.show = seclvl_attr_show,
-	.store = seclvl_attr_store,
-};
-
-static struct kobj_type seclvl_ktype = {
-	.sysfs_ops = &seclvlfs_sysfs_ops
-};
-
-decl_subsys(seclvl, &seclvl_ktype, NULL);
-
-/**
  * The actual security level.  Ranges between -1 and 2 inclusive.
  */
 static int seclvl;
@@ -213,97 +150,44 @@ static int seclvl_sanity(int reqlvl)
 }
 
 /**
- * Called whenever the user reads the sysfs handle to this kernel
- * object
- */
-static ssize_t seclvl_read_file(struct seclvl_obj *obj, char *buff)
-{
-	return snprintf(buff, PAGE_SIZE, "%d\n", seclvl);
-}
-
-/**
  * security level advancement rules:
  *   Valid levels are -1 through 2, inclusive.
  *   From -1, stuck.  [ in case compiled into kernel ]
  *   From 0 or above, can only increment.
  */
-static int do_seclvl_advance(int newlvl)
+static void do_seclvl_advance(void *data, u64 val)
 {
-	if (newlvl <= seclvl) {
-		seclvl_printk(1, KERN_WARNING, "Cannot advance to seclvl "
-			      "[%d]\n", newlvl);
-		return -EINVAL;
-	}
+	int ret;
+	int newlvl = (int)val;
+
+	ret = seclvl_sanity(newlvl);
+	if (ret)
+		return;
+
 	if (newlvl > 2) {
 		seclvl_printk(1, KERN_WARNING, "Cannot advance to seclvl "
 			      "[%d]\n", newlvl);
-		return -EINVAL;
+		return;
 	}
 	if (seclvl == -1) {
 		seclvl_printk(1, KERN_WARNING, "Not allowed to advance to "
 			      "seclvl [%d]\n", seclvl);
-		return -EPERM;
+		return;
 	}
-	seclvl = newlvl;
-	return 0;
+	seclvl = newlvl;  /* would it be more "correct" to set *data? */
+	return;
 }
 
-/**
- * Called whenever the user writes to the sysfs handle to this kernel
- * object (seclvl/seclvl).  It expects a single-digit number.
- */
-static ssize_t
-seclvl_write_file(struct seclvl_obj *obj, const char *buff, size_t count)
+static u64 seclvl_int_get(void *data)
 {
-	unsigned long val;
-	if (count > 2 || (count == 2 && buff[1] != '\n')) {
-		seclvl_printk(1, KERN_WARNING, "Invalid value passed to "
-			      "seclvl: [%s]\n", buff);
-		return -EINVAL;
-	}
-	val = buff[0] - 48;
-	if (seclvl_sanity(val)) {
-		seclvl_printk(1, KERN_WARNING, "Illegal secure level "
-			      "requested: [%d]\n", (int)val);
-		return -EPERM;
-	}
-	if (do_seclvl_advance(val)) {
-		seclvl_printk(0, KERN_ERR, "Failure advancing security level "
-			      "to %lu\n", val);
-	}
-	return count;
+	return *(int *)data;
 }
 
-/* Generate sysfs_attr_seclvl */
-static struct seclvl_attribute sysfs_attr_seclvl =
-__ATTR(seclvl, (S_IFREG | S_IRUGO | S_IWUSR), seclvl_read_file,
-       seclvl_write_file);
+DEFINE_SIMPLE_ATTRIBUTE(seclvl_file_ops, seclvl_int_get, do_seclvl_advance, "%d\n");
 
 static unsigned char hashedPassword[SHA1_DIGEST_SIZE];
 
 /**
- * Called whenever the user reads the sysfs passwd handle.
- */
-static ssize_t seclvl_read_passwd(struct seclvl_obj *obj, char *buff)
-{
-	/* So just how good *is* your password? :-) */
-	char tmp[3];
-	int i = 0;
-	buff[0] = '\0';
-	if (hideHash) {
-		/* Security through obscurity */
-		return 0;
-	}
-	while (i < SHA1_DIGEST_SIZE) {
-		snprintf(tmp, 3, "%02x", hashedPassword[i]);
-		strncat(buff, tmp, 2);
-		i++;
-	}
-	strcat(buff, "\n");
-	return ((SHA1_DIGEST_SIZE * 2) + 1);
-}
-
-/**
  * Converts a block of plaintext of into its SHA1 hashed value.
  *
  * It would be nice if crypto had a wrapper to do this for us linear
@@ -347,12 +231,15 @@ plaintext_to_sha1(unsigned char *hash, c
  * object.  It hashes the password and compares the hashed results.
  */
 static ssize_t
-seclvl_write_passwd(struct seclvl_obj *obj, const char *buff, size_t count)
+passwd_write_file(struct file * file, const char __user * buf,
+				size_t count, loff_t *ppos)
 {
 	int i;
 	unsigned char tmp[SHA1_DIGEST_SIZE];
+	char *page;
 	int rc;
 	int len;
+
 	if (!*passwd && !*sha1_passwd) {
 		seclvl_printk(0, KERN_ERR, "Attempt to password-unlock the "
 			      "seclvl module, but neither a plain text "
@@ -363,13 +250,26 @@ seclvl_write_passwd(struct seclvl_obj *o
 			      "maintainer about this event.\n");
 		return -EINVAL;
 	}
-	len = strlen(buff);
+
+	if (count < 0 || count >= PAGE_SIZE)
+		return -ENOMEM;
+	if (*ppos != 0) {
+		return -EINVAL;
+	}
+	page = (char *)get_zeroed_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+	len = -EFAULT;
+	if (copy_from_user(page, buf, count))
+		goto out;
+	
+	len = strlen(page);
 	/* ``echo "secret" > seclvl/passwd'' includes a newline */
-	if (buff[len - 1] == '\n') {
+	if (page[len - 1] == '\n') {
 		len--;
 	}
 	/* Hash the password, then compare the hashed values */
-	if ((rc = plaintext_to_sha1(tmp, buff, len))) {
+	if ((rc = plaintext_to_sha1(tmp, page, len))) {
 		seclvl_printk(0, KERN_ERR, "Error hashing password: rc = "
 			      "[%d]\n", rc);
 		return rc;
@@ -382,13 +282,16 @@ seclvl_write_passwd(struct seclvl_obj *o
 	seclvl_printk(0, KERN_INFO,
 		      "Password accepted; seclvl reduced to 0.\n");
 	seclvl = 0;
-	return count;
+	len = count;
+
+out:
+	free_page((unsigned long)page);
+	return len;
 }
 
-/* Generate sysfs_attr_passwd */
-static struct seclvl_attribute sysfs_attr_passwd =
-__ATTR(passwd, (S_IFREG | S_IRUGO | S_IWUSR), seclvl_read_passwd,
-       seclvl_write_passwd);
+static struct file_operations passwd_file_ops = {
+	.write = passwd_write_file,
+};
 
 /**
  * Explicitely disallow ptrace'ing the init process.
@@ -647,22 +550,34 @@ static int processPassword(void)
 }
 
 /**
- * Sysfs registrations
+ * securityfs registrations
  */
-static int doSysfsRegistrations(void)
+struct dentry *dir_ino, *seclvl_ino, *passwd_ino;
+
+static int seclvlfs_register(void)
 {
-	int rc = 0;
-	if ((rc = subsystem_register(&seclvl_subsys))) {
-		seclvl_printk(0, KERN_WARNING,
-			      "Error [%d] registering seclvl subsystem\n", rc);
-		return rc;
-	}
-	sysfs_create_file(&seclvl_subsys.kset.kobj, &sysfs_attr_seclvl.attr);
+	dir_ino = securityfs_create_dir("seclvl", NULL);
+	if (!dir_ino)
+		return -EFAULT;
+
+	seclvl_ino = securityfs_create_file("seclvl", S_IRUGO | S_IWUSR,
+				dir_ino, &seclvl, &seclvl_file_ops);
+	if (!seclvl_ino)
+		goto out_deldir;
 	if (*passwd || *sha1_passwd) {
-		sysfs_create_file(&seclvl_subsys.kset.kobj,
-				  &sysfs_attr_passwd.attr);
+		passwd_ino = securityfs_create_file("passwd", S_IRUGO | S_IWUSR,
+				dir_ino, NULL, &passwd_file_ops);
+		if (!passwd_ino)
+			goto out_delf;
 	}
 	return 0;
+
+out_deldir:
+	securityfs_remove(dir_ino);
+out_delf:
+	securityfs_remove(seclvl_ino);
+
+	return -EFAULT;
 }
 
 /**
@@ -677,8 +592,6 @@ static int __init seclvl_init(void)
 		rc = -EINVAL;
 		goto exit;
 	}
-	sysfs_attr_seclvl.attr.owner = THIS_MODULE;
-	sysfs_attr_passwd.attr.owner = THIS_MODULE;
 	if (initlvl < -1 || initlvl > 2) {
 		seclvl_printk(0, KERN_ERR, "Error: bad initial securelevel "
 			      "[%d].\n", initlvl);
@@ -706,7 +619,7 @@ static int __init seclvl_init(void)
 		}		/* if primary module registered */
 		secondary = 1;
 	}			/* if we registered ourselves with the security framework */
-	if ((rc = doSysfsRegistrations())) {
+	if ((rc = seclvlfs_register())) {
 		seclvl_printk(0, KERN_ERR, "Error registering with sysfs\n");
 		goto exit;
 	}
@@ -724,12 +637,11 @@ static int __init seclvl_init(void)
  */
 static void __exit seclvl_exit(void)
 {
-	sysfs_remove_file(&seclvl_subsys.kset.kobj, &sysfs_attr_seclvl.attr);
+	securityfs_remove(seclvl_ino);
 	if (*passwd || *sha1_passwd) {
-		sysfs_remove_file(&seclvl_subsys.kset.kobj,
-				  &sysfs_attr_passwd.attr);
+		securityfs_remove(passwd_ino);
 	}
-	subsystem_unregister(&seclvl_subsys);
+	securityfs_remove(dir_ino);
 	if (secondary == 1) {
 		mod_unreg_security(MY_NAME, &seclvl_ops);
 	} else if (unregister_security(&seclvl_ops)) {

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

* Re: [PATCH] securityfs
  2005-07-07 22:46                       ` serge
@ 2005-07-07 23:06                         ` Greg KH
  2005-07-07 23:12                           ` serue
  2005-07-08 20:44                           ` serue
  0 siblings, 2 replies; 57+ messages in thread
From: Greg KH @ 2005-07-07 23:06 UTC (permalink / raw)
  To: serge
  Cc: serue, James Morris, Tony Jones, lkml, Chris Wright,
	Stephen Smalley, Andrew Morton, Michael Halcrow, David Safford,
	Reiner Sailer, Gerrit Huizenga

On Thu, Jul 07, 2005 at 05:46:04PM -0500, serge@hallyn.com wrote:
> 
> With the obvious fix, that does in fact work (patch appended).

Good.

> The __simple_attr_check_format problem remains however.  I assume we
> don't really want to just take it out, though, like this patch does?

No we do not.

> The error I get without the fs.h patch is:
> 
> security/seclvl.c: In function `seclvl_file_ops_open':
> security/seclvl.c:186: warning: int format, different type arg (arg 2)

Care to work to try to fix it up?

thanks,

greg k-h

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

* Re: [PATCH] securityfs
  2005-07-07 23:06                         ` Greg KH
@ 2005-07-07 23:12                           ` serue
  2005-07-08 20:44                           ` serue
  1 sibling, 0 replies; 57+ messages in thread
From: serue @ 2005-07-07 23:12 UTC (permalink / raw)
  To: Greg KH
  Cc: serge, serue, James Morris, Tony Jones, lkml, Chris Wright,
	Stephen Smalley, Andrew Morton, Michael Halcrow, David Safford,
	Reiner Sailer, Gerrit Huizenga

Quoting Greg KH (greg@kroah.com):
> On Thu, Jul 07, 2005 at 05:46:04PM -0500, serge@hallyn.com wrote:
> > 
> > With the obvious fix, that does in fact work (patch appended).
> 
> Good.
> 
> > The __simple_attr_check_format problem remains however.  I assume we
> > don't really want to just take it out, though, like this patch does?
> 
> No we do not.
> 
> > The error I get without the fs.h patch is:
> > 
> > security/seclvl.c: In function `seclvl_file_ops_open':
> > security/seclvl.c:186: warning: int format, different type arg (arg 2)
> 
> Care to work to try to fix it up?

Yes I do, thanks :)

-serge

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

* Re: [PATCH] securityfs
  2005-07-07 23:06                         ` Greg KH
  2005-07-07 23:12                           ` serue
@ 2005-07-08 20:44                           ` serue
  2005-07-08 20:49                             ` Greg KH
  1 sibling, 1 reply; 57+ messages in thread
From: serue @ 2005-07-08 20:44 UTC (permalink / raw)
  To: Greg KH
  Cc: James Morris, Tony Jones, lkml, Chris Wright, Stephen Smalley,
	Andrew Morton, Michael Halcrow, David Safford, Reiner Sailer,
	Gerrit Huizenga

Quoting Greg KH (greg@kroah.com):
> On Thu, Jul 07, 2005 at 05:46:04PM -0500, serge@hallyn.com wrote:
> > 
> > With the obvious fix, that does in fact work (patch appended).
> 
> Good.
> 
> > The __simple_attr_check_format problem remains however.  I assume we
> > don't really want to just take it out, though, like this patch does?
> 
> No we do not.
> 
> > The error I get without the fs.h patch is:
> > 
> > security/seclvl.c: In function `seclvl_file_ops_open':
> > security/seclvl.c:186: warning: int format, different type arg (arg 2)
> 
> Care to work to try to fix it up?

Once again, the simple_attr in libfs was actually sufficient - I'd
thought the __attribute__(format(printk(1,2))) was more mysterious than
it really is.

At last, here is the full patch to make seclvl use securityfs.

thanks,
-serge

Signed-off-by: Serge Hallyn <serue@us.ibm.com>
--
 seclvl.c |  228 +++++++++++++++++++--------------------------------------------
 1 files changed, 70 insertions(+), 158 deletions(-)

Index: linux-2.6.13-rc1/security/seclvl.c
===================================================================
--- linux-2.6.13-rc1.orig/security/seclvl.c	2005-07-08 19:38:22.000000000 -0500
+++ linux-2.6.13-rc1/security/seclvl.c	2005-07-08 19:39:49.000000000 -0500
@@ -119,69 +119,6 @@ MODULE_PARM_DESC(hideHash, "When set to 
 	} while (0)
 
 /**
- * kobject stuff
- */
-
-struct subsystem seclvl_subsys;
-
-struct seclvl_obj {
-	char *name;
-	struct list_head slot_list;
-	struct kobject kobj;
-};
-
-/**
- * There is a seclvl_attribute struct for each file in sysfs.
- *
- * In our case, we have one of these structs for "passwd" and another
- * for "seclvl".
- */
-struct seclvl_attribute {
-	struct attribute attr;
-	ssize_t(*show) (struct seclvl_obj *, char *);
-	ssize_t(*store) (struct seclvl_obj *, const char *, size_t);
-};
-
-/**
- * When this function is called, one of the files in sysfs is being
- * written to.  attribute->store is a function pointer to whatever the
- * struct seclvl_attribute store function pointer points to.  It is
- * unique for "passwd" and "seclvl".
- */
-static ssize_t
-seclvl_attr_store(struct kobject *kobj,
-		  struct attribute *attr, const char *buf, size_t len)
-{
-	struct seclvl_obj *obj = container_of(kobj, struct seclvl_obj, kobj);
-	struct seclvl_attribute *attribute =
-	    container_of(attr, struct seclvl_attribute, attr);
-	return attribute->store ? attribute->store(obj, buf, len) : -EIO;
-}
-
-static ssize_t
-seclvl_attr_show(struct kobject *kobj, struct attribute *attr, char *buf)
-{
-	struct seclvl_obj *obj = container_of(kobj, struct seclvl_obj, kobj);
-	struct seclvl_attribute *attribute =
-	    container_of(attr, struct seclvl_attribute, attr);
-	return attribute->show ? attribute->show(obj, buf) : -EIO;
-}
-
-/**
- * Callback function pointers for show and store
- */
-static struct sysfs_ops seclvlfs_sysfs_ops = {
-	.show = seclvl_attr_show,
-	.store = seclvl_attr_store,
-};
-
-static struct kobj_type seclvl_ktype = {
-	.sysfs_ops = &seclvlfs_sysfs_ops
-};
-
-decl_subsys(seclvl, &seclvl_ktype, NULL);
-
-/**
  * The actual security level.  Ranges between -1 and 2 inclusive.
  */
 static int seclvl;
@@ -213,97 +150,44 @@ static int seclvl_sanity(int reqlvl)
 }
 
 /**
- * Called whenever the user reads the sysfs handle to this kernel
- * object
- */
-static ssize_t seclvl_read_file(struct seclvl_obj *obj, char *buff)
-{
-	return snprintf(buff, PAGE_SIZE, "%d\n", seclvl);
-}
-
-/**
  * security level advancement rules:
  *   Valid levels are -1 through 2, inclusive.
  *   From -1, stuck.  [ in case compiled into kernel ]
  *   From 0 or above, can only increment.
  */
-static int do_seclvl_advance(int newlvl)
+static void do_seclvl_advance(void *data, u64 val)
 {
-	if (newlvl <= seclvl) {
-		seclvl_printk(1, KERN_WARNING, "Cannot advance to seclvl "
-			      "[%d]\n", newlvl);
-		return -EINVAL;
-	}
+	int ret;
+	int newlvl = (int)val;
+
+	ret = seclvl_sanity(newlvl);
+	if (ret)
+		return;
+
 	if (newlvl > 2) {
 		seclvl_printk(1, KERN_WARNING, "Cannot advance to seclvl "
 			      "[%d]\n", newlvl);
-		return -EINVAL;
+		return;
 	}
 	if (seclvl == -1) {
 		seclvl_printk(1, KERN_WARNING, "Not allowed to advance to "
 			      "seclvl [%d]\n", seclvl);
-		return -EPERM;
+		return;
 	}
-	seclvl = newlvl;
-	return 0;
+	seclvl = newlvl;  /* would it be more "correct" to set *data? */
+	return;
 }
 
-/**
- * Called whenever the user writes to the sysfs handle to this kernel
- * object (seclvl/seclvl).  It expects a single-digit number.
- */
-static ssize_t
-seclvl_write_file(struct seclvl_obj *obj, const char *buff, size_t count)
+static u64 seclvl_int_get(void *data)
 {
-	unsigned long val;
-	if (count > 2 || (count == 2 && buff[1] != '\n')) {
-		seclvl_printk(1, KERN_WARNING, "Invalid value passed to "
-			      "seclvl: [%s]\n", buff);
-		return -EINVAL;
-	}
-	val = buff[0] - 48;
-	if (seclvl_sanity(val)) {
-		seclvl_printk(1, KERN_WARNING, "Illegal secure level "
-			      "requested: [%d]\n", (int)val);
-		return -EPERM;
-	}
-	if (do_seclvl_advance(val)) {
-		seclvl_printk(0, KERN_ERR, "Failure advancing security level "
-			      "to %lu\n", val);
-	}
-	return count;
+	return *(int *)data;
 }
 
-/* Generate sysfs_attr_seclvl */
-static struct seclvl_attribute sysfs_attr_seclvl =
-__ATTR(seclvl, (S_IFREG | S_IRUGO | S_IWUSR), seclvl_read_file,
-       seclvl_write_file);
+DEFINE_SIMPLE_ATTRIBUTE(seclvl_file_ops, seclvl_int_get, do_seclvl_advance, "%lld\n");
 
 static unsigned char hashedPassword[SHA1_DIGEST_SIZE];
 
 /**
- * Called whenever the user reads the sysfs passwd handle.
- */
-static ssize_t seclvl_read_passwd(struct seclvl_obj *obj, char *buff)
-{
-	/* So just how good *is* your password? :-) */
-	char tmp[3];
-	int i = 0;
-	buff[0] = '\0';
-	if (hideHash) {
-		/* Security through obscurity */
-		return 0;
-	}
-	while (i < SHA1_DIGEST_SIZE) {
-		snprintf(tmp, 3, "%02x", hashedPassword[i]);
-		strncat(buff, tmp, 2);
-		i++;
-	}
-	strcat(buff, "\n");
-	return ((SHA1_DIGEST_SIZE * 2) + 1);
-}
-
-/**
  * Converts a block of plaintext of into its SHA1 hashed value.
  *
  * It would be nice if crypto had a wrapper to do this for us linear
@@ -347,12 +231,15 @@ plaintext_to_sha1(unsigned char *hash, c
  * object.  It hashes the password and compares the hashed results.
  */
 static ssize_t
-seclvl_write_passwd(struct seclvl_obj *obj, const char *buff, size_t count)
+passwd_write_file(struct file * file, const char __user * buf,
+				size_t count, loff_t *ppos)
 {
 	int i;
 	unsigned char tmp[SHA1_DIGEST_SIZE];
+	char *page;
 	int rc;
 	int len;
+
 	if (!*passwd && !*sha1_passwd) {
 		seclvl_printk(0, KERN_ERR, "Attempt to password-unlock the "
 			      "seclvl module, but neither a plain text "
@@ -363,13 +250,26 @@ seclvl_write_passwd(struct seclvl_obj *o
 			      "maintainer about this event.\n");
 		return -EINVAL;
 	}
-	len = strlen(buff);
+
+	if (count < 0 || count >= PAGE_SIZE)
+		return -ENOMEM;
+	if (*ppos != 0) {
+		return -EINVAL;
+	}
+	page = (char *)get_zeroed_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
+	len = -EFAULT;
+	if (copy_from_user(page, buf, count))
+		goto out;
+	
+	len = strlen(page);
 	/* ``echo "secret" > seclvl/passwd'' includes a newline */
-	if (buff[len - 1] == '\n') {
+	if (page[len - 1] == '\n') {
 		len--;
 	}
 	/* Hash the password, then compare the hashed values */
-	if ((rc = plaintext_to_sha1(tmp, buff, len))) {
+	if ((rc = plaintext_to_sha1(tmp, page, len))) {
 		seclvl_printk(0, KERN_ERR, "Error hashing password: rc = "
 			      "[%d]\n", rc);
 		return rc;
@@ -382,13 +282,16 @@ seclvl_write_passwd(struct seclvl_obj *o
 	seclvl_printk(0, KERN_INFO,
 		      "Password accepted; seclvl reduced to 0.\n");
 	seclvl = 0;
-	return count;
+	len = count;
+
+out:
+	free_page((unsigned long)page);
+	return len;
 }
 
-/* Generate sysfs_attr_passwd */
-static struct seclvl_attribute sysfs_attr_passwd =
-__ATTR(passwd, (S_IFREG | S_IRUGO | S_IWUSR), seclvl_read_passwd,
-       seclvl_write_passwd);
+static struct file_operations passwd_file_ops = {
+	.write = passwd_write_file,
+};
 
 /**
  * Explicitely disallow ptrace'ing the init process.
@@ -647,22 +550,34 @@ static int processPassword(void)
 }
 
 /**
- * Sysfs registrations
+ * securityfs registrations
  */
-static int doSysfsRegistrations(void)
+struct dentry *dir_ino, *seclvl_ino, *passwd_ino;
+
+static int seclvlfs_register(void)
 {
-	int rc = 0;
-	if ((rc = subsystem_register(&seclvl_subsys))) {
-		seclvl_printk(0, KERN_WARNING,
-			      "Error [%d] registering seclvl subsystem\n", rc);
-		return rc;
-	}
-	sysfs_create_file(&seclvl_subsys.kset.kobj, &sysfs_attr_seclvl.attr);
+	dir_ino = securityfs_create_dir("seclvl", NULL);
+	if (!dir_ino)
+		return -EFAULT;
+
+	seclvl_ino = securityfs_create_file("seclvl", S_IRUGO | S_IWUSR,
+				dir_ino, &seclvl, &seclvl_file_ops);
+	if (!seclvl_ino)
+		goto out_deldir;
 	if (*passwd || *sha1_passwd) {
-		sysfs_create_file(&seclvl_subsys.kset.kobj,
-				  &sysfs_attr_passwd.attr);
+		passwd_ino = securityfs_create_file("passwd", S_IRUGO | S_IWUSR,
+				dir_ino, NULL, &passwd_file_ops);
+		if (!passwd_ino)
+			goto out_delf;
 	}
 	return 0;
+
+out_deldir:
+	securityfs_remove(dir_ino);
+out_delf:
+	securityfs_remove(seclvl_ino);
+
+	return -EFAULT;
 }
 
 /**
@@ -677,8 +592,6 @@ static int __init seclvl_init(void)
 		rc = -EINVAL;
 		goto exit;
 	}
-	sysfs_attr_seclvl.attr.owner = THIS_MODULE;
-	sysfs_attr_passwd.attr.owner = THIS_MODULE;
 	if (initlvl < -1 || initlvl > 2) {
 		seclvl_printk(0, KERN_ERR, "Error: bad initial securelevel "
 			      "[%d].\n", initlvl);
@@ -706,7 +619,7 @@ static int __init seclvl_init(void)
 		}		/* if primary module registered */
 		secondary = 1;
 	}			/* if we registered ourselves with the security framework */
-	if ((rc = doSysfsRegistrations())) {
+	if ((rc = seclvlfs_register())) {
 		seclvl_printk(0, KERN_ERR, "Error registering with sysfs\n");
 		goto exit;
 	}
@@ -724,12 +637,11 @@ static int __init seclvl_init(void)
  */
 static void __exit seclvl_exit(void)
 {
-	sysfs_remove_file(&seclvl_subsys.kset.kobj, &sysfs_attr_seclvl.attr);
+	securityfs_remove(seclvl_ino);
 	if (*passwd || *sha1_passwd) {
-		sysfs_remove_file(&seclvl_subsys.kset.kobj,
-				  &sysfs_attr_passwd.attr);
+		securityfs_remove(passwd_ino);
 	}
-	subsystem_unregister(&seclvl_subsys);
+	securityfs_remove(dir_ino);
 	if (secondary == 1) {
 		mod_unreg_security(MY_NAME, &seclvl_ops);
 	} else if (unregister_security(&seclvl_ops)) {

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

* Re: [PATCH] securityfs
  2005-07-08 20:44                           ` serue
@ 2005-07-08 20:49                             ` Greg KH
  2005-07-08 21:03                               ` Chris Wright
  0 siblings, 1 reply; 57+ messages in thread
From: Greg KH @ 2005-07-08 20:49 UTC (permalink / raw)
  To: serue
  Cc: James Morris, Tony Jones, lkml, Chris Wright, Stephen Smalley,
	Andrew Morton, Michael Halcrow, David Safford, Reiner Sailer,
	Gerrit Huizenga

On Fri, Jul 08, 2005 at 03:44:19PM -0500, serue@us.ibm.com wrote:
> Quoting Greg KH (greg@kroah.com):
> > On Thu, Jul 07, 2005 at 05:46:04PM -0500, serge@hallyn.com wrote:
> > > 
> > > With the obvious fix, that does in fact work (patch appended).
> > 
> > Good.
> > 
> > > The __simple_attr_check_format problem remains however.  I assume we
> > > don't really want to just take it out, though, like this patch does?
> > 
> > No we do not.
> > 
> > > The error I get without the fs.h patch is:
> > > 
> > > security/seclvl.c: In function `seclvl_file_ops_open':
> > > security/seclvl.c:186: warning: int format, different type arg (arg 2)
> > 
> > Care to work to try to fix it up?
> 
> Once again, the simple_attr in libfs was actually sufficient - I'd
> thought the __attribute__(format(printk(1,2))) was more mysterious than
> it really is.
> 
> At last, here is the full patch to make seclvl use securityfs.
> 
> thanks,
> -serge
> 
> Signed-off-by: Serge Hallyn <serue@us.ibm.com>
> --
>  seclvl.c |  228 +++++++++++++++++++--------------------------------------------
>  1 files changed, 70 insertions(+), 158 deletions(-)

Very nice, it's always good to end up removing lines of code :)

thanks for verifying that it all works properly.

Chris, care to forward the securityfs patch to Linus?

thanks,

greg k-h

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

* Re: [PATCH] securityfs
  2005-07-08 20:49                             ` Greg KH
@ 2005-07-08 21:03                               ` Chris Wright
  0 siblings, 0 replies; 57+ messages in thread
From: Chris Wright @ 2005-07-08 21:03 UTC (permalink / raw)
  To: Greg KH
  Cc: serue, James Morris, Tony Jones, lkml, Chris Wright,
	Stephen Smalley, Andrew Morton, Michael Halcrow, David Safford,
	Reiner Sailer, Gerrit Huizenga

* Greg KH (greg@kroah.com) wrote:
> Chris, care to forward the securityfs patch to Linus?

Yeah, I've got it queued up right now, and I'm playing with it a bit.
As well as this one.  Thanks guys.

-chris

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

* Re: [patch 5/12] lsm stacking v0.2: actual stacker module
  2005-07-04  3:18   ` [patch 5/12] lsm stacking v0.2: actual stacker module Tony Jones
  2005-07-04 11:51     ` serge
@ 2005-07-08 21:43     ` serue
  2005-07-08 22:12       ` serue
  1 sibling, 1 reply; 57+ messages in thread
From: serue @ 2005-07-08 21:43 UTC (permalink / raw)
  To: Tony Jones; +Cc: serue, lkml

Quoting Tony Jones (tonyj@suse.de):
> Hey Serge,
> Seemed useful to be able to view which modules had been unloaded.
> Easier to maintain them on their own list than to compute the difference
> of <stacked_modules> and <all_modules>.  Patch attached, not sure if you
> are cool with reusing the 'unload' file.

Attached is a patch to re-introduce the necessary locking to allow
unloading of LSMs.  I don't have any performance results nor hardcore
stability tests yet.

This version does not support dynamic removal of ->security data,
though - that still has to be done when the object is deleted.
So while unloading an LSM is safe, it is also likely to leak
memory.  If we decide this patch is the way to go, then we can
tackle ->security data next.

Hopefully I'll have performance data to send out next week.

thanks,
-serge

Signed-off-by: Serge Hallyn <serue@us.ibm.com>
--
 stacker.c |  255 ++++++++++++++++++++++++++++++++++++++------------------------
 1 files changed, 160 insertions(+), 95 deletions(-)

Index: linux-2.6.12/security/stacker.c
===================================================================
--- linux-2.6.12.orig/security/stacker.c	2005-07-08 13:43:15.000000000 -0500
+++ linux-2.6.12/security/stacker.c	2005-07-08 16:21:54.000000000 -0500
@@ -33,13 +33,13 @@
 
 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;
+	struct rcu_head m_rcu;
+	atomic_t use;
 };
 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;
 
@@ -84,6 +84,32 @@ MODULE_PARM_DESC(debug, "Debug enabled o
  * We return as soon as an error is returned.
  */
 
+static inline void stacker_free_module(struct module_entry *m)
+{
+	kfree(m->module_name);
+	kfree(m);
+}
+
+/*
+ * Version of stacker_free_module called from call_rcu
+ */
+static void free_mod_fromrcu(struct rcu_head *head)
+{
+	struct module_entry *m;
+
+	m = container_of(head, struct module_entry, m_rcu);
+	stacker_free_module(m);
+}
+
+static void stacker_del_module(struct rcu_head *head)
+{
+	struct module_entry *m;
+	
+	m = container_of(head, struct module_entry, m_rcu);
+	if (atomic_dec_and_test(&m->use))
+		stacker_free_module(m);
+}
+
 #define stack_for_each_entry(pos, head, member)				\
 	for (pos = list_entry((head)->next, typeof(*pos), member);	\
 		&pos->member != (head);					\
@@ -93,16 +119,27 @@ MODULE_PARM_DESC(debug, "Debug enabled o
 /* to make this safe for module deletion, we would need to
  * add a reference count to m as we had before
  */
+/*
+ * XXX We can't quite do this - we delete the module before we grab
+ * m->next?
+ * We could just do a call_rcu.  Then the call_rcu happens in same
+ * rcu cycle has dereference, so module won't be deleted until the
+ * next cycle.
+ * That's what I'm going to do.
+ */
 #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 (m->module_operations.BASE_FUNC) { \
+			atomic_inc(&m->use); \
+			rcu_read_unlock(); \
+			result = m->module_operations.FUNC_WITH_ARGS; \
+			rcu_read_lock(); \
+			if (unlikely(atomic_dec_and_test(&m->use))) \
+				call_rcu(&m->m_rcu, free_mod_fromrcu); \
+		} \
 		if (result) \
 			break; \
 	} \
@@ -116,9 +153,12 @@ MODULE_PARM_DESC(debug, "Debug enabled o
 	rcu_read_lock(); \
 	stack_for_each_entry(m, &stacked_modules, lsm_list) { \
 		if (m->module_operations.BASE_FUNC) { \
+			atomic_inc(&m->use); \
 			rcu_read_unlock(); \
 			m->module_operations.FUNC_WITH_ARGS; \
 			rcu_read_lock(); \
+			if (unlikely(atomic_dec_and_test(&m->use))) \
+				call_rcu(&m->m_rcu, free_mod_fromrcu); \
 		} \
 	} \
 	rcu_read_unlock(); \
@@ -129,38 +169,47 @@ MODULE_PARM_DESC(debug, "Debug enabled o
 	rcu_read_lock(); \
 	stack_for_each_entry(m, &stacked_modules, lsm_list ) { \
 		if (m->module_operations.BASE_FREE) { \
+			atomic_inc(&m->use); \
 			rcu_read_unlock(); \
 			m->module_operations.FREE_WITH_ARGS; \
 			rcu_read_lock(); \
+			if (unlikely(atomic_dec_and_test(&m->use))) \
+				call_rcu(&m->m_rcu, free_mod_fromrcu); \
 		} \
 	} \
 	rcu_read_unlock(); \
 } while (0)
 
 #define ALLOC_SECURITY(BASE_FUNC,FUNC_WITH_ARGS,BASE_FREE,FREE_WITH_ARGS) do { \
-	int result; \
+	int result = 0; \
 	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 (m->module_operations.BASE_FUNC) { \
+			atomic_inc(&m->use); \
+			rcu_read_unlock(); \
+			result = m->module_operations.FUNC_WITH_ARGS; \
+			rcu_read_lock(); \
+			if (unlikely(atomic_dec_and_test(&m->use))) \
+				call_rcu(&m->m_rcu, free_mod_fromrcu); \
+		} \
 		if (result) \
 			goto bad; \
 	} \
 	rcu_read_unlock(); \
 	return 0; \
 bad: \
-	stack_for_each_entry(m2, &all_modules, all_lsms) { \
+	stack_for_each_entry(m2, &stacked_modules, lsm_list) { \
 		if (m == m2) \
 			break; \
 		if (!m2->module_operations.BASE_FREE) \
 			continue; \
+		atomic_inc(&m2->use); \
 		rcu_read_unlock(); \
 		m2->module_operations.FREE_WITH_ARGS; \
 		rcu_read_lock(); \
+		if (unlikely(atomic_dec_and_test(&m2->use))) \
+			call_rcu(&m2->m_rcu, free_mod_fromrcu); \
 	} \
 	rcu_read_unlock(); \
 	return result; \
@@ -251,10 +300,16 @@ static int stacker_vm_enough_memory(long
 
 	rcu_read_lock();
 	stack_for_each_entry(m, &stacked_modules, lsm_list) {
-		if (!m->module_operations.vm_enough_memory)
+		if (!m->module_operations.vm_enough_memory) {
 			continue;
+		}
+		atomic_inc(&m->use);
 		rcu_read_unlock();
 		result = m->module_operations.vm_enough_memory(pages);
+		rcu_read_lock();
+		if (unlikely(atomic_dec_and_test(&m->use)))
+			stacker_free_module(m);
+		rcu_read_unlock();
 		return result;
 	}
 	rcu_read_unlock();
@@ -281,9 +336,12 @@ static int stacker_netlink_send (struct 
 		if (!m->module_operations.netlink_send)
 			continue;
 		NETLINK_CB(skb).eff_cap = ~0;
+		atomic_inc(&m->use);
 		rcu_read_unlock();
 		result = m->module_operations.netlink_send(sk, skb);
 		rcu_read_lock();
+		if (unlikely(atomic_dec_and_test(&m->use)))
+			call_rcu(&m->m_rcu, free_mod_fromrcu);
 		tmpcap &= NETLINK_CB(skb).eff_cap;
 		if (result)
 			break;
@@ -987,33 +1045,42 @@ stacker_getprocattr(struct task_struct *
 	stack_for_each_entry(m, &stacked_modules, lsm_list) {
 		if (!m->module_operations.getprocattr)
 			continue;
+		atomic_inc(&m->use);
 		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) {
+		if (ret > 0) {
+			found_noneinval = 1;
+			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);
+			}
+		} else if (ret != -EINVAL) {
+			found_noneinval = 1;
 			memset(value, 0, len);
 			len = ret;
+		} else
+			ret = 0;
+
+		if (unlikely(atomic_dec_and_test(&m->use)))
+			call_rcu(&m->m_rcu, free_mod_fromrcu);
+
+		if (ret < 0)
 			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;
 }
 
+/*
+ * find an lsm by name.  If found, increment its use count and return it
+ */
 static struct module_entry *
 find_active_lsm(const char *name, int len)
 {
@@ -1022,6 +1089,7 @@ find_active_lsm(const char *name, int le
 	rcu_read_lock();
 	stack_for_each_entry(m, &stacked_modules, lsm_list) {
 		if (m->namelen == len && !strncmp(m->module_name, name, len)) {
+			atomic_inc(&m->use);
 			ret = m;
 			break;
 		}
@@ -1043,6 +1111,7 @@ stacker_setprocattr(struct task_struct *
 	char *realv = (char *)value;
 	size_t dsize = size;
 	int loc = 0, end_data = size;
+	int ret, free_module = 0;
 
 	if (list_empty(&stacked_modules))
 		return -EINVAL;
@@ -1063,7 +1132,7 @@ stacker_setprocattr(struct task_struct *
 	callm = find_active_lsm(realv+loc+1, dsize-loc-1);
 	if (!callm)
 		goto call;
-
+	free_module = 1;
 
 	loc--;
 	while (loc && realv[loc]==' ')
@@ -1074,8 +1143,14 @@ call:
 	if (!callm || !callm->module_operations.setprocattr)
 		return -EINVAL;
 
-	return callm->module_operations.setprocattr(p, name, value, end_data) +
+	ret = callm->module_operations.setprocattr(p, name, value, end_data) +
 			(size-end_data);
+
+	if (free_module && atomic_dec_and_test(&callm->use))
+		stacker_free_module(callm);
+
+	return ret;
+
 }
 
 /*
@@ -1116,15 +1191,15 @@ static int stacker_register (const char 
 	new_module_entry->module_name = new_module_name;
 	new_module_entry->namelen = namelen;
 
+	atomic_set(&new_module_entry->use, 1);
+
 	INIT_LIST_HEAD(&new_module_entry->lsm_list);
-	INIT_LIST_HEAD(&new_module_entry->all_lsms);
 
 	rcu_read_lock();
 	if (!modules_registered) {
 		modules_registered++;
 		list_del_rcu(&default_module.lsm_list);
 	}
-	list_add_tail_rcu(&new_module_entry->all_lsms, &all_modules);
 	list_add_tail_rcu(&new_module_entry->lsm_list, &stacked_modules);
 	if (strcmp(name, "selinux") == 0)
 		selinux_module = new_module_entry;
@@ -1141,16 +1216,60 @@ out:
 }
 
 /*
- * 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.
+ * find_lsm_module_by_name:
+ * Find a module by name.  Used by stacker_unregister.  Called with
+ * stacker spinlock held.
+ */
+static struct module_entry *
+find_lsm_with_namelen(const char *name, int len)
+{
+	struct module_entry *m, *ret = NULL;
+
+	rcu_read_lock();
+	list_for_each_entry_rcu(m, &stacked_modules, lsm_list) {
+		atomic_inc(&m->use);
+		rcu_read_unlock();
+		if (m->namelen == len && !strncmp(m->module_name, name, len))
+			ret = m;
+		rcu_read_lock();
+		if (unlikely(atomic_dec_and_test(&m->use)))
+			call_rcu(&m->m_rcu, free_mod_fromrcu);
+		if (ret)
+			break;
+	}
+	rcu_read_unlock();
+
+	return ret;
+}
+
+/*
  */
 static int stacker_unregister (const char *name, struct security_operations *ops)
 {
-	return -EPERM;
+	struct module_entry *m;
+	int len = strnlen(name, MAX_MODULE_NAME_LEN);
+	int ret = 0;
+
+	spin_lock(&stacker_lock);
+	m = find_lsm_with_namelen(name, len);
+
+	if (!m) {
+		printk(KERN_INFO "%s: could not find module %s.\n",
+				__FUNCTION__, name);
+		ret = -ENOENT;
+		goto out;
+	}
+
+	list_del_rcu(&m->lsm_list);
+
+	if (strcmp(m->module_name, "selinux") == 0)
+		selinux_module = NULL;
+	call_rcu(&m->m_rcu, stacker_del_module);
+
+out:
+	spin_unlock(&stacker_lock);
+
+	return ret;
 }
 
 static struct security_operations stacker_ops = {
@@ -1407,57 +1526,6 @@ static struct stacker_attribute stacker_
 	.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;
-
-	if (!modules_registered)
-		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;
-
-	rcu_read_lock();
-	list_del_rcu(&m->lsm_list);
-	if (list_empty(&stacked_modules)) {
-		INIT_LIST_HEAD(&default_module.lsm_list);
-		list_add_tail_rcu(&default_module.lsm_list, &stacked_modules);
-		modules_registered = 0;
-	}
-	rcu_read_unlock();
-
-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)
@@ -1483,7 +1551,6 @@ static void unregister_sysfs_files(void)
 	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;
 }
@@ -1506,8 +1573,6 @@ static int register_sysfs_files(void)
 			&stacker_attr_listmodules.attr);
 	sysfs_create_file(&stacker_subsys.kset.kobj,
 			&stacker_attr_stop_responding.attr);
-	sysfs_create_file(&stacker_subsys.kset.kobj,
-			&stacker_attr_unload.attr);
 	sysfsfiles_registered = 1;
 	stacker_dbg("sysfs files registered\n");
 	return 0;
@@ -1524,13 +1589,13 @@ static int __init stacker_init (void)
 	sysfsfiles_registered = 0;
 
 	INIT_LIST_HEAD(&stacked_modules);
-	INIT_LIST_HEAD(&all_modules);
 	spin_lock_init(&stacker_lock);
 	default_module.module_name = DEFAULT_MODULE_NAME;
 	default_module.namelen = strlen(DEFAULT_MODULE_NAME);
 	memcpy(&default_module.module_operations, &dummy_security_ops,
 			sizeof(struct security_operations));
 	INIT_LIST_HEAD(&default_module.lsm_list);
+	atomic_set(&default_module.use, 1);
 	list_add_tail(&default_module.lsm_list, &stacked_modules);
 
 	if (register_security (&stacker_ops)) {

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

* Re: [patch 5/12] lsm stacking v0.2: actual stacker module
  2005-07-08 21:43     ` serue
@ 2005-07-08 22:12       ` serue
  0 siblings, 0 replies; 57+ messages in thread
From: serue @ 2005-07-08 22:12 UTC (permalink / raw)
  To: serue; +Cc: Tony Jones, lkml

Quoting serue@us.ibm.com (serue@us.ibm.com):
> Quoting Tony Jones (tonyj@suse.de):
> Attached is a patch to re-introduce the necessary locking to allow
> unloading of LSMs.  I don't have any performance results nor hardcore
> stability tests yet.

And here is a patch on top of that to use securityfs.

thanks,
-serge

Signed-off-by: Serge Hallyn <serue@us.ibm.com>
--
 stacker.c |  169 +++++++++++++++++++-------------------------------------------
 1 files changed, 53 insertions(+), 116 deletions(-)

Index: linux-2.6.12/security/stacker.c
===================================================================
--- linux-2.6.12.orig/security/stacker.c	2005-07-08 16:21:54.000000000 -0500
+++ linux-2.6.12/security/stacker.c	2005-07-08 21:51:08.000000000 -0500
@@ -41,8 +41,6 @@ struct module_entry {
 };
 static struct list_head stacked_modules;  /* list of stacked modules */
 
-static short sysfsfiles_registered;
-
 /*
  * when !modules_registered, the default_module, defined
  * below, will be stacked
@@ -104,7 +102,7 @@ static void free_mod_fromrcu(struct rcu_
 static void stacker_del_module(struct rcu_head *head)
 {
 	struct module_entry *m;
-	
+
 	m = container_of(head, struct module_entry, m_rcu);
 	if (atomic_dec_and_test(&m->use))
 		stacker_free_module(m);
@@ -1430,155 +1428,95 @@ static struct security_operations stacke
 #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)
+static u64 stacker_u8_get(void *data)
 {
-	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;
+	return *(u8 *)data;
 }
 
-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)
+static void lockdown_write(void *data, u64 val)
 {
-	if (count>0)
-		forbid_stacker_register = 1;
-
-	return count;
+	forbid_stacker_register = 1;
 }
 
-static struct stacker_attribute stacker_attr_lockdown = {
-	.attr = {.name = "lockdown", .mode = S_IFREG | S_IRUGO | S_IWUSR},
-	.show = lockdown_read,
-	.store = lockdown_write
-};
+DEFINE_SIMPLE_ATTRIBUTE(lockdown_fops, stacker_u8_get, lockdown_write, "%llu\n");
 
 /* list modules */
-static ssize_t listmodules_read (struct stacker_kobj *obj, char *buff)
+static ssize_t listmodules_read ( struct file *filp, char __user *user_buf,
+				       size_t count, loff_t *ppos)
 {
 	ssize_t len = 0;
 	struct module_entry *m;
+	char *page;
+
+	page = (char *)__get_free_page(GFP_KERNEL);
+	if (!page)
+		return -ENOMEM;
 
 	rcu_read_lock();
 	stack_for_each_entry(m, &stacked_modules, lsm_list) {
-		len += snprintf(buff+len, PAGE_SIZE - len, "%s\n",
+		len += snprintf(page+len, PAGE_SIZE - len, "%s\n",
 			m->module_name);
 	}
 	rcu_read_unlock();
 
+	if (len >= 0)
+		len = simple_read_from_buffer(user_buf, count, ppos, page, len);
+	free_page((unsigned long)page);
+
 	return len;
 }
 
-static struct stacker_attribute stacker_attr_listmodules = {
-	.attr = {.name = "list_modules", .mode = S_IFREG | S_IRUGO | S_IWUSR},
-	.show = listmodules_read,
+static struct file_operations listmodules_fops = {
+	.read =		listmodules_read,
 };
 
+static void unregister_stacker_files(void);
+
 /* stop responding to sysfs */
-static ssize_t stop_responding_write (struct stacker_kobj *obj,
-					const char *buff, size_t count)
+static void stop_responding_write(void *data, u64 val)
 {
-	if (count>0)
-		unregister_sysfs_files();
-	return count;
+	unregister_stacker_files();
 }
 
-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;
+DEFINE_SIMPLE_ATTRIBUTE(stopresp_fops, NULL, stop_responding_write, "%llu\n");
 
-	if (!sysfsfiles_registered)
-		return;
+struct dentry   * stacker_dir_ino,
+		* lockdown_ino,
+		* listmodules_ino,
+		* stopresp_ino,
+		* modunload_ino;
 
-	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);
-
-	sysfsfiles_registered = 0;
+static void unregister_stacker_files(void)
+{
+	securityfs_remove(stacker_dir_ino);
+	securityfs_remove(lockdown_ino);
+	securityfs_remove(listmodules_ino);
+	securityfs_remove(stopresp_ino);
 }
 
-static int register_sysfs_files(void)
+static int register_stacker_files(void)
 {
-	int result;
+	stacker_dir_ino = securityfs_create_dir("stacker", NULL);
+	if (!stacker_dir_ino)
+		return -EFAULT;
 
-	result = subsystem_register(&stacker_subsys);
-	if (result) {
-		printk(KERN_WARNING
-			"Error (%d) registering stacker sysfs subsystem\n",
-			result);
-		return result;
-	}
+	lockdown_ino = securityfs_create_file("lockdown", S_IRUGO | S_IWUSR,
+			stacker_dir_ino, &forbid_stacker_register,
+			&lockdown_fops);
+	listmodules_ino = securityfs_create_file("listmodules", S_IRUGO,
+			stacker_dir_ino, NULL, &listmodules_fops);
+	stopresp_ino = securityfs_create_file("stop_responding", S_IWUSR,
+			stacker_dir_ino, NULL, &stopresp_fops);
 
-	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_stop_responding.attr);
-	sysfsfiles_registered = 1;
-	stacker_dbg("sysfs files registered\n");
+	if (!lockdown_ino || !listmodules_ino || !stopresp_ino) {
+		unregister_stacker_files();
+		return -EFAULT;
+	}
 	return 0;
 }
 
-module_init(register_sysfs_files);
+module_init(register_stacker_files);
 
 extern struct security_operations dummy_security_ops;
 #define DEFAULT_MODULE_NAME "dummy"
@@ -1586,7 +1524,6 @@ extern struct security_operations dummy_
 static int __init stacker_init (void)
 {
 	forbid_stacker_register = 0;
-	sysfsfiles_registered = 0;
 
 	INIT_LIST_HEAD(&stacked_modules);
 	spin_lock_init(&stacker_lock);
@@ -1620,7 +1557,7 @@ static void __exit stacker_exit (void)
 	 * Should probably force all child modules to exit somehow...
 	 */
 
-	unregister_sysfs_files();
+	unregister_stacker_files();
 	if (unregister_security (&stacker_ops))
 		printk(KERN_WARNING "Error unregistering LSM stacker.\n");
 	else

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

* Re: [patch 5/12] lsm stacking v0.2: actual stacker module
  2005-06-30 19:50 ` [patch 5/12] lsm stacking v0.2: actual stacker module serue
                     ` (2 preceding siblings ...)
  2005-07-04  3:18   ` [patch 5/12] lsm stacking v0.2: actual stacker module Tony Jones
@ 2005-07-11 14:40   ` Stephen Smalley
  2005-07-11 17:51     ` serue
  2005-07-13 16:39     ` serue
  3 siblings, 2 replies; 57+ messages in thread
From: Stephen Smalley @ 2005-07-11 14:40 UTC (permalink / raw)
  To: serue
  Cc: lkml, Chris Wright, James Morris, Andrew Morton, Michael Halcrow,
	David Safford, Reiner Sailer, Gerrit Huizenga

On Thu, 2005-06-30 at 14:50 -0500, serue@us.ibm.com wrote:
> Adds the actual stacker LSM.
<snip>
> +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));
> +}

These hooks pose a similar problem for stacking as with the
[gs]etprocattr hooks, although [gs]etsecurity have the benefit of
already taking a distinguishing name suffix (the part after the
security. prefix).  Note also that inode_getsecurity returns the number
of bytes used/required on success.

The proposed inode_init_security hook will likewise have an issue for
stacking.

-- 
Stephen Smalley
National Security Agency


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

* Re: [patch 5/12] lsm stacking v0.2: actual stacker module
  2005-07-11 14:40   ` Stephen Smalley
@ 2005-07-11 17:51     ` serue
  2005-07-11 19:03       ` Stephen Smalley
  2005-07-13 16:39     ` serue
  1 sibling, 1 reply; 57+ messages in thread
From: serue @ 2005-07-11 17:51 UTC (permalink / raw)
  To: Stephen Smalley
  Cc: serue, lkml, Chris Wright, James Morris, Andrew Morton,
	Michael Halcrow, David Safford, Reiner Sailer, Gerrit Huizenga

Thanks Stephen.

More comments below.  This finally proves that I need to provide some
documentation for each hook under stacker showing how modules are
expected to interact.  This hopefully will help me catch things like
this.  Hopefully it would also be useful to module writers in general.

Quoting Stephen Smalley (sds@epoch.ncsc.mil):
> On Thu, 2005-06-30 at 14:50 -0500, serue@us.ibm.com wrote:
> > Adds the actual stacker LSM.
> <snip>
> > +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));
> > +}
> 
> These hooks pose a similar problem for stacking as with the
> [gs]etprocattr hooks, although [gs]etsecurity have the benefit of
> already taking a distinguishing name suffix (the part after the
> security. prefix).  Note also that inode_getsecurity returns the number
> of bytes used/required on success.
> 
> The proposed inode_init_security hook will likewise have an issue for
> stacking.

I can imagine a few ways of fixing this:

	1.	We simply expect that only one module use xattrs.  This
	is probably unacceptable, as we will want both EVM and selinux
	to store xattrs.

	2.	A module registers an xattr name when it registers
	itself.  Then only the registered module is consulted on one of
	these calls.  If no module is registered, all are consulted as
	they are now.

		This prevents a module like capability from deciding
	based on its own credentials whether another module's hook
	should be called.  Is that a good or bad thing?

		This might have the added bonus of obviating the need
	for a separate cap_stack module.
	
	3.	We return an error <0 only if all modules return <0.
	Otherwise we do the obvious thing:  setxattr, return 0.
	getxattr: do we return the first nonzero and stop there, or
	do we return a concatenation of the results?  I assume the
	former...

thanks,
-serge

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

* Re: [patch 5/12] lsm stacking v0.2: actual stacker module
  2005-07-11 17:51     ` serue
@ 2005-07-11 19:03       ` Stephen Smalley
  0 siblings, 0 replies; 57+ messages in thread
From: Stephen Smalley @ 2005-07-11 19:03 UTC (permalink / raw)
  To: serue
  Cc: lkml, Chris Wright, James Morris, Andrew Morton, Michael Halcrow,
	David Safford, Reiner Sailer, Gerrit Huizenga

On Mon, 2005-07-11 at 12:51 -0500, serue@us.ibm.com wrote:
> I can imagine a few ways of fixing this:
> 
> 	1.	We simply expect that only one module use xattrs.  This
> 	is probably unacceptable, as we will want both EVM and selinux
> 	to store xattrs.

Note that these particular hooks are only used for filesystems like
devpts and tmpfs where there is no underlying storage for the security
xattrs but we still need a way to [gs]et the incore inode security label
from userspace.

> 	2.	A module registers an xattr name when it registers
> 	itself.  Then only the registered module is consulted on one of
> 	these calls.  If no module is registered, all are consulted as
> 	they are now.

SELinux already checks the name suffix in inode_getsecurity and
inode_setsecurity, and returns -EOPNOTSUPP if it isn't selinux.  Hence,
stacker could just iterate through the modules until it gets a result
other than -EOPNOTSUPP, relying on the modules to check the name.

listsecurity is different, as it is supposed to yield the list of
attribute names concatenated together, but that shouldn't be difficult
for stacker to construct, similar to your getprocattr logic but without
the need to add tags.

> 		This prevents a module like capability from deciding
> 	based on its own credentials whether another module's hook
> 	should be called.  Is that a good or bad thing?

These hooks aren't supposed to be doing permission checking; that is
handled by the separate security_inode_*xattr hooks.  They are just for
getting/setting the incore inode security label.

> 		This might have the added bonus of obviating the need
> 	for a separate cap_stack module.

I don't think so - different hooks are involved (inode_setxattr vs.
inode_setsecurity).

-- 
Stephen Smalley
National Security Agency


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

* Re: [patch 5/12] lsm stacking v0.2: actual stacker module
  2005-07-11 14:40   ` Stephen Smalley
  2005-07-11 17:51     ` serue
@ 2005-07-13 16:39     ` serue
  2005-07-13 18:27       ` serue
  1 sibling, 1 reply; 57+ messages in thread
From: serue @ 2005-07-13 16:39 UTC (permalink / raw)
  To: Stephen Smalley
  Cc: lkml, Chris Wright, James Morris, Andrew Morton, Michael Halcrow,
	David Safford, Reiner Sailer, Gerrit Huizenga

Quoting Stephen Smalley (sds@epoch.ncsc.mil):
> These hooks pose a similar problem for stacking as with the
> [gs]etprocattr hooks, although [gs]etsecurity have the benefit of
> already taking a distinguishing name suffix (the part after the
> security. prefix).  Note also that inode_getsecurity returns the number
> of bytes used/required on success.

The attached patch tries to handle the get,set, and listsecurity hooks.

> The proposed inode_init_security hook will likewise have an issue for
> stacking.

I guess I'll wait to patch that until the hook shows up in 2.6.13-rc?,
since my patches are generally against that tree.

thanks,
-serge

Signed-off-by: Serge Hallyn <serue@us.ibm.com>
--
 stacker.c |   79 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 76 insertions(+), 3 deletions(-)

Index: linux-2.6.13-rc3/security/stacker.c
===================================================================
--- linux-2.6.13-rc3.orig/security/stacker.c	2005-07-13 15:21:01.000000000 -0500
+++ linux-2.6.13-rc3/security/stacker.c	2005-07-13 15:21:05.000000000 -0500
@@ -569,19 +569,92 @@ static int stacker_inode_removexattr (st
 	RETURN_ERROR_IF_ANY_ERROR(inode_removexattr,inode_removexattr(dentry,name));
 }
 
+/*
+ * inode_getsecurity: We loop through all modules until one does not return
+ * -EOPNOTSUPP.
+ * Note that if some LSM returns -EPERM, stacker assumes the LSM knows what
+ * it's doing.  If you don't want to control the name, then return
+ * -EOPNOTSUPP!
+ */
 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));
+	struct module_entry *m;
+	int ret = -EOPNOTSUPP;
+
+	rcu_read_lock();
+	stack_for_each_entry(m, &stacked_modules, lsm_list) {
+		if (!m->module_operations.inode_getsecurity)
+			continue;
+		rcu_read_unlock();
+		ret = m->module_operations.inode_getsecurity(inode,name,buffer,size);
+		rcu_read_lock();
+		if (ret != -EOPNOTSUPP)
+			break;
+	}
+	rcu_read_unlock();
+
+	return ret;
 }
 
+/*
+ * inode_setsecurity: We loop through all modules until one does not return
+ * -EOPNOTSUPP.
+ * Note that if some LSM returns -EPERM, stacker assumes the LSM knows what
+ * it's doing.  If you don't want to control the name, then return
+ * -EOPNOTSUPP!
+ */
 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));
+	struct module_entry *m;
+	int ret = -EOPNOTSUPP;
+
+	rcu_read_lock();
+	stack_for_each_entry(m, &stacked_modules, lsm_list) {
+		if (!m->module_operations.inode_setsecurity)
+			continue;
+		rcu_read_unlock();
+		ret = m->module_operations.inode_setsecurity(inode, name,
+						value, size, flags);
+		rcu_read_lock();
+		if (ret != -EOPNOTSUPP)
+			break;
+	}
+	rcu_read_unlock();
+
+	return ret;
 }
 
+/*
+ * inode_listsecurity: We loop through all modules appending to buffer, and return
+ * the newline-separated list of security names defined for this inode.
+ */
 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));
+	int ret = 0;
+	struct module_entry *m;
+
+	rcu_read_lock();
+	stack_for_each_entry(m, &stacked_modules, lsm_list) {
+		int thislen;
+
+		if (!m->module_operations.inode_listsecurity)
+			continue;
+		rcu_read_unlock();
+		thislen = m->module_operations.inode_listsecurity(inode,
+				buffer+ret, buffer_size-ret);
+		rcu_read_lock();
+		if (thislen < 0)
+			continue;
+		ret += thislen;
+		if (ret >= buffer_size) {
+			ret = -ERANGE;
+			break;
+		}
+		buffer[ret++] = '\n';
+	}
+	rcu_read_unlock();
+
+	return ret;
 }
 
 static int stacker_file_permission (struct file *file, int mask)

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

* Re: [patch 5/12] lsm stacking v0.2: actual stacker module
  2005-07-13 16:39     ` serue
@ 2005-07-13 18:27       ` serue
  0 siblings, 0 replies; 57+ messages in thread
From: serue @ 2005-07-13 18:27 UTC (permalink / raw)
  To: Stephen Smalley
  Cc: lkml, Chris Wright, James Morris, Andrew Morton, Michael Halcrow,
	David Safford, Reiner Sailer, Gerrit Huizenga

Stephen points out listsecurity results should simply be separated by
the \0 which modules already append.  New patch appended.

Thanks, Stephen.

-serge

Signed-off-by: Serge Hallyn <serue@us.ibm.com>
--
 stacker.c |   78 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 files changed, 75 insertions(+), 3 deletions(-)

Index: linux-2.6.13-rc3/security/stacker.c
===================================================================
--- linux-2.6.13-rc3.orig/security/stacker.c	2005-07-13 15:37:29.000000000 -0500
+++ linux-2.6.13-rc3/security/stacker.c	2005-07-13 18:08:03.000000000 -0500
@@ -569,19 +569,91 @@ static int stacker_inode_removexattr (st
 	RETURN_ERROR_IF_ANY_ERROR(inode_removexattr,inode_removexattr(dentry,name));
 }
 
+/*
+ * inode_getsecurity: We loop through all modules until one does not return
+ * -EOPNOTSUPP.
+ * Note that if some LSM returns -EPERM, stacker assumes the LSM knows what
+ * it's doing.  If you don't want to control the name, then return
+ * -EOPNOTSUPP!
+ */
 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));
+	struct module_entry *m;
+	int ret = -EOPNOTSUPP;
+
+	rcu_read_lock();
+	stack_for_each_entry(m, &stacked_modules, lsm_list) {
+		if (!m->module_operations.inode_getsecurity)
+			continue;
+		rcu_read_unlock();
+		ret = m->module_operations.inode_getsecurity(inode,name,buffer,size);
+		rcu_read_lock();
+		if (ret != -EOPNOTSUPP)
+			break;
+	}
+	rcu_read_unlock();
+
+	return ret;
 }
 
+/*
+ * inode_setsecurity: We loop through all modules until one does not return
+ * -EOPNOTSUPP.
+ * Note that if some LSM returns -EPERM, stacker assumes the LSM knows what
+ * it's doing.  If you don't want to control the name, then return
+ * -EOPNOTSUPP!
+ */
 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));
+	struct module_entry *m;
+	int ret = -EOPNOTSUPP;
+
+	rcu_read_lock();
+	stack_for_each_entry(m, &stacked_modules, lsm_list) {
+		if (!m->module_operations.inode_setsecurity)
+			continue;
+		rcu_read_unlock();
+		ret = m->module_operations.inode_setsecurity(inode, name,
+						value, size, flags);
+		rcu_read_lock();
+		if (ret != -EOPNOTSUPP)
+			break;
+	}
+	rcu_read_unlock();
+
+	return ret;
 }
 
+/*
+ * inode_listsecurity: We loop through all modules appending to buffer, and return
+ * the \0-separated list of security names defined for this inode.
+ */
 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));
+	int ret = 0;
+	struct module_entry *m;
+
+	rcu_read_lock();
+	stack_for_each_entry(m, &stacked_modules, lsm_list) {
+		int thislen;
+
+		if (!m->module_operations.inode_listsecurity)
+			continue;
+		rcu_read_unlock();
+		thislen = m->module_operations.inode_listsecurity(inode,
+				buffer+ret, buffer_size-ret);
+		rcu_read_lock();
+		if (thislen < 0)
+			continue;
+		ret += thislen;
+		if (ret >= buffer_size) {
+			ret = -ERANGE;
+			break;
+		}
+	}
+	rcu_read_unlock();
+
+	return ret;
 }
 
 static int stacker_file_permission (struct file *file, int mask)

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

end of thread, other threads:[~2005-07-13 18:30 UTC | newest]

Thread overview: 57+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2005-06-30 19:44 [patch 0/12] lsm stacking v0.2: intro serue
2005-06-30 19:48 ` [patch 1/12] lsm stacking v0.2: don't default to dummy_##hook serue
2005-06-30 19:48 ` [patch 2/12] lsm stacking v0.2: replace void* security with hlist serue
2005-06-30 19:49 ` [patch 3/12] lsm stacking v0.2: introduce security_*_value API serue
2005-06-30 19:49 ` [patch 4/12] lsm stacking v0.2: stacker documentation serue
2005-06-30 19:50 ` [patch 5/12] lsm stacking v0.2: actual stacker module serue
2005-07-01  2:32   ` James Morris
2005-07-01 19:24     ` serge
2005-07-01 20:35   ` Greg KH
2005-07-03  0:24     ` serge
2005-07-03 18:25       ` Tony Jones
2005-07-03 18:53         ` James Morris
2005-07-03 19:09           ` Tony Jones
2005-07-03 20:44           ` [PATCH] securityfs Greg KH
2005-07-04 12:39             ` serge
2005-07-04 15:53             ` serge
2005-07-05  6:07               ` Greg KH
2005-07-06 12:25                 ` serge
2005-07-06  6:52             ` James Morris
2005-07-06  7:04               ` Greg KH
2005-07-06 12:29               ` Stephen Smalley
2005-07-06 15:35                 ` James Morris
2005-07-06 16:06                   ` Stephen Smalley
2005-07-06 16:16                     ` Greg KH
2005-07-06 18:01                     ` Chris Wright
2005-07-06 22:08             ` serue
2005-07-06 22:22               ` Greg KH
2005-07-06 23:32                 ` serge
2005-07-07 17:30                 ` serge
2005-07-07 17:48                   ` Greg KH
2005-07-07 18:27                     ` serue
2005-07-07 22:46                       ` serge
2005-07-07 23:06                         ` Greg KH
2005-07-07 23:12                           ` serue
2005-07-08 20:44                           ` serue
2005-07-08 20:49                             ` Greg KH
2005-07-08 21:03                               ` Chris Wright
2005-07-04  3:18   ` [patch 5/12] lsm stacking v0.2: actual stacker module Tony Jones
2005-07-04 11:51     ` serge
2005-07-04 19:37       ` Tony Jones
2005-07-04 20:06         ` serge
2005-07-04 20:41           ` Tony Jones
2005-07-05 18:17             ` serge
2005-07-08 21:43     ` serue
2005-07-08 22:12       ` serue
2005-07-11 14:40   ` Stephen Smalley
2005-07-11 17:51     ` serue
2005-07-11 19:03       ` Stephen Smalley
2005-07-13 16:39     ` serue
2005-07-13 18:27       ` serue
2005-06-30 19:51 ` [patch 6/12] lsm stacking v0.2: stackable capability lsm serue
2005-06-30 19:52 ` [patch 7/12] lsm stacking v0.2: selinux: update security structs serue
2005-06-30 19:53 ` [patch 8/12] lsm stacking v0.2: selinux: use security_*_value API serue
2005-06-30 19:53 ` [patch 9/12] lsm stacking v0.2: selinux: remove secondary support serue
2005-06-30 19:54 ` [patch 10/12] lsm stacking v0.2: hook completeness verification serue
2005-06-30 19:55 ` [patch 11/12] lsm stacking v0.2: /proc/$$/attr/ sharing serue
2005-06-30 19:55 ` [patch 12/12] lsm stacking v0.2: update seclvl for stacking serue

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).