LWN.net Logo

[Stacking v4 3/3] Cleaned up stacker patch

From:  Serge Hallyn <serue@us.ibm.com>
To:  Chris Wright <chrisw@osdl.org>, Stephen Smalley <sds@epoch.ncsc.mil>, James Morris <jmorris@redhat.com>
Subject:  [RFC] [Stacking v4 3/3] Cleaned up stacker patch
Date:  Fri, 03 Dec 2004 12:04:02 -0600
Cc:  LSM Mailing List <linux-security-module@wirex.com>
Archive-link:  Article, Thread

Hi,

Attached is a cleaned up version of stacker.

Changes:
  1. uses RCU to protect the list elements.
  2. capable() now just uses RETURN_ERROR_IF_ANY_ERROR explicitly.
  3. stacker exports lsm_adopt_next_secondary(char *name), which will
delegate stacking of the next loaded LSM to the module identified by
(name).
  4. stacker doesn't touch the get/setprocattr functions.  There's no
point messing with that unless/until userspace code can handle it, as
there's no clean way to handle all cases otherwise.
  5. mod_unreg_security is removed.  All modules use unregister_security
() regardless of whether they were loaded using register_security() or
mod_reg_security().  In this way, if capability() was escalated by
selinux from secondary to a primary module, it doesn't end up
unregistering the wrong way.

I attach lmbench results on a 700Mhz 4-way SMP box comparing a stock -
rc2-bk7 kernel with no stacking patches at all (nostack.lmbench), one
with the stacking patches applied (chain-newrcu.lmbench), and one with
roughly the same stacker.c, except rather than protect the list with
rcu, we do not free memory when a LSM is unloaded, so no RCU protection
in CALL_ALL and RETURN_ERROR_IF_ANY_ERROR.

thanks,
-serge
--
=======================================================
Serge Hallyn
Security Software Engineer, IBM Linux Technology Center
serue@us.ibm.com

Index: linux-2.6.9/Documentation/stacker.txt
===================================================================
--- linux-2.6.9.orig/Documentation/stacker.txt	2004-12-02 12:15:35.390617408
-0600
+++ linux-2.6.9/Documentation/stacker.txt	2004-12-01 11:00:48.000000000 -0600
@@ -0,0 +1,54 @@
+------------
+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 it's sysfs interface, located
+under /sys/stacker/.  This consists of the following files:
+
+/sys/stacker/next_secondary:
+In some cases, pairs or sets of LSMs may work together in subtle ways.
+For instance, SELinux and the capabilities modules interact such that
+it is better to have SELinux load the capabilities module as its own
+secondary.  To accomplish this, you would
+	1. compile stacker and selinux both into the kernel
+	2. compile capabilities as a module.
+	3. During init,
+		echo selinux > /sys/stacker/next_secondary
+		modprobe capability
+
+/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. Note that
+LSMs which have been loaded as secondaries of stacked modules will
+not be shown.  [ This could be done, but seems deceptive - SEH ]
+
+/sys/stacker/stop_responding:
+Unregisters the /sys/stacker directory, so that you can no longer
+interact with stacker.
+
+/sys/stacker/shortcircuit_restrictive:
+Toggle whether to query all security modules for permission to proceed
+with an action, regardless of whether an early module has denied
+permission.  By default, all security modules will be queried, as
+they may need to update some state to reflect the attempted action,
+although an error will still be returned.
+
+---------------------------------------------
+Readying an LSM for stacking with other LSMs.
+---------------------------------------------
+
Index: linux-2.6.9/include/linux/security.h
===================================================================
--- linux-2.6.9.orig/include/linux/security.h	2004-12-01 11:00:43.000000000
-0600
+++ linux-2.6.9/include/linux/security.h	2004-12-01 11:00:48.000000000 -0600
@@ -1946,9 +1946,8 @@
 /* prototypes */
 extern int security_init	(void);
 extern int register_security	(struct security_operations *ops);
-extern int unregister_security	(struct security_operations *ops);
+extern int unregister_security	(const char *name, 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);
 
 
 #else /* CONFIG_SECURITY */
Index: linux-2.6.9/security/Kconfig
===================================================================
--- linux-2.6.9.orig/security/Kconfig	2004-12-01 11:00:11.000000000 -0600
+++ linux-2.6.9/security/Kconfig	2004-12-01 11:00:48.000000000 -0600
@@ -86,5 +86,20 @@
 
 source security/selinux/Kconfig
 
+config SECURITY_STACKER
+	boolean "LSM Stacking"
+	depends on SECURITY
+	help
+	  Stack multiple LSMs.
+
+config SECURITY_STACKER_SHORTCIRCUIT
+	int "Short circuit restrictive hooks by default."
+	range 0 1
+	default 1
+	depends on SECURITY_STACKER
+	help
+	  If set, then security modules will be queried for a particular
+	  restrictive hook only until a module denies permission.
+
 endmenu
 
Index: linux-2.6.9/security/Makefile
===================================================================
--- linux-2.6.9.orig/security/Makefile	2004-12-01 11:00:11.000000000 -0600
+++ linux-2.6.9/security/Makefile	2004-12-01 11:00:48.000000000 -0600
@@ -2,6 +2,7 @@
 # Makefile for the kernel security code
 #
 
+obj-$(CONFIG_SECURITY_STACKER)		+= stacker.o
 obj-$(CONFIG_KEYS)			+= keys/
 subdir-$(CONFIG_SECURITY_SELINUX)	+= selinux
 
Index: linux-2.6.9/security/capability.c
===================================================================
--- linux-2.6.9.orig/security/capability.c	2004-12-01 11:00:11.000000000 -0600
+++ linux-2.6.9/security/capability.c	2004-12-01 11:00:48.000000000 -0600
@@ -83,15 +83,8 @@
 {
 	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)) {
+	if (unregister_security (MY_NAME, &capability_ops)) {
 		printk (KERN_INFO
 			"Failure unregistering capabilities with the kernel\n");
 	}
Index: linux-2.6.9/security/root_plug.c
===================================================================
--- linux-2.6.9.orig/security/root_plug.c	2004-10-18 16:55:28.000000000 -0500
+++ linux-2.6.9/security/root_plug.c	2004-12-01 11:00:48.000000000 -0600
@@ -121,17 +121,10 @@
 static void __exit rootplug_exit (void)
 {
 	/* remove ourselves from the security framework */
-	if (secondary) {
-		if (mod_unreg_security (MY_NAME, &rootplug_security_ops))
-			printk (KERN_INFO "Failure unregistering Root Plug "
-				" module with primary module.\n");
-	} else { 
-		if (unregister_security (&rootplug_security_ops)) {
-			printk (KERN_INFO "Failure unregistering Root Plug "
-				"module with the kernel\n");
-		}
-	}
-	printk (KERN_INFO "Root Plug module removed\n");
+	if (unregister_security(MY_NAME, &rootplug_security_ops))
+		printk (KERN_INFO "Failure unregistering Root Plug\n");
+	else
+		printk (KERN_INFO "Root Plug module removed\n");
 }
 
 security_initcall (rootplug_init);
Index: linux-2.6.9/security/seclvl.c
===================================================================
--- linux-2.6.9.orig/security/seclvl.c	2004-12-01 11:00:44.000000000 -0600
+++ linux-2.6.9/security/seclvl.c	2004-12-01 14:06:10.000000000 -0600
@@ -758,13 +758,10 @@
 				  &sysfs_attr_passwd.attr);
 	}
 	subsystem_unregister(&seclvl_subsys);
-	if (secondary == 1) {
-		mod_unreg_security(MY_NAME, &seclvl_ops);
-	} else if (unregister_security(&seclvl_ops)) {
-		seclvl_printk(0, KERN_INFO,
-			      "seclvl: Failure unregistering with the "
-			      "kernel\n");
-	}
+	if (unregister_security(MY_NAME, &seclvl_ops))
+		seclvl_printk(0, KERN_INFO, "seclvl: failure unregistering.\n");
+	else
+		seclvl_printk(0, KERN_INFO, "seclvl unregistered.\n");
 }
 
 module_init(seclvl_init);
Index: linux-2.6.9/security/security.c
===================================================================
--- linux-2.6.9.orig/security/security.c	2004-12-01 11:00:43.000000000 -0600
+++ linux-2.6.9/security/security.c	2004-12-01 11:00:48.000000000 -0600
@@ -222,20 +222,13 @@
  * @ops: a pointer to the struct security_options that is to be registered
  *
  * This function removes a struct security_operations variable that had
- * previously been registered with a successful call to register_security().
- *
- * If @ops does not match the valued previously passed to register_security()
- * an error is returned.  Otherwise the default security options is set to
the
- * the dummy_security_ops structure, and 0 is returned.
+ * previously been registered with a successful call to register_security()
+ * or mod_reg_security().
  */
-int unregister_security(struct security_operations *ops)
+int unregister_security(const char *name, struct security_operations *ops)
 {
-	if (ops != security_ops) {
-		printk(KERN_INFO "%s: trying to unregister "
-		       "a security_opts structure that is not "
-		       "registered, failing.\n", __FUNCTION__);
-		return -EINVAL;
-	}
+	if (ops != security_ops)
+		return security_ops->unregister_security(name, ops);
 
 	security_ops = &dummy_security_ops;
 
@@ -272,30 +265,6 @@
 }
 
 /**
- * mod_unreg_security - allows a security module registered with mod_reg_security() to be
unloaded
- * @name: a pointer to a string with the name of the security_options to be
removed
- * @ops: a pointer to the struct security_options that is to be removed
- *
- * This function allows security modules that have been successfully
registered
- * with a call to mod_reg_security() to be unloaded from the system.
- * This calls the currently loaded security module's unregister_security()
call
- * with the @name and @ops variables.
- *
- * The return value depends on the currently loaded security module, with 0
as
- * success.
- */
-int mod_unreg_security(const char *name, struct security_operations *ops)
-{
-	if (ops == security_ops) {
-		printk(KERN_INFO "%s invalid attempt to unregister "
-		       " primary security ops.\n", __FUNCTION__);
-		return -EINVAL;
-	}
-
-	return security_ops->unregister_security(name, ops);
-}
-
-/**
  * capable - calls the currently loaded security module's capable() function with the specified
capability
  * @cap: the requested capability level.
  *
@@ -320,6 +289,5 @@
 EXPORT_SYMBOL_GPL(register_security);
 EXPORT_SYMBOL_GPL(unregister_security);
 EXPORT_SYMBOL_GPL(mod_reg_security);
-EXPORT_SYMBOL_GPL(mod_unreg_security);
 EXPORT_SYMBOL(capable);
 EXPORT_SYMBOL(security_ops);
Index: linux-2.6.9/security/selinux/hooks.c
===================================================================
--- linux-2.6.9.orig/security/selinux/hooks.c	2004-12-01 11:00:45.000000000
-0600
+++ linux-2.6.9/security/selinux/hooks.c	2004-12-01 11:00:48.000000000 -0600
@@ -4648,22 +4648,26 @@
 
 	selinux_disabled = 1;
 
-	if (secondary) {
-		if (mod_unreg_security(MY_NAME, &selinux_ops))
-			printk(KERN_INFO "Failure unregistering selinux.\n");
+	if (unregister_security(MY_NAME, &selinux_ops))
+		printk(KERN_INFO "Failure unregistering selinux.\n");
+	else
+		printk(KERN_INFO "Unregistered selinux.\n");
+
+	if (secondary_ops) {
+		int ret;
+
+		if (secondary) {
+			ret = mod_reg_security(secondary_name, secondary_ops);
+		} else
+			ret = register_security(secondary_ops);
+
+		if (ret)
+			printk(KERN_INFO
+				"Failure re-registering secondary (%s).\n",
+				secondary_name);
 		else
-			printk(KERN_INFO "Unregistered selinux.\n");
-		secondary = 0;
-		if (secondary_name)
-			if (mod_reg_security(secondary_name, secondary_ops))
-				printk(KERN_INFO "Failure registering secondary.\n");
-	} else {
-		if (unregister_security(&selinux_ops))
-			printk(KERN_INFO "Failure unregistering selinux.\n");
-		else
-			printk(KERN_INFO "Unregistered selinux.\n");
-		if (secondary_ops)
-			register_security(secondary_ops);
+			printk(KERN_INFO "Re-registered secondary (%s).\n",
+				secondary_name);
 	}
 
 	/* Unregister netfilter hooks. */
Index: linux-2.6.9/security/stacker.c
===================================================================
--- linux-2.6.9.orig/security/stacker.c	2004-12-02 12:15:35.390617408 -0600
+++ linux-2.6.9/security/stacker.c	2004-12-03 11:38:52.969215280 -0600
@@ -0,0 +1,1546 @@
+/* "Stacker" Linux security module (LSM).
+ *
+ * version 2004-11-29
+ * Load this module first as the primary LSM module,
+ * and you can then stack (load) multiple additional LSM modules.
+ *
+ * Copyright (C) 2002,2003,2004 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 stacked 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 short sysfsfiles_registered;
+static int num_stacked_modules;
+
+static spinlock_t stacker_lock;
+static int short_circuit_restrictive;   /* = 0; if 1, short-circuit
restrictive
+					     hooks */
+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 *next_secondary;
+
+/* 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)
+
+static inline void stacker_free_module(struct module_entry *m)
+{
+	kfree(m->module_name);
+	kfree(m);
+}
+
+/*
+ * Delete a module entry
+ */
+static void stacker_del_module(struct rcu_head *head)
+{
+	struct module_entry *m = container_of(head, struct module_entry,
+		m_rcu);
+	if (atomic_dec_and_test(&m->use))
+		stacker_free_module(m);
+}
+
+/* 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.
+ *
+ * If shortcircuit_restrictive is set, then we return as soon
+ * as an error is returned.  Otherwise, we check all modules.
+ * This may be necessary if some modules have to update their
+ * state based on the permission request.
+ */
+
+#define RETURN_ERROR_IF_ANY_ERROR(BASE_FUNC,FUNC_WITH_ARGS) do { \
+	int final_result = 0; \
+	struct module_entry *m; \
+	rcu_read_lock(); \
+	list_for_each_entry_rcu(m, &stacked_modules, lsm_list) { \
+		int result = 0, stop = 0; \
+		atomic_inc(&m->use); \
+		rcu_read_unlock(); \
+		if (m->module_operations.BASE_FUNC) \
+			result = m->module_operations.FUNC_WITH_ARGS; \
+		if (result && !final_result) { \
+			final_result = result; \
+			if (short_circuit_restrictive) \
+				stop = 1; \
+		} \
+		rcu_read_lock(); \
+		if (unlikely(atomic_dec_and_test(&m->use))) \
+			stacker_free_module(m); \
+		if (stop) \
+			break; \
+	} \
+	rcu_read_unlock(); \
+	return final_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(); \
+	list_for_each_entry_rcu(m, &stacked_modules, lsm_list) { \
+		atomic_inc(&m->use); \
+		rcu_read_unlock(); \
+		if (m->module_operations.BASE_FUNC) \
+			m->module_operations.FUNC_WITH_ARGS; \
+		rcu_read_lock(); \
+		if (unlikely(atomic_dec_and_test(&m->use))) \
+			stacker_free_module(m); \
+	} \
+	rcu_read_unlock(); \
+} 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 file *f)
+{
+	RETURN_ERROR_IF_ANY_ERROR(quota_on,quota_on(f));
+}
+
+static int stacker_syslog (int type)
+{
+	RETURN_ERROR_IF_ANY_ERROR(syslog,syslog(type));
+}
+
+static int stacker_vm_enough_memory(long pages)
+{
+	RETURN_ERROR_IF_ANY_ERROR(vm_enough_memory,vm_enough_memory(pages));
+}
+
+static int stacker_netlink_send (struct sock *sk, struct sk_buff *skb)
+{
+	/* NOTE: The dummy module does this:
+		if (current->euid == 0)
+			cap_raise (NETLINK_CB (skb).eff_cap, CAP_NET_ADMIN);
+		else
+			NETLINK_CB (skb).eff_cap = 0;
+	 * if this would be a problem with your module, then tell
+	 * your administrators what to do. */
+
+	RETURN_ERROR_IF_ANY_ERROR(netlink_send,netlink_send(sk,skb));
+}
+
+
+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)
+{
+	RETURN_ERROR_IF_ANY_ERROR(bprm_alloc_security,bprm_alloc_security(bprm));
+}
+
+static void stacker_bprm_free_security (struct linux_binprm *bprm)
+{
+	CALL_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 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)
+{
+	RETURN_ERROR_IF_ANY_ERROR(sb_alloc_security,sb_alloc_security(sb));
+}
+
+static void stacker_sb_free_security (struct super_block *sb)
+{
+	CALL_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)
+{
+	RETURN_ERROR_IF_ANY_ERROR(inode_alloc_security,inode_alloc_security(inode));
+}
+
+static void stacker_inode_free_security (struct inode *inode)
+{
+	CALL_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)
+{
+	RETURN_ERROR_IF_ANY_ERROR(file_alloc_security,file_alloc_security(file));
+}
+
+static void stacker_file_free_security (struct file *file)
+{
+	CALL_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 prot,
+			    unsigned long flags)
+{
+	RETURN_ERROR_IF_ANY_ERROR(file_mmap,file_mmap(file, prot, flags));
+}
+
+static int stacker_file_mprotect (struct vm_area_struct *vma,
+	       	unsigned long prot)
+{
+	RETURN_ERROR_IF_ANY_ERROR(file_mprotect,file_mprotect(vma,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)
+{
+	RETURN_ERROR_IF_ANY_ERROR(task_alloc_security,task_alloc_security(p));
+}
+
+static void stacker_task_free_security (struct task_struct *p)
+{
+	CALL_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)
+{
+	RETURN_ERROR_IF_ANY_ERROR(sk_alloc_security,sk_alloc_security(sk,family,priority));
+}
+
+static void stacker_sk_free_security (struct sock *sk)
+{
+	CALL_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)
+{
+	RETURN_ERROR_IF_ANY_ERROR(msg_msg_alloc_security,msg_msg_alloc_security(msg));
+}
+
+static void stacker_msg_msg_free_security (struct msg_msg *msg)
+{
+	CALL_ALL(msg_msg_free_security,msg_msg_free_security(msg));
+}
+
+static int stacker_msg_queue_alloc_security (struct msg_queue *msq)
+{
+	RETURN_ERROR_IF_ANY_ERROR(msg_queue_alloc_security,msg_queue_alloc_security(msq));
+}
+
+static void stacker_msg_queue_free_security (struct msg_queue *msq)
+{
+	CALL_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)
+{
+	RETURN_ERROR_IF_ANY_ERROR(shm_alloc_security,shm_alloc_security(shp));
+}
+
+static void stacker_shm_free_security (struct shmid_kernel *shp)
+{
+	CALL_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)
+{
+	RETURN_ERROR_IF_ANY_ERROR(sem_alloc_security,sem_alloc_security(sma));
+}
+
+static void stacker_sem_free_security (struct sem_array *sma)
+{
+	CALL_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)
+ * according to the current ordering policy.
+ */
+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 (next_secondary) {
+		ret =  next_secondary->module_operations.register_security(name,
+				ops);
+		printk(KERN_INFO "%s: %s loaded %s (returned %d)\n",
+			__FUNCTION__, next_secondary->module_name,
+			name, ret);
+		next_secondary = NULL;
+		goto out;
+	}
+
+	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;
+
+	atomic_set(&new_module_entry->use, 1);
+	INIT_LIST_HEAD(&new_module_entry->lsm_list);
+	list_add_tail_rcu(&new_module_entry->lsm_list, &stacked_modules);
+	num_stacked_modules++;
+	if (strcmp(name, "selinux") == 0)
+		selinux_module = new_module_entry;
+
+	printk(KERN_INFO "%s: registered %s module\n", __FUNCTION__,
+		new_module_entry->module_name);
+
+out:
+	spin_unlock(&stacker_lock);
+	return ret;
+}
+
+/*
+ * try to get a stacked module to unregister this module.
+ * called with spinlock held.
+ */
+static inline struct module_entry *
+try_all_unregister(const char *name, struct security_operations *ops)
+{
+	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->module_operations.unregister_security)
+			goto setup_next_iter;
+		if ( !m->module_operations.unregister_security(name, ops))
+			 ret = m;
+
+setup_next_iter:
+		rcu_read_lock();
+		if (unlikely(atomic_dec_and_test(&m->use)))
+			stacker_free_module(m);
+		if (ret)
+			break;
+	}
+	rcu_read_unlock();
+
+	return ret;
+}
+
+/*
+ * find_lsm_module_by_name:
+ * Find a module by name.  Used by next_secondary_write.  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)))
+			stacker_free_module(m);
+		if (ret)
+			break;
+	}
+	rcu_read_unlock();
+
+	return ret;
+}
+
+/*
+ * Unregister a registered LSM.
+ * It would be nice if we could veto this, but we can't...
+ */
+static int stacker_unregister (const char *name, struct security_operations
*ops)
+{
+	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) {
+		m = try_all_unregister(name, ops);
+		if (m) {
+			printk(KERN_NOTICE "%s: %s unregistered %s\n",
+				__FUNCTION__, m->module_name, name);
+			goto out;
+		}
+	}
+
+	if (!m) {
+		printk(KERN_INFO "%s: could not find module %s.\n",
+			__FUNCTION__, name);
+		ret = -ENOENT;
+		goto out;
+	}
+
+	list_del_rcu(&m->lsm_list);
+	num_stacked_modules--;
+
+	if (strcmp(m->module_name, "selinux") == 0)
+		selinux_module = NULL;
+	if (next_secondary == m)
+		next_secondary = NULL;
+	call_rcu(&m->m_rcu, stacker_del_module);
+
+out:
+	spin_unlock(&stacker_lock);
+
+	return ret;
+}
+
+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,
+	.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_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)
+{
+	ssize_t len;
+
+	if (forbid_stacker_register)
+		len = sprintf(buff, "Locked down\n");
+	else
+		len = sprintf(buff, "Unlocked\n");
+
+	return len;
+}
+
+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();
+	list_for_each_entry_rcu(m, &stacked_modules, lsm_list) {
+		atomic_inc(&m->use);
+		rcu_read_unlock();
+		len += snprintf(buff+len, PAGE_SIZE - len, "%s\n",
+			m->module_name);
+		rcu_read_lock();
+		if (unlikely(atomic_dec_and_test(&m->use)))
+			stacker_free_module(m);
+	}
+	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,
+};
+
+/* stop responding to sysfs */
+static ssize_t stop_responding_read (struct stacker_kobj *obj, char *buff)
+{
+	ssize_t len;
+
+	len = sprintf(buff, "Obviously not\n");
+
+	return len;
+}
+
+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},
+	.show = stop_responding_read,
+	.store = stop_responding_write
+};
+
+/* short-circuit restrictive */
+static ssize_t shortcircuit_restrictive_read (struct stacker_kobj *obj, char
*buff)
+{
+	ssize_t len;
+
+	if (short_circuit_restrictive)
+		len = sprintf(buff, "Restrictive hooks ARE being short-circuited.\n");
+	else
+		len = sprintf(buff, "Restrictive hooks are NOT being short-circuited.\n");
+
+	return len;
+}
+
+static ssize_t shortcircuit_restrictive_write (struct stacker_kobj *obj, const char *buff, size_t
count)
+{
+	int ret = count;
+
+	if (!count)
+		return count;
+
+	if (buff[0]=='0')
+		short_circuit_restrictive = 0;
+	else if (buff[0]=='1')
+		short_circuit_restrictive = 1;
+	else
+		ret = -ENOENT;
+
+	return ret;
+}
+
+static struct stacker_attribute stacker_attr_shortcircuit_restr = {
+	.attr = {.name = "shortcircuit_restrictive", .mode = S_IFREG | S_IRUGO |
S_IWUSR},
+	.show = shortcircuit_restrictive_read,
+	.store = shortcircuit_restrictive_write
+};
+
+static ssize_t next_secondary_read (struct stacker_kobj *obj, char *buff)
+{
+	if (!next_secondary)
+		return 0;
+	return sprintf(buff, next_secondary->module_name);
+}
+
+static ssize_t next_secondary_write (struct stacker_kobj *obj, const char *buff, size_t
count)
+{
+	unsigned long flags;
+	size_t len = count;
+	ssize_t ret = count;
+
+	if (!len)
+		return count;
+	if (buff[len-1] == '\n')
+		len--;
+	spin_lock_irqsave(&stacker_lock, flags);
+	next_secondary = find_lsm_with_namelen(buff, len);
+	if (!next_secondary)
+		ret = -EINVAL;
+	spin_unlock_irqrestore(&stacker_lock, flags);
+
+	return ret;
+}
+
+/*
+ * An EXPORTed function to allow stacked LSMs to directly ask to adopt
+ * the next LSM, without needing to go through userspace
+ */
+int lsm_adopt_next_secondary(char *name)
+{
+	unsigned long flags;
+	size_t len = strnlen(name, MAX_MODULE_NAME_LEN);
+	int ret = 0;
+
+	spin_lock_irqsave(&stacker_lock, flags);
+	next_secondary = find_lsm_with_namelen(name, len);
+	if (!next_secondary)
+		ret = -EINVAL;
+	spin_unlock_irqrestore(&stacker_lock, flags);
+	return ret;
+}
+
+EXPORT_SYMBOL(lsm_adopt_next_secondary);
+
+static struct stacker_attribute stacker_attr_nextsec = {
+	.attr = {.name = "next_secondary", .mode = S_IFREG | S_IRUGO | S_IWUSR},
+	.show = next_secondary_read,
+	.store = next_secondary_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_nextsec.attr);
+	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_shortcircuit_restr.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_shortcircuit_restr.attr);
+	sysfs_create_file(&stacker_subsys.kset.kobj,
+			&stacker_attr_nextsec.attr);
+	sysfsfiles_registered = 1;
+	stacker_dbg("sysfs files registered\n");
+	return 0;
+}
+
+module_init(register_sysfs_files);
+
+/*
+ * Structure sent back to security modules for getting and
+ * setting security blobs
+ */
+
+static int __init stacker_init (void)
+{
+	forbid_stacker_register = 0;
+	short_circuit_restrictive = CONFIG_SECURITY_STACKER_SHORTCIRCUIT;
+	INIT_LIST_HEAD(&stacked_modules);
+	sysfsfiles_registered = 0;
+	num_stacked_modules = 0;
+	spin_lock_init(&stacker_lock);
+
+	if (register_security (&stacker_ops)) {
+		/*
+		 * stacking stacker is just a stupid idea, so don't ask
+		 * the current module to load us.
+		 */
+		printk (KERN_WARNING "Failure registering stacker module "
+			"as primary security module.\n");
+		return -EINVAL;
+	}
+	stacker_dbg("LSM stacker initialized\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 (MY_NAME, &stacker_ops))
+		printk (KERN_WARNING
+			"Error unregistering LSM stacker.\n");
+	else
+		stacker_dbg("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");


                 L M B E N C H  2 . 0   S U M M A R Y
                 ------------------------------------


Basic system parameters
----------------------------------------------------
Host                 OS Description              Mhz
                                                    
--------- ------------- ----------------------- ----
vega.ltc. Linux 2.6.10-       i686-pc-linux-gnu  700
vega.ltc. Linux 2.6.10-       i686-pc-linux-gnu  700
vega.ltc. Linux 2.6.10-       i686-pc-linux-gnu  700
vega.ltc. Linux 2.6.10-       i686-pc-linux-gnu  700

Processor, Processes - times in microseconds - smaller is better
----------------------------------------------------------------
Host                 OS  Mhz null null      open selct sig  sig  fork exec sh
                             call  I/O stat clos TCP   inst hndl proc proc
proc
--------- ------------- ---- ---- ---- ---- ---- ----- ---- ---- ---- ----
----
vega.ltc. Linux 2.6.10-  700 0.30 1.10 10.8 12.7  37.0 1.45 5.47 250. 1119
3825
vega.ltc. Linux 2.6.10-  700 0.30 1.13 10.9 12.8  38.2 1.43 5.57 249. 1110
3816
vega.ltc. Linux 2.6.10-  700 0.30 1.12 11.0 12.8  38.8 1.44 5.54 249. 1120
3835
vega.ltc. Linux 2.6.10-  700 0.30 1.11 10.9 12.8  36.5 1.43 5.57 249. 1156
3827

MEAN                              1.12 10.9 12.8  37.6 1.44 5.54 249  1126
3826
STDEV                              .01  0.1  .04   0.9 0.01 0.04  .4    18
7
CI (95%)

Context switching - times in microseconds - smaller is better
-------------------------------------------------------------
Host                 OS 2p/0K 2p/16K 2p/64K 8p/16K 8p/64K 16p/16K 16p/64K
                        ctxsw  ctxsw  ctxsw ctxsw  ctxsw   ctxsw   ctxsw
--------- ------------- ----- ------ ------ ------ ------ ------- -------
vega.ltc. Linux 2.6.10-  11.6   15.9   32.3   17.7   33.1    16.7    32.8
vega.ltc. Linux 2.6.10-  11.0   16.1   32.9   16.4   31.3    16.3    33.1
vega.ltc. Linux 2.6.10-  11.6   15.7   32.5   18.6   31.8    16.9    34.0
vega.ltc. Linux 2.6.10-  11.1   15.7   32.5   17.9   32.8    17.2    32.8

MEAN                     11.3   15.9   32.6   17.7   32.3    16.8    33.2
STDEV                     0.3    0.2    0.2    0.8    0.7     0.3     0.5
CI (95%)

*Local* Communication latencies in microseconds - smaller is better
-------------------------------------------------------------------
Host                 OS 2p/0K  Pipe AF     UDP  RPC/   TCP  RPC/ TCP
                        ctxsw       UNIX         UDP         TCP conn
--------- ------------- ----- ----- ---- ----- ----- ----- ----- ----
vega.ltc. Linux 2.6.10-  11.6  53.1 61.5             100.1       179.
vega.ltc. Linux 2.6.10-  11.0  46.2 72.9              98.5       178.
vega.ltc. Linux 2.6.10-  11.6  54.9 69.9             128.4       179.
vega.ltc. Linux 2.6.10-  11.1  55.6 68.9              99.2       181.

MEAN                     11.3  52.5 68.3             106.6       179
STDEV                     0.3   3.7  4.2              12.6         1
CI (95%)

File & VM system latencies in microseconds - smaller is better
--------------------------------------------------------------
Host                 OS   0K File      10K File      Mmap    Prot    Page	
                        Create Delete Create Delete  Latency Fault   Fault 
--------- ------------- ------ ------ ------ ------  ------- -----   ----- 
vega.ltc. Linux 2.6.10-   80.5   42.5  209.6   79.6    11.2K 0.220 4.00000
vega.ltc. Linux 2.6.10-   80.6   42.7  210.4   79.9    11.1K 0.269 5.00000
vega.ltc. Linux 2.6.10-   80.9   42.6  208.1   80.1    11.1K 0.200 5.00000
vega.ltc. Linux 2.6.10-   80.6   43.0  208.9   80.0    11.3K 0.230 4.00000

MEAN                      80.7   42.7  209.3   79.9    11.2K 0.230 4.5
STDEV                      0.2    0.2    0.9    0.2     0.1K 0.025 0.5
CI (95%)

*Local* Communication bandwidths in MB/s - bigger is better
-----------------------------------------------------------
Host                OS  Pipe AF    TCP  File   Mmap  Bcopy  Bcopy  Mem   Mem
                             UNIX      reread reread (libc) (hand) read write
--------- ------------- ---- ---- ---- ------ ------ ------ ------ ---- -----
vega.ltc. Linux 2.6.10- 291. 283. 198.  278.8  331.7  185.9  158.5 328. 202.6
vega.ltc. Linux 2.6.10- 292. 284. 196.  282.2  327.9  185.9  147.0 331. 202.9
vega.ltc. Linux 2.6.10- 294. 282. 197.  282.1  331.4  187.0  146.6 328. 202.8
vega.ltc. Linux 2.6.10- 293. 283. 199.  278.8  328.0  185.8  145.2 328. 204.9

MEAN                    293  283  198   280.5  329.8  186.2  149.3 329  203.3
STDEV                     1    1    1     1.7    1.8    0.5    5.3   1    0.9
CI (95%)

Memory latencies in nanoseconds - smaller is better
    (WARNING - may not be correct, check graphs)
---------------------------------------------------
Host                 OS   Mhz  L1 $   L2 $    Main mem    Guesses
--------- -------------  ---- ----- ------    --------    -------
vega.ltc. Linux 2.6.10-   700 4.329   13.0  183.3
vega.ltc. Linux 2.6.10-   700 4.284   12.9  181.3
vega.ltc. Linux 2.6.10-   700 4.284   12.9  181.2
vega.ltc. Linux 2.6.10-   700 4.286   12.9  181.3


                 L M B E N C H  2 . 0   S U M M A R Y
                 ------------------------------------


Basic system parameters
----------------------------------------------------
Host                 OS Description              Mhz
                                                    
--------- ------------- ----------------------- ----
vega.ltc. Linux 2.6.10-       i686-pc-linux-gnu  700
vega.ltc. Linux 2.6.10-       i686-pc-linux-gnu  700
vega.ltc. Linux 2.6.10-       i686-pc-linux-gnu  700
vega.ltc. Linux 2.6.10-       i686-pc-linux-gnu  700

Processor, Processes - times in microseconds - smaller is better
----------------------------------------------------------------
Host                 OS  Mhz null null      open selct sig  sig  fork exec sh
                             call  I/O stat clos TCP   inst hndl proc proc
proc
--------- ------------- ---- ---- ---- ---- ---- ----- ---- ---- ---- ----
----
vega.ltc. Linux 2.6.10-  700 0.30 1.97 15.0 18.5  36.6 1.43 6.20 258. 1172
4011
vega.ltc. Linux 2.6.10-  700 0.30 2.02 15.2 18.4  38.0 1.43 6.31 257. 1179
4041
vega.ltc. Linux 2.6.10-  700 0.30 1.99 15.2 18.7  38.2 1.44 6.13 257. 1189
4041
vega.ltc. Linux 2.6.10-  700 0.30 1.99 15.3 18.7  36.4 1.43 6.18 255. 1176
4043

MEAN                              1.99 15.2 18.6  37.3 1.43 6.21 257  1179
4034
STDEV                             0.02  0.1  0.1   0.8 .004 0.07   1     6
13
CI (95%)

Context switching - times in microseconds - smaller is better
-------------------------------------------------------------
Host                 OS 2p/0K 2p/16K 2p/64K 8p/16K 8p/64K 16p/16K 16p/64K
                        ctxsw  ctxsw  ctxsw ctxsw  ctxsw   ctxsw   ctxsw
--------- ------------- ----- ------ ------ ------ ------ ------- -------
vega.ltc. Linux 2.6.10-  10.1   14.6   31.3   14.9   30.8    16.5    41.8
vega.ltc. Linux 2.6.10-  10.1   14.6   26.1   15.4   33.1    16.0    33.1
vega.ltc. Linux 2.6.10-  10.3   14.6   32.0   15.2   32.9    14.7    32.8
vega.ltc. Linux 2.6.10-  10.4   14.5   31.3   15.0   33.1    15.0    35.2

MEAN                     10.2   14.6   30.2   15.1   32.5    15.6    35.7
STDEV                     0.1   0.04    2.4    0.2    1.0     0.7     3.6
CI (95%)

*Local* Communication latencies in microseconds - smaller is better
-------------------------------------------------------------------
Host                 OS 2p/0K  Pipe AF     UDP  RPC/   TCP  RPC/ TCP
                        ctxsw       UNIX         UDP         TCP conn
--------- ------------- ----- ----- ---- ----- ----- ----- ----- ----
vega.ltc. Linux 2.6.10-  10.1  49.8 97.2             104.8       186.
vega.ltc. Linux 2.6.10-  10.1  48.6 86.7             127.8       187.
vega.ltc. Linux 2.6.10-  10.3  48.9 96.3             105.3       189.
vega.ltc. Linux 2.6.10-  10.4  49.7 100.             103.7       187.

MEAN                     10.2  49.3 95.1             110.4       187
STDEV                     0.1   0.5  5.0              10.1         1
CI (95%)

File & VM system latencies in microseconds - smaller is better
--------------------------------------------------------------
Host                 OS   0K File      10K File      Mmap    Prot    Page	
                        Create Delete Create Delete  Latency Fault   Fault 
--------- ------------- ------ ------ ------ ------  ------- -----   ----- 
vega.ltc. Linux 2.6.10-   88.3   46.4  213.9   82.6    12.0K       5.00000
vega.ltc. Linux 2.6.10-   88.9   46.8  214.4   82.9    11.4K       4.00000
vega.ltc. Linux 2.6.10-   89.0   46.7  215.5   82.6    11.1K       4.00000
vega.ltc. Linux 2.6.10-   88.2   46.3  214.5   81.9    11.0K       5.00000

MEAN                      88.6   46.6  214.6   82.5    11.4K       4.5
STDEV                      0.4    0.2    0.6    0.4     0.4K       0.5
CI (95%)

*Local* Communication bandwidths in MB/s - bigger is better
-----------------------------------------------------------
Host                OS  Pipe AF    TCP  File   Mmap  Bcopy  Bcopy  Mem   Mem
                             UNIX      reread reread (libc) (hand) read write
--------- ------------- ---- ---- ---- ------ ------ ------ ------ ---- -----
vega.ltc. Linux 2.6.10- 292. 283. 200.  277.8  328.0  183.8  145.1 331. 202.8
vega.ltc. Linux 2.6.10- 289. 283. 196.  277.9  331.5  183.7  146.6 331. 202.9
vega.ltc. Linux 2.6.10- 288. 283. 198.  281.5  328.0  185.3  145.2 328. 202.4
vega.ltc. Linux 2.6.10- 288. 282. 196.  277.3  331.5  185.9  145.3 331. 205.4

MEAN                    289  283  198   278.6  329.8  184.7  145.6 330  203.4
STDEV                     2   .4    2     1.7    1.8    0.9    0.6   1    1.2
CI (95%)

Memory latencies in nanoseconds - smaller is better
    (WARNING - may not be correct, check graphs)
---------------------------------------------------
Host                 OS   Mhz  L1 $   L2 $    Main mem    Guesses
--------- -------------  ---- ----- ------    --------    -------
vega.ltc. Linux 2.6.10-   700 4.329   13.0  184.9
vega.ltc. Linux 2.6.10-   700 4.329   13.0  184.9
vega.ltc. Linux 2.6.10-   700 4.330   13.0  184.8
vega.ltc. Linux 2.6.10-   700 4.329   13.0  182.9


                 L M B E N C H  2 . 0   S U M M A R Y
                 ------------------------------------


Basic system parameters
----------------------------------------------------
Host                 OS Description              Mhz
                                                    
--------- ------------- ----------------------- ----
vega.ltc. Linux 2.6.10-       i686-pc-linux-gnu  700
vega.ltc. Linux 2.6.10-       i686-pc-linux-gnu  700
vega.ltc. Linux 2.6.10-       i686-pc-linux-gnu  700
vega.ltc. Linux 2.6.10-       i686-pc-linux-gnu  700

Processor, Processes - times in microseconds - smaller is better
----------------------------------------------------------------
Host                 OS  Mhz null null      open selct sig  sig  fork exec sh
                             call  I/O stat clos TCP   inst hndl proc proc
proc
--------- ------------- ---- ---- ---- ---- ---- ----- ---- ---- ---- ----
----
vega.ltc. Linux 2.6.10-  700 0.30 1.86 14.4 17.2  36.5 1.43 5.71 260. 1167
4024
vega.ltc. Linux 2.6.10-  700 0.30 1.89 14.7 17.5  40.7 1.45 5.77 259. 1179
3984
vega.ltc. Linux 2.6.10-  700 0.30 1.88 14.6 17.4  41.6 1.43 5.77 258. 1166
4043
vega.ltc. Linux 2.6.10-  700 0.30 1.88 14.4 17.2  36.7 1.45 5.67 260. 1183
4052

MEAN                         0.30 1.88 14.5 17.3  38.9 1.44 5.73 259  1174
4026
STDEV                             0.01  0.1  0.1   2.3 0.01 0.04   1     7
26
CI (95%)

Context switching - times in microseconds - smaller is better
-------------------------------------------------------------
Host                 OS 2p/0K 2p/16K 2p/64K 8p/16K 8p/64K 16p/16K 16p/64K
                        ctxsw  ctxsw  ctxsw ctxsw  ctxsw   ctxsw   ctxsw
--------- ------------- ----- ------ ------ ------ ------ ------- -------
vega.ltc. Linux 2.6.10-  10.1   14.5   31.6   15.0   32.8    14.9    32.9
vega.ltc. Linux 2.6.10-  10.2   14.6   31.1   14.8   32.8    15.6    32.4
vega.ltc. Linux 2.6.10-  10.0   14.8   31.7   15.2   32.3    14.8    38.3
vega.ltc. Linux 2.6.10- 9.900   14.3   31.4   14.8   32.1    15.8    32.9

MEAN                    10.05   14.6   31.5   15.0   32.5    15.3    34.1
STDEV                    0.11    0.2    0.2    0.2    0.3     0.4     2.4
CI (95%)

*Local* Communication latencies in microseconds - smaller is better
-------------------------------------------------------------------
Host                 OS 2p/0K  Pipe AF     UDP  RPC/   TCP  RPC/ TCP
                        ctxsw       UNIX         UDP         TCP conn
--------- ------------- ----- ----- ---- ----- ----- ----- ----- ----
vega.ltc. Linux 2.6.10-  10.1  46.4 55.6             127.2       187.
vega.ltc. Linux 2.6.10-  10.2  49.2 93.3             104.3       188.
vega.ltc. Linux 2.6.10-  10.0  44.2 85.9             129.0       187.
vega.ltc. Linux 2.6.10- 9.900  45.6 97.4             104.6       188.

MEAN                    10.05  46.4 83.1             116.3       188
STDEV                    0.11   1.8 16.4              11.8         1
CI (95%)

File & VM system latencies in microseconds - smaller is better
--------------------------------------------------------------
Host                 OS   0K File      10K File      Mmap    Prot    Page	
                        Create Delete Create Delete  Latency Fault   Fault 
--------- ------------- ------ ------ ------ ------  ------- -----   ----- 
vega.ltc. Linux 2.6.10-   89.9   45.5  215.2   82.3    11.0K       5.00000
vega.ltc. Linux 2.6.10-   90.6   45.9  217.9   81.5    11.1K       4.00000
vega.ltc. Linux 2.6.10-   90.8   45.8  218.4   83.0    10.7K 0.027 4.00000
vega.ltc. Linux 2.6.10-   90.4   45.9  215.7   81.7    10.8K 0.052 4.00000

MEAN                      90.4   45.8  216.8   82.1    10.9K 0.040 4.250
STDEV                      0.3    0.2    1.4    0.6     0.2K 0.013 0.433
CI (95%)

*Local* Communication bandwidths in MB/s - bigger is better
-----------------------------------------------------------
Host                OS  Pipe AF    TCP  File   Mmap  Bcopy  Bcopy  Mem   Mem
                             UNIX      reread reread (libc) (hand) read write
--------- ------------- ---- ---- ---- ------ ------ ------ ------ ---- -----
vega.ltc. Linux 2.6.10- 289. 281. 233.  281.9  331.6  183.6  145.0 331. 205.3
vega.ltc. Linux 2.6.10- 288. 282. 197.  277.7  327.7  186.0  145.0 331. 202.5
vega.ltc. Linux 2.6.10- 293. 283. 194.  281.6  331.6  183.8  144.0 328. 202.3
vega.ltc. Linux 2.6.10- 291. 282. 195.  281.6  327.8  183.7  145.0 327. 202.4

MEAN                    290  282  205   280.7  329.7  184.3  144.8 329  203.1
STDEV                     2    1   16     1.7    1.9    1      0.4   2    1.3
CI (95%)

Memory latencies in nanoseconds - smaller is better
    (WARNING - may not be correct, check graphs)
---------------------------------------------------
Host                 OS   Mhz  L1 $   L2 $    Main mem    Guesses
--------- -------------  ---- ----- ------    --------    -------
vega.ltc. Linux 2.6.10-   700 4.285   12.9  182.8
vega.ltc. Linux 2.6.10-   700 4.329   13.0  184.8
vega.ltc. Linux 2.6.10-   700 4.328   13.0  184.8
vega.ltc. Linux 2.6.10-   700 4.284   12.8  182.8


Copyright © 2004, Eklektix, Inc.
Comments and public postings are copyrighted by their creators.
Linux is a registered trademark of Linus Torvalds