@@ -346,27 +346,7 @@ static struct inode_security_struct *backing_inode_security(struct dentry *dentr
static void inode_free_security(struct inode *inode)
{
- struct inode_security_struct *isec = selinux_inode(inode);
- struct superblock_security_struct *sbsec;
-
- if (!isec)
- return;
- sbsec = selinux_superblock(inode->i_sb);
- /*
- * As not all inode security structures are in a list, we check for
- * empty list outside of the lock to make sure that we won't waste
- * time taking a lock doing nothing.
- *
- * The list_del_init() function can be safely called more than once.
- * It should not be possible for this function to be called with
- * concurrent list_add(), but for better safety against future changes
- * in the code, we use list_empty_careful() here.
- */
- if (!list_empty_careful(&isec->list)) {
- spin_lock(&sbsec->isec_lock);
- list_del_init(&isec->list);
- spin_unlock(&sbsec->isec_lock);
- }
+ /* NOTHING TO DO NOW */
}
struct selinux_mnt_opts {
@@ -641,27 +621,6 @@ static int sb_finish_set_opts(struct super_block *sb)
/* Initialize the root inode. */
rc = inode_doinit_with_dentry(root_inode, 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);
- while (!list_empty(&sbsec->isec_head)) {
- struct inode_security_struct *isec =
- list_first_entry(&sbsec->isec_head,
- struct inode_security_struct, list);
- struct inode *inode = isec->inode;
- list_del_init(&isec->list);
- spin_unlock(&sbsec->isec_lock);
- inode = igrab(inode);
- if (inode) {
- if (!IS_PRIVATE(inode))
- inode_doinit_with_dentry(inode, NULL);
- iput(inode);
- }
- spin_lock(&sbsec->isec_lock);
- }
- spin_unlock(&sbsec->isec_lock);
out:
return rc;
}
@@ -1602,13 +1561,6 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
sbsec = selinux_superblock(inode->i_sb);
if (!(sbsec->flags & SE_SBINITIALIZED)) {
- /* Defer initialization until selinux_complete_init,
- after the initial policy is loaded and the security
- server is ready to handle calls. */
- spin_lock(&sbsec->isec_lock);
- if (list_empty(&isec->list))
- list_add(&isec->list, &sbsec->isec_head);
- spin_unlock(&sbsec->isec_lock);
return 0;
}
@@ -2786,8 +2738,6 @@ sbsec_alloc(struct superblock_security_head *sbsech)
if (!sbsec)
return NULL;
mutex_init(&sbsec->lock);
- INIT_LIST_HEAD(&sbsec->isec_head);
- spin_lock_init(&sbsec->isec_lock);
sbsec->sbsech = sbsech;
sbsec->sid = SECINITSID_UNLABELED;
sbsec->def_sid = SECINITSID_FILE;
@@ -3133,7 +3083,6 @@ static int selinux_inode_alloc_security(struct inode *inode)
u32 sid = current_sid();
spin_lock_init(&isec->lock);
- INIT_LIST_HEAD(&isec->list);
isec->inode = inode;
isec->sid = SECINITSID_UNLABELED;
isec->sclass = SECCLASS_FILE;
@@ -7654,6 +7603,8 @@ void __put_selinux_state(struct selinux_state *state)
schedule_work(&state->work);
}
+extern struct mutex selinuxfs_mutex;
+
static __init int selinux_init(void)
{
pr_info("SELinux: Initializing.\n");
@@ -7664,6 +7615,7 @@ static __init int selinux_init(void)
init_selinux_state->checkreqprot = selinux_checkreqprot_boot;
spin_lock_init(&sb_state_lock);
+ mutex_init(&selinuxfs_mutex);
/* Set the security state for the initial task. */
cred_init_security();
@@ -36,7 +36,6 @@ enum label_initialized {
struct inode_security_struct {
struct inode *inode; /* back pointer to inode object */
- struct list_head list; /* list of inode_security_struct */
u32 task_sid; /* SID of creating task */
u32 sid; /* SID of this object */
u16 sclass; /* security class of this object */
@@ -43,6 +43,8 @@
#include "objsec.h"
#include "conditional.h"
+struct mutex selinuxfs_mutex; /* GLobal mutex for all selinuxfs access */
+
enum sel_inos {
SEL_ROOT_INO = 2,
SEL_LOAD, /* load policy */
@@ -102,15 +104,16 @@ static void selinux_fs_info_free(struct super_block *sb)
struct selinux_fs_info *fsi = sb->s_fs_info;
int i;
+ sb->s_fs_info = NULL;
if (fsi) {
put_selinux_state(fsi->state);
for (i = 0; i < fsi->bool_num; i++)
kfree(fsi->bool_pending_names[i]);
kfree(fsi->bool_pending_names);
kfree(fsi->bool_pending_values);
+ kfree(fsi);
}
- kfree(sb->s_fs_info);
- sb->s_fs_info = NULL;
+
}
#define SEL_INITCON_INO_OFFSET 0x01000000
@@ -131,6 +134,9 @@ static ssize_t sel_read_enforce(struct file *filp, char __user *buf,
char tmpbuf[TMPBUFLEN];
ssize_t length;
+ if (fsi == NULL)
+ return -EINVAL;
+
length = scnprintf(tmpbuf, TMPBUFLEN, "%d",
enforcing_enabled(fsi->state));
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
@@ -142,11 +148,15 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
{
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
- struct selinux_state *state = fsi->state;
+ struct selinux_state *state;
char *page = NULL;
ssize_t length;
int old_value, new_value;
+ if (fsi == NULL)
+ return -EINVAL;
+
+ state = fsi->state;
if (state != current_selinux_state)
return -EPERM;
@@ -157,9 +167,13 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
if (*ppos != 0)
return -EINVAL;
+ mutex_lock(&selinuxfs_mutex);
+
page = memdup_user_nul(buf, count);
- if (IS_ERR(page))
- return PTR_ERR(page);
+ if (IS_ERR(page)) {
+ length = PTR_ERR(page);
+ goto out_unlock;
+ }
length = -EINVAL;
if (sscanf(page, "%d", &new_value) != 1)
@@ -192,6 +206,8 @@ static ssize_t sel_write_enforce(struct file *file, const char __user *buf,
length = count;
out:
kfree(page);
+out_unlock:
+ mutex_unlock(&selinuxfs_mutex);
return length;
}
#else
@@ -208,11 +224,17 @@ static ssize_t sel_read_handle_unknown(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
- struct selinux_state *state = fsi->state;
+ struct selinux_state *state;
char tmpbuf[TMPBUFLEN];
ssize_t length;
ino_t ino = file_inode(filp)->i_ino;
- int handle_unknown = (ino == SEL_REJECT_UNKNOWN) ?
+ int handle_unknown;
+
+ if (fsi == NULL)
+ return -EINVAL;
+
+ state = fsi->state;
+ handle_unknown = (ino == SEL_REJECT_UNKNOWN) ?
security_get_reject_unknown(state) :
!security_get_allow_unknown(state);
@@ -228,7 +250,12 @@ static const struct file_operations sel_handle_unknown_ops = {
static int sel_open_handle_status(struct inode *inode, struct file *filp)
{
struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
- struct page *status = selinux_kernel_status_page(fsi->state);
+ struct page *status;
+
+ if (fsi == NULL)
+ return -EINVAL;
+
+ status = selinux_kernel_status_page(fsi->state);
if (!status)
return -ENOMEM;
@@ -290,6 +317,9 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf,
int new_value;
int enforcing;
+ if (fsi == NULL)
+ return -EINVAL;
+
if (fsi->state != current_selinux_state)
return -EPERM;
@@ -316,8 +346,10 @@ static ssize_t sel_write_disable(struct file *file, const char __user *buf,
goto out;
if (new_value) {
+ mutex_lock(&selinuxfs_mutex);
enforcing = enforcing_enabled(fsi->state);
length = selinux_disable(fsi->state);
+ mutex_unlock(&selinuxfs_mutex);
if (length)
goto out;
audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_STATUS,
@@ -347,31 +379,33 @@ static ssize_t sel_write_unshare(struct file *file, const char __user *buf,
{
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
- struct selinux_state *state = fsi->state;
+ struct selinux_state *state;
struct cred *cred;
struct task_security_struct *tsec;
char *suffix, *p;
ssize_t len;
+ if (fsi == NULL)
+ return -EINVAL;
+
+ state = fsi->state;
if (state != current_selinux_state)
return -EPERM;
- if (count >= PAGE_SIZE)
- return -ENOMEM;
-
/* No partial writes. */
if (*ppos != 0)
return -EINVAL;
+ if ((count >= PAGE_SIZE) ||
+ (count > XATTR_NAME_MAX - sizeof(XATTR_NAME_SELINUX) - 2))
+ return -EINVAL;
+
len = avc_has_perm(current_selinux_state, current_sid(),
SECINITSID_SECURITY, SECCLASS_SECURITY,
SECURITY__UNSHARE, NULL);
if (len)
return len;
- if (count > XATTR_NAME_MAX - sizeof(XATTR_NAME_SELINUX) - 2)
- return -EINVAL;
-
suffix = memdup_user_nul(buf, count);
if (IS_ERR(suffix))
return PTR_ERR(suffix);
@@ -423,14 +457,19 @@ static ssize_t sel_read_unshare(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
- struct selinux_state *state = fsi->state;
+ struct selinux_state *state;
size_t slen = sizeof(XATTR_SELINUX_SUFFIX);
+ if (fsi == NULL)
+ return -EINVAL;
+
+ state = fsi->state;
+
if (state->id != current_selinux_state->id)
return -EPERM;
return simple_read_from_buffer(buf, count, ppos, state->xattr_name + slen,
- strlen(state->xattr_name + slen));
+ strlen(state->xattr_name + slen));
}
static const struct file_operations sel_unshare_ops = {
@@ -480,6 +519,9 @@ static ssize_t sel_read_mls(struct file *filp, char __user *buf,
char tmpbuf[TMPBUFLEN];
ssize_t length;
+ if (fsi == NULL)
+ return -EINVAL;
+
length = scnprintf(tmpbuf, TMPBUFLEN, "%d",
security_mls_enabled(fsi->state));
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
@@ -498,13 +540,17 @@ struct policy_load_memory {
static int sel_open_policy(struct inode *inode, struct file *filp)
{
struct selinux_fs_info *fsi = inode->i_sb->s_fs_info;
- struct selinux_state *state = fsi->state;
+ struct selinux_state *state;
struct policy_load_memory *plm = NULL;
int rc;
+ if (fsi == NULL)
+ return -EINVAL;
+
+ state = fsi->state;
BUG_ON(filp->private_data);
- mutex_lock(&fsi->state->policy_mutex);
+ mutex_lock(&selinuxfs_mutex);
rc = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
@@ -535,11 +581,11 @@ static int sel_open_policy(struct inode *inode, struct file *filp)
filp->private_data = plm;
- mutex_unlock(&fsi->state->policy_mutex);
+ mutex_unlock(&selinuxfs_mutex);
return 0;
err:
- mutex_unlock(&fsi->state->policy_mutex);
+ mutex_unlock(&selinuxfs_mutex);
if (plm)
vfree(plm->data);
@@ -552,6 +598,9 @@ static int sel_release_policy(struct inode *inode, struct file *filp)
struct selinux_fs_info *fsi = inode->i_sb->s_fs_info;
struct policy_load_memory *plm = filp->private_data;
+ if (fsi == NULL)
+ return -EINVAL;
+
BUG_ON(!plm);
fsi->policy_opened = 0;
@@ -726,10 +775,13 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
ssize_t length;
void *data = NULL;
+ if (fsi == NULL)
+ return -EINVAL;
+
if (fsi->state != current_selinux_state)
return -EPERM;
- mutex_lock(&fsi->state->policy_mutex);
+ mutex_lock(&selinuxfs_mutex);
length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
@@ -773,7 +825,7 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
from_kuid(&init_user_ns, audit_get_loginuid(current)),
audit_get_sessionid(current));
out:
- mutex_unlock(&fsi->state->policy_mutex);
+ mutex_unlock(&selinuxfs_mutex);
vfree(data);
return length;
}
@@ -786,16 +838,20 @@ static const struct file_operations sel_load_ops = {
static ssize_t sel_write_context(struct file *file, char *buf, size_t size)
{
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
- struct selinux_state *state = fsi->state;
+ struct selinux_state *state;
char *canon = NULL;
u32 sid, len;
ssize_t length;
+ if (fsi == NULL)
+ return -EINVAL;
+
+ state = fsi->state;
length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__CHECK_CONTEXT, NULL);
if (length)
- goto out;
+ return length;
length = security_context_to_sid(state, buf, size, &sid, GFP_KERNEL);
if (length)
@@ -826,6 +882,9 @@ static ssize_t sel_read_checkreqprot(struct file *filp, char __user *buf,
char tmpbuf[TMPBUFLEN];
ssize_t length;
+ if (fsi == NULL)
+ return -EINVAL;
+
length = scnprintf(tmpbuf, TMPBUFLEN, "%u", fsi->state->checkreqprot);
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
}
@@ -838,6 +897,9 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
ssize_t length;
unsigned int new_value;
+ if (fsi == NULL)
+ return -EINVAL;
+
if (fsi->state != current_selinux_state)
return -EPERM;
@@ -855,9 +917,13 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
if (*ppos != 0)
return -EINVAL;
+ mutex_lock(&selinuxfs_mutex);
+
page = memdup_user_nul(buf, count);
- if (IS_ERR(page))
- return PTR_ERR(page);
+ if (IS_ERR(page)) {
+ length = PTR_ERR(page);
+ goto out_unlock;
+ }
length = -EINVAL;
if (sscanf(page, "%u", &new_value) != 1)
@@ -875,6 +941,8 @@ static ssize_t sel_write_checkreqprot(struct file *file, const char __user *buf,
length = count;
out:
kfree(page);
+out_unlock:
+ mutex_unlock(&selinuxfs_mutex);
return length;
}
static const struct file_operations sel_checkreqprot_ops = {
@@ -888,13 +956,17 @@ static ssize_t sel_write_validatetrans(struct file *file,
size_t count, loff_t *ppos)
{
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
- struct selinux_state *state = fsi->state;
+ struct selinux_state *state;
char *oldcon = NULL, *newcon = NULL, *taskcon = NULL;
char *req = NULL;
u32 osid, nsid, tsid;
u16 tclass;
int rc;
+ if (fsi == NULL)
+ return -EINVAL;
+
+ state = fsi->state;
if (state != current_selinux_state)
return -EPERM;
@@ -902,16 +974,16 @@ static ssize_t sel_write_validatetrans(struct file *file,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__VALIDATE_TRANS, NULL);
if (rc)
- goto out;
+ return rc;
rc = -ENOMEM;
if (count >= PAGE_SIZE)
- goto out;
+ return rc;
/* No partial writes. */
rc = -EINVAL;
if (*ppos != 0)
- goto out;
+ return rc;
req = memdup_user_nul(buf, count);
if (IS_ERR(req)) {
@@ -953,10 +1025,10 @@ static ssize_t sel_write_validatetrans(struct file *file,
if (!rc)
rc = count;
out:
- kfree(req);
- kfree(oldcon);
- kfree(newcon);
kfree(taskcon);
+ kfree(newcon);
+ kfree(oldcon);
+ kfree(req);
return rc;
}
@@ -990,6 +1062,9 @@ static ssize_t selinux_transaction_write(struct file *file, const char __user *b
char *data;
ssize_t rv;
+ if (fsi == NULL)
+ return -EINVAL;
+
if (fsi->state != current_selinux_state)
return -EPERM;
@@ -1005,6 +1080,7 @@ static ssize_t selinux_transaction_write(struct file *file, const char __user *b
simple_transaction_set(file, rv);
rv = size;
}
+
return rv;
}
@@ -1024,18 +1100,23 @@ static const struct file_operations transaction_ops = {
static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
{
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
- struct selinux_state *state = fsi->state;
+ struct selinux_state *state;
char *scon = NULL, *tcon = NULL;
u32 ssid, tsid;
u16 tclass;
struct av_decision avd;
ssize_t length;
+ if (fsi == NULL)
+ return -EINVAL;
+
+ state = fsi->state;
length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_AV, NULL);
if (length)
- goto out;
+ return length;
+
length = -ENOMEM;
scon = kzalloc(size + 1, GFP_KERNEL);
@@ -1075,7 +1156,7 @@ static ssize_t sel_write_access(struct file *file, char *buf, size_t size)
static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
{
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
- struct selinux_state *state = fsi->state;
+ struct selinux_state *state;
char *scon = NULL, *tcon = NULL;
char *namebuf = NULL, *objname = NULL;
u32 ssid, tsid, newsid;
@@ -1085,6 +1166,10 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
u32 len;
int nargs;
+ if (fsi == NULL)
+ return -EINVAL;
+ state = fsi->state;
+
length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_CREATE,
@@ -1179,7 +1264,7 @@ static ssize_t sel_write_create(struct file *file, char *buf, size_t size)
static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
{
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
- struct selinux_state *state = fsi->state;
+ struct selinux_state *state;
char *scon = NULL, *tcon = NULL;
u32 ssid, tsid, newsid;
u16 tclass;
@@ -1187,6 +1272,10 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
char *newcon = NULL;
u32 len;
+ if (fsi == NULL)
+ return -EINVAL;
+ state = fsi->state;
+
length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_RELABEL,
@@ -1240,7 +1329,7 @@ static ssize_t sel_write_relabel(struct file *file, char *buf, size_t size)
static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
{
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
- struct selinux_state *state = fsi->state;
+ struct selinux_state *state;
char *con = NULL, *user = NULL, *ptr;
u32 sid, *sids = NULL;
ssize_t length;
@@ -1248,6 +1337,10 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
int i, rc;
u32 len, nsids;
+ if (fsi == NULL)
+ return -EINVAL;
+ state = fsi->state;
+
length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_USER,
@@ -1305,7 +1398,7 @@ static ssize_t sel_write_user(struct file *file, char *buf, size_t size)
static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
{
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
- struct selinux_state *state = fsi->state;
+ struct selinux_state *state;
char *scon = NULL, *tcon = NULL;
u32 ssid, tsid, newsid;
u16 tclass;
@@ -1313,6 +1406,10 @@ static ssize_t sel_write_member(struct file *file, char *buf, size_t size)
char *newcon = NULL;
u32 len;
+ if (fsi == NULL)
+ return -EINVAL;
+ state = fsi->state;
+
length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
SECCLASS_SECURITY, SECURITY__COMPUTE_MEMBER,
@@ -1388,7 +1485,10 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf,
unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK;
const char *name = filep->f_path.dentry->d_name.name;
- mutex_lock(&fsi->state->policy_mutex);
+ if (fsi == NULL)
+ return -EINVAL;
+
+ mutex_lock(&selinuxfs_mutex);
ret = -EINVAL;
if (index >= fsi->bool_num || strcmp(name,
@@ -1407,14 +1507,14 @@ static ssize_t sel_read_bool(struct file *filep, char __user *buf,
}
length = scnprintf(page, PAGE_SIZE, "%d %d", cur_enforcing,
fsi->bool_pending_values[index]);
- mutex_unlock(&fsi->state->policy_mutex);
+ mutex_unlock(&selinuxfs_mutex);
ret = simple_read_from_buffer(buf, count, ppos, page, length);
out_free:
free_page((unsigned long)page);
return ret;
out_unlock:
- mutex_unlock(&fsi->state->policy_mutex);
+ mutex_unlock(&selinuxfs_mutex);
goto out_free;
}
@@ -1428,6 +1528,9 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
unsigned index = file_inode(filep)->i_ino & SEL_INO_MASK;
const char *name = filep->f_path.dentry->d_name.name;
+ if (fsi == NULL)
+ return -EINVAL;
+
if (fsi->state != current_selinux_state)
return -EPERM;
@@ -1438,11 +1541,13 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
if (*ppos != 0)
return -EINVAL;
- page = memdup_user_nul(buf, count);
- if (IS_ERR(page))
- return PTR_ERR(page);
+ mutex_lock(&selinuxfs_mutex);
- mutex_lock(&fsi->state->policy_mutex);
+ page = memdup_user_nul(buf, count);
+ if (IS_ERR(page)) {
+ length = PTR_ERR(page);
+ goto out_unlock;
+ }
length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
@@ -1467,8 +1572,10 @@ static ssize_t sel_write_bool(struct file *filep, const char __user *buf,
length = count;
out:
- mutex_unlock(&fsi->state->policy_mutex);
kfree(page);
+out_unlock:
+ mutex_unlock(&selinuxfs_mutex);
+
return length;
}
@@ -1487,6 +1594,9 @@ static ssize_t sel_commit_bools_write(struct file *filep,
ssize_t length;
int new_value;
+ if (fsi == NULL)
+ return -EINVAL;
+
if (fsi->state != current_selinux_state)
return -EPERM;
@@ -1497,11 +1607,13 @@ static ssize_t sel_commit_bools_write(struct file *filep,
if (*ppos != 0)
return -EINVAL;
- page = memdup_user_nul(buf, count);
- if (IS_ERR(page))
- return PTR_ERR(page);
+ mutex_lock(&selinuxfs_mutex);
- mutex_lock(&fsi->state->policy_mutex);
+ page = memdup_user_nul(buf, count);
+ if (IS_ERR(page)) {
+ length = PTR_ERR(page);
+ goto out_unlock;
+ }
length = avc_has_perm(current_selinux_state,
current_sid(), SECINITSID_SECURITY,
@@ -1523,8 +1635,9 @@ static ssize_t sel_commit_bools_write(struct file *filep,
length = count;
out:
- mutex_unlock(&fsi->state->policy_mutex);
kfree(page);
+out_unlock:
+ mutex_unlock(&selinuxfs_mutex);
return length;
}
@@ -1622,10 +1735,14 @@ static ssize_t sel_read_avc_cache_threshold(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
- struct selinux_state *state = fsi->state;
+ struct selinux_state *state;
char tmpbuf[TMPBUFLEN];
ssize_t length;
+ if (fsi == NULL)
+ return -EINVAL;
+ state = fsi->state;
+
length = scnprintf(tmpbuf, TMPBUFLEN, "%u",
avc_get_cache_threshold(state->avc));
return simple_read_from_buffer(buf, count, ppos, tmpbuf, length);
@@ -1637,11 +1754,15 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file,
{
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info;
- struct selinux_state *state = fsi->state;
+ struct selinux_state *state;
char *page;
ssize_t ret;
unsigned int new_value;
+ if (fsi == NULL)
+ return -EINVAL;
+ state = fsi->state;
+
if (state != current_selinux_state)
return -EPERM;
@@ -1659,9 +1780,13 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file,
if (*ppos != 0)
return -EINVAL;
+ mutex_lock(&selinuxfs_mutex);
+
page = memdup_user_nul(buf, count);
- if (IS_ERR(page))
- return PTR_ERR(page);
+ if (IS_ERR(page)) {
+ ret = PTR_ERR(page);
+ goto out_unlock;
+ }
ret = -EINVAL;
if (sscanf(page, "%u", &new_value) != 1)
@@ -1672,6 +1797,8 @@ static ssize_t sel_write_avc_cache_threshold(struct file *file,
ret = count;
out:
kfree(page);
+out_unlock:
+ mutex_unlock(&selinuxfs_mutex);
return ret;
}
@@ -1679,10 +1806,14 @@ static ssize_t sel_read_avc_hash_stats(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
- struct selinux_state *state = fsi->state;
+ struct selinux_state *state;
char *page;
ssize_t length;
+ if (fsi == NULL)
+ return -EINVAL;
+ state = fsi->state;
+
page = (char *)__get_free_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
@@ -1699,10 +1830,14 @@ static ssize_t sel_read_sidtab_hash_stats(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
struct selinux_fs_info *fsi = file_inode(filp)->i_sb->s_fs_info;
- struct selinux_state *state = fsi->state;
+ struct selinux_state *state;
char *page;
ssize_t length;
+ if (fsi == NULL)
+ return -EINVAL;
+ state = fsi->state;
+
page = (char *)__get_free_page(GFP_KERNEL);
if (!page)
return -ENOMEM;
@@ -1817,6 +1952,9 @@ static int sel_make_avc_files(struct dentry *dir)
#endif
};
+ if (fsi == NULL)
+ return -EINVAL;
+
for (i = 0; i < ARRAY_SIZE(files); i++) {
struct inode *inode;
struct dentry *dentry;
@@ -1848,6 +1986,9 @@ static int sel_make_ss_files(struct dentry *dir)
{ "sidtab_hash_stats", &sel_sidtab_hash_stats_ops, S_IRUGO },
};
+ if (fsi == NULL)
+ return -EINVAL;
+
for (i = 0; i < ARRAY_SIZE(files); i++) {
struct inode *inode;
struct dentry *dentry;
@@ -1878,6 +2019,9 @@ static ssize_t sel_read_initcon(struct file *file, char __user *buf,
u32 sid, len;
ssize_t ret;
+ if (fsi == NULL)
+ return -EINVAL;
+
sid = file_inode(file)->i_ino&SEL_INO_MASK;
ret = security_sid_to_context(fsi->state, sid, &con, &len);
if (ret)
@@ -1979,6 +2123,9 @@ static ssize_t sel_read_policycap(struct file *file, char __user *buf,
ssize_t length;
unsigned long i_ino = file_inode(file)->i_ino;
+ if (fsi == NULL)
+ return -EINVAL;
+
value = security_policycap_supported(fsi->state, i_ino & SEL_INO_MASK);
length = scnprintf(tmpbuf, TMPBUFLEN, "%d", value);
@@ -2040,6 +2187,9 @@ static int sel_make_class_dir_entries(struct selinux_policy *newpolicy,
struct inode *inode = NULL;
int rc;
+ if (fsi == NULL)
+ return -EINVAL;
+
dentry = d_alloc_name(dir, "index");
if (!dentry)
return -ENOMEM;
@@ -2218,6 +2368,10 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc)
goto err;
fsi = sb->s_fs_info;
+
+ if (fsi == NULL)
+ goto err;
+
fsi->bool_dir = sel_make_dir(sb->s_root, BOOL_DIR_NAME, &fsi->last_ino);
if (IS_ERR(fsi->bool_dir)) {
ret = PTR_ERR(fsi->bool_dir);
@@ -2309,6 +2463,9 @@ static int selinuxfs_compare(struct super_block *sb, struct fs_context *fc)
{
struct selinux_fs_info *fsi = sb->s_fs_info;
+ if (fsi == NULL)
+ return 0;
+
return (current_selinux_state->id == fsi->state->id);
}
@@ -67,6 +67,8 @@
#include "audit.h"
#include "policycap_names.h"
+extern struct mutex selinuxfs_mutex; /* GLobal mutex for all selinuxfs access */
+
/* Forward declaration. */
static int context_struct_to_string(struct policydb *policydb,
struct context *context,
@@ -2165,7 +2167,7 @@ void selinux_policy_cancel(struct selinux_state *state,
struct selinux_policy *oldpolicy;
oldpolicy = rcu_dereference_protected(state->policy,
- lockdep_is_held(&state->policy_mutex));
+ lockdep_is_held(&selinuxfs_mutex));
sidtab_cancel_convert(oldpolicy->sidtab);
selinux_policy_free(policy);
@@ -2189,7 +2191,7 @@ void selinux_policy_commit(struct selinux_state *state,
u32 seqno;
oldpolicy = rcu_dereference_protected(state->policy,
- lockdep_is_held(&state->policy_mutex));
+ lockdep_is_held(&selinuxfs_mutex));
/* If switching between different policy types, log MLS status */
if (oldpolicy) {
@@ -2283,7 +2285,7 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len,
}
oldpolicy = rcu_dereference_protected(state->policy,
- lockdep_is_held(&state->policy_mutex));
+ lockdep_is_held(&selinuxfs_mutex));
/* Preserve active boolean values from the old policy */
rc = security_preserve_bools(oldpolicy, newpolicy);
@@ -2983,7 +2985,7 @@ int security_set_bools(struct selinux_state *state, u32 len, int *values)
return -EINVAL;
oldpolicy = rcu_dereference_protected(state->policy,
- lockdep_is_held(&state->policy_mutex));
+ lockdep_is_held(&selinuxfs_mutex));
/* Consistency check on number of booleans, should never fail */
if (WARN_ON(len != oldpolicy->policydb.p_bools.nprim))
@@ -3888,7 +3890,7 @@ int security_read_policy(struct selinux_state *state,
struct policy_file fp;
policy = rcu_dereference_protected(
- state->policy, lockdep_is_held(&state->policy_mutex));
+ state->policy, lockdep_is_held(&selinuxfs_mutex));
if (!policy)
return -EINVAL;