summaryrefslogtreecommitdiff
path: root/security/selinux
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2014-01-21 09:06:02 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2014-01-21 09:06:02 -0800
commitfb2e2c85375a0380d6818f153ffa2ae9ebbd055f (patch)
treecf8498a01357c220e4d664ff67125f60146f0da3 /security/selinux
parentec513b16c480c6cdda1e3d597e611eafca05227b (diff)
parent923b49ff69fcbffe6f8b2739de218c45544392a7 (diff)
downloadlinux-rpi-fb2e2c85375a0380d6818f153ffa2ae9ebbd055f.tar.gz
linux-rpi-fb2e2c85375a0380d6818f153ffa2ae9ebbd055f.tar.bz2
linux-rpi-fb2e2c85375a0380d6818f153ffa2ae9ebbd055f.zip
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security
Pull security layer updates from James Morris: "Changes for this kernel include maintenance updates for Smack, SELinux (and several networking fixes), IMA and TPM" * 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: (39 commits) SELinux: Fix memory leak upon loading policy tpm/tpm-sysfs: active_show() can be static tpm: tpm_tis: Fix compile problems with CONFIG_PM_SLEEP/CONFIG_PNP tpm: Make tpm-dev allocate a per-file structure tpm: Use the ops structure instead of a copy in tpm_vendor_specific tpm: Create a tpm_class_ops structure and use it in the drivers tpm: Pull all driver sysfs code into tpm-sysfs.c tpm: Move sysfs functions from tpm-interface to tpm-sysfs tpm: Pull everything related to /dev/tpmX into tpm-dev.c char: tpm: nuvoton: remove unused variable tpm: MAINTAINERS: Cleanup TPM Maintainers file tpm/tpm_i2c_atmel: fix coccinelle warnings tpm/tpm_ibmvtpm: fix unreachable code warning (smatch warning) tpm/tpm_i2c_stm_st33: Check return code of get_burstcount tpm/tpm_ppi: Check return value of acpi_get_name tpm/tpm_ppi: Do not compare strcmp(a,b) == -1 ima: remove unneeded size_limit argument from ima_eventdigest_init_common() ima: update IMA-templates.txt documentation ima: pass HASH_ALGO__LAST as hash algo in ima_eventdigest_init() ima: change the default hash algorithm to SHA1 in ima_eventdigest_ng_init() ...
Diffstat (limited to 'security/selinux')
-rw-r--r--security/selinux/hooks.c7
-rw-r--r--security/selinux/include/security.h3
-rw-r--r--security/selinux/netlabel.c31
-rw-r--r--security/selinux/ss/constraint.h1
-rw-r--r--security/selinux/ss/policydb.c110
-rw-r--r--security/selinux/ss/policydb.h11
-rw-r--r--security/selinux/ss/services.c54
7 files changed, 177 insertions, 40 deletions
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 57b0b49f4e6e..4b34847208cc 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -82,7 +82,6 @@
#include <linux/syslog.h>
#include <linux/user_namespace.h>
#include <linux/export.h>
-#include <linux/security.h>
#include <linux/msg.h>
#include <linux/shm.h>
@@ -4490,14 +4489,10 @@ static int selinux_inet_conn_request(struct sock *sk, struct sk_buff *skb,
{
struct sk_security_struct *sksec = sk->sk_security;
int err;
- u16 family = sk->sk_family;
+ u16 family = req->rsk_ops->family;
u32 connsid;
u32 peersid;
- /* handle mapped IPv4 packets arriving via IPv6 sockets */
- if (family == PF_INET6 && skb->protocol == htons(ETH_P_IP))
- family = PF_INET;
-
err = selinux_skb_peerlbl_sid(skb, family, &peersid);
if (err)
return err;
diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
index fe341ae37004..8ed8daf7f1ee 100644
--- a/security/selinux/include/security.h
+++ b/security/selinux/include/security.h
@@ -33,13 +33,14 @@
#define POLICYDB_VERSION_ROLETRANS 26
#define POLICYDB_VERSION_NEW_OBJECT_DEFAULTS 27
#define POLICYDB_VERSION_DEFAULT_TYPE 28
+#define POLICYDB_VERSION_CONSTRAINT_NAMES 29
/* Range of policy versions we understand*/
#define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE
#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_DEFAULT_TYPE
+#define POLICYDB_VERSION_MAX POLICYDB_VERSION_CONSTRAINT_NAMES
#endif
/* Mask for just the mount related flags */
diff --git a/security/selinux/netlabel.c b/security/selinux/netlabel.c
index 6235d052338b..0364120d1ec8 100644
--- a/security/selinux/netlabel.c
+++ b/security/selinux/netlabel.c
@@ -101,6 +101,32 @@ static struct netlbl_lsm_secattr *selinux_netlbl_sock_genattr(struct sock *sk)
}
/**
+ * selinux_netlbl_sock_getattr - Get the cached NetLabel secattr
+ * @sk: the socket
+ * @sid: the SID
+ *
+ * Query the socket's cached secattr and if the SID matches the cached value
+ * return the cache, otherwise return NULL.
+ *
+ */
+static struct netlbl_lsm_secattr *selinux_netlbl_sock_getattr(
+ const struct sock *sk,
+ u32 sid)
+{
+ struct sk_security_struct *sksec = sk->sk_security;
+ struct netlbl_lsm_secattr *secattr = sksec->nlbl_secattr;
+
+ if (secattr == NULL)
+ return NULL;
+
+ if ((secattr->flags & NETLBL_SECATTR_SECID) &&
+ (secattr->attr.secid == sid))
+ return secattr;
+
+ return NULL;
+}
+
+/**
* selinux_netlbl_cache_invalidate - Invalidate the NetLabel cache
*
* Description:
@@ -224,7 +250,7 @@ int selinux_netlbl_skbuff_setsid(struct sk_buff *skb,
struct sk_security_struct *sksec = sk->sk_security;
if (sksec->nlbl_state != NLBL_REQSKB)
return 0;
- secattr = sksec->nlbl_secattr;
+ secattr = selinux_netlbl_sock_getattr(sk, sid);
}
if (secattr == NULL) {
secattr = &secattr_storage;
@@ -410,6 +436,9 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
sksec->nlbl_state == NLBL_CONNLABELED)) {
netlbl_secattr_init(&secattr);
lock_sock(sk);
+ /* call the netlabel function directly as we want to see the
+ * on-the-wire label that is assigned via the socket's options
+ * and not the cached netlabel/lsm attributes */
rc = netlbl_sock_getattr(sk, &secattr);
release_sock(sk);
if (rc == 0)
diff --git a/security/selinux/ss/constraint.h b/security/selinux/ss/constraint.h
index 149dda731fd3..96fd947c494b 100644
--- a/security/selinux/ss/constraint.h
+++ b/security/selinux/ss/constraint.h
@@ -48,6 +48,7 @@ struct constraint_expr {
u32 op; /* operator */
struct ebitmap names; /* names */
+ struct type_set *type_names;
struct constraint_expr *next; /* next expression */
};
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index f6195ebde3c9..c0f498842129 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -143,6 +143,11 @@ static struct policydb_compat_info policydb_compat[] = {
.sym_num = SYM_NUM,
.ocon_num = OCON_NUM,
},
+ {
+ .version = POLICYDB_VERSION_CONSTRAINT_NAMES,
+ .sym_num = SYM_NUM,
+ .ocon_num = OCON_NUM,
+ },
};
static struct policydb_compat_info *policydb_lookup_compat(int version)
@@ -613,6 +618,19 @@ static int common_destroy(void *key, void *datum, void *p)
return 0;
}
+static void constraint_expr_destroy(struct constraint_expr *expr)
+{
+ if (expr) {
+ ebitmap_destroy(&expr->names);
+ if (expr->type_names) {
+ ebitmap_destroy(&expr->type_names->types);
+ ebitmap_destroy(&expr->type_names->negset);
+ kfree(expr->type_names);
+ }
+ kfree(expr);
+ }
+}
+
static int cls_destroy(void *key, void *datum, void *p)
{
struct class_datum *cladatum;
@@ -628,10 +646,9 @@ static int cls_destroy(void *key, void *datum, void *p)
while (constraint) {
e = constraint->expr;
while (e) {
- ebitmap_destroy(&e->names);
etmp = e;
e = e->next;
- kfree(etmp);
+ constraint_expr_destroy(etmp);
}
ctemp = constraint;
constraint = constraint->next;
@@ -642,16 +659,14 @@ static int cls_destroy(void *key, void *datum, void *p)
while (constraint) {
e = constraint->expr;
while (e) {
- ebitmap_destroy(&e->names);
etmp = e;
e = e->next;
- kfree(etmp);
+ constraint_expr_destroy(etmp);
}
ctemp = constraint;
constraint = constraint->next;
kfree(ctemp);
}
-
kfree(cladatum->comkey);
}
kfree(datum);
@@ -1156,8 +1171,34 @@ bad:
return rc;
}
-static int read_cons_helper(struct constraint_node **nodep, int ncons,
- int allowxtarget, void *fp)
+static void type_set_init(struct type_set *t)
+{
+ ebitmap_init(&t->types);
+ ebitmap_init(&t->negset);
+}
+
+static int type_set_read(struct type_set *t, void *fp)
+{
+ __le32 buf[1];
+ int rc;
+
+ if (ebitmap_read(&t->types, fp))
+ return -EINVAL;
+ if (ebitmap_read(&t->negset, fp))
+ return -EINVAL;
+
+ rc = next_entry(buf, fp, sizeof(u32));
+ if (rc < 0)
+ return -EINVAL;
+ t->flags = le32_to_cpu(buf[0]);
+
+ return 0;
+}
+
+
+static int read_cons_helper(struct policydb *p,
+ struct constraint_node **nodep,
+ int ncons, int allowxtarget, void *fp)
{
struct constraint_node *c, *lc;
struct constraint_expr *e, *le;
@@ -1225,6 +1266,18 @@ static int read_cons_helper(struct constraint_node **nodep, int ncons,
rc = ebitmap_read(&e->names, fp);
if (rc)
return rc;
+ if (p->policyvers >=
+ POLICYDB_VERSION_CONSTRAINT_NAMES) {
+ e->type_names = kzalloc(sizeof
+ (*e->type_names),
+ GFP_KERNEL);
+ if (!e->type_names)
+ return -ENOMEM;
+ type_set_init(e->type_names);
+ rc = type_set_read(e->type_names, fp);
+ if (rc)
+ return rc;
+ }
break;
default:
return -EINVAL;
@@ -1301,7 +1354,7 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
goto bad;
}
- rc = read_cons_helper(&cladatum->constraints, ncons, 0, fp);
+ rc = read_cons_helper(p, &cladatum->constraints, ncons, 0, fp);
if (rc)
goto bad;
@@ -1311,7 +1364,8 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)
if (rc)
goto bad;
ncons = le32_to_cpu(buf[0]);
- rc = read_cons_helper(&cladatum->validatetrans, ncons, 1, fp);
+ rc = read_cons_helper(p, &cladatum->validatetrans,
+ ncons, 1, fp);
if (rc)
goto bad;
}
@@ -1941,7 +1995,19 @@ static int filename_trans_read(struct policydb *p, void *fp)
if (rc)
goto out;
- hashtab_insert(p->filename_trans, ft, otype);
+ rc = hashtab_insert(p->filename_trans, ft, otype);
+ if (rc) {
+ /*
+ * Do not return -EEXIST to the caller, or the system
+ * will not boot.
+ */
+ if (rc != -EEXIST)
+ goto out;
+ /* But free memory to avoid memory leak. */
+ kfree(ft);
+ kfree(name);
+ kfree(otype);
+ }
}
hash_eval(p->filename_trans, "filenametr");
return 0;
@@ -2753,6 +2819,24 @@ static int common_write(void *vkey, void *datum, void *ptr)
return 0;
}
+static int type_set_write(struct type_set *t, void *fp)
+{
+ int rc;
+ __le32 buf[1];
+
+ if (ebitmap_write(&t->types, fp))
+ return -EINVAL;
+ if (ebitmap_write(&t->negset, fp))
+ return -EINVAL;
+
+ buf[0] = cpu_to_le32(t->flags);
+ rc = put_entry(buf, sizeof(u32), 1, fp);
+ if (rc)
+ return -EINVAL;
+
+ return 0;
+}
+
static int write_cons_helper(struct policydb *p, struct constraint_node *node,
void *fp)
{
@@ -2784,6 +2868,12 @@ static int write_cons_helper(struct policydb *p, struct constraint_node *node,
rc = ebitmap_write(&e->names, fp);
if (rc)
return rc;
+ if (p->policyvers >=
+ POLICYDB_VERSION_CONSTRAINT_NAMES) {
+ rc = type_set_write(e->type_names, fp);
+ if (rc)
+ return rc;
+ }
break;
default:
break;
diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h
index da637471d4ce..725d5945a97e 100644
--- a/security/selinux/ss/policydb.h
+++ b/security/selinux/ss/policydb.h
@@ -154,6 +154,17 @@ struct cond_bool_datum {
struct cond_node;
/*
+ * type set preserves data needed to determine constraint info from
+ * policy source. This is not used by the kernel policy but allows
+ * utilities such as audit2allow to determine constraint denials.
+ */
+struct type_set {
+ struct ebitmap types;
+ struct ebitmap negset;
+ u32 flags;
+};
+
+/*
* The configuration data includes security contexts for
* initial SIDs, unlabeled file systems, TCP and UDP port numbers,
* network interfaces, and nodes. This structure stores the
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index d106733ad987..fc5a63a05a1c 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -1831,7 +1831,7 @@ static int security_preserve_bools(struct policydb *p);
*/
int security_load_policy(void *data, size_t len)
{
- struct policydb oldpolicydb, newpolicydb;
+ struct policydb *oldpolicydb, *newpolicydb;
struct sidtab oldsidtab, newsidtab;
struct selinux_mapping *oldmap, *map = NULL;
struct convert_context_args args;
@@ -1840,12 +1840,19 @@ int security_load_policy(void *data, size_t len)
int rc = 0;
struct policy_file file = { data, len }, *fp = &file;
+ oldpolicydb = kzalloc(2 * sizeof(*oldpolicydb), GFP_KERNEL);
+ if (!oldpolicydb) {
+ rc = -ENOMEM;
+ goto out;
+ }
+ newpolicydb = oldpolicydb + 1;
+
if (!ss_initialized) {
avtab_cache_init();
rc = policydb_read(&policydb, fp);
if (rc) {
avtab_cache_destroy();
- return rc;
+ goto out;
}
policydb.len = len;
@@ -1855,14 +1862,14 @@ int security_load_policy(void *data, size_t len)
if (rc) {
policydb_destroy(&policydb);
avtab_cache_destroy();
- return rc;
+ goto out;
}
rc = policydb_load_isids(&policydb, &sidtab);
if (rc) {
policydb_destroy(&policydb);
avtab_cache_destroy();
- return rc;
+ goto out;
}
security_load_policycaps();
@@ -1874,36 +1881,36 @@ int security_load_policy(void *data, size_t len)
selinux_status_update_policyload(seqno);
selinux_netlbl_cache_invalidate();
selinux_xfrm_notify_policyload();
- return 0;
+ goto out;
}
#if 0
sidtab_hash_eval(&sidtab, "sids");
#endif
- rc = policydb_read(&newpolicydb, fp);
+ rc = policydb_read(newpolicydb, fp);
if (rc)
- return rc;
+ goto out;
- newpolicydb.len = len;
+ newpolicydb->len = len;
/* If switching between different policy types, log MLS status */
- if (policydb.mls_enabled && !newpolicydb.mls_enabled)
+ if (policydb.mls_enabled && !newpolicydb->mls_enabled)
printk(KERN_INFO "SELinux: Disabling MLS support...\n");
- else if (!policydb.mls_enabled && newpolicydb.mls_enabled)
+ else if (!policydb.mls_enabled && newpolicydb->mls_enabled)
printk(KERN_INFO "SELinux: Enabling MLS support...\n");
- rc = policydb_load_isids(&newpolicydb, &newsidtab);
+ rc = policydb_load_isids(newpolicydb, &newsidtab);
if (rc) {
printk(KERN_ERR "SELinux: unable to load the initial SIDs\n");
- policydb_destroy(&newpolicydb);
- return rc;
+ policydb_destroy(newpolicydb);
+ goto out;
}
- rc = selinux_set_mapping(&newpolicydb, secclass_map, &map, &map_size);
+ rc = selinux_set_mapping(newpolicydb, secclass_map, &map, &map_size);
if (rc)
goto err;
- rc = security_preserve_bools(&newpolicydb);
+ rc = security_preserve_bools(newpolicydb);
if (rc) {
printk(KERN_ERR "SELinux: unable to preserve booleans\n");
goto err;
@@ -1921,7 +1928,7 @@ int security_load_policy(void *data, size_t len)
* in the new SID table.
*/
args.oldp = &policydb;
- args.newp = &newpolicydb;
+ args.newp = newpolicydb;
rc = sidtab_map(&newsidtab, convert_context, &args);
if (rc) {
printk(KERN_ERR "SELinux: unable to convert the internal"
@@ -1931,12 +1938,12 @@ int security_load_policy(void *data, size_t len)
}
/* Save the old policydb and SID table to free later. */
- memcpy(&oldpolicydb, &policydb, sizeof policydb);
+ memcpy(oldpolicydb, &policydb, sizeof(policydb));
sidtab_set(&oldsidtab, &sidtab);
/* Install the new policydb and SID table. */
write_lock_irq(&policy_rwlock);
- memcpy(&policydb, &newpolicydb, sizeof policydb);
+ memcpy(&policydb, newpolicydb, sizeof(policydb));
sidtab_set(&sidtab, &newsidtab);
security_load_policycaps();
oldmap = current_mapping;
@@ -1946,7 +1953,7 @@ int security_load_policy(void *data, size_t len)
write_unlock_irq(&policy_rwlock);
/* Free the old policydb and SID table. */
- policydb_destroy(&oldpolicydb);
+ policydb_destroy(oldpolicydb);
sidtab_destroy(&oldsidtab);
kfree(oldmap);
@@ -1956,14 +1963,17 @@ int security_load_policy(void *data, size_t len)
selinux_netlbl_cache_invalidate();
selinux_xfrm_notify_policyload();
- return 0;
+ rc = 0;
+ goto out;
err:
kfree(map);
sidtab_destroy(&newsidtab);
- policydb_destroy(&newpolicydb);
- return rc;
+ policydb_destroy(newpolicydb);
+out:
+ kfree(oldpolicydb);
+ return rc;
}
size_t security_policydb_len(void)