Updated stacker.c (the real one, ignore the last post)

From: dwheelerat_private
Date: Fri Jul 19 2002 - 22:09:25 PDT

  • Next message: Greg KH: "Re: [BK PATCH] LSM task control for 2.5.26"

    Well, my apologies.  My last post labelled "Updated stacker.c" posted
    the OLDER version of stacker.c, and NOT updated version I promised.  Ugh!
    Below really _is_ the updated stacker.c, with the changes
    I promised in the previous post.  Again, I hoping for feedback on
    the approach - even just reading the comments on the top and responding
    to them would be great.
    
    
    /*
     * "Stacker" LSM security module.
     * Load this module first as the primary LSM module,
     * and you can then load multiple LSM modules "under" it as "children".
     *
     * Copyright (C) 2002 David A. Wheeler <dwheelerat_private>
     *
     *	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.
     *
     * This module asks for permissions from ALL of the loaded child LSM modules,
     * and if any child module says "no, it's forbidden", then it returns the
     * message that the operation is forbidden.
     * The error code of the FIRST module that forbids the request is returned;
     * modules are asked in the order they were inserted (first added first asked).
     * The exception are the authoritative hooks (e.g., "capable") - in that
     * case, if ANY child module grants the capability, it's granted, else it's
     * not granted.  Stacker ALWAYS calls all of the modules for every request,
     * so that child LSM modules can reliability manipulate their internal state.
     *
     * When stacker first starts, it acts as though the "dummy" module
     * is also loaded as the last module. This effect (called pseudo_dummy)
     * can be turned off. When the "capability" module is loaded,
     * pseudo_dummy is automatically turned off.
     * Loading the "capabilities" module as the last module after any other
     * modules is a normal and expected use of the stacker module.
     * The pseudo_dummy value is also turned off if stacker itself is
     * loaded as a child module, so that stacker itself can be a child of
     * yet another master module if desired.
     *
     * WARNING! Not all LSM modules can be combined with all other modules;
     * it's up to the administrator who is doing the stacking to determine
     * if any specific stacking is appropriate.  For example, many kernel
     * structures have a (void *) field that can be used by security modules;
     * if more than one security module is stacked that use the same field for the
     * same kernel structure, then they MUST agree on the meaning of the
     * field or they'll violently conflict.  As a result, stacking is
     * more likely to be successful if you're combining several "small" LSM modules
     * that don't use any kernel structure security fields, optionally with
     * a "large" LSM module that uses one or more such fields.
     * Modules that are designed to work together (e.g., they store the
     * same information in a field) or are designed to heterogeneously stack 
     * (e.g., creating a linked list of different data) may also work.
     *
     * LSM module authors should write their modules so that they'll stack
     * more easily, if that's a possibility:
     * 1. To stack at all, a module needs to call
     * mod_reg_security() if register_security() fails (see capability.c for an
     * example how to do this), and in that case should set a "secondary" flag.
     * 2. The LSM module should NOT try to duplicate the nontrivial actions
     * of the "dummy" or "capability" module when the module is loaded as a stacked
     * module (e.g., its "secondary" flag is on), because this can limit the
     * amount of control an administrator has over a stacked system.
     * Instead, if "secondary" is on, the LSM module should do ONLY the checks
     * unique to the LSM module and let the stacking module
     * determine the defaults.   This particularly an issue for the hooks
     * which have nontrivial implementations in dummy.c or capability.c.
     * So, look carefully at the LSM module's implementation of the following
     * hooks: capable, netlink_send, netlink_recv, task_reparent_to_init, and
     * ip_decode_options (these are calls that have nontrivial implementations
     * in "dummy.c").  Also look carefully at these hooks:
     * ptrace, capget, capset_check, capset_set, bprm_set_security,
     * bprm_compute_creds, task_post_setuid, kmod_set_label, task_reparent_to_init,
     * ip_decode_options (these have nontrivial implementations in "capability.c").
     * 3. DOCUMENT CLEARLY if the module uses or does not use any
     * of the (void*) security fields in the kernel structures
     * (ideally, if you use them please document WHICH ones).  That way,
     * administrators can quickly detect certain kinds of conflicts.
     */
    
    /* WARNING!  THIS IS AN EARLY DRAFT.  IT IS _NOT_ INTENDED FOR USE YET;
       I'm only releasing it so that people can start reviewing the code
       (e.g., is the approach reasonable, what's been forgotten, etc.).
       Look especially for the text marked "TODO".
       Testing level: "The source loads into vim.  It probably doesn't compile.
         Run it only if you need to erase your hard drive.".
    */
    
    #include <linux/config.h>
    #include <linux/module.h>
    #include <linux/kernel.h>
    #include <linux/security.h>
    #include <linux/skbuff.h>
    #include <linux/netlink.h>
    
    /* Magic number (id) for stacker - computed using
     * echo "stacker" | md5sum | cut -c -8
     */
    #define STACKER_MAGIC 0xaf8d3836
    
    /* Flag to keep track of how we were registered */
    static int secondary;
    
    /* While pseudo_dummy is true, the stacker module will act
     * as though the "dummy" module is stacked underneath it and is
     * last in line.  Even when the intent is to eventually not use
     * the "dummy" module (e.g., to use the capability module)
     * this is still useful during the time that the modules are being loaded.
     * The theory of operation is that the stacker module will be loaded,
     * other LSM modules will then be loaded (underneath the stacker module),
     * and then if desired pseudo_dummy is turned off.
     * Loading the "capability" module automatically turns off pseudo_dummy. */
    /* TODO: should the automatic dummy be FIRST or LAST in the list
     * while modules are being loaded?  Or, are there different times
     * depending on the function call?  I started off making it "first",
     * but I now think that "last" is the right answer.
     * Need to re-examine all uses of pseudo_dummy, esp. to compare to
     * the "real" dummy module. */
    
    static int pseudo_dummy = 1;
    
    
    /* A "module entry" keeps track of one of the stacked modules */
    struct module_entry {
    	struct security_operations *next;
    	char *module_name;
    	struct security_operations *module_operations;
    };
    
    /* The set of LSM modules stacked by this "stacker" module
       is stored as a singly linked list of module_entries
       pointed to by stacked_modules. It's initially NULL. */
    static struct module_entry *stacked_modules;
    
    /* Maximum number of characters in a module name */
    #define MAX_MODULE_NAME_LEN 32
    
    
    /* Walk through the linked 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 one.  Note that this ALWAYS calls ALL modules, since
       some modules may change state when called.
       TODO: Possibly add a "short-circuit" option that stops when anything
       says "no"; however,  that only optimizes if a module reports an error,
       so it probably isn't worth it. */
    #define COMPUTE_ERROR_IF_ANY_ERROR(CALL) \
    	int final_result = 0; \
    	int result; \
    	struct module_entry *module_p; \
    	for (module_p = stacked_modules; module_p; module_p->next) { \
    		result = module_p->module_operations->CALL; \
    		if (result && !final_result) final_result = result; \
    	}
    
    #define RETURN_ERROR_IF_ANY_ERROR(CALL) \
            COMPUTE_ERROR_IF_ANY_ERROR(CALL); return final_result
    
    /* Walk through the linked list of modules in stacked_modules
       and ask each (in turn) for their results, then return the
       results.  Place the final result in final_result;
       if any module reports success (0), final_result==0, else it's nonzero.
       Note that this ALWAYS calls ALL modules, since
       some modules may change state when called.
       The value of stacked_modules is loaded into module_p, and then module_p
       is always used, to avoid some race conditions.
       TODO: Is there still a potential significant race problem due to
       compiler optimizations?
       This is used for authoritative calls, e.g., capable. */
    #define COMPUTE_SUCCESS_IF_ANY_SUCCESS(CALL) \
    	int final_result = -EPERM; \
    	int result; \
    	struct module_entry *module_p = stacked_modules; \
    	if (!module_p) return -EPERM; \
    	final_result = module_p->module_operations->CALL; \
    	if (!final_result) return 0; \
    	for (module_p = module_p->next; module_p; module_p->next) { \
    		result = module_p->module_operations->CALL; \
    		if (!result) final_result = 0; \
    	}
    
    
    /* Call all modules in stacked_modules' CALL routine */
    #define CALL_ALL(CALL) \
    	struct module_entry *module_p; \
    	for (module_p = stacked_modules; module_p; module_p->next) { \
    		module_p->module_operations->CALL; \
    	}
    
    
    /* TODO: Re-examine all uses of pseudo_dummy - are they reasonable?
     * TODO: Authoritative hooks need to be handled differently, e.g.,
     * "capable".  See the code below - is it right?
     * TODO: The alloc_security/free_security hooks are simply called down.
     * Is there anything better to do?
     * TODO: This version applies to patch-2.5.26-lsm1, thus, it doesn't
     * include a hook to control setting the system time (a recent
     * proposal for implementing *BSD Secure Levels); if that hook is added
     * to the LSM, that will need to be propogated here.
    */
    
    static int stacker_sethostname (char *hostname)
    {
    	RETURN_ERROR_IF_ANY_ERROR(sethostname(hostname));
    }
    
    static int stacker_setdomainname (char *domainname)
    {
    	RETURN_ERROR_IF_ANY_ERROR(setdomainname(hostname));
    }
    
    static int stacker_reboot (unsigned int cmd)
    {
    	RETURN_ERROR_IF_ANY_ERROR(reboot(cmd));
    }
    
    static int stacker_ioperm (unsigned long from, unsigned long num, int turn_on)
    {
    	RETURN_ERROR_IF_ANY_ERROR(ioperm(from, num, turn_on));
    }
    
    static int stacker_iopl (unsigned int old, unsigned int level)
    {
    	RETURN_ERROR_IF_ANY_ERROR(iopl(old, level));
    }
    
    static int stacker_ptrace (struct task_struct *parent, struct task_struct *child)
    {
    	RETURN_ERROR_IF_ANY_ERROR(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(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(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(target, effective, inheritable, permitted));
    }
    
    static int stacker_acct (struct file *file)
    {
    	RETURN_ERROR_IF_ANY_ERROR(acct(file));
    }
    
    static int stacker_capable (struct task_struct *tsk, int cap)
    {
    	/* This is an AUTHORITATIVE hook, so it needs to be
    	   handled differently. Instead of returning a failure
    	   if any module fails, we need to return success if
    	   any module succeeds. */
    
    	COMPUTE_SUCCESS_IF_ANY_SUCCESS(capable(tsk, cap));
    
    	if (pseudo_dummy)
    		/* TODO: check - can this infinitely recurse? */
    		if (cap_is_fs_cap (cap) ? tsk->fsuid == 0 : tsk->euid == 0)
    			/* capability granted */
    			final_result = 0;
    
    	return final_result;
    }
    
    
    static int stacker_sysctl (ctl_table * table, int op)
    {
    	RETURN_ERROR_IF_ANY_ERROR(sysctl(table, op));
    }
    
    static int stacker_sys_security (unsigned int id, unsigned int call,
    			       unsigned long *args)
    {
    	/* TODO: This has a serious problem - the caller can't always get
    	 * the return value from the correct stacked module, because
    	 * the "stacker" module has no way to know which LSM module
    	 * should be called when it's given an id.
    	 * Stacker could recompute an id from the name
    	 * if the id follows the hashing convention,
    	 * but now suddenly an MD5 implementation has to embedded
    	 * just to perform this simple action.  Stacker could call
    	 * EVERY module, but then which result should it return?
    	 * It can just "return the first error", or
    	 * "return anything that isn't -EPERM or -ENOSYS",
    	 * but this isn't really right, especially since
    	 * sys_security might return something OTHER than an error code.
    	 * Thus, it would be REALLY HELPFUL for stacking modules like
    	 * stacker if the security_ops structure or mod_reg_security
    	 * parameters also included the _id_ of the LSM module being inserted.
    	 */
    	/* TODO: Stacker should implement its own calls, e.g.:
    	   + forbid adding new modules
    	   + forbid removing existing modules
    	   + forbid removing yourself (stacker)
    	   + list loaded LSM modules by name (in their order)
    	   + turn off pseudo_dummy */
    	/* For the moment, we'll just presume that sys_security
    	 * returns an error code and return the first nonzero error code.
    	 * This isn't very good - I hope others will agree to add an
    	 * "id" value to security_ops or mod_reg_security's parameter list
    	 * to support stacking modules. */
    	if (id == STACKER_MAGIC) {
    		return -ENOSYS; /* Sorry, not yet implemented. */
    	} else {
    		/* This is bogus but it's the best I can do currently -
    		 * see the to-do text above. */
    		RETURN_ERROR_IF_ANY_ERROR(sys_security(id,call,args));
    	}
    }
    
    static int stacker_swapon (struct swap_info_struct *swap)
    {
    	RETURN_ERROR_IF_ANY_ERROR(swapon(swap));
    }
    
    static int stacker_swapoff (struct swap_info_struct *swap)
    {
    	RETURN_ERROR_IF_ANY_ERROR(swapoff(swap));
    }
    
    static int stacker_quotactl (int cmds, int type, int id, struct super_block *sb)
    {
    	RETURN_ERROR_IF_ANY_ERROR(quotactl(cmds,type,id,sb));
    }
    
    static int stacker_quota_on (struct file *f)
    {
    	RETURN_ERROR_IF_ANY_ERROR(quota_on(f));
    }
    
    static int stacker_syslog (int type)
    {
    	RETURN_ERROR_IF_ANY_ERROR(syslog(type));
    }
    
    static int stacker_netlink_send (struct sk_buff *skb)
    {
    	/* TODO: I'm not really sure how to handle this when
    	 * pseudo_dummy is true. Suggestions? */
    	if (pseudo_dummy) {
    		if (current->euid == 0)
    			cap_raise (NETLINK_CB (skb).eff_cap, CAP_NET_ADMIN);
    		else
    			NETLINK_CB (skb).eff_cap = 0;
    	}
    	COMPUTE_ERROR_IF_ANY_ERROR(send(skb));
    	return final_result;
    }
    
    static int stacker_netlink_recv (struct sk_buff *skb)
    {
    	COMPUTE_ERROR_IF_ANY_ERROR(netlink_recv(skb));
    	if (pseudo_dummy)
    		if (!cap_raised (NETLINK_CB (skb).eff_cap, CAP_NET_ADMIN) &&
    		    !final_result)
    			final_result = -EPERM;
    	return final_result;
    }
    
    static int stacker_bprm_alloc_security (struct linux_binprm *bprm)
    {
    	RETURN_ERROR_IF_ANY_ERROR(bprm_alloc_security(bprm));
    }
    
    static void stacker_bprm_free_security (struct linux_binprm *bprm)
    {
    	CALL_ALL(bprm_free_security(bprm));
    }
    
    static void stacker_bprm_compute_creds (struct linux_binprm *bprm)
    {
    	CALL_ALL(bprm_free_compute_creds(bprm));
    }
    
    static int stacker_bprm_set_security (struct linux_binprm *bprm)
    {
    	RETURN_ERROR_IF_ANY_ERROR(bprm_set_security(bprm));
    }
    
    static int stacker_bprm_check_security (struct linux_binprm *bprm)
    {
    	RETURN_ERROR_IF_ANY_ERROR(bprm_check_security(bprm));
    }
    
    static int stacker_sb_alloc_security (struct super_block *sb)
    {
    	RETURN_ERROR_IF_ANY_ERROR(sb_alloc_security(sb));
    }
    
    static void stacker_sb_free_security (struct super_block *sb)
    {
    	CALL_ALL(sb_free_security(sb));
    }
    
    static int stacker_sb_statfs (struct super_block *sb)
    {
    	RETURN_ERROR_IF_ANY_ERROR(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(mount(dev_name, nd, type, flags, data));
    }
    
    static int stacker_check_sb (struct vfsmount *mnt, struct nameidata *nd)
    {
    	RETURN_ERROR_IF_ANY_ERROR(check_sb(mnt, nd));
    }
    
    static int stacker_umount (struct vfsmount *mnt, int flags)
    {
    	RETURN_ERROR_IF_ANY_ERROR(umount(mnt, flags));
    }
    
    static void stacker_umount_close (struct vfsmount *mnt)
    {
    	CALL_ALL(umount_close(mnt));
    }
    
    static void stacker_umount_busy (struct vfsmount *mnt)
    {
    	CALL_ALL(umount_busy(mnt));
    }
    
    static void stacker_post_remount (struct vfsmount *mnt, unsigned long flags,
    				void *data)
    {
    	CALL_ALL(post_remount(mnt, flags, data));
    }
    
    
    static void stacker_post_mountroot (void)
    {
    	CALL_ALL(post_mountroot());
    }
    
    static void stacker_post_addmount (struct vfsmount *mnt, struct nameidata *nd)
    {
    	CALL_ALL(post_addmount(mnt, nd));
    }
    
    static int stacker_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd)
    {
    	RETURN_ERROR_IF_ANY_ERROR(pivotroot(old_nd, new_nd));
    }
    
    static void stacker_post_pivotroot (struct nameidata *old_nd, struct nameidata *new_nd)
    {
    	CALL_ALL(post_pivotroot(old_nd, new_nd));
    }
    
    static int stacker_inode_alloc_security (struct inode *inode)
    {
    	RETURN_ERROR_IF_ANY_ERROR(inode_alloc_security(inode));
    }
    
    static void stacker_inode_free_security (struct inode *inode)
    {
    	CALL_ALL(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, dentry, mask));
    }
    
    static void stacker_inode_post_create (struct inode *inode, struct dentry *dentry,
    				     int mask)
    {
    	CALL_ALL(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(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(old_dentry, inode, new_dentry));
    }
    
    static int stacker_inode_unlink (struct inode *inode, struct dentry *dentry)
    {
    	RETURN_ERROR_IF_ANY_ERROR(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, denstry, name));
    }
    
    static void stacker_inode_post_symlink (struct inode *inode,
    				      struct dentry *dentry, const char *name)
    {
    	CALL_ALL(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, dentry, mask));
    }
    
    static void stacker_inode_post_mkdir (struct inode *inode, struct dentry *dentry,
    				    int mask)
    {
    	CALL_ALL(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, 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, 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, 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(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(old_inode, old_dentry,
    				  new_inode, new_dentry));
    }
    
    static int stacker_inode_readlink (struct dentry *dentry)
    {
    	RETURN_ERROR_IF_ANY_ERROR(inode_readlink(dentry));
    }
    
    static int stacker_inode_follow_link (struct dentry *dentry,
    				    struct nameidata *nameidata)
    {
    	RETURN_ERROR_IF_ANY_ERROR(inode_follow_link(dentry, nameidata));
    }
    
    static int stacker_inode_permission (struct inode *inode, int mask)
    {
    	/* TODO: Think this one through!! */
    	RETURN_ERROR_IF_ANY_ERROR(inode_permission(inode, mask));
    }
    
    static int stacker_inode_permission_lite (struct inode *inode, int mask)
    {
    	/* TODO: Think this one through!! */
    	RETURN_ERROR_IF_ANY_ERROR(inode_permission_lite(inode, mask));
    }
    
    static int stacker_inode_setattr (struct dentry *dentry, struct iattr *iattr)
    {
    	RETURN_ERROR_IF_ANY_ERROR(inode_setattr(dentry, iattr));
    }
    
    static int stacker_inode_getattr (struct vfsmount *mnt, struct dentry *dentry)
    {
    	RETURN_ERROR_IF_ANY_ERROR(inode_getattr(mnt,dentry);
    }
    
    static void stacker_post_lookup (struct inode *ino, struct dentry *d)
    {
    	CALL_ALL(post_lookup(ino,d));
    }
    
    static void stacker_delete (struct inode *ino)
    {
    	CALL_ALL(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(dentry,name,value,size,flags));
    }
    
    static int stacker_inode_getxattr (struct dentry *dentry, char *name)
    {
    	RETURN_ERROR_IF_ANY_ERROR(inode_getxattr(dentry,name));
    }
    
    static int stacker_inode_listxattr (struct dentry *dentry)
    {
    	RETURN_ERROR_IF_ANY_ERROR(inode_listxattr(dentry));
    }
    
    static int stacker_inode_removexattr (struct dentry *dentry, char *name)
    {
    	RETURN_ERROR_IF_ANY_ERROR(inode_removexattr(dentry,name));
    }
    
    static int stacker_file_permission (struct file *file, int mask)
    {
    	/* TODO: Re-examine */
    	RETURN_ERROR_IF_ANY_ERROR(file_permission(file,mask));
    }
    
    static int stacker_file_alloc_security (struct file *file)
    {
    	RETURN_ERROR_IF_ANY_ERROR(file_alloc_security(file));
    }
    
    static void stacker_file_free_security (struct file *file)
    {
    	CALL_ALL(file_free_security(file));
    }
    
    static int stacker_file_llseek (struct file *file)
    {
    	RETURN_ERROR_IF_ANY_ERROR(file_llseek(file));
    }
    
    static int stacker_file_ioctl (struct file *file, unsigned int command,
    			     unsigned long arg)
    {
    	RETURN_ERROR_IF_ANY_ERROR(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, prot, flags));
    }
    
    static int stacker_file_mprotect (struct vm_area_struct *vma, unsigned long prot)
    {
    	RETURN_ERROR_IF_ANY_ERROR(file_mprotect(vma,prot));
    }
    
    static int stacker_file_lock (struct file *file, unsigned int cmd, int blocking)
    {
    	RETURN_ERROR_IF_ANY_ERROR(file_lock(file,cmd,blocking));
    }
    
    static int stacker_file_fcntl (struct file *file, unsigned int cmd,
    			     unsigned long arg)
    {
    	RETURN_ERROR_IF_ANY_ERROR(file_fcntl(file,cmd,arg));
    }
    
    /* TODO: Keep going... */
    
    static int stacker_file_set_fowner (struct file *file)
    {
    	RETURN_ERROR_IF_ANY_ERROR(file_set_fowner(file));
    }
    
    static int stacker_file_send_sigiotask (struct task_struct *tsk,
    				      struct fown_struct *fown, int fd,
    				      int reason)
    {
    	RETURN_ERROR_IF_ANY_ERROR(file_send_sigiotask(tsk,fown,fd,reason));
    }
    
    static int stacker_file_receive (struct file *file)
    {
    	RETURN_ERROR_IF_ANY_ERROR(file_receive(file));
    }
    
    static int stacker_task_create (unsigned long clone_flags)
    {
    	RETURN_ERROR_IF_ANY_ERROR(task_create(clone_flags));
    }
    
    static int stacker_task_alloc_security (struct task_struct *p)
    {
    	RETURN_ERROR_IF_ANY_ERROR(task_alloc_security(p));
    }
    
    static void stacker_task_free_security (struct task_struct *p)
    {
    	CALL_ALL(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(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(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(id0,id1,id2,flags));
    }
    
    static int stacker_task_setpgid (struct task_struct *p, pid_t pgid)
    {
    	RETURN_ERROR_IF_ANY_ERROR(task_setpgid(p,pgid));
    }
    
    static int stacker_task_getpgid (struct task_struct *p)
    {
    	RETURN_ERROR_IF_ANY_ERROR(task_getpgid(p));
    }
    
    static int stacker_task_getsid (struct task_struct *p)
    {
    	RETURN_ERROR_IF_ANY_ERROR(task_getsid(p));
    }
    
    static int stacker_task_setgroups (int gidsetsize, gid_t * grouplist)
    {
    	RETURN_ERROR_IF_ANY_ERROR(task_setgroups(gidsetsize,grouplist));
    }
    
    static int stacker_task_setnice (struct task_struct *p, int nice)
    {
    	RETURN_ERROR_IF_ANY_ERROR(task_setnice(p,nice));
    }
    
    static int stacker_task_setrlimit (unsigned int resource, struct rlimit *new_rlim)
    {
    	RETURN_ERROR_IF_ANY_ERROR(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(p,policy,lp));
    }
    
    static int stacker_task_getscheduler (struct task_struct *p)
    {
    	RETURN_ERROR_IF_ANY_ERROR(task_getscheduler(p));
    }
    
    static int stacker_task_wait (struct task_struct *p)
    {
    	RETURN_ERROR_IF_ANY_ERROR(task_wait(p));
    }
    
    static int stacker_task_kill (struct task_struct *p, struct siginfo *info,
    			    int sig)
    {
    	RETURN_ERROR_IF_ANY_ERROR(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(option,arg2,arg3,arg4,arg5));
    }
    
    static void stacker_task_kmod_set_label (void)
    {
    	CALL_ALL(task_kmod_set_label());
    }
    
    static void stacker_task_reparent_to_init (struct task_struct *p)
    {
    	CALL_ALL(task_reparent_to_init(p));
    	/* TODO: this is from dummy, but is it a good idea??
    	 * I do it after everything else, so that the other modules
    	 * don't lose this information, but this also means they can't
    	 * override it. */
    	if (pseudo_dummy) {
    		p->euid = p->fsuid = 0;
    	}
    }
    
    static void stacker_ip_fragment (struct sk_buff *newskb,
    			       const struct sk_buff *oldskb)
    {
    	CALL_ALL(ip_fragment(newskb,oldskb));
    }
    
    static int stacker_ip_defragment (struct sk_buff *skb)
    {
    	RETURN_ERROR_IF_ANY_ERROR(ip_defragment(skb));
    }
    
    static void stacker_ip_decapsulate (struct sk_buff *skb)
    {
    	CALL_ALL(ip_decapsulate(skb));
    }
    
    static void stacker_ip_encapsulate (struct sk_buff *skb)
    {
    	CALL_ALL(ip_encapsulate(skb));
    }
    
    static int stacker_ip_decode_options (struct sk_buff *skb, const char *optptr,
    				    unsigned char **pp_ptr)
    {
    	COMPUTE_ERROR_IF_ANY_ERROR(ip_decode_options(skb,optptr,pp_ptr));
    	if (pseudo_dummy) {
    		if (!skb && !capable (CAP_NET_RAW)) {
    			(const unsigned char *) *pp_ptr = optptr;
    			final_result = -EPERM;
    		}
    	}
    	return final_result;
    }
    
    static void stacker_netdev_unregister (struct net_device *dev)
    {
    	CALL_ALL(netdev_unregister(dev));
    }
    
    static int stacker_socket_create (int family, int type, int protocol)
    {
    	RETURN_ERROR_IF_ANY_ERROR(socket_create(family,type,protocol));
    }
    
    static void stacker_socket_post_create (struct socket *sock, int family, int type,
    				      int protocol)
    {
    	CALL_ALL(socket_post_crete(sock,family,type,protocol));
    }
    
    static int stacker_socket_bind (struct socket *sock, struct sockaddr *address,
    			      int addrlen)
    {
    	RETURN_ERROR_IF_ANY_ERROR(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(sock,address,addrlen));
    }
    
    static int stacker_socket_listen (struct socket *sock, int backlog)
    {
    	RETURN_ERROR_IF_ANY_ERROR(socket_listen(sock,backlog));
    }
    
    static int stacker_socket_accept (struct socket *sock, struct socket *newsock)
    {
    	RETURN_ERROR_IF_ANY_ERROR(socket_accept(sock,newsock));
    }
    
    static void stacker_socket_post_accept (struct socket *sock, 
    				      struct socket *newsock)
    {
    	CALL_ALL(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(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(sock,msg,size,flags));
    }
    
    static int stacker_socket_getsockname (struct socket *sock)
    {
    	RETURN_ERROR_IF_ANY_ERROR(socket_getsockname(sock));
    }
    
    static int stacker_socket_getpeername (struct socket *sock)
    {
    	RETURN_ERROR_IF_ANY_ERROR(socket_getpeername(sock));
    }
    
    static int stacker_socket_setsockopt (struct socket *sock, int level, int optname)
    {
    	RETURN_ERROR_IF_ANY_ERROR(socket_setsockopt(sock,level,optname));
    }
    
    static int stacker_socket_getsockopt (struct socket *sock, int level, int optname)
    {
    	RETURN_ERROR_IF_ANY_ERROR(socket_getsockopt(sock,level,optname));
    }
    
    static int stacker_socket_shutdown (struct socket *sock, int how)
    {
    	RETURN_ERROR_IF_ANY_ERROR(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(sk,skb));
    }
    
    static int stacker_socket_unix_stream_connect (struct socket *sock,
    					     struct socket *other)
    {
    	RETURN_ERROR_IF_ANY_ERROR(socket_unix_stream_connect(sock,other));
    }
    
    static int stacker_socket_unix_may_send (struct socket *sock,
    				       struct socket *other)
    {
    	RETURN_ERROR_IF_ANY_ERROR(socket_unix_may_send(sock,other));
    }
    
    static int stacker_module_create (const char *name_user, size_t size)
    {
    	RETURN_ERROR_IF_ANY_ERROR(module_create(name_user,size));
    }
    
    static int stacker_module_initialize (struct module *mod_user)
    {
    	RETURN_ERROR_IF_ANY_ERROR(module_initialize(mod_user));
    }
    
    static int stacker_module_delete (const struct module *mod)
    {
    	RETURN_ERROR_IF_ANY_ERROR(module_delete(mod));
    
    }
    
    static int stacker_ipc_permission (struct kern_ipc_perm *ipcp, short flag)
    {
    	RETURN_ERROR_IF_ANY_ERROR(ipc_permission(ipcp,flag));
    }
    
    static int stacker_ipc_getinfo (int id, int cmd)
    {
    	RETURN_ERROR_IF_ANY_ERROR(ipc_getinfo(id,cmd));
    }
    
    static int stacker_msg_msg_alloc_security (struct msg_msg *msg)
    {
    	RETURN_ERROR_IF_ANY_ERROR(msg_msg_alloc_security(msg));
    }
    
    static void stacker_msg_msg_free_security (struct msg_msg *msg)
    {
    	CALL_ALL(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(msq));
    }
    
    static void stacker_msg_queue_free_security (struct msg_queue *msq)
    {
    	CALL_ALL(msg_queue_free_security(msq));
    }
    
    static int stacker_msg_queue_associate (struct msg_queue *msq, int msqid,
    				      int msqflg)
    {
    	RETURN_ERROR_IF_ANY_ERROR(msg_queue_associate(msq,msqid,msqflg));
    }
    
    static int stacker_msg_queue_msgctl (struct msg_queue *msq, int msqid, int cmd)
    {
    	RETURN_ERROR_IF_ANY_ERROR(msg_queue_msgctl(msq,msqid,cmd));
    }
    
    static int stacker_msg_queue_msgsnd (struct msg_queue *msq, struct msg_msg *msg,
    				   int msqid, int msgflg)
    {
    	RETURN_ERROR_IF_ANY_ERROR(msg_queue_msgsnd(msq,msg,msqid,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(msq,msg,target,type,mode));
    }
    
    static int stacker_shm_alloc_security (struct shmid_kernel *shp)
    {
    	RETURN_ERROR_IF_ANY_ERROR(shm_alloc_security(shp));
    }
    
    static void stacker_shm_free_security (struct shmid_kernel *shp)
    {
    	CALL_ALL(shm_free_security(shp));
    }
    
    static int stacker_shm_associate (struct shmid_kernel *shp, int shmid, int shmflg)
    {
    	RETURN_ERROR_IF_ANY_ERROR(shm_associate(shp,shmid,shmflg));
    }
    
    static int stacker_shm_shmctl (struct shmid_kernel *shp, int shmid, int cmd)
    {
    	RETURN_ERROR_IF_ANY_ERROR(shm_shmctl(shp,shmid,cmd));
    }
    
    static int stacker_shm_shmat (struct shmid_kernel *shp, int shmid, char *shmaddr,
    			    int shmflg)
    {
    	RETURN_ERROR_IF_ANY_ERROR(shm_shmat(shp,shmid,shmaddr,shmflg));
    }
    
    static int stacker_sem_alloc_security (struct sem_array *sma)
    {
    	RETURN_ERROR_IF_ANY_ERROR(sem_alloc_security(sma));
    }
    
    static void stacker_sem_free_security (struct sem_array *sma)
    {
    	CALL_ALL(sem_free_security(sma));
    }
    
    static int stacker_sem_associate (struct sem_array *sma, int semid, int semflg)
    {
    	RETURN_ERROR_IF_ANY_ERROR(sem_associate(sma,semid,semflg));
    }
    
    static int stacker_sem_semctl (struct sem_array *sma, int semid, int cmd)
    {
    	RETURN_ERROR_IF_ANY_ERROR(sem_semctl(sma,semid,cmd));
    }
    
    static int stacker_sem_semop (struct sem_array *sma, int semid,
    			    struct sembuf *sops, unsigned nsops, int alter)
    {
    	RETURN_ERROR_IF_ANY_ERROR(sem_semop(sma,semid,sops,nsops,alter));
    }
    
    static int stacker_skb_alloc_security (struct sk_buff *skb)
    {
    	RETURN_ERROR_IF_ANY_ERROR(skb_alloc_security(skb));
    }
    
    static int stacker_skb_clone (struct sk_buff *newskb,
    			     const struct sk_buff *oldskb)
    {
    	RETURN_ERROR_IF_ANY_ERROR(skb_clone(newskb,oldskb));
    }
    
    static void stacker_skb_copy (struct sk_buff *newskb,
    			    const struct sk_buff *oldskb)
    {
    	CALL_ALL(skb_copy(newskb,oldskb));
    
    }
    
    static void stacker_skb_set_owner_w (struct sk_buff *skb, struct sock *sk)
    {
    	CALL_ALL(skb_set_owner_w(skb,sk));
    
    }
    
    static void stacker_skb_recv_datagram (struct sk_buff *skb, struct sock *sk,
    				     unsigned flags)
    {
    	CALL_ALL(skb_recv_datagram(skb,sk,flags));
    }
    
    static void stacker_skb_free_security (struct sk_buff *skb)
    {
    	CALL_ALL(skb_free_security(skb));
    }
    
    
    
    static int stacker_register (const char *name, struct security_operations *ops)
    {
    	/* This function is the primary reason for the stacker module.
    	   Add the name security_operations provided to us at the end
    	   of stacked_modules (the linked list of stacked modules).  */
    
    	char *new_module_name;
    	struct security_operations *new_module_operations;
    	struct module_entry *new_module_entry;
    	struct module_entry *p; /* Used to walk stacked_modules */
    	int should_disable_pseudo_dummy = 0;
    
    	/* TODO: What should I check on re: security?  Should I check
    	   for euid == 0? Has that already been checked? */
    	/* Note that we do NOT call the stacker_register entries of
    	   any currently installed modules, since we aren't installing
    	   a child under them.  A future version should support a new
    	   security operation to forbid adding new modules.  */
    
    	/* TODO: is GFP_KERNEL appropriate here? */
    	/* TODO: need strnlen */
    	new_module_name = kmalloc(strnlen(name, MAX_MODULE_NAME_LEN)+1, GFP_KERNEL);
    	new_module_operations = kmalloc(sizeof(struct security_operations), GFP_KERNEL);
    	new_module_entry = kmalloc(sizeof(struct module_entry), GFP_KERNEL);
    	if (!new_module_name || !new_module_operations || !new_module_entry) {
    		printk (KERN_INFO
    			"Failure registering module - out of memory\n");
    		return -EINVAL;
    	}
    
    	new_module_name = strncpy(new_module_name, name, MAX_MODULE_NAME_LEN);
    	new_module_name[MAX_MODULE_NAME_LEN-1] = '\0';
    	*new_module_operations = *ops;
    	new_module_entry->module_name = new_module_name;
    	new_module_entry->module_operations = new_module_operations;
    	new_module_entry->next = NULL;
    
    	if (!strcmp(new_module_name, "capability")) {
    		should_disable_pseudo_dummy = 1;
    	}
    
    	/* Finally, add it.  This must be the very last step, since
    	   once this code is executed the module will IMMEDIATELY go live. */
    	if (!stacked_modules) {
    		stacked_modules = new_module_entry;
    	} else {
    		/* Find last module in the list of stacked_modules */
    		for (p = stacked_modules; p->next; p = p->next);
    		p->next = new_module_entry;
    	}
    	/* TODO: there's a small race condition here - when adding
    	 * the "capability" module, there's a brief moment where
    	 * pseudo_dummy is on _AND_ the capability module is being used.
    	 * Is that a problem?  If it is, we'll need to set up some locks.
    	 */
    	if (should_disable_pseudo_dummy) pseudo_dummy = 0;
    	return 0;
    }
    
    static int stacker_unregister (const char *name, struct security_operations *ops)
    {
    	/* TODO: Eventually this should remove the corresponding entry
    	   from the stacked_modules list, but for simplicity that
    	   functionality hasn't been implemented yet.
    	   If this IS added: here are some key notes:
    	   - DON'T kfree() the corresponding data until ALL threads
    	     have passed it.  The simple solution may be to simply
    	     leak a little memory in that case.
    	   - Add a security operation that "locks down" registering and
    	     unregistering and doesn't permit "unlocking".
    	*/
    	return -EINVAL;
    }
    
    struct security_operations stacker_ops = {
    	sethostname:			stacker_sethostname,
    	setdomainname:			stacker_setdomainname,
    	reboot:				stacker_reboot,
    	ioperm:				stacker_ioperm,
    	iopl:				stacker_iopl,
    	ptrace:				stacker_ptrace,
    	capget:				stacker_capget,
    	capset_check:			stacker_capset_check,
    	capset_set:			stacker_capset_set,
    	acct:				stacker_acct,
    	capable:			stacker_capable,
    	sysctl:				stacker_sysctl,
    	sys_security:			stacker_sys_security,
    	swapon:				stacker_swapon,
    	swapoff:			stacker_swapoff,
    	quotactl:			stacker_quotactl,
    	quota_on:			stacker_quota_on,
    	syslog:				stacker_syslog,
    	
    	netlink_send:			stacker_netlink_send,
    	netlink_recv:			stacker_netlink_recv,
    	
    	unix_stream_connect:		stacker_socket_unix_stream_connect,
    	unix_may_send:			stacker_socket_unix_may_send,
    	
    	bprm_alloc_security:		stacker_bprm_alloc_security,
    	bprm_free_security:		stacker_bprm_free_security,
    	bprm_compute_creds:		stacker_bprm_compute_creds,
    	bprm_set_security:		stacker_bprm_set_security,
    	bprm_check_security:		stacker_bprm_check_security,
    
    	sb_alloc_security:		stacker_sb_alloc_security,
    	sb_free_security:		stacker_sb_free_security,
    	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_permission_lite:		stacker_inode_permission_lite,
    	inode_setattr:			stacker_inode_setattr,
    	inode_getattr:			stacker_inode_getattr,
    	inode_post_lookup:		stacker_post_lookup,
    	inode_delete:			stacker_delete,
    	inode_setxattr:			stacker_inode_setxattr,
    	inode_getxattr:			stacker_inode_getxattr,
    	inode_listxattr:		stacker_inode_listxattr,
    	inode_removexattr:		stacker_inode_removexattr,
    
    	file_permission:		stacker_file_permission,
    	file_alloc_security:		stacker_file_alloc_security,
    	file_free_security:		stacker_file_free_security,
    	file_llseek:			stacker_file_llseek,
    	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_wait:			stacker_task_wait,
    	task_kill:			stacker_task_kill,
    	task_prctl:			stacker_task_prctl,
    	task_kmod_set_label:		stacker_task_kmod_set_label,
    	task_reparent_to_init:		stacker_task_reparent_to_init,
    	
    	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,
    	
    	skb_alloc_security:		stacker_skb_alloc_security,
    	skb_clone:			stacker_skb_clone,
    	skb_copy:			stacker_skb_copy,
    	skb_set_owner_w:		stacker_skb_set_owner_w,
    	skb_recv_datagram:		stacker_skb_recv_datagram,
    	skb_free_security:		stacker_skb_free_security,
    	
    	ip_fragment:			stacker_ip_fragment,
    	ip_defragment:			stacker_ip_defragment,
    	ip_encapsulate:			stacker_ip_encapsulate,
    	ip_decapsulate:			stacker_ip_decapsulate,
    	ip_decode_options:		stacker_ip_decode_options,
    	
    	ipc_permission:			stacker_ipc_permission,
    	ipc_getinfo:			stacker_ipc_getinfo,
    	
    	netdev_unregister:		stacker_netdev_unregister,
    	
    	module_create:			stacker_module_create,
    	module_initialize:		stacker_module_initialize,
    	module_delete:			stacker_module_delete,
    	
    	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,
    	
    	register_security:		stacker_register,
    	unregister_security:		stacker_unregister,
    };
    
    
    #if defined(CONFIG_SECURITY_stacker_MODULE)
    # define MYNAME THIS_MODULE->name
    #else
    # define MYNAME "stacker"
    #endif
    
    
    static int __init stacker_init (void)
    {
    	/* register ourselves with the security framework */
    	if (register_security (&stacker_ops)) {
    		printk (KERN_INFO 
    			"Failure registering stacker module with the kernel\n");
    		/* try registering with primary module */
    		/* Note that this module allows itself to be stacked, but
    		   doesn't yet have a way to add LSM modules under it
    		   when that happens.  Still, it might be stacked under
    		   ANOTHER module that DOES, and supporting levels of
    		   of stacking is more flexible. */
    		if (mod_reg_security (MY_NAME, &stacker_ops)) {
    			printk (KERN_INFO "Failure registering stacker module "
    				"with primary security module.\n");
    			return -EINVAL;
    		}
    		secondary = 1;
    		/* This is special to the stacker module - if
    		 * we're a secondary, do NOT simulate the dummy module.
    		 * This allows the "stacker" module ITSELF to be stacked
    		 * under some other primary module, and still be a
    		 * "good citizen" by not simulating the dummy module itself.
    		 * Of course, anybody who needs multiple levels of stacking
    		 * has a security policy I wouldn't want to analyze. */
    		pseudo_dummy = 0;
    	}
    	printk(KERN_INFO "stacker LSM initialized\n");
    	return 0;
    }
    
    static void __exit stacker_exit (void)
    {
    	/* remove ourselves from the security framework */
    	if (secondary) {
    		if (mod_unreg_security (MY_NAME, &stacker_ops))
    			printk (KERN_INFO "Failure unregistering stacker module "
    				"with primary module.\n");
    		return;
    	}
     
    	if (unregister_security (&stacker_ops)) {
    		printk (KERN_INFO
    			"Failure unregistering stacker module with the kernel\n");
    	}
    }
    
    /*
     TODO: Double-check all the functions above.  Are the right ones called?
     Are the parameters correct?
    */
    
    module_init (stacker_init);
    module_exit (stacker_exit);
    
    MODULE_DESCRIPTION("LSM Stacker for installing multiple LSM modules simultaneously");
    MODULE_AUTHOR("David A. Wheeler");
    MODULE_LICENSE("GPL");
    
    _______________________________________________
    linux-security-module mailing list
    linux-security-moduleat_private
    http://mail.wirex.com/mailman/listinfo/linux-security-module
    



    This archive was generated by hypermail 2b30 : Fri Jul 19 2002 - 22:17:35 PDT