Re: sys_setpriority error

From: Stephen Smalley (sdsat_private)
Date: Thu May 31 2001 - 07:15:56 PDT

  • Next message: Greg KH: "Re: 2001-05-27 patch against 2.4.5"

    > The dummy functions don't really provide much in the way of security.  They
    > fall some where between DAC and everybody is root.  Stephen Smalley has
    > suggested re-evaluating the dummy code and adding root checks to align with
    > DAC.  I am inclined to fix this in dummy_setnice rather than
    > sys_setpriority.
    
    This doesn't fix the setpriority problem, as others have mentioned.
    However, it does need to be addressed in the dummy code.  I also had to
    address this issue in the SELinux module code so that a LSM kernel with
    the SELinux module provides both the traditional root checks and the
    SELinux checks.  See the root checks in the task_has_capability() function
    in the attached file.  This function is called by each of the hooks that 
    corresponds to a capability check (with a few exceptions due to confusion
    over whether the hook is supposed to be "authoritative" or "override").
    Likewise, each of the dummy hooks that corresponds to a capability check
    should call a function to perform these root checks so that a kernel
    built without any security modules provides reasonable behavior.
    
    Also, the dummy code either needs to implement traditional setuid/setgid
    program handling in the compute_creds hook (as in both the capabilities
    plug and the SELinux module), or we need to restore the base kernel
    compute_creds function with that processing (in which case it would
    call the hook, and the current hook calls would be restored to
    calling the base kernel function), as I've previously suggested.
    As the LSM patch currently exists, setuid/setgid program execution
    doesn't work when no modules are enabled.
    
    --
    Stephen D. Smalley, NAI Labs
    ssmalleyat_private
    
    
    
    
    
    
    
    
    /*
     *  NSA Security-Enhanced Linux plug
     *
     *  Author:  Stephen Smalley, NAI Labs, <sdsat_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/mm.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 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);
    }
    
    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. */
    static 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. */
    static 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. */
    static 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. */
    static 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 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;
    
    	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;
    
    	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;
    
    	/* 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;
    
    	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)
    {
    	return superblock_has_perm(current, sb, FILESYSTEM__GETATTR, NULL);
    }
    
    /* 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)
    {
    	return inode_has_perm(current, inode, FILE__GETATTR, NULL, NULL);
    }
    
    
    /* 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)
    {
    	/* XXX:  Need the flags (is it shared or private?) and protection */
    	return 0;
    }
    
    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);
    }
    
    /* 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_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,
    	lock:		selinux_file_lock,
    	readv:		selinux_file_readv,
    	writev:		selinux_file_writev,
    };
    
    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,
    	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,
    	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,
    };
    
    static int __init selinux_plug_init (void)
    {
    	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;
    
    	/* 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 : Thu May 31 2001 - 07:23:12 PDT