Commit 573429e3 authored by Andrew Morton's avatar Andrew Morton Committed by Linus Torvalds

[PATCH] SELinux inode security init

From: Stephen Smalley <sds@epoch.ncsc.mil>

This patch reworks the SELinux module code that handles inodes initialized
before the policy is initially loaded to also cover the case where a pseudo
filesystem such as selinuxfs or nfsd directly populate themselves.

The list of inode security structures is split into per-superblock lists
associated with each superblock security structure, and the initialization
is performed by superblock_doinit.
parent b99f2adc
...@@ -84,9 +84,6 @@ static struct security_operations *secondary_ops = NULL; ...@@ -84,9 +84,6 @@ static struct security_operations *secondary_ops = NULL;
/* Lists of inode and superblock security structures initialized /* Lists of inode and superblock security structures initialized
before the policy was loaded. */ before the policy was loaded. */
static LIST_HEAD(inode_security_head);
static spinlock_t inode_security_lock = SPIN_LOCK_UNLOCKED;
static LIST_HEAD(superblock_security_head); static LIST_HEAD(superblock_security_head);
static spinlock_t sb_security_lock = SPIN_LOCK_UNLOCKED; static spinlock_t sb_security_lock = SPIN_LOCK_UNLOCKED;
...@@ -148,14 +145,15 @@ static int inode_alloc_security(struct inode *inode) ...@@ -148,14 +145,15 @@ static int inode_alloc_security(struct inode *inode)
static void inode_free_security(struct inode *inode) static void inode_free_security(struct inode *inode)
{ {
struct inode_security_struct *isec = inode->i_security; struct inode_security_struct *isec = inode->i_security;
struct superblock_security_struct *sbsec = inode->i_sb->s_security;
if (!isec || isec->magic != SELINUX_MAGIC) if (!isec || isec->magic != SELINUX_MAGIC)
return; return;
spin_lock(&inode_security_lock); spin_lock(&sbsec->isec_lock);
if (!list_empty(&isec->list)) if (!list_empty(&isec->list))
list_del_init(&isec->list); list_del_init(&isec->list);
spin_unlock(&inode_security_lock); spin_unlock(&sbsec->isec_lock);
inode->i_security = NULL; inode->i_security = NULL;
kfree(isec); kfree(isec);
...@@ -207,6 +205,8 @@ static int superblock_alloc_security(struct super_block *sb) ...@@ -207,6 +205,8 @@ static int superblock_alloc_security(struct super_block *sb)
memset(sbsec, 0, sizeof(struct superblock_security_struct)); memset(sbsec, 0, sizeof(struct superblock_security_struct));
init_MUTEX(&sbsec->sem); init_MUTEX(&sbsec->sem);
INIT_LIST_HEAD(&sbsec->list); INIT_LIST_HEAD(&sbsec->list);
INIT_LIST_HEAD(&sbsec->isec_head);
spin_lock_init(&sbsec->isec_lock);
sbsec->magic = SELINUX_MAGIC; sbsec->magic = SELINUX_MAGIC;
sbsec->sb = sb; sbsec->sb = sb;
sbsec->sid = SECINITSID_UNLABELED; sbsec->sid = SECINITSID_UNLABELED;
...@@ -319,6 +319,29 @@ static int superblock_doinit(struct super_block *sb) ...@@ -319,6 +319,29 @@ static int superblock_doinit(struct super_block *sb)
/* Initialize the root inode. */ /* Initialize the root inode. */
rc = inode_doinit_with_dentry(sb->s_root->d_inode, sb->s_root); rc = inode_doinit_with_dentry(sb->s_root->d_inode, sb->s_root);
/* Initialize any other inodes associated with the superblock, e.g.
inodes created prior to initial policy load or inodes created
during get_sb by a pseudo filesystem that directly
populates itself. */
spin_lock(&sbsec->isec_lock);
next_inode:
if (!list_empty(&sbsec->isec_head)) {
struct inode_security_struct *isec =
list_entry(sbsec->isec_head.next,
struct inode_security_struct, list);
struct inode *inode = isec->inode;
spin_unlock(&sbsec->isec_lock);
inode = igrab(inode);
if (inode) {
inode_doinit(inode);
iput(inode);
}
spin_lock(&sbsec->isec_lock);
list_del_init(&isec->list);
goto next_inode;
}
spin_unlock(&sbsec->isec_lock);
out: out:
up(&sbsec->sem); up(&sbsec->sem);
return rc; return rc;
...@@ -441,14 +464,14 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent ...@@ -441,14 +464,14 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
goto out; goto out;
sbsec = inode->i_sb->s_security; sbsec = inode->i_sb->s_security;
if (!sbsec || !sbsec->initialized) { if (!sbsec->initialized) {
/* Defer initialization until selinux_complete_init, /* Defer initialization until selinux_complete_init,
after the initial policy is loaded and the security after the initial policy is loaded and the security
server is ready to handle calls. */ server is ready to handle calls. */
spin_lock(&inode_security_lock); spin_lock(&sbsec->isec_lock);
if (list_empty(&isec->list)) if (list_empty(&isec->list))
list_add(&isec->list, &inode_security_head); list_add(&isec->list, &sbsec->isec_head);
spin_unlock(&inode_security_lock); spin_unlock(&sbsec->isec_lock);
goto out; goto out;
} }
...@@ -3376,27 +3399,6 @@ void selinux_complete_init(void) ...@@ -3376,27 +3399,6 @@ void selinux_complete_init(void)
goto next_sb; goto next_sb;
} }
spin_unlock(&sb_security_lock); spin_unlock(&sb_security_lock);
/* Set up any inodes initialized prior to the policy load. */
printk(KERN_INFO "SELinux: Setting up existing inodes.\n");
spin_lock(&inode_security_lock);
next_inode:
if (!list_empty(&inode_security_head)) {
struct inode_security_struct *isec =
list_entry(inode_security_head.next,
struct inode_security_struct, list);
struct inode *inode = isec->inode;
spin_unlock(&inode_security_lock);
inode = igrab(inode);
if (inode) {
inode_doinit(inode);
iput(inode);
}
spin_lock(&inode_security_lock);
list_del_init(&isec->list);
goto next_inode;
}
spin_unlock(&inode_security_lock);
} }
/* SELinux requires early initialization in order to label /* SELinux requires early initialization in order to label
......
...@@ -66,6 +66,8 @@ struct superblock_security_struct { ...@@ -66,6 +66,8 @@ struct superblock_security_struct {
unsigned char initialized; /* initialization flag */ unsigned char initialized; /* initialization flag */
unsigned char proc; /* proc fs */ unsigned char proc; /* proc fs */
struct semaphore sem; struct semaphore sem;
struct list_head isec_head;
spinlock_t isec_lock;
}; };
struct msg_security_struct { struct msg_security_struct {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment