aboutsummaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/selinux/Kconfig37
-rw-r--r--security/selinux/exports.c13
-rw-r--r--security/selinux/hooks.c69
-rw-r--r--security/selinux/include/objsec.h4
-rw-r--r--security/selinux/include/security.h7
-rw-r--r--security/selinux/ss/mls.c21
-rw-r--r--security/selinux/ss/policydb.c27
-rw-r--r--security/selinux/ss/policydb.h7
-rw-r--r--security/selinux/ss/services.c30
9 files changed, 129 insertions, 86 deletions
diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig
index 814ddc42f1f..293dbd6246c 100644
--- a/security/selinux/Kconfig
+++ b/security/selinux/Kconfig
@@ -124,3 +124,40 @@ config SECURITY_SELINUX_ENABLE_SECMARK_DEFAULT
If you are unsure what do do here, select N.
+config SECURITY_SELINUX_POLICYDB_VERSION_MAX
+ bool "NSA SELinux maximum supported policy format version"
+ depends on SECURITY_SELINUX
+ default n
+ help
+ This option enables the maximum policy format version supported
+ by SELinux to be set to a particular value. This value is reported
+ to userspace via /selinux/policyvers and used at policy load time.
+ It can be adjusted downward to support legacy userland (init) that
+ does not correctly handle kernels that support newer policy versions.
+
+ Examples:
+ For the Fedora Core 3 or 4 Linux distributions, enable this option
+ and set the value via the next option. For Fedore Core 5 and later,
+ do not enable this option.
+
+ If you are unsure how to answer this question, answer N.
+
+config SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
+ int "NSA SELinux maximum supported policy format version value"
+ depends on SECURITY_SELINUX_POLICYDB_VERSION_MAX
+ range 15 21
+ default 19
+ help
+ This option sets the value for the maximum policy format version
+ supported by SELinux.
+
+ Examples:
+ For Fedora Core 3, use 18.
+ For Fedora Core 4, use 19.
+
+ If you are unsure how to answer this question, look for the
+ policy format version supported by your policy toolchain, by
+ running 'checkpolicy -V'. Or look at what policy you have
+ installed under /etc/selinux/$SELINUXTYPE/policy, where
+ SELINUXTYPE is defined in your /etc/selinux/config.
+
diff --git a/security/selinux/exports.c b/security/selinux/exports.c
index 9d7737db5e5..b6f96943be1 100644
--- a/security/selinux/exports.c
+++ b/security/selinux/exports.c
@@ -21,19 +21,10 @@
#include "security.h"
#include "objsec.h"
-void selinux_task_ctxid(struct task_struct *tsk, u32 *ctxid)
+int selinux_sid_to_string(u32 sid, char **ctx, u32 *ctxlen)
{
- struct task_security_struct *tsec = tsk->security;
if (selinux_enabled)
- *ctxid = tsec->sid;
- else
- *ctxid = 0;
-}
-
-int selinux_ctxid_to_string(u32 ctxid, char **ctx, u32 *ctxlen)
-{
- if (selinux_enabled)
- return security_sid_to_context(ctxid, ctx, ctxlen);
+ return security_sid_to_context(sid, ctx, ctxlen);
else {
*ctx = NULL;
*ctxlen = 0;
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 5a66c4c09f7..e4d81a42fca 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);
@@ -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. */
@@ -2091,7 +2072,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;
diff --git a/security/selinux/include/objsec.h b/security/selinux/include/objsec.h
index 0a39bfd1319..ef2267fea8b 100644
--- a/security/selinux/include/objsec.h
+++ b/security/selinux/include/objsec.h
@@ -44,7 +44,7 @@ struct inode_security_struct {
u32 sid; /* SID of this object */
u16 sclass; /* security class of this object */
unsigned char initialized; /* initialization flag */
- struct semaphore sem;
+ struct mutex lock;
unsigned char inherit; /* inherit SID from parent entry */
};
@@ -63,7 +63,7 @@ struct superblock_security_struct {
unsigned int behavior; /* labeling behavior */
unsigned char initialized; /* initialization flag */
unsigned char proc; /* proc fs */
- struct semaphore sem;
+ struct mutex lock;
struct list_head isec_head;
spinlock_t isec_lock;
};
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index 911954a692f..1ef79172cc8 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -24,10 +24,15 @@
#define POLICYDB_VERSION_VALIDATETRANS 19
#define POLICYDB_VERSION_MLS 19
#define POLICYDB_VERSION_AVTAB 20
+#define POLICYDB_VERSION_RANGETRANS 21
/* Range of policy versions we understand*/
#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
-#define POLICYDB_VERSION_MAX POLICYDB_VERSION_AVTAB
+#ifdef CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX
+#define POLICYDB_VERSION_MAX CONFIG_SECURITY_SELINUX_POLICYDB_VERSION_MAX_VALUE
+#else
+#define POLICYDB_VERSION_MAX POLICYDB_VERSION_RANGETRANS
+#endif
extern int selinux_enabled;
extern int selinux_mls_enabled;
diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c
index 119bd6078ba..c713af23250 100644
--- a/security/selinux/ss/mls.c
+++ b/security/selinux/ss/mls.c
@@ -530,22 +530,21 @@ int mls_compute_sid(struct context *scontext,
u32 specified,
struct context *newcontext)
{
+ struct range_trans *rtr;
+
if (!selinux_mls_enabled)
return 0;
switch (specified) {
case AVTAB_TRANSITION:
- if (tclass == SECCLASS_PROCESS) {
- struct range_trans *rangetr;
- /* Look for a range transition rule. */
- for (rangetr = policydb.range_tr; rangetr;
- rangetr = rangetr->next) {
- if (rangetr->dom == scontext->type &&
- rangetr->type == tcontext->type) {
- /* Set the range from the rule */
- return mls_range_set(newcontext,
- &rangetr->range);
- }
+ /* Look for a range transition rule. */
+ for (rtr = policydb.range_tr; rtr; rtr = rtr->next) {
+ if (rtr->source_type == scontext->type &&
+ rtr->target_type == tcontext->type &&
+ rtr->target_class == tclass) {
+ /* Set the range from the rule */
+ return mls_range_set(newcontext,
+ &rtr->target_range);
}
}
/* Fallthrough */
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index f03960e697c..b1889530255 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -96,6 +96,11 @@ static struct policydb_compat_info policydb_compat[] = {
.sym_num = SYM_NUM,
.ocon_num = OCON_NUM,
},
+ {
+ .version = POLICYDB_VERSION_RANGETRANS,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM,
+ },
};
static struct policydb_compat_info *policydb_lookup_compat(int version)
@@ -645,15 +650,15 @@ void policydb_destroy(struct policydb *p)
for (rt = p->range_tr; rt; rt = rt -> next) {
if (lrt) {
- ebitmap_destroy(&lrt->range.level[0].cat);
- ebitmap_destroy(&lrt->range.level[1].cat);
+ ebitmap_destroy(&lrt->target_range.level[0].cat);
+ ebitmap_destroy(&lrt->target_range.level[1].cat);
kfree(lrt);
}
lrt = rt;
}
if (lrt) {
- ebitmap_destroy(&lrt->range.level[0].cat);
- ebitmap_destroy(&lrt->range.level[1].cat);
+ ebitmap_destroy(&lrt->target_range.level[0].cat);
+ ebitmap_destroy(&lrt->target_range.level[1].cat);
kfree(lrt);
}
@@ -1829,6 +1834,7 @@ int policydb_read(struct policydb *p, void *fp)
}
if (p->policyvers >= POLICYDB_VERSION_MLS) {
+ int new_rangetr = p->policyvers >= POLICYDB_VERSION_RANGETRANS;
rc = next_entry(buf, fp, sizeof(u32));
if (rc < 0)
goto bad;
@@ -1847,9 +1853,16 @@ int policydb_read(struct policydb *p, void *fp)
rc = next_entry(buf, fp, (sizeof(u32) * 2));
if (rc < 0)
goto bad;
- rt->dom = le32_to_cpu(buf[0]);
- rt->type = le32_to_cpu(buf[1]);
- rc = mls_read_range_helper(&rt->range, fp);
+ rt->source_type = le32_to_cpu(buf[0]);
+ rt->target_type = le32_to_cpu(buf[1]);
+ if (new_rangetr) {
+ rc = next_entry(buf, fp, sizeof(u32));
+ if (rc < 0)
+ goto bad;
+ rt->target_class = le32_to_cpu(buf[0]);
+ } else
+ rt->target_class = SECCLASS_PROCESS;
+ rc = mls_read_range_helper(&rt->target_range, fp);
if (rc)
goto bad;
lrt = rt;
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
index b1340711f72..8319d5ff594 100644
--- a/security/selinux/ss/policydb.h
+++ b/security/selinux/ss/policydb.h
@@ -106,9 +106,10 @@ struct cat_datum {
};
struct range_trans {
- u32 dom; /* current process domain */
- u32 type; /* program executable type */
- struct mls_range range; /* new range */
+ u32 source_type;
+ u32 target_type;
+ u32 target_class;
+ struct mls_range target_range;
struct range_trans *next;
};
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 7eb69a602d8..0c219a1b324 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -2003,7 +2003,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr,
return rc;
}
-int selinux_audit_rule_match(u32 ctxid, u32 field, u32 op,
+int selinux_audit_rule_match(u32 sid, u32 field, u32 op,
struct selinux_audit_rule *rule,
struct audit_context *actx)
{
@@ -2026,11 +2026,11 @@ int selinux_audit_rule_match(u32 ctxid, u32 field, u32 op,
goto out;
}
- ctxt = sidtab_search(&sidtab, ctxid);
+ ctxt = sidtab_search(&sidtab, sid);
if (!ctxt) {
audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR,
"selinux_audit_rule_match: unrecognized SID %d\n",
- ctxid);
+ sid);
match = -ENOENT;
goto out;
}
@@ -2502,14 +2502,24 @@ void selinux_netlbl_sock_graft(struct sock *sk, struct socket *sock)
{
struct inode_security_struct *isec = SOCK_INODE(sock)->i_security;
struct sk_security_struct *sksec = sk->sk_security;
+ struct netlbl_lsm_secattr secattr;
+ u32 nlbl_peer_sid;
sksec->sclass = isec->sclass;
if (sk->sk_family != PF_INET)
return;
+ netlbl_secattr_init(&secattr);
+ if (netlbl_sock_getattr(sk, &secattr) == 0 &&
+ selinux_netlbl_secattr_to_sid(NULL,
+ &secattr,
+ sksec->sid,
+ &nlbl_peer_sid) == 0)
+ sksec->peer_sid = nlbl_peer_sid;
+ netlbl_secattr_destroy(&secattr, 0);
+
sksec->nlbl_state = NLBL_REQUIRE;
- sksec->peer_sid = sksec->sid;
/* Try to set the NetLabel on the socket to save time later, if we fail
* here we will pick up the pieces in later calls to
@@ -2568,7 +2578,7 @@ int selinux_netlbl_inode_permission(struct inode *inode, int mask)
sock = SOCKET_I(inode);
isec = inode->i_security;
sksec = sock->sk->sk_security;
- down(&isec->sem);
+ mutex_lock(&isec->lock);
if (unlikely(sksec->nlbl_state == NLBL_REQUIRE &&
(mask & (MAY_WRITE | MAY_APPEND)))) {
lock_sock(sock->sk);
@@ -2576,7 +2586,7 @@ int selinux_netlbl_inode_permission(struct inode *inode, int mask)
release_sock(sock->sk);
} else
rc = 0;
- up(&isec->sem);
+ mutex_unlock(&isec->lock);
return rc;
}
@@ -2601,7 +2611,7 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
u32 netlbl_sid;
u32 recv_perm;
- rc = selinux_netlbl_skbuff_getsid(skb, sksec->sid, &netlbl_sid);
+ rc = selinux_netlbl_skbuff_getsid(skb, SECINITSID_NETMSG, &netlbl_sid);
if (rc != 0)
return rc;
@@ -2610,13 +2620,13 @@ int selinux_netlbl_sock_rcv_skb(struct sk_security_struct *sksec,
switch (sksec->sclass) {
case SECCLASS_UDP_SOCKET:
- recv_perm = UDP_SOCKET__RECV_MSG;
+ recv_perm = UDP_SOCKET__RECVFROM;
break;
case SECCLASS_TCP_SOCKET:
- recv_perm = TCP_SOCKET__RECV_MSG;
+ recv_perm = TCP_SOCKET__RECVFROM;
break;
default:
- recv_perm = RAWIP_SOCKET__RECV_MSG;
+ recv_perm = RAWIP_SOCKET__RECVFROM;
}
rc = avc_has_perm(sksec->sid,