#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>
#include <linux/audit.h>
#include <linux/string.h>
#include <linux/selinux.h>
+#include <linux/mutex.h>
#include "avc.h"
#include "objsec.h"
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;
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);
ssec->sid = SECINITSID_UNLABELED;
sk->sk_security = ssec;
+ selinux_netlbl_sk_security_init(ssec, family);
+
return 0;
}
/* 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];
struct inode *inode = root->d_inode;
int rc = 0;
- down(&sbsec->sem);
+ mutex_lock(&sbsec->lock);
if (sbsec->initialized)
goto out;
}
spin_unlock(&sbsec->isec_lock);
out:
- up(&sbsec->sem);
+ mutex_unlock(&sbsec->lock);
return rc;
}
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) {
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) {
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;
if (!context) {
rc = -ENOMEM;
dput(dentry);
- goto out;
+ goto out_unlock;
}
rc = inode->i_op->getxattr(dentry, XATTR_NAME_SELINUX,
context, len);
NULL, 0);
if (rc < 0) {
dput(dentry);
- goto out;
+ goto out_unlock;
}
kfree(context);
len = rc;
if (!context) {
rc = -ENOMEM;
dput(dentry);
- goto out;
+ goto out_unlock;
}
rc = inode->i_op->getxattr(dentry,
XATTR_NAME_SELINUX,
"%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;
isec->sclass,
&sid);
if (rc)
- goto out;
+ goto out_unlock;
isec->sid = sid;
break;
case SECURITY_FS_USE_MNTPOINT:
isec->sclass,
&sid);
if (rc)
- goto out;
+ goto out_unlock;
isec->sid = sid;
}
}
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;
}
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)
{
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);
}
file_list_unlock();
}
+ mutex_unlock(&tty_mutex);
/* Revalidate access to inherited open files. */
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;
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);
}
}
- 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;
static int selinux_socket_setsockopt(struct socket *sock,int level,int optname)
{
- return socket_has_perm(current, sock, SOCKET__SETOPT);
+ int err;
+
+ err = socket_has_perm(current, sock, SOCKET__SETOPT);
+ if (err)
+ return err;
+
+ return selinux_netlbl_socket_setsockopt(sock, level, optname);
}
static int selinux_socket_getsockopt(struct socket *sock, int level,
newssec->sid = ssec->sid;
newssec->peer_sid = ssec->peer_sid;
+
+ selinux_netlbl_sk_clone_security(ssec, newssec);
}
static void selinux_sk_getsecid(struct sock *sk, u32 *secid)
}
}
-void selinux_sock_graft(struct sock* sk, struct socket *parent)
+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);
}
-int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
- struct request_sock *req)
+static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
+ struct request_sock *req)
{
struct sk_security_struct *sksec = sk->sk_security;
int err;
return 0;
}
-void selinux_inet_csk_clone(struct sock *newsk, const struct request_sock *req)
+static void selinux_inet_csk_clone(struct sock *newsk,
+ const struct request_sock *req)
{
struct sk_security_struct *newsksec = newsk->sk_security;
new socket in sync, but we don't have the isec available yet.
So we will wait until sock_graft to do it, by which
time it will have been created and available. */
+
+ selinux_netlbl_sk_security_init(newsksec, req->rsk_ops->family);
}
-void selinux_req_classify_flow(const struct request_sock *req, struct flowi *fl)
+static void selinux_req_classify_flow(const struct request_sock *req,
+ struct flowi *fl)
{
fl->secid = req->secid;
}