[patch 5/12] lsm stacking v0.2: actual stacker module

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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 <[email protected]>
---
 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 <[email protected]>
+ * Copyright (C) 2002 David A. Wheeler <[email protected]>.
+ *  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");
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux