summaryrefslogtreecommitdiff
path: root/security/selinux/hooks.c
diff options
context:
space:
mode:
Diffstat (limited to 'security/selinux/hooks.c')
-rw-r--r--security/selinux/hooks.c108
1 files changed, 61 insertions, 47 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 5a66c4c09f7a..e9969a2fc846 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -51,7 +51,6 @@
#include <net/ip.h> /* for sysctl_local_port_range[] */
#include <net/tcp.h> /* struct or_callable used in sock_rcv_skb */
#include <asm/uaccess.h>
-#include <asm/semaphore.h>
#include <asm/ioctls.h>
#include <linux/bitops.h>
#include <linux/interrupt.h>
@@ -71,6 +70,7 @@
#include <linux/audit.h>
#include <linux/string.h>
#include <linux/selinux.h>
+#include <linux/mutex.h>
#include "avc.h"
#include "objsec.h"
@@ -185,7 +185,7 @@ static int inode_alloc_security(struct inode *inode)
return -ENOMEM;
memset(isec, 0, sizeof(*isec));
- init_MUTEX(&isec->sem);
+ mutex_init(&isec->lock);
INIT_LIST_HEAD(&isec->list);
isec->inode = inode;
isec->sid = SECINITSID_UNLABELED;
@@ -242,7 +242,7 @@ static int superblock_alloc_security(struct super_block *sb)
if (!sbsec)
return -ENOMEM;
- init_MUTEX(&sbsec->sem);
+ mutex_init(&sbsec->lock);
INIT_LIST_HEAD(&sbsec->list);
INIT_LIST_HEAD(&sbsec->isec_head);
spin_lock_init(&sbsec->isec_lock);
@@ -398,7 +398,7 @@ static int try_context_mount(struct super_block *sb, void *data)
/* Standard string-based options. */
char *p, *options = data;
- while ((p = strsep(&options, ",")) != NULL) {
+ while ((p = strsep(&options, "|")) != NULL) {
int token;
substring_t args[MAX_OPT_ARGS];
@@ -594,7 +594,7 @@ static int superblock_doinit(struct super_block *sb, void *data)
struct inode *inode = root->d_inode;
int rc = 0;
- down(&sbsec->sem);
+ mutex_lock(&sbsec->lock);
if (sbsec->initialized)
goto out;
@@ -689,7 +689,7 @@ next_inode:
}
spin_unlock(&sbsec->isec_lock);
out:
- up(&sbsec->sem);
+ mutex_unlock(&sbsec->lock);
return rc;
}
@@ -843,15 +843,13 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
char *context = NULL;
unsigned len = 0;
int rc = 0;
- int hold_sem = 0;
if (isec->initialized)
goto out;
- down(&isec->sem);
- hold_sem = 1;
+ mutex_lock(&isec->lock);
if (isec->initialized)
- goto out;
+ goto out_unlock;
sbsec = inode->i_sb->s_security;
if (!sbsec->initialized) {
@@ -862,7 +860,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
if (list_empty(&isec->list))
list_add(&isec->list, &sbsec->isec_head);
spin_unlock(&sbsec->isec_lock);
- goto out;
+ goto out_unlock;
}
switch (sbsec->behavior) {
@@ -885,7 +883,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
printk(KERN_WARNING "%s: no dentry for dev=%s "
"ino=%ld\n", __FUNCTION__, inode->i_sb->s_id,
inode->i_ino);
- goto out;
+ goto out_unlock;
}
len = INITCONTEXTLEN;
@@ -893,7 +891,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
if (!context) {
rc = -ENOMEM;
dput(dentry);
- goto out;
+ goto out_unlock;
}
rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
context, len);
@@ -903,7 +901,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
NULL, 0);
if (rc < 0) {
dput(dentry);
- goto out;
+ goto out_unlock;
}
kfree(context);
len = rc;
@@ -911,7 +909,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
if (!context) {
rc = -ENOMEM;
dput(dentry);
- goto out;
+ goto out_unlock;
}
rc = inode->i_op->getxattr(dentry,
XATTR_NAME_SELINUX,
@@ -924,7 +922,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
"%d for dev=%s ino=%ld\n", __FUNCTION__,
-rc, inode->i_sb->s_id, inode->i_ino);
kfree(context);
- goto out;
+ goto out_unlock;
}
/* Map ENODATA to the default file SID */
sid = sbsec->def_sid;
@@ -960,7 +958,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
isec->sclass,
&sid);
if (rc)
- goto out;
+ goto out_unlock;
isec->sid = sid;
break;
case SECURITY_FS_USE_MNTPOINT:
@@ -978,7 +976,7 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
isec->sclass,
&sid);
if (rc)
- goto out;
+ goto out_unlock;
isec->sid = sid;
}
}
@@ -987,12 +985,11 @@ static int inode_doinit_with_dentry(struct inode *inode, struct dentry *opt_dent
isec->initialized = 1;
+out_unlock:
+ mutex_unlock(&isec->lock);
out:
if (isec->sclass == SECCLASS_FILE)
isec->sclass = inode_mode_to_security_class(inode->i_mode);
-
- if (hold_sem)
- up(&isec->sem);
return rc;
}
@@ -1364,25 +1361,6 @@ static inline u32 file_to_av(struct file *file)
return av;
}
-/* Set an inode's SID to a specified value. */
-static int inode_security_set_sid(struct inode *inode, u32 sid)
-{
- struct inode_security_struct *isec = inode->i_security;
- struct superblock_security_struct *sbsec = inode->i_sb->s_security;
-
- if (!sbsec->initialized) {
- /* Defer initialization to selinux_complete_init. */
- return 0;
- }
-
- down(&isec->sem);
- isec->sclass = inode_mode_to_security_class(inode->i_mode);
- isec->sid = sid;
- isec->initialized = 1;
- up(&isec->sem);
- return 0;
-}
-
/* Hook functions begin here. */
static int selinux_ptrace(struct task_struct *parent, struct task_struct *child)
@@ -1711,10 +1689,12 @@ static inline void flush_unauthorized_files(struct files_struct * files)
{
struct avc_audit_data ad;
struct file *file, *devnull = NULL;
- struct tty_struct *tty = current->signal->tty;
+ struct tty_struct *tty;
struct fdtable *fdt;
long j = -1;
+ mutex_lock(&tty_mutex);
+ tty = current->signal->tty;
if (tty) {
file_list_lock();
file = list_entry(tty->tty_files.next, typeof(*file), f_u.fu_list);
@@ -1734,6 +1714,7 @@ static inline void flush_unauthorized_files(struct files_struct * files)
}
file_list_unlock();
}
+ mutex_unlock(&tty_mutex);
/* Revalidate access to inherited open files. */
@@ -1942,18 +1923,40 @@ static inline void take_option(char **to, char *from, int *first, int len)
if (!*first) {
**to = ',';
*to += 1;
- }
- else
+ } else
*first = 0;
memcpy(*to, from, len);
*to += len;
}
+static inline void take_selinux_option(char **to, char *from, int *first,
+ int len)
+{
+ int current_size = 0;
+
+ if (!*first) {
+ **to = '|';
+ *to += 1;
+ }
+ else
+ *first = 0;
+
+ while (current_size < len) {
+ if (*from != '"') {
+ **to = *from;
+ *to += 1;
+ }
+ from += 1;
+ current_size += 1;
+ }
+}
+
static int selinux_sb_copy_data(struct file_system_type *type, void *orig, void *copy)
{
int fnosec, fsec, rc = 0;
char *in_save, *in_curr, *in_end;
char *sec_curr, *nosec_save, *nosec;
+ int open_quote = 0;
in_curr = orig;
sec_curr = copy;
@@ -1975,11 +1978,14 @@ static int selinux_sb_copy_data(struct file_system_type *type, void *orig, void
in_save = in_end = orig;
do {
- if (*in_end == ',' || *in_end == '\0') {
+ if (*in_end == '"')
+ open_quote = !open_quote;
+ if ((*in_end == ',' && open_quote == 0) ||
+ *in_end == '\0') {
int len = in_end - in_curr;
if (selinux_option(in_curr, len))
- take_option(&sec_curr, in_curr, &fsec, len);
+ take_selinux_option(&sec_curr, in_curr, &fsec, len);
else
take_option(&nosec, in_curr, &fnosec, len);
@@ -2091,7 +2097,13 @@ static int selinux_inode_init_security(struct inode *inode, struct inode *dir,
}
}
- inode_security_set_sid(inode, newsid);
+ /* Possibly defer initialization to selinux_complete_init. */
+ if (sbsec->initialized) {
+ struct inode_security_struct *isec = inode->i_security;
+ isec->sclass = inode_mode_to_security_class(inode->i_mode);
+ isec->sid = newsid;
+ isec->initialized = 1;
+ }
if (!ss_initialized || sbsec->behavior == SECURITY_FS_USE_MNTPOINT)
return -EOPNOTSUPP;
@@ -3607,7 +3619,9 @@ static void selinux_sock_graft(struct sock* sk, struct socket *parent)
struct inode_security_struct *isec = SOCK_INODE(parent)->i_security;
struct sk_security_struct *sksec = sk->sk_security;
- isec->sid = sksec->sid;
+ if (sk->sk_family == PF_INET || sk->sk_family == PF_INET6 ||
+ sk->sk_family == PF_UNIX)
+ isec->sid = sksec->sid;
selinux_netlbl_sock_graft(sk, parent);
}