Some New Hooks

From: Chris Vance (cvanceat_private)
Date: Tue Jun 05 2001 - 08:14:58 PDT

  • Next message: jmjonesat_private: "Re: permissive vs. restrictive issue and solutions..."

    By way of introduction, I am at NAI Labs working on SELinux. 
    
    Attached is a patch against the current LSM patched 2.4.5 kernel,
    dated May 30, 2001 (selinux-lsm-patch). I have also attached the
    SELinux implementation for these new hooks (hooks.c), to help explain
    why they are necessary.
    
    I realize that we have not reached a consensus on what a consistent
    hook interface should look like, but in the meantime I would like to
    continue moving foward by identifying locations where hooks are
    necessary.
    
    I have added hooks in the following locations:
    
    fcntl/fcntl64 (sys_fcntl/sys_fcntl64): Added hooks to authorize these
    	operations.  Additionally, a security field was added to the
    	fown_struct so that the attributes of the owning process could
    	be maintained for later use in send_sigio_to_task.
    
    fcntl (send_sigio_to_task): Added hook to verify signal permissions.
    
    wait (sys_wait4): Added hook to verify that the parent is authorized
    	to receive the exit status of the child.
    
    mmap (do_mmap_pgoff): Added hook to check read/write/execute
    	permission for the request.
    
    mprotect (sys_mprotect): Added a hook to verify read/write/execute status for
    	requested change.
    
    
    ---------------------
    Chris Vance, NAI Labs
    cvanceat_private
    
    
    Index: fs/fcntl.c
    ===================================================================
    RCS file: /cvs/lsm/lsm/fs/fcntl.c,v
    retrieving revision 1.1.1.2
    retrieving revision 1.2
    diff -u -r1.1.1.2 -r1.2
    --- fs/fcntl.c	2001/05/29 17:00:48	1.1.1.2
    +++ fs/fcntl.c	2001/06/04 17:19:28	1.2
    @@ -10,6 +10,7 @@
     #include <linux/dnotify.h>
     #include <linux/smp_lock.h>
     #include <linux/slab.h>
    +#include <linux/security.h>
     
     #include <asm/poll.h>
     #include <asm/siginfo.h>
    @@ -278,6 +279,9 @@
     			err = 0;
     			if (S_ISSOCK (filp->f_dentry->d_inode->i_mode))
     				err = sock_fcntl (filp, F_SETOWN, arg);
    +
    +			if (!err)
    +				err = security_ops->fown_ops->alloc_security(&filp->f_owner);
     			unlock_kernel();
     			break;
     		case F_GETSIG:
    @@ -320,6 +324,12 @@
     	if (!filp)
     		goto out;
     
    +	err = security_ops->file_ops->fcntl(filp, cmd, arg);
    +	if (err) {
    +		fput(filp);
    +		return err;
    +	}
    +
     	err = do_fcntl(fd, cmd, arg, filp);
     
      	fput(filp);
    @@ -338,6 +348,13 @@
     	if (!filp)
     		goto out;
     
    +	err = security_ops->file_ops->fcntl64(filp, cmd, arg);
    +	if (err) {
    +		fput(filp);
    +		return err;
    +	}
    +	err = -EBADF;
    +	
     	switch (cmd) {
     		case F_GETLK64:
     			err = fcntl_getlk64(fd, (struct flock64 *) arg);
    @@ -378,6 +395,10 @@
     	    (fown->euid ^ p->suid) && (fown->euid ^ p->uid) &&
     	    (fown->uid ^ p->suid) && (fown->uid ^ p->uid))
     		return;
    +
    +	if (security_ops->fown_ops->send_sigiotask(p, fown, fd, reason))
    +		return;
    +
     	switch (fown->signum) {
     		siginfo_t si;
     		default:
    Index: include/linux/fs.h
    ===================================================================
    RCS file: /cvs/lsm/lsm/include/linux/fs.h,v
    retrieving revision 1.4
    retrieving revision 1.5
    diff -u -r1.4 -r1.5
    --- include/linux/fs.h	2001/05/29 17:29:14	1.4
    +++ include/linux/fs.h	2001/06/04 17:17:42	1.5
    @@ -486,6 +486,7 @@
     	int pid;		/* pid or -pgrp where SIGIO should be sent */
     	uid_t uid, euid;	/* uid/euid of process setting the owner */
     	int signum;		/* posix.1b rt signal to be delivered on IO */
    +	void *security;
     };
     
     struct file {
    Index: include/linux/security.h
    ===================================================================
    RCS file: /cvs/lsm/lsm/include/linux/security.h,v
    retrieving revision 1.6
    retrieving revision 1.9
    diff -u -r1.6 -r1.9
    --- include/linux/security.h	2001/05/29 17:29:14	1.6
    +++ include/linux/security.h	2001/06/05 13:43:46	1.9
    @@ -80,12 +80,21 @@
     	int (* read)			(struct file *);
     	int (* write)			(struct file *);
     	int (* ioctl)			(struct file *);	// need more than file*
    -	int (* mmap)			(struct file *);
    +	int (* mmap)			(struct file *, unsigned long, unsigned long);
    +	int (* mprotect)		(struct vm_area_struct *, unsigned long);
     	int (* lock)			(struct file *);
     	int (* readv)			(struct file *);
     	int (* writev)			(struct file *);
    +	int (* fcntl)			(struct file *, unsigned int, unsigned long);
    +	int (* fcntl64)			(struct file *, unsigned int, unsigned long);
     };
     
    +struct fown_security_ops {
    +	int (* alloc_security)		(struct fown_struct *);
    +	void (* free_security)		(struct fown_struct *);
    +	int (* send_sigiotask)		(struct task_struct *, struct fown_struct *, int, int);
    +};
    +
     struct task_security_ops {
     	int (* create)			(void);
     	int (* alloc_security)		(struct task_struct *p);	// create per process security stuff
    @@ -97,6 +106,7 @@
     	int (* setrlimit)		(unsigned int resource);	// CAP_SYS_RESOURCE
     	int (* setscheduler)		(struct task_struct *p, int policy); // CAP_SYS_NICE
     	int (* kill)			(struct task_struct *p, struct siginfo *info, int sig);	// CAP_KILL
    +	int (* wait)			(struct task_struct *p);
     	
     	/* set and (in case of exec failure) unset security label */
     	int (* set_label)		(char *filename);
    @@ -157,6 +167,7 @@
     	struct super_block_security_ops	* sb_ops;
     	struct inode_security_ops	* inode_ops;
     	struct file_security_ops	* file_ops;
    +	struct fown_security_ops	* fown_ops;
     	struct task_security_ops	* task_ops;
     	struct socket_security_ops	* socket_ops;
     	struct module_security_ops 	* module_ops;
    Index: kernel/capability_plug.c
    ===================================================================
    RCS file: /cvs/lsm/lsm/kernel/capability_plug.c,v
    retrieving revision 1.5
    retrieving revision 1.8
    diff -u -r1.5 -r1.8
    --- kernel/capability_plug.c	2001/05/29 17:29:14	1.5
    +++ kernel/capability_plug.c	2001/06/05 14:06:38	1.8
    @@ -376,10 +376,14 @@
     {
     	return 0;
     }
    -static int cap_file_mmap(struct file *file)
    +static int cap_file_mmap(struct file *file, unsigned long prot, unsigned long flags)
     {
     	return 0;
     }
    +static int cap_file_mprotect(struct vm_area_struct *vma, unsigned long prot)
    +{
    +	return 0;
    +}
     static int cap_file_lock(struct file *file)
     {
     	return 0;
    @@ -393,6 +397,36 @@
     	return 0;
     }
     
    +static int cap_file_fcntl(struct file *file, unsigned int cmd,
    +			  unsigned long arg)
    +{
    +	return 0;
    +}
    +
    +static int cap_file_fcntl64(struct file *file, unsigned int cmd, 
    +			    unsigned long arg)
    +{
    +	return 0;
    +}
    +
    +/* fown security operations */
    +static int cap_fown_alloc_security(struct fown_struct *fown)
    +{
    +	return 0;
    +}
    +
    +static void cap_fown_free_security(struct fown_struct *fown)
    +{
    +	return;
    +}
    +
    +static int cap_fown_send_sigiotask(struct task_struct *tsk, 
    +				   struct fown_struct *fown, int fd, 
    +				   int reason)
    +{
    +	return 0;
    +}
    +
     /* task security operations */
     static int cap_task_create(void)
     {
    @@ -444,6 +478,10 @@
     {
     	return is_capable(CAP_SYS_NICE) ? 0 : -EPERM;
     }
    +static int cap_task_wait(struct task_struct *p)
    +{
    +	return 0;
    +}
     static int cap_task_kill(struct task_struct *p, struct siginfo *info, int sig)
     {
     	return is_capable(CAP_KILL) ? 0 : -EPERM;
    @@ -568,9 +606,18 @@
     	write:		cap_file_write,
     	ioctl:		cap_file_ioctl,
     	mmap:		cap_file_mmap,
    +	mprotect:	cap_file_mprotect,
     	lock:		cap_file_lock,
     	readv:		cap_file_readv,
     	writev:		cap_file_writev,
    +	fcntl:		cap_file_fcntl,
    +	fcntl64:	cap_file_fcntl64,
    +};
    +
    +static struct fown_security_ops cap_fown_ops = {
    +	alloc_security:	cap_fown_alloc_security,
    +	free_security:	cap_fown_free_security,
    +	send_sigiotask:	cap_fown_send_sigiotask,
     };
     
     static struct task_security_ops	cap_task_ops = {
    @@ -583,6 +630,7 @@
     	setnice:	cap_task_setnice,
     	setrlimit:	cap_task_setrlimit,
     	setscheduler:	cap_task_setscheduler,
    +	wait:		cap_task_wait,
     	kill:		cap_task_kill,
     	set_label:	cap_task_set_label,
     	reset_label:	cap_task_reset_label,
    @@ -636,6 +684,7 @@
     	sb_ops:			&cap_sb_ops,
     	inode_ops:		&cap_inode_ops,
     	file_ops:		&cap_file_ops,
    +	fown_ops:		&cap_fown_ops,
     	task_ops:		&cap_task_ops,
     	socket_ops:		&cap_socket_ops,
     	module_ops:		&cap_module_ops,
    Index: kernel/exit.c
    ===================================================================
    RCS file: /cvs/lsm/lsm/kernel/exit.c,v
    retrieving revision 1.3
    retrieving revision 1.4
    diff -u -r1.3 -r1.4
    --- kernel/exit.c	2001/05/29 17:29:14	1.3
    +++ kernel/exit.c	2001/06/04 17:20:04	1.4
    @@ -524,6 +524,10 @@
     			if (((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0))
     			    && !(options & __WALL))
     				continue;
    +
    +			if (security_ops->task_ops->wait(p))
    +				continue;
    +
     			flag = 1;
     			switch (p->state) {
     			case TASK_STOPPED:
    Index: kernel/security.c
    ===================================================================
    RCS file: /cvs/lsm/lsm/kernel/security.c,v
    retrieving revision 1.5
    retrieving revision 1.8
    diff -u -r1.5 -r1.8
    --- kernel/security.c	2001/05/29 17:29:14	1.5
    +++ kernel/security.c	2001/06/05 14:06:38	1.8
    @@ -88,11 +88,18 @@
     static int dummy_file_read		(struct file *file)	{return 0;}
     static int dummy_file_write		(struct file *file)	{return 0;}
     static int dummy_file_ioctl		(struct file *file)	{return 0;}
    -static int dummy_file_mmap		(struct file *file)	{return 0;}
    +static int dummy_file_mmap		(struct file *file, unsigned long prot, unsigned long flags)	{return 0;}
    +static int dummy_file_mprotect		(struct vm_area_struct *vma, unsigned long prot)	{return 0;}
     static int dummy_file_lock		(struct file *file)	{return 0;}
     static int dummy_file_readv		(struct file *file)	{return 0;}
     static int dummy_file_writev		(struct file *file)	{return 0;}
    +static int dummy_file_fcntl		(struct file *file, unsigned int cmd, unsigned long arg)	{return 0;}
    +static int dummy_file_fcntl64		(struct file *file, unsigned int cmd, unsigned long arg)	{return 0;}
     
    +static int dummy_fown_alloc_security	(struct fown_struct *fown)	{return 0;}
    +static void dummy_fown_free_security	(struct fown_struct *fown)	{return;}
    +static int dummy_fown_send_sigiotask	(struct task_struct *tsk, struct fown_struct *fown, int fd, int reason)		{return 0;}
    +
     static int dummy_task_create		(void)	{return 0;}
     static int dummy_task_alloc_security	(struct task_struct *p)	{return 0;}
     static void dummy_task_free_security	(struct task_struct *p)	{return;}
    @@ -102,6 +109,7 @@
     static int dummy_task_setnice		(struct task_struct *p, int nice)			{return 0;}
     static int dummy_task_setrlimit		(unsigned int resource)	{return 0;}
     static int dummy_task_setscheduler	(struct task_struct *p, int policy)			{return 0;}
    +static int dummy_task_wait		(struct task_struct *p) {return 0;}
     static int dummy_task_kill		(struct task_struct *p, struct siginfo *info, int sig)	{return 0;}
     static int dummy_task_set_label		(char *filename)	{return 0;}
     static void dummy_task_reset_label	(void)			{return;}
    @@ -172,9 +180,18 @@
     	write:		dummy_file_write,
     	ioctl:		dummy_file_ioctl,
     	mmap:		dummy_file_mmap,
    +	mprotect:	dummy_file_mprotect,
     	lock:		dummy_file_lock,
     	readv:		dummy_file_readv,
     	writev:		dummy_file_writev,
    +	fcntl:		dummy_file_fcntl,
    +	fcntl64:	dummy_file_fcntl64,
    +};
    +
    +static struct fown_security_ops dummy_fown_ops = {
    +	alloc_security:	dummy_fown_alloc_security,
    +	free_security:	dummy_fown_free_security,
    +	send_sigiotask:	dummy_fown_send_sigiotask,
     };
     
     static struct task_security_ops	dummy_task_ops = {
    @@ -187,6 +204,7 @@
     	setnice:	dummy_task_setnice,
     	setrlimit:	dummy_task_setrlimit,
     	setscheduler:	dummy_task_setscheduler,
    +	wait:		dummy_task_wait,
     	kill:		dummy_task_kill,
     	set_label:	dummy_task_set_label,
     	reset_label:	dummy_task_reset_label,
    Index: mm/mmap.c
    ===================================================================
    RCS file: /cvs/lsm/lsm/mm/mmap.c,v
    retrieving revision 1.1.1.2
    retrieving revision 1.2
    diff -u -r1.1.1.2 -r1.2
    --- mm/mmap.c	2001/05/29 17:00:58	1.1.1.2
    +++ mm/mmap.c	2001/06/05 12:47:05	1.2
    @@ -13,6 +13,7 @@
     #include <linux/init.h>
     #include <linux/file.h>
     #include <linux/fs.h>
    +#include <linux/security.h>
     
     #include <asm/uaccess.h>
     #include <asm/pgalloc.h>
    @@ -251,6 +252,10 @@
     			return -EAGAIN;
     	}
     
    +	error = security_ops->file_ops->mmap(file, flags, prot);
    +	if (error)
    +		return error;
    +		
     	if (file) {
     		switch (flags & MAP_TYPE) {
     		case MAP_SHARED:
    Index: mm/mprotect.c
    ===================================================================
    RCS file: /cvs/lsm/lsm/mm/mprotect.c,v
    retrieving revision 1.1.1.1
    retrieving revision 1.2
    diff -u -r1.1.1.1 -r1.2
    --- mm/mprotect.c	2001/05/09 20:09:31	1.1.1.1
    +++ mm/mprotect.c	2001/06/05 13:42:37	1.2
    @@ -7,6 +7,7 @@
     #include <linux/smp_lock.h>
     #include <linux/shm.h>
     #include <linux/mman.h>
    +#include <linux/security.h>
     
     #include <asm/uaccess.h>
     #include <asm/pgalloc.h>
    @@ -260,6 +261,10 @@
     			error = -EACCES;
     			break;
     		}
    +
    +		error = security_ops->file_ops->mprotect(vma, prot);
    +		if (error)
    +			break;
     
     		if (vma->vm_end >= end) {
     			error = mprotect_fixup(vma, nstart, end, newflags);
    
    /*
     *  NSA Security-Enhanced Linux plug
     *
     *  Authors:  Stephen Smalley, NAI Labs, <sdsat_private>
     *            Chris Vance, <cvanceat_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.
     */ 
    
    #include <linux/config.h>
    #include <linux/module.h>
    #include <linux/init.h>
    #include <linux/kernel.h>
    #include <linux/errno.h>
    #include <linux/security.h>
    #include <linux/capability.h>
    #include <linux/flask/avc.h>
    #include <linux/flask/psid.h>
    #include <linux/flask/syscalls.h>
    #include <linux/mm.h>
    #include <linux/mman.h>
    #include <linux/slab.h>
    #include <linux/smp_lock.h>
    #include <linux/spinlock.h>
    #include <linux/file.h>
    #include <asm/uaccess.h>
    #include "selinux_plug.h"
    
    /* Lists of security blobs created by this module. 
       Used to deallocate all security blobs and clear security 
       fields when the module exits. */
    static LIST_HEAD(task_security_head);
    static LIST_HEAD(inode_security_head);
    static LIST_HEAD(file_security_head);
    static LIST_HEAD(superblock_security_head);
    
    /* Allocate and free functions for each kind of security blob. */
    
    static int task_alloc_security(struct task_struct *task)
    {
    	struct task_security_struct *tsec = task->security;
    
    	tsec = kmalloc(sizeof(struct task_security_struct), GFP_KERNEL);
    	if (!tsec)
    		return -ENOMEM; 
    	memset(tsec, 0, sizeof(struct task_security_struct));
    	tsec->magic = SELINUX_MAGIC;
    	tsec->task = task;
    	list_add(&tsec->list, &task_security_head);
    	tsec->osid = tsec->sid = SECINITSID_UNLABELED;
    	task->security = tsec;
    	return 0;
    }
    
    static void task_free_security(struct task_struct *task)
    {
    	struct task_security_struct *tsec = task->security;
    
    	if (!tsec || tsec->magic != SELINUX_MAGIC)
    		return; 
    
    	task->security = NULL;
    	list_del(&tsec->list);
    	kfree(tsec);
    }
    
    static int inode_alloc_security(struct inode *inode)
    {
    	struct task_security_struct *tsec = current->security;
    	struct inode_security_struct *isec = inode->i_security;
    
    	isec = kmalloc(sizeof(struct inode_security_struct), GFP_KERNEL);
    	if (!isec)
    		return -ENOMEM; 
    	memset(isec, 0, sizeof(struct inode_security_struct));
    	isec->magic = SELINUX_MAGIC;
    	isec->inode = inode;
    	list_add(&isec->list, &inode_security_head);
    	if (tsec && tsec->magic == SELINUX_MAGIC)
    		isec->sid = tsec->sid;
    	else
    		isec->sid = SECINITSID_UNLABELED;
    	inode->i_security = isec;
    	return 0;
    }
    
    static void inode_free_security(struct inode *inode)
    {
    	struct inode_security_struct *isec = inode->i_security;
    
    	if (!isec || isec->magic != SELINUX_MAGIC) 
    		return; 
    
    	inode->i_security = NULL;
    	list_del(&isec->list);
    	kfree(isec);
    }
    
    static int fown_alloc_security(struct task_struct *task, 
    			       struct fown_struct *fown)
    {
    	struct task_security_struct *tsec = task->security;
    	struct fown_security_struct *fsec;
    
    	if (!tsec || tsec->magic != SELINUX_MAGIC) {
    		printk("file_alloc_security:  task pid=%d does not have a security field\n",
    		       task->pid);
    		tsec = NULL;
    	}
    
    	fsec = kmalloc(sizeof(struct fown_security_struct), GFP_KERNEL);
    	if (!fsec)
    		return -ENOMEM;
    	memset(fsec, 0, sizeof(struct fown_security_struct));
    	fsec->magic = SELINUX_MAGIC;
    	fsec->sid = tsec ? tsec->sid : SECINITSID_UNLABELED;
    	fown->security = fsec;
    
    	return 0;
    }
    
    static void fown_free_security(struct fown_struct *fown)
    {
    	struct fown_security_struct *fsec = fown->security;
    
    	if (!fsec || fsec->magic != SELINUX_MAGIC)
    		return;
    
    	fown->security = NULL;
    	kfree(fsec);
    }
    
    static int file_alloc_security(struct task_struct *task, struct file *file)
    {
    	struct task_security_struct *tsec = task->security;
    	struct file_security_struct *fsec = file->f_security;
    
    	if (!tsec || tsec->magic != SELINUX_MAGIC) {
    		printk("file_alloc_security:  task pid=%d does not have a security field\n",
    		       task->pid);
    		tsec = NULL;
    	}
    
    	fsec = kmalloc(sizeof(struct file_security_struct), GFP_KERNEL);
    	if (!fsec)
    		return -ENOMEM; 
    	memset(fsec, 0, sizeof(struct file_security_struct));
    	fsec->magic = SELINUX_MAGIC;
    	fsec->file = file;
    	list_add(&fsec->list, &file_security_head);
    	fsec->sid = tsec ? tsec->sid : SECINITSID_UNLABELED;
    	file->f_security = fsec;
    	return 0;
    }
    
    static void file_free_security(struct file *file)
    {
    	struct file_security_struct *fsec = file->f_security;
    
    	if (!fsec || fsec->magic != SELINUX_MAGIC) 
    		return; 
    
    	file->f_security = NULL;
    	list_del(&fsec->list);
    	kfree(fsec);
    
    	fown_free_security(&(file->f_owner));
    }
    
    static int superblock_alloc_security(struct super_block *sb)
    {
    	struct superblock_security_struct *sbsec = sb->s_security;
    
    	sbsec = kmalloc(sizeof(struct superblock_security_struct), GFP_KERNEL);
    	if (!sbsec)
    		return -ENOMEM; 
    	memset(sbsec, 0, sizeof(struct superblock_security_struct));
    	sbsec->magic = SELINUX_MAGIC;
    	sbsec->sb = sb;
    	list_add(&sbsec->list, &superblock_security_head);
    	sbsec->sid = SECINITSID_UNLABELED;
    	sb->s_security = sbsec;
    	return 0;
    }
    
    static void superblock_free_security(struct super_block *sb)
    {
    	struct superblock_security_struct *sbsec = sb->s_security;
    
    	if (!sbsec || sbsec->magic != SELINUX_MAGIC) 
    		return; 
    
    	if (sbsec->uses_psids && sbsec->psidtab)
    		psid_release(sb);
    
    	sb->s_security = NULL;
    	list_del(&sbsec->list);
    	kfree(sbsec);
    }
    
    /* The security server must be initialized before
       any labeling or access decisions can be provided. */
    static int ss_precondition(void) 
    {
    	static int ss_initializing = 0, ss_initialized = 0;
    
    	if (ss_initialized) 
    		return 0; /* ready for service */
    
    	if (ss_initializing)
    		return -1; /* currently initializing */
    
    	if (!current->fs->rootmnt)
    		return -1; /* waiting for root file system */
    
    	ss_initializing = 1; /* start initialization */
    	security_init(); 
    	ss_initialized = 1;  /* done initialization */
    	return 0; /* ready for service */
    }
    
    /* The file system's label must be initialized prior to use.
       If the file system is persistent, then its persistent label mapping 
       must be initialized before labels for files in it can be obtained. */
    int superblock_precondition(struct super_block *sb) 
    {
    	struct superblock_security_struct *sbsec = sb->s_security;
    	int rc;
    
    	if (ss_precondition())
    		return -1;
    
    	if (sbsec && sbsec->magic == SELINUX_MAGIC) {
    		if (sbsec->initialized) 
    			return 0;  /* ready for service */
    
    		if (sbsec->initializing)
    			return -1; /* currently inititalizing */
    	}
    
    	if (!sbsec || sbsec->magic != SELINUX_MAGIC) {
    		rc = superblock_alloc_security(sb);
    		if (rc)
    			return rc;
    		sbsec = sb->s_security;
    	}
    	
    	sbsec->initializing = 1;
     	
    	if ((strcmp(sb->s_type->name, "ext2") == 0) ||
    	    (strcmp(sb->s_type->name, "ufs") == 0) ||
    	    (strcmp(sb->s_type->name, "reiserfs") == 0)) {
    		/* PSIDs only work for persistent file systems with
    		   persistent inode numbers. */
    		rc = psid_init(sb);
    		if (rc) {
    			printk("superblock_precondition: psid_init returned %d\n", -rc);
    			return rc;
    		}
    		sbsec->uses_psids = 1;
    	} else if (strcmp(sb->s_type->name, "proc") == 0)
    		sbsec->sid = SECINITSID_PROC;
    	else if (strcmp(sb->s_type->name, "devpts") == 0)
    		sbsec->sid = SECINITSID_DEVPTS;
    	else if (strcmp(sb->s_type->name, "nfs") == 0)
    		sbsec->sid = SECINITSID_NFS;
    	else
    		/* Nothing to do here. */
    		;
    
    	sbsec->initialized = 1;
    
    	return 0;
    }
    
    /* The inode's security attributes must be initialized before first use. */
    int inode_precondition(struct inode *inode) 
    {
    	struct superblock_security_struct *sbsec = NULL; 
    	struct inode_security_struct *isec = inode->i_security;
    	int rc;
    
    	if (ss_precondition())
    		return -1;
    
    	if (isec && isec->magic == SELINUX_MAGIC) {
    		if (isec->initialized) 
    			return 0;
    		
    		if (isec->initializing)
    			return -1;
    	}
    
    	if (inode->i_sb) {
    		rc = superblock_precondition(inode->i_sb);
    		if (rc)
    			return rc;
    		sbsec = inode->i_sb->s_security;
    	}
    
    	if (!isec || isec->magic != SELINUX_MAGIC) {
    		rc = inode_alloc_security(inode);
    		if (rc)
    			return rc;
    		isec = inode->i_security;
    	}
    
    	isec->initializing = 1;
    
    	isec->sclass = inode_mode_to_security_class(inode->i_mode);
    
    	if (sbsec) {
    		if (sbsec->uses_psids) {
    			rc = psid_to_sid(inode, &isec->sid);
    			if (rc) {
    				printk("inode_precondition:  psid_to_sid returned %d for inode %p\n", -rc, inode);
    			}
    		}
    		else if (sbsec->sid != SECINITSID_UNLABELED) {
    		        /* inherit from file system */
    			isec->sid = sbsec->sid;
    		}
    /* XXX:  Still need to provide equivalents for SELinux handling of
       special file systems like devpts and procfs. */
    	}
    
    	isec->initialized = 1;
    
    	return 0;
    }
    
    /* The task's security attributes must be initialized before first use. */
    int task_precondition(struct task_struct *task) 
    {
    	struct task_security_struct *tsec = task->security, *psec;
    	struct task_struct *parent = task->p_pptr;
    	struct vm_area_struct *vma = NULL;
    	struct inode *inode = NULL;
    	struct inode_security_struct *isec;
    	security_id_t newsid;
    	security_context_t context;
    	char *buffer = NULL, *path = NULL;
    	__u32 len;
    	int rc;
    
    	if (ss_precondition())
    		return -1;
    	     
    	if (tsec && tsec->magic == SELINUX_MAGIC)
    		return 0;
    
    	parent = task->p_pptr;
    	if (parent == task) {
    		rc = task_alloc_security(task);
    		if (rc)
    			return rc;
    		tsec = task->security;
    		tsec->osid = tsec->sid = SECINITSID_KERNEL;
    		goto out;
    	}
    		
    	rc = task_precondition(parent);
    	if (rc)
    		return rc; 
    	psec = parent->security;
    
    	rc = task_alloc_security(task);
    	if (rc)
    		return rc;
    	tsec = task->security;
    
    	/* Default to the attributes of my parent. */
    	tsec->osid = psec->osid;
    	tsec->sid = psec->sid;
    
    	/* Try to determine the executable. */
    	if (!task->mm) 
    		goto out;
    	for (vma = task->mm->mmap; vma; vma = vma->vm_next) {
    		if ((vma->vm_flags & VM_EXECUTABLE) && 
    		    vma->vm_file) {
    			break;
    		}
    	}
    	if (!vma) 
    		goto out;
    
    	/* Try to obtain the executable's security attributes. */
    	inode = vma->vm_file->f_dentry->d_inode;
    	if (!inode)
    		goto out;
    	rc = inode_precondition(inode);
    	if (rc) {
    		/* May be in the midst of initializing the PSID mapping. */
    		task_free_security(task);
    		return rc;
    	}
    	isec = inode->i_security;
    
    	/* Compute my attributes based on the attributes of my
    	   parent and my executable. */
    	rc = security_transition_sid(psec->sid, 
    				     isec->sid,
    				     SECCLASS_PROCESS,
    				     &newsid);
    	if (rc) {
    		printk("task_precondition:  security_transition_sid returned %d\n", -rc);
    		goto out;
    	}
    
    	tsec->sid = newsid;
    
    
    out:
    	/* Typically, a task's attributes are initially assigned
    	   by task_alloc_security and changed upon program execution
    	   by bprm_compute_creds.  So task_precondition should
    	   only determine a task's attributes if the task
    	   was created prior to the initialization of this module.
    	   Show all such assignments until we are sure that they
    	   occur correctly both in the static case and the dynamically
    	   loaded case. */
    	
    	if (vma) {
    		buffer = (char*)__get_free_page(GFP_KERNEL);
    		if (buffer) {
    			path = d_path(vma->vm_file->f_dentry, 
    				      vma->vm_file->f_vfsmnt,
    				      buffer, PAGE_SIZE);
    		}
    	}
    
    	rc = security_sid_to_context(tsec->sid, &context, &len);
    	if (rc) {
    		printk("task_precondition:  assigning SID %d to pid %d exe=%s\n", tsec->sid, task->pid, path ? path : "none");
    	} else {
    		printk("task_precondition:  assigning context %s to pid %d exe=%s\n", context, task->pid, path ? path : "none");		
    		kfree(context);
    	}
    	if (buffer)
    		free_page((unsigned long)buffer);
    
    	return 0;
    }
    
    /* The file's security attributes must be initialized before first use. */
    int file_precondition(struct file *file) 
    {
            struct task_security_struct *tsec;
    	struct file_security_struct *fsec = file->f_security;
    
    	if (ss_precondition())
    		return -1;
    
    	if (fsec && fsec->magic == SELINUX_MAGIC) 
    		return 0;
    
    	if (task_precondition(current))
    		return -1;
    	tsec = current->security;
    
    	return file_alloc_security(current, file);
    }
    
    /* Check permission betweeen a pair of tasks, e.g. signal checks,
       fork check, ptrace check, etc. */
    int task_has_perm(struct task_struct *tsk1,
    		  struct task_struct *tsk2,
    		  access_vector_t perms)
    {
    	struct task_security_struct *tsec1, *tsec2;
    
    	if (task_precondition(tsk1))
    		return 0;
    	if (task_precondition(tsk2))
    		return 0;
    	tsec1 = tsk1->security;
    	tsec2 = tsk2->security;
    	return avc_has_perm_ref(tsec1->sid, tsec2->sid, 
    				SECCLASS_PROCESS, perms, &tsec2->avcr);
    }
    
    /* Check whether a task is allowed to use a capability. */
    int task_has_capability(struct task_struct *tsk,
    			int cap)
    {
    	struct task_security_struct *tsec;
    	avc_audit_data_t ad;
    	int rc;
    
    	/* XXX First, apply the traditional superuser test. 
    	   XXX This test can be removed if we stack the SELinux
    	   XXX module with the capabilities module. */
    	if (cap_is_fs_cap(cap)) {
    		if (tsk->fsuid != 0)
    			return -EPERM;
    	} else {
    		if (tsk->euid != 0)
    			return -EPERM;
    	}
    
    	/* If the superuser test passes, then check the SELinux permission. */
    
    	if (task_precondition(tsk))
    		goto grant;
    
    	tsec = tsk->security;
    	AVC_AUDIT_DATA_INIT(&ad,CAP);
    	ad.u.cap = cap;
    	rc = avc_has_perm_audit(tsec->sid, tsec->sid, 
    				SECCLASS_CAPABILITY, CAP_TO_MASK(cap), &ad);
    	if (rc)
    		return rc;
    
    grant:
    	current->flags |= PF_SUPERPRIV;
    	return 0;
    }
    
    /* Check whether a task is allowed to use a system operation. */
    int task_has_system(struct task_struct *tsk,
    		    access_vector_t perms)
    {
    	struct task_security_struct *tsec;
    
    	if (task_precondition(tsk))
    		return 0;
    
    	tsec = tsk->security;
    
    	return avc_has_perm(tsec->sid, SECINITSID_KERNEL, 
    			    SECCLASS_SYSTEM, perms);
    }
    
    /* Check whether a task is allowed to use a security operation. */
    int task_has_security(struct task_struct *tsk,
    		      access_vector_t perms)
    {
    	struct task_security_struct *tsec;
    
    	if (task_precondition(tsk))
    		return 0;
    
    	tsec = tsk->security;
    
    	return avc_has_perm(tsec->sid, SECINITSID_SECURITY, 
    			    SECCLASS_SECURITY, perms);
    }
    
    /* Check whether a task has a particular permission to an inode.
       The 'aeref' parameter is optional and allows other AVC
       entry references to be passed (e.g. the one in the struct file).
       The 'adp' parameter is optional and allows other audit
       data to be passed (e.g. the dentry). */
    int inode_has_perm(struct task_struct *tsk,
    		   struct inode *inode,
    		   access_vector_t perms,
    		   avc_entry_ref_t *aeref,
    		   avc_audit_data_t *adp)
    {
    	struct task_security_struct *tsec;
    	struct inode_security_struct *isec;
    	avc_audit_data_t ad;
    
    	if (task_precondition(tsk))
    		return 0;
    	if (inode_precondition(inode))
    		return 0;
    	tsec = tsk->security;
    	isec = inode->i_security;
    
    	if (!adp) {
    		adp = &ad;
    		AVC_AUDIT_DATA_INIT(&ad, FS);
    		ad.u.fs.inode = inode;
    	}
    
    	return avc_has_perm_ref_audit(tsec->sid, isec->sid, isec->sclass, 
    				      perms, aeref ? aeref : &isec->avcr, adp);
    }
    
    /* Same as inode_has_perm, but pass explicit audit data containing 
       the dentry to help the auditing code to more easily generate the 
       pathname if needed. */
    static inline int dentry_has_perm(struct task_struct *tsk,
    				  struct dentry *dentry, 
    				  access_vector_t av,
    				  avc_entry_ref_t *aeref) 
    {
    	struct inode *inode = dentry->d_inode;
    	avc_audit_data_t ad;
    	AVC_AUDIT_DATA_INIT(&ad,FS);
    	ad.u.fs.dentry = dentry;
    	return inode_has_perm(tsk, inode, av, aeref, &ad);
    }
    
    /* Check whether a task can use an open file descriptor to
       access an inode in a given way.  Check access to the
       descriptor itself, and then use dentry_has_perm to
       check a particular permission to the file.
       Access to the descriptor is implicitly granted if it
       has the same SID as the process.  If av is zero, then
       access to the file is not checked, e.g. for cases
       where only the descriptor is affected like seek. */
    static inline int file_has_perm(struct task_struct *tsk,
    				struct file *file, 
    				access_vector_t av)
    {
    	struct task_security_struct *tsec;
    	struct file_security_struct *fsec;
    	struct dentry *dentry = file->f_dentry;
    	avc_audit_data_t ad;
    	int rc;
    
    	if (task_precondition(current))
    		return 0;
    	if (file_precondition(file))
    		return 0;
    
    	tsec = current->security;
    	fsec = file->f_security;
    
    	if (tsec->sid != fsec->sid) {
    		AVC_AUDIT_DATA_INIT(&ad, FS);
    		ad.u.fs.dentry = file->f_dentry;
    
    		rc = avc_has_perm_ref_audit(tsec->sid, fsec->sid, 
    					    SECCLASS_FD,
    					    FD__USE,
    					    &fsec->avcr, &ad);
    		if (rc)
    			return rc;
    	}
    
    	/* av is zero if only checking access to the descriptor. */
    	if (av)
    		return dentry_has_perm(tsk, dentry, av, &fsec->inode_avcr);
    	
    	return 0;
    }
    
    /* Check whether a task can create a file. */
    static int may_create(struct inode *dir, 
    		      struct dentry *dentry, 
    		      security_class_t tclass)
    {
    	struct task_security_struct *tsec;
    	struct inode_security_struct *dsec;
    	struct superblock_security_struct *sbsec;
    	security_id_t newsid;
    	avc_audit_data_t ad;
    	int rc;
    
    	if (task_precondition(current))
    		return 0;
    	if (inode_precondition(dir))
    		return 0;
    
    	tsec = current->security;
    	dsec = dir->i_security;
    
    	AVC_AUDIT_DATA_INIT(&ad, FS);
    	ad.u.fs.dentry = dentry;
    
    	rc = avc_has_perm_ref_audit(tsec->sid, dsec->sid, SECCLASS_DIR, 
    				    DIR__ADD_NAME | DIR__SEARCH, 
    				    &dsec->avcr, &ad);
    	if (rc)
    		return rc;
    
    	if (tsec->in_sid[0]) {
    		newsid = tsec->in_sid[0];
    	} else {
    		rc = security_transition_sid(tsec->sid, dsec->sid, tclass, 
    					     &newsid);
    		if (rc)
    			return rc;
    	}
    
    	rc = avc_has_perm_audit(tsec->sid, newsid, tclass, FILE__CREATE, &ad);
    	if (rc)
    		return rc;
    
    	if (dir->i_sb) {
    		sbsec = dir->i_sb->s_security;
    
    		rc = avc_has_perm_audit(newsid, sbsec->sid, 
    					SECCLASS_FILESYSTEM, 
    					FILESYSTEM__ASSOCIATE, &ad);
    		if (rc)
    			return rc;
    	}
    
    	return 0;
    }
    
    #define MAY_LINK   0
    #define MAY_UNLINK 1
    #define MAY_RMDIR  2
    
    /* Check whether a task can link, unlink, or rmdir a file/directory. */
    static int may_link(struct inode *dir, 
    		    struct dentry *dentry,
    		    int kind)
    				 
    {
    	struct task_security_struct *tsec;
    	struct inode_security_struct *dsec, *isec;
    	avc_audit_data_t ad;
    	access_vector_t av;
    	int rc;
    
    	if (task_precondition(current))
    		return 0;
    	if (inode_precondition(dir))
    		return 0;
    	if (inode_precondition(dentry->d_inode))
    		return 0;
    
    	tsec = current->security;
    	dsec = dir->i_security;
    	isec = dentry->d_inode->i_security;
    
    	AVC_AUDIT_DATA_INIT(&ad, FS);
    	ad.u.fs.dentry = dentry;
    
    	av = DIR__SEARCH;
    	av |= (kind ? DIR__REMOVE_NAME : DIR__ADD_NAME);
    	rc = avc_has_perm_ref_audit(tsec->sid, dsec->sid, SECCLASS_DIR, 
    				    av, &dsec->avcr, &ad);
    	if (rc)
    		return rc;
    
    	switch (kind) {
    	case MAY_LINK:
    		av = FILE__LINK;
    		break;
    	case MAY_UNLINK:
    		av = FILE__UNLINK;
    		break;
    	case MAY_RMDIR:
    		av = DIR__RMDIR;
    		break;
    	default:
    		printk("may_link:  unrecognized kind %d\n", kind);
    		return 0;
    	}
    
    	rc = avc_has_perm_ref_audit(tsec->sid, isec->sid, isec->sclass, 
    				    av, &isec->avcr, &ad);
    	return rc;
    }
    
    static inline int may_rename(struct inode *old_dir, 
    			     struct dentry *old_dentry, 
    			     struct inode *new_dir, 
    			     struct dentry *new_dentry)
    {
    	struct task_security_struct *tsec;
    	struct inode_security_struct *old_dsec, *new_dsec, *old_isec, *new_isec;
    	avc_audit_data_t ad;
    	access_vector_t av;
    	int old_is_dir, new_is_dir;
    	int rc;
    
    	if (task_precondition(current))
    		return 0;
    	if (inode_precondition(old_dir))
    		return 0;
    	if (inode_precondition(new_dir))
    		return 0;
    	if (inode_precondition(old_dentry->d_inode))
    		return 0;
    	if (new_dentry->d_inode &&
    	    inode_precondition(new_dentry->d_inode))
    		return 0;
    
    	tsec = current->security;
    	old_dsec = old_dir->i_security;
    	old_isec = old_dentry->d_inode->i_security;
    	old_is_dir = S_ISDIR(old_dentry->d_inode->i_mode);
    	new_dsec = new_dir->i_security;
    
    	AVC_AUDIT_DATA_INIT(&ad, FS);
    
    	ad.u.fs.dentry = old_dentry;
    	rc = avc_has_perm_ref_audit(tsec->sid, old_dsec->sid, SECCLASS_DIR, 
    				    DIR__REMOVE_NAME | DIR__SEARCH, 
    				    &old_dsec->avcr, &ad);
    	if (rc)
    		return rc;
    	rc = avc_has_perm_ref_audit(tsec->sid, old_isec->sid, 
    				    old_isec->sclass, 
    				    FILE__RENAME, 
    				    &old_isec->avcr, &ad);
    	if (rc)
    		return rc;
    	if (old_is_dir && new_dir != old_dir) {
    		rc = avc_has_perm_ref_audit(tsec->sid, old_isec->sid, 
    					    old_isec->sclass, 
    					    DIR__REPARENT, 
    					    &old_isec->avcr, &ad);
    		if (rc)
    			return rc;
    	}
    
    	ad.u.fs.dentry = new_dentry;
    	av = DIR__ADD_NAME | DIR__SEARCH;
    	if (new_dentry->d_inode)
    		av |= DIR__REMOVE_NAME;
    	rc = avc_has_perm_ref_audit(tsec->sid, new_dsec->sid, SECCLASS_DIR, 
    				    av,&new_dsec->avcr, &ad);
    	if (rc)
    		return rc;
    	if (new_dentry->d_inode) {
    		new_isec = new_dentry->d_inode->i_security;
    		new_is_dir = S_ISDIR(new_dentry->d_inode->i_mode);
    		rc = avc_has_perm_ref_audit(tsec->sid, new_isec->sid, 
    					    new_isec->sclass,
    					    (new_is_dir ? DIR__RMDIR : FILE__UNLINK),
    					    &new_isec->avcr, &ad);
    		if (rc)
    			return rc;
    	}
    
    	return 0;
    }
    
    /* Check whether a task can perform a filesystem operation. */
    int superblock_has_perm(struct task_struct *tsk,
    			struct super_block *sb,
    			access_vector_t perms,
    			avc_audit_data_t *ad)
    {
    	struct task_security_struct *tsec;
    	struct superblock_security_struct *sbsec;
    
    	if (task_precondition(tsk))
    		return 0;
    	if (superblock_precondition(sb))
    		return 0;
    	tsec = tsk->security;
    	sbsec = sb->s_security;
    	return avc_has_perm_audit(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, 
    				  perms, ad);
    }
    
    /* Convert a Linux mode and permission mask to an access vector. */
    static inline access_vector_t file_mask_to_av(int mode, int mask) 
    {
    	access_vector_t av = 0;
    
    	if ((mode & S_IFMT) != S_IFDIR) {
    		if (mask & MAY_EXEC) 
    			av |= FILE__EXECUTE;
    		if (mask & MAY_WRITE) 
    			av |= FILE__WRITE;
    		if (mask & MAY_READ) 
    			av |= FILE__READ;
    	} else {
    		if (mask & MAY_EXEC) 
    			av |= DIR__SEARCH;
    		if (mask & MAY_WRITE) 
    			av |= DIR__WRITE;
    		if (mask & MAY_READ) 
    			av |= DIR__READ;
    	}
    
    	return av;
    }
    
    /* Convert a Linux file mode to an access vector. */
    static inline access_vector_t file_mode_to_av(mode_t mode) 
    {
    	access_vector_t av = 0;
    
    	if (mode & FMODE_READ) 
    		av |= FILE__READ;
    	if (mode & FMODE_WRITE) 
    		av |= FILE__WRITE;
    	return av;
    }
    
    /* Set an inode's SID, where the inode may or may not already
       have a security structure. */
    int inode_security_set_sid(struct inode *inode, security_id_t sid)
    {
    	struct inode_security_struct *isec = inode->i_security;
    	int rc;
    
    	if (!isec) {
    		rc = inode_alloc_security(inode);
    		if (rc)
    			return rc;
    		isec = inode->i_security;
    	}
    	isec->sclass = inode_mode_to_security_class(inode->i_mode);
    	isec->sid = sid;
    	isec->initialized = 1;
    	return 0;
    }
    
    /* Set the security attributes on a newly created file. */
    static int post_create(struct inode *dir, 
    		       struct dentry *dentry)
    {
    
    	struct task_security_struct *tsec;
    	struct inode_security_struct *dsec;
    	struct superblock_security_struct *sbsec;
    	security_id_t newsid;
    	int rc;
    
    	if (task_precondition(current))
    		return 0;
    	if (inode_precondition(dir))
    		return 0;
    
    	tsec = current->security;
    	dsec = dir->i_security;
    
    	/* XXX:  Need a way to propagate SID from may_create to post_create. */
    	if (tsec->in_sid[0]) {
    		newsid = tsec->in_sid[0];
    	} else {
    		rc = security_transition_sid(tsec->sid, dsec->sid, 
    					     inode_mode_to_security_class(dentry->d_inode->i_mode), 
    					     &newsid);
    		if (rc) {
    			printk("post_create:  unable to obtain new SID, rc=%d\n",-rc);
    			return rc;
    		}
    	}
    	
    	rc = inode_security_set_sid(dentry->d_inode, newsid);
    	if (rc) {
    		printk("post_create:  unable to set new SID, rc=%d\n",-rc);
    		return rc;
    	}
    
    	if (dir->i_sb) {
    		sbsec = dir->i_sb->s_security;
    		if (sbsec && sbsec->uses_psids) {
    			rc = sid_to_psid(dentry->d_inode, newsid);
    			if (rc) {
    				printk("post_create:  unable to set new PSID, rc=%d\n",-rc);
    				return rc;
    			}
    		}
    	}
    
    	return 0;
    }	
    
    
    /* Hook functions begin here. */
    
    /* assorted security operations  (mostly syscall interposition) */
    
    static int selinux_sethostname(void)
    {
    	return task_has_capability(current,CAP_SYS_ADMIN);
    }
    
    static int selinux_setdomainname(void)
    {
    	return task_has_capability(current,CAP_SYS_ADMIN);
    }
    
    static int selinux_reboot(unsigned int cmd)
    {
    	return task_has_capability(current,CAP_SYS_BOOT);
    }
    
    static int selinux_mount(char * dev_name, 
                             struct nameidata *nd, 
                             char * type, 
                             unsigned long flags, 
                             void * data)	
    {
    	return dentry_has_perm(current, nd->dentry, DIR__MOUNTON, NULL);
    }
    
    static int selinux_add_vfsmnt(struct nameidata *nd, 
    			      struct super_block *sb, 
    			      char * dev_name)
    {
    	struct inode_security_struct *isec1, *isec2;
    	struct inode *inode;
    	avc_audit_data_t ad;
    	int rc;
    
    	AVC_AUDIT_DATA_INIT(&ad,FS);
    	ad.u.fs.dentry = nd->dentry;
    	rc = superblock_has_perm(current, sb, FILESYSTEM__MOUNT, &ad);
    	if (rc) 
    		return rc;
    
    	inode = sb->s_root->d_inode;
    	if (!inode || inode_precondition(inode))
    		return 0;
    	isec1 = inode->i_security;
    
    	inode = nd->dentry->d_inode;
    	if (!inode || inode_precondition(inode))
    		return 0;
    	isec2 = inode->i_security;
    
    	return avc_has_perm_audit(isec1->sid, isec2->sid, 
    				  SECCLASS_DIR, DIR__MOUNTASSOCIATE, &ad);
    }
    
    static int selinux_umount(struct vfsmount *mnt, int flags)
    {
    	return superblock_has_perm(current,mnt->mnt_sb, FILESYSTEM__UNMOUNT,NULL);
    }
    
    static void selinux_umount_close(struct vfsmount *mnt)
    {
    	struct super_block *sb = mnt->mnt_sb;
    	struct superblock_security_struct *sbsec = sb->s_security;
    
    	if (sbsec && sbsec->uses_psids)
    		psid_release(sb);
    	return;
    }
    
    static void selinux_umount_busy	(struct vfsmount *mnt)
    {
    	struct super_block *sb = mnt->mnt_sb;
    	struct superblock_security_struct *sbsec = sb->s_security;
    
    	if (sbsec && sbsec->uses_psids)
    		psid_init(sb);
    
    	return;
    }
    
    static int selinux_remount(struct vfsmount *mnt, unsigned long flags, void *data)
    {
    	return superblock_has_perm(current, mnt->mnt_sb, FILESYSTEM__REMOUNT, NULL);
    }
    
    static void selinux_post_remount(struct vfsmount *mnt, unsigned long flags, void *data)
    {
    	struct super_block *sb = mnt->mnt_sb;
    	struct superblock_security_struct *sbsec = sb->s_security;
    
    	if (sbsec && sbsec->uses_psids)
    		psid_remount(sb);
    }
    
    static int selinux_ioperm(void)
    {
    	return task_has_capability(current,CAP_SYS_RAWIO);
    }
    
    static int selinux_iopl(void)
    {
    	return task_has_capability(current,CAP_SYS_RAWIO);
    }
    
    static int selinux_ptrace(struct task_struct *parent, struct task_struct *child)
    {
    	return task_has_perm(parent, child, PROCESS__PTRACE);
    }
    
    static int selinux_setcapablity(void)
    {
    	return task_has_capability(current,CAP_SETPCAP);
    }
    
    static int selinux_acct(void)
    {
    	return task_has_capability(current,CAP_SYS_PACCT);
    }
    
    static int selinux_capable(int cap)
    {
    	return task_has_capability(current,cap);
    }
    
    /* binprm security operations */
    
    static int selinux_bprm_alloc_security(struct linux_binprm *bprm)
    {
    	struct task_security_struct *tsec;
    	struct inode *inode = bprm->file->f_dentry->d_inode;
    	struct inode_security_struct *isec;
    	security_id_t newsid;
    	avc_audit_data_t ad;
    	int rc;
    
    	if (bprm->sh_bang)
    		/* The security field should already be set properly. */
    		return 0;
    
    	/* Clear the field since it may contain garbage. */
    	bprm->security = NULL;
    
    	/* Preconditions */
    	if (task_precondition(current))
    		return 0;
    	if (inode_precondition(inode))
    		return 0;
    
    	tsec = current->security;
    	isec = inode->i_security;
    
    	/* Default to the current task SID. */
    	bprm->security = (void *)tsec->sid;
    
    	if (tsec->in_sid[0]) {
    		newsid = tsec->in_sid[0];
    	} else {
    		/* Check for a default transition on this program. */
    		rc = security_transition_sid(tsec->sid, isec->sid, SECCLASS_PROCESS, 
    					     &newsid);
    		if (rc)
    			return rc;
    	}
    
    	AVC_AUDIT_DATA_INIT(&ad, FS);
    	ad.u.fs.dentry = bprm->file->f_dentry;
    
            if (tsec->sid == newsid) {
    		rc = avc_has_perm_ref_audit(tsec->sid, isec->sid, 
    					    SECCLASS_FILE, FILE__EXECUTE_NO_TRANS, 
    					    &isec->avcr, &ad);
    		if (rc)
    			return rc;
    	} else {
    		/* Check permissions for the transition. */
    		rc = avc_has_perm_audit(tsec->sid, newsid, 
    					SECCLASS_PROCESS, PROCESS__TRANSITION, 
    					&ad);
    		if (rc)
    			return rc;
    
    		rc = avc_has_perm_ref_audit(newsid, isec->sid, 
    					    SECCLASS_FILE, FILE__ENTRYPOINT, 
    					    &isec->avcr, &ad);
    		if (rc)
    			return rc;
    
    		/* Set the security field to the new SID. */
    		bprm->security = (void*) newsid;
    	}
    
    	return 0;
    }
    
    static void selinux_bprm_free_security(struct linux_binprm *bprm)
    {
    	/* Nothing to do - not dynamically allocated. */
    	return;
    }
    
    static inline int must_not_trace_exec(struct task_struct * p,
    					    struct linux_binprm *bprm)
    {
    	struct task_security_struct *tsec;
    	security_id_t newsid;
    
    	if (task_precondition(p->p_pptr))
    		return 0;
    	tsec = p->p_pptr->security;
    
    	if (bprm->security)
    		newsid = (security_id_t)bprm->security;
    	else
    		newsid = tsec->sid;
    
    	return (p->flags & PT_PTRACED) && 
    		avc_has_perm(tsec->sid, newsid, 
    			     SECCLASS_PROCESS, PROCESS__PTRACE);
    }
    
    /* Derived from fs/exec.c:flush_old_files. */
    static inline void flush_unauthorized_files(struct files_struct * files)
    {
    	avc_audit_data_t ad;
    	struct file *file;
    	long j = -1;
    
    	AVC_AUDIT_DATA_INIT(&ad,FS);
    
    	read_lock(&files->file_lock);
    	for (;;) {
    		unsigned long set, i;
    
    		j++;
    		i = j * __NFDBITS;
    		if (i >= files->max_fds || i >= files->max_fdset)
    			break;
    		set = files->open_fds->fds_bits[j];
    		if (!set)
    			continue;
    		read_unlock(&files->file_lock);
    		for ( ; set ; i++,set >>= 1) {
    			if (set & 1) {
    				file = fget(i);
    				if (!file)
    					continue;
    				if (file_has_perm(current,
    						  file, 
    						  file_mode_to_av(file->f_mode))) 
    					sys_close(i);
    				fput(file);
    			}
    		}
    		read_lock(&files->file_lock);
    
    	}
    	read_unlock(&files->file_lock);
    }
    
    static void selinux_bprm_compute_creds(struct linux_binprm *bprm)
    {
    	struct task_security_struct *tsec;
    	security_id_t sid;
    	int do_unlock = 0;
    
    	if (task_precondition(current))
    		return;
    	if (!bprm->security)
    		return;
    
    	tsec = current->security;
    	sid = (security_id_t)bprm->security;
    
    	/* XXX The following code addresses both 
    	   XXX traditional setuid/setgid programs and
    	   XXX SELinux SID transitions.  The setuid/setgid
    	   XXX logic can be removed if it is reintegrated
    	   XXX back into the base LSM kernel.  Currently,
    	   XXX it is absent from the base LSM kernel. */
    
    	if (bprm->e_uid != current->uid || 
    	    bprm->e_gid != current->gid ||
    	    tsec->sid != sid) {
                    current->dumpable = 0;
    
    		lock_kernel();
    		if (must_not_trace_exec(current, bprm) 
    		    || atomic_read(&current->fs->count) > 1
    		    || atomic_read(&current->files->count) > 1
    		    || atomic_read(&current->sig->count) > 1) {
    			if(task_has_capability(current,CAP_SETUID)) {
    				bprm->e_uid = current->uid;
    				bprm->e_gid = current->gid;
    			}
    			if (current->pid != 1)
    				sid = tsec->sid;
    		}
    		do_unlock = 1;
    	}
    
    	/* XXX More code for setuid/setgid programs. */
            current->suid = current->euid = current->fsuid = bprm->e_uid;
            current->sgid = current->egid = current->fsgid = bprm->e_gid;
    
    	tsec->osid = tsec->sid;
    	if (tsec->sid != sid) {
    		tsec->sid = sid;
    
    		flush_unauthorized_files(current->files);
    
    		/* need to force wait permission check if parent is waiting */
    		wake_up_interruptible(&current->p_pptr->wait_chldexit);
    	}
    
    	if(do_unlock)
    		unlock_kernel();
    }
    
    /* superblock security operations */
    
    static int selinux_sb_alloc_security(struct super_block *sb)
    {
    	if (ss_precondition())
    		return 0;
    	if (task_precondition(current))
    		return 0;
    
    	return superblock_alloc_security(sb);
    }
    
    static void selinux_sb_free_security(struct super_block *sb)
    {
    	superblock_free_security(sb);
    }
    
    static int selinux_sb_statfs(struct super_block *sb)
    {
    	struct task_security_struct *tsec;
    	struct superblock_security_struct *sbsec;
    
    	/* This hook function would simply call superblock_has_perm,
    	   but it also needs to save the sb SID to support
    	   statfs_secure, so we just inline superblock_has_perm. */
    
    	if (task_precondition(current))
    		return 0;
    	if (superblock_precondition(sb))
    		return 0;
    	tsec = current->security;
    	sbsec = sb->s_security;
    
    	tsec->out_sid[0] = sbsec->sid;
    
    	return avc_has_perm(tsec->sid, sbsec->sid, SECCLASS_FILESYSTEM, 
    			    FILESYSTEM__GETATTR);
    }
    
    /* inode security operations */
    
    static int selinux_inode_alloc_security(struct inode *inode)
    {
    	/* Initialize inode security field to some reasonable defaults. 
    	   The security class (sclass) will be changed later to a more
    	   specific value when the mode is available.  For some kinds
    	   of objects (e.g. files), the security identifier (sid) will
    	   be changed later to a different value when the file system
    	   and inode number is available.  These changes are handled
    	   by inode_precondition before the inode is first used. */
    
    	if (ss_precondition())
    		return 0;
    	if (task_precondition(current))
    		return 0;
    
    	return inode_alloc_security(inode);
    }
    
    static void selinux_inode_free_security(struct inode *inode)
    {
    	inode_free_security(inode);
    }
    
    static int selinux_inode_create(struct inode *dir, struct dentry *dentry, int mask)
    {
    	return may_create(dir, dentry, SECCLASS_FILE);
    }
    
    static void selinux_inode_post_create(struct inode *dir, struct dentry *dentry, int mask)
    {
    	post_create(dir, dentry);
    }
    
    static int selinux_inode_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry)
    {
    	return may_link(dir, old_dentry, MAY_LINK);
    }
    
    static void selinux_inode_post_link(struct dentry *old_dentry, struct inode *inode, struct dentry *new_dentry)
    {
    	return;
    }
    
    static int selinux_inode_unlink(struct inode *dir, struct dentry *dentry)
    {
    	return may_link(dir, dentry, MAY_UNLINK);
    }
    
    static int selinux_inode_symlink(struct inode *dir, struct dentry *dentry, const char *name)
    {
    	return may_create(dir, dentry, SECCLASS_LNK_FILE);
    }
    
    static void selinux_inode_post_symlink(struct inode *dir, struct dentry *dentry, const char *name)
    {
    	post_create(dir, dentry);
    }
    
    static int selinux_inode_mkdir(struct inode *dir, struct dentry *dentry, int mask)
    {
    	return may_create(dir, dentry, SECCLASS_DIR);
    }
    
    static void selinux_inode_post_mkdir(struct inode *dir, struct dentry *dentry, int mask)
    {
    	post_create(dir, dentry);
    }
    
    static int selinux_inode_rmdir(struct inode *dir, struct dentry *dentry)
    {
    	return may_link(dir, dentry, MAY_RMDIR);
    }
    
    static int selinux_inode_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
    {
    	return may_create(dir, dentry, inode_mode_to_security_class(mode));
    }
    
    static void selinux_inode_post_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
    {
    	post_create(dir, dentry);
    }
    
    static int selinux_inode_rename(struct inode *old_inode, struct dentry *old_dentry, struct inode *new_inode, struct dentry *new_dentry)
    {
    	return may_rename(old_inode, old_dentry, new_inode, new_dentry);
    }
    
    static void selinux_inode_post_rename(struct inode *old_inode, struct dentry *old_dentry, struct inode *new_inode, struct dentry *new_dentry)
    {
    	return;
    }
    
    static int selinux_inode_readlink(struct dentry *dentry, char *name, int mask)
    {
    	return dentry_has_perm(current, dentry, FILE__READ, NULL);
    }
    
    static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
    {
    	return dentry_has_perm(current, dentry, FILE__READ, NULL);
    }
    
    static int selinux_inode_truncate(struct inode *inode)
    {
    	return inode_has_perm(current, inode, FILE__SETATTR | FILE__WRITE, NULL, NULL);
    }
    
    static int selinux_inode_permission(struct inode *inode, int mask)
    {
    	return inode_has_perm(current, inode, 
    			       file_mask_to_av(inode->i_mode, mask), NULL, NULL);
    }
    
    static int selinux_inode_revalidate(struct dentry *inode)
    {
    	return 0;
    }
    
    static int selinux_inode_setattr(struct dentry *dentry, struct iattr *iattr)
    {
    	return dentry_has_perm(current, dentry, FILE__SETATTR, NULL);
    }
    
    static void selinux_inode_attach_pathlabel(struct dentry *dentry, struct vfsmount *mnt)
    {
    	if (!dentry->d_inode) 
    		/* May be NULL since attach_pathlabel is always called,
    		   even after failed lookup/create operations. */
    		return;
    
    	inode_precondition(dentry->d_inode);
    }
    
    static int selinux_inode_stat(struct inode *inode)
    {
    	struct task_security_struct *tsec;
    	struct inode_security_struct *isec;
    	avc_audit_data_t ad;
    
    	/* This hook function would simply call inode_has_perm,
    	   but it also needs to save the inode SID to support
    	   stat_secure, so we just inline inode_has_perm. */
    
    	if (task_precondition(current))
    		return 0;
    	if (inode_precondition(inode))
    		return 0;
    	tsec = current->security;
    	isec = inode->i_security;
    
    	tsec->out_sid[0] = isec->sid;
    
    	AVC_AUDIT_DATA_INIT(&ad, FS);
    	ad.u.fs.inode = inode;
    	return avc_has_perm_ref_audit(tsec->sid, isec->sid, isec->sclass, 
    				      FILE__GETATTR, &isec->avcr, &ad);
    }
    
    
    /* file security operations */
    
    static int selinux_file_permission(struct file *file, int mask)
    {
    	struct inode *inode = file->f_dentry->d_inode;
    	return file_has_perm(current, file, 
    			     file_mask_to_av(inode->i_mode, mask));
    }
    
    static int selinux_file_alloc_security(struct file *file)
    {
    	if (ss_precondition())
    		return 0;
    
    	if (task_precondition(current))
    		return 0;
    
    	return file_alloc_security(current, file);
    }
    
    static void selinux_file_free_security(struct file *file)
    {
    	file_free_security(file);
    }
    
    static int selinux_file_llseek(struct file *file)
    {
    	return file_has_perm(current, file, 0 /* descriptor only */);
    }
    
    static int selinux_file_read(struct file *file)
    {
    	return file_has_perm(current, file, FILE__READ);
    }
    
    static int selinux_file_write(struct file *file)
    {
    	return file_has_perm(current, file, FILE__WRITE);
    }
    
    static int selinux_file_ioctl(struct file *file)
    {
    	return file_has_perm(current, file, FILE__IOCTL);
    }
    
    static int selinux_file_mmap(struct file *file, unsigned long prot,
    			     unsigned long flags)
    {
    	int error;
    	if (file) {
    		/* write access only matters if the mapping is shared */
    		if ((flags & MAP_TYPE) == MAP_SHARED && (prot & PROT_WRITE)) {
    			error = file_has_perm(current, file, FILE__WRITE);
    			if (error)
    				return error;
    		}
    
    		/* read access is always possible with a mapping */
    		error = file_has_perm(current, file, FILE__READ);
    		if (error)
    			return error;
    
    		if ((prot & PROT_EXEC)) {
    			error = file_has_perm(current, file, FILE__EXECUTE);
    			if (error)
    				return error;
    		}
    
    	}
    	return 0;
    }
    
    static int selinux_file_mprotect(struct vm_area_struct *vma, 
    				 unsigned long prot)
    {
    	return selinux_file_mmap(vma->vm_file, prot, vma->vm_flags);
    }
    
    static int selinux_file_lock(struct file *file)
    {
    	return file_has_perm(current, file, FILE__LOCK);
    }
    
    static int selinux_file_readv(struct file *file)
    {
    	return file_has_perm(current, file, FILE__READ);
    }
    
    static int selinux_file_writev(struct file *file)
    {
    	return file_has_perm(current, file, FILE__WRITE);
    }
    
    static int selinux_file_fcntl(struct file *file, unsigned int cmd,
    			      unsigned long arg)
    {
    	int err = 0;
    
    	switch (cmd) {
    	        case F_SETFL: 
    			if (!file->f_dentry || !file->f_dentry->d_inode) {
    				err = -EINVAL;
    				break;
    			}
    
    			if ((file->f_flags & O_APPEND) && !(arg & O_APPEND)) {
    				err = file_has_perm(current, file,FILE__WRITE);
    				if (err)
    					break;
    			}
    			/* fall through */
    	        case F_SETOWN:
    	        case F_SETSIG:
    	        case F_GETFL:
    	        case F_GETOWN:
    	        case F_GETSIG:
    			/* Just check FD__USE permission */
    			err = file_has_perm(current, file, 0);
    			break;
    		case F_GETLK:
    		case F_SETLK:
    	        case F_SETLKW: 
    			if (!file->f_dentry || !file->f_dentry->d_inode) {
    				err = -EINVAL;
    				break;
    			}
    			err = file_has_perm(current, file, FILE__LOCK);
    			break;
    	}
    
    	return err;
    }
    
    static int selinux_file_fcntl64(struct file *file, unsigned int cmd,
    				unsigned long arg)
    {
    	int err = 0;
    	switch (cmd) {
    		case F_GETLK64:
    		case F_SETLK64:
    	        case F_SETLKW64: 
    			if (!file->f_dentry || !file->f_dentry->d_inode) {
    				err = -EINVAL;
    				break;
    			}
    
    			err = file_has_perm(current, file, FILE__LOCK);
    			break;
    		default:
    			/*
    			 * Otherwise, just use 32bit version
    			 */
    			err = selinux_file_fcntl(file, cmd, arg);
    			break;
    	}
    
    	return err;
    }
    
    static int selinux_fown_alloc_security(struct fown_struct *fown)
    {
     	if (task_precondition(current)) 
     		return 0;
    
    	return fown_alloc_security(current, fown);
    }
    
    static void selinux_fown_free_security(struct fown_struct *fown)
    {
    	fown_free_security(fown);
    }
    
    static int selinux_fown_send_sigiotask(struct task_struct *tsk, 
    				       struct fown_struct *fown, 
    				       int fd, int reason)
    {
    	avc_audit_data_t ad;
    	access_vector_t perm;
    	struct task_security_struct *tsec;
    	struct fown_security_struct *fsec = fown->security;
    
    	if (task_precondition(tsk))
    		return 0;
    
    	tsec = tsk->security;
    
    	switch (fown->signum) {
    	case SIGCHLD:
    		perm = PROCESS__SIGCHLD;
    		break;
    	case SIGKILL:
    		perm = PROCESS__SIGKILL;
    		break;
    	case SIGSTOP:
    		perm = PROCESS__SIGSTOP;
    		break;
    	default:
    		perm = PROCESS__SIGNAL;
    		break;
    	}
    
    	return avc_has_perm_audit(fsec->sid, tsec->sid, 
    				  SECCLASS_PROCESS, perm, &ad);
    }
    
    /* task security operations */
    
    static int selinux_task_create(void)
    {
    	return task_has_perm(current, current, PROCESS__FORK);
    }
    
    static int selinux_task_alloc_security(struct task_struct *tsk)
    {
    	struct task_security_struct *tsec1, *tsec2;
    	int rc;
    
    	if (task_precondition(current))
    		return 0;
    	tsec1 = current->security;
    
    	rc = task_alloc_security(tsk);
    	if (rc)
    		return rc;
    	tsec2 = tsk->security;
    
    	tsec2->osid = tsec1->osid;
    	tsec2->sid = tsec1->sid;
    
    	return 0;
    }
    
    static void selinux_task_free_security(struct task_struct *tsk)
    {
    	task_free_security(tsk);
    }
    
    static int selinux_task_setuid(void)
    {
    	return task_has_capability(current,CAP_SETUID);
    }
    static int selinux_task_setgid(void)
    {
    	return task_has_capability(current,CAP_SETGID);
    }
    static int selinux_task_setgroups(void)
    {
    	return task_has_capability(current,CAP_SETGID);
    }
    static int selinux_task_setnice(struct task_struct *p, int nice)
    {
    	return task_has_perm(current,p, PROCESS__SETSCHED);
    }
    
    static int selinux_task_setrlimit(unsigned int resource)
    {
    	return task_has_capability(current,CAP_SYS_RESOURCE);
    }
    
    static int selinux_task_setscheduler(struct task_struct *p, int policy)
    {
    	return task_has_perm(current, p, PROCESS__SETSCHED);
    }
    
    static int selinux_task_kill(struct task_struct *p, struct siginfo *info, int sig)
    {
    	access_vector_t perm;
    
    	switch (sig) {
    	case SIGCHLD:
    		perm = PROCESS__SIGCHLD;
    		break;
    	case SIGKILL:
    		perm = PROCESS__SIGKILL;
    		break;
    	case SIGSTOP:
    		perm = PROCESS__SIGSTOP;
    		break;
    	default:
    		perm = PROCESS__SIGNAL;
    		break;
    	}
    
    	return task_has_perm(current, p, perm);
    }
    
    static int selinux_task_wait(struct task_struct *p)
    {
    	access_vector_t perm;
    
    	switch (p->exit_signal) {
    	case SIGCHLD:
    		perm = PROCESS__SIGCHLD;
    		break;
    	case SIGKILL:
    		perm = PROCESS__SIGKILL;
    		break;
    	case SIGSTOP:
    		perm = PROCESS__SIGSTOP;
    		break;
    	default:
    		perm = PROCESS__SIGNAL;
    		break;
    	}
    
    	return task_has_perm(p, current, perm);
    }
    
    static int selinux_task_set_label(char *filename)
    {
    	/* This hook is used by DTE for domain transitions.  
    	   The equivalent in SELinux is implemented using
    	   the binprm security operations. */
    	return 0;
    }
    
    static void selinux_task_reset_label(void)
    {
    	/* This hook is used by DTE to revert domains on an exec failure.
    	   Since SELinux does not change the SID until compute_creds,
    	   this hook is not necessary for SELinux. */
    	return;
    }
    
    /* module security operations */
    
    static int selinux_module_create_module(const char *name_user, size_t size)
    {
    	return task_has_capability(current,CAP_SYS_MODULE);
    }
    
    static int selinux_module_init_module(const char *name_user, struct module *mod_user)
    {
    	return task_has_capability(current,CAP_SYS_MODULE);
    }
    
    static int selinux_module_delete_module(const char *name_user)
    {
    	return task_has_capability(current,CAP_SYS_MODULE);
    }
    
    /* message queue security operations */
    
    static int selinux_msg_queue_create(key_t key)
    {
    	return 0;
    }
    
    static int selinux_msg_queue_permission(void)
    {
    	return 0;
    }
    
    static int selinux_msg_queue_setmaxqbytes(void)
    {
    	return 0;
    }
    
    static int selinux_msg_queue_setattr(void)
    {
    	return 0;
    }
    static int selinux_msg_queue_delete(void)
    {
    	return 0;
    }
    
    /* shared memory security operations */
    static int selinux_shm_create(key_t key)
    {
    	return 0;
    }
    static int selinux_shm_permission(void)
    {
    	return 0;
    }
    static int selinux_shm_setattr(void)
    {
    	return 0;
    }
    static int selinux_shm_delete(void)
    {
    	return 0;
    }
    
    /* module stacking operations */
    int selinux_register_security (struct security_operations *ops)
    {
    	return -EPERM;
    }
    
    int selinux_unregister_security (struct security_operations *ops)
    {
    	return -EPERM;
    }
    
    
    static struct binprm_security_ops selinux_bprm_ops = {
    	alloc_security:	selinux_bprm_alloc_security,
    	free_security:	selinux_bprm_free_security,
    	compute_creds:	selinux_bprm_compute_creds,
    };
    
    static struct super_block_security_ops selinux_sb_ops = {
    	alloc_security:	selinux_sb_alloc_security,
    	free_security:	selinux_sb_free_security,
    	statfs:         selinux_sb_statfs,
    };
    
    static struct inode_security_ops selinux_inode_ops = {
    	alloc_security:	selinux_inode_alloc_security,
    	free_security:	selinux_inode_free_security,
    	create:		selinux_inode_create,
    	post_create:	selinux_inode_post_create,
    	link:		selinux_inode_link,
    	post_link:	selinux_inode_post_link,
    	unlink:		selinux_inode_unlink,
    	symlink:	selinux_inode_symlink,
    	post_symlink:	selinux_inode_post_symlink,
    	mkdir:		selinux_inode_mkdir,
    	post_mkdir:	selinux_inode_post_mkdir,
    	rmdir:		selinux_inode_rmdir,
    	mknod:		selinux_inode_mknod,
    	post_mknod:	selinux_inode_post_mknod,
    	rename:		selinux_inode_rename,
    	post_rename:	selinux_inode_post_rename,
    	readlink:	selinux_inode_readlink,
    	follow_link:	selinux_inode_follow_link,
    	truncate:	selinux_inode_truncate,
    	permission:	selinux_inode_permission,
    	revalidate:	selinux_inode_revalidate,
    	setattr:	selinux_inode_setattr,
    	attach_pathlabel:selinux_inode_attach_pathlabel,
    	stat:           selinux_inode_stat,
    };
    
    static struct file_security_ops	selinux_file_ops = {
    	permission:	selinux_file_permission,
    	alloc_security:	selinux_file_alloc_security,
    	free_security:	selinux_file_free_security,
    	llseek:		selinux_file_llseek,
    	read:		selinux_file_read,
    	write:		selinux_file_write,
    	ioctl:		selinux_file_ioctl,
    	mmap:		selinux_file_mmap,
    	mprotect:	selinux_file_mprotect,
    	lock:		selinux_file_lock,
    	readv:		selinux_file_readv,
    	writev:		selinux_file_writev,
    	fcntl:		selinux_file_fcntl,
    	fcntl64:	selinux_file_fcntl64,
    };
    
    static struct fown_security_ops	selinux_fown_ops = {
    	alloc_security:	selinux_fown_alloc_security,
    	free_security:	selinux_fown_free_security,
    	send_sigiotask:	selinux_fown_send_sigiotask,
    };
    
    static struct task_security_ops	selinux_task_ops = {
    	create:		selinux_task_create,
    	alloc_security:	selinux_task_alloc_security,
    	free_security:	selinux_task_free_security,
    	setuid:		selinux_task_setuid,
    	setgid:		selinux_task_setgid,
    	setgroups:	selinux_task_setgroups,
    	setnice:	selinux_task_setnice,
    	setrlimit:	selinux_task_setrlimit,
    	setscheduler:	selinux_task_setscheduler,
    	kill:		selinux_task_kill,
    	wait:		selinux_task_wait,
    	set_label:	selinux_task_set_label,
    	reset_label:	selinux_task_reset_label,
    };
    
    static struct socket_security_ops selinux_socket_ops = {};
    
    static struct module_security_ops selinux_module_ops = {
    	create_module:	selinux_module_create_module,
    	init_module:	selinux_module_init_module,
    	delete_module:	selinux_module_delete_module,
    
    };
    
    static struct msg_queue_security_ops selinux_msg_queue_ops = {
    	create:		selinux_msg_queue_create,
    	permission:	selinux_msg_queue_permission,
    	setmaxqbytes:	selinux_msg_queue_setmaxqbytes,
    	setattr:	selinux_msg_queue_setattr,
    	delete:		selinux_msg_queue_delete,
    };
    
    static struct shm_security_ops selinux_shm_ops = {
    	create:		selinux_shm_create,
    	permission:	selinux_shm_permission,
    	setattr:	selinux_shm_setattr,
    	delete:		selinux_shm_delete,
    };
    
    struct security_operations selinux_ops = {
            version:                SECURITY_INTERFACE_VERSION,
    
    	sethostname:		selinux_sethostname,
    	setdomainname:		selinux_setdomainname,
    	reboot:			selinux_reboot,
    	mount:			selinux_mount,
    	add_vfsmnt:             selinux_add_vfsmnt,
    	umount:			selinux_umount,
    	umount_close:		selinux_umount_close,
    	umount_busy:		selinux_umount_busy,
    	remount:		selinux_remount,
    	post_remount:		selinux_post_remount,
    	ioperm:			selinux_ioperm,
    	iopl:			selinux_iopl,
    	ptrace:			selinux_ptrace,
    	setcapability:		selinux_setcapablity,
    	acct:			selinux_acct,
    	capable:                selinux_capable,
    
    	bprm_ops:		&selinux_bprm_ops,
    	sb_ops:                 &selinux_sb_ops,
    	inode_ops:		&selinux_inode_ops,
    	file_ops:		&selinux_file_ops,
    	fown_ops:		&selinux_fown_ops,
    	task_ops:		&selinux_task_ops,
    	socket_ops:		&selinux_socket_ops,
    	module_ops:		&selinux_module_ops,
    	msg_queue_ops:		&selinux_msg_queue_ops,
    	shm_ops:		&selinux_shm_ops,
    
    	register_security:	&selinux_register_security,
    	unregister_security:	&selinux_unregister_security,
    };
    
    extern void *sys_call_table[];
    extern long sys_ni_syscall(void);
    
    static int __init selinux_plug_init (void)
    {
    	if (sys_call_table[__NR_lsm] != sys_ni_syscall) {
    		printk (KERN_INFO "Unable to register lsm syscall\n");
    		return -EINVAL;
    	}
    	sys_call_table[__NR_lsm] = sys_selinux;
    
    	if (sys_call_table[__NR_execve_secure] != sys_ni_syscall) {
    		printk (KERN_INFO "Unable to register execve_secure syscall\n");
    		return -EINVAL;
    	}
    	sys_call_table[__NR_execve_secure] = sys_execve_secure;
    
    
    	avc_init();
    
    	if (register_security (&selinux_ops)) {
    		printk (KERN_INFO "Failure registering SELinux with the kernel\n");
    		return -EINVAL;
    	}
    
    	printk (KERN_INFO "SELinux:  module inserted\n");
    
    	return 0;
    }
    
    
    static void __exit selinux_plug_exit (void)
    {
    	struct list_head *p;
    
    	sys_call_table[__NR_lsm] = NULL;
    	sys_call_table[__NR_execve_secure] = NULL;
    
    	/* remove ourselves from the security framework */
    	if (unregister_security (&selinux_ops)) {
    		printk (KERN_INFO "Failure unregistering SELinux with the kernel\n");
    	}
    
    	/* Deallocate all of the security blobs created by this module
    	   and clear the security fields in the corresponding objects. */
    
    	p = task_security_head.next; 
    	while (p != &task_security_head) {
    		struct task_security_struct *tsec = list_entry(p, struct task_security_struct, list);
    		p = p->next;
    		task_free_security(tsec->task);
    	}
    
    	p = inode_security_head.next; 
    	while (p != &inode_security_head) {
    		struct inode_security_struct *isec = list_entry(p, struct inode_security_struct, list);
    		p = p->next;
    		inode_free_security(isec->inode);
    	}
    
    	p = file_security_head.next; 
    	while (p != &file_security_head) {
    		struct file_security_struct *fsec = list_entry(p, struct file_security_struct, list);
    		p = p->next;
    		file_free_security(fsec->file);
    	}
    
    	p = superblock_security_head.next; 
    	while (p != &superblock_security_head) {
    		struct superblock_security_struct *sbsec = list_entry(p, struct superblock_security_struct, list);
    		p = p->next;
    		superblock_free_security(sbsec->sb);
    	}
    
    	/* XXX:  Need AVC and security server interfaces for cleaning up. */
    		
    	printk (KERN_INFO "SELinux:  module removed\n");
    }
    
    module_init (selinux_plug_init);
    module_exit (selinux_plug_exit);
    
    EXPORT_SYMBOL(selinux_ops);
    
    
    _______________________________________________
    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 : Tue Jun 05 2001 - 08:24:26 PDT