summaryrefslogtreecommitdiff
path: root/security
diff options
context:
space:
mode:
Diffstat (limited to 'security')
-rw-r--r--security/selinux/avc.c3
-rw-r--r--security/selinux/hooks.c27
-rw-r--r--security/selinux/ima.c65
-rw-r--r--security/selinux/include/ima.h4
-rw-r--r--security/selinux/selinuxfs.c19
-rw-r--r--security/selinux/ss/policydb.c46
-rw-r--r--security/selinux/ss/services.c18
7 files changed, 121 insertions, 61 deletions
diff --git a/security/selinux/avc.c b/security/selinux/avc.c
index 813e82bcfc27..a9401d6c2e5f 100644
--- a/security/selinux/avc.c
+++ b/security/selinux/avc.c
@@ -497,7 +497,7 @@ static struct avc_node *avc_alloc_node(void)
node = kmem_cache_zalloc(avc_node_cachep, GFP_NOWAIT);
if (!node)
- goto out;
+ return NULL;
INIT_HLIST_NODE(&node->list);
avc_cache_stats_incr(allocations);
@@ -506,7 +506,6 @@ static struct avc_node *avc_alloc_node(void)
selinux_avc.avc_cache_threshold)
avc_reclaim_node();
-out:
return node;
}
diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
index 18dd28b2bb13..035aaf113d1d 100644
--- a/security/selinux/hooks.c
+++ b/security/selinux/hooks.c
@@ -94,6 +94,7 @@
#include <linux/io_uring/cmd.h>
#include <uapi/linux/lsm.h>
#include <linux/memfd.h>
+#include <uapi/linux/inet_diag.h>
#include "initcalls.h"
#include "avc.h"
@@ -106,6 +107,7 @@
#include "netlabel.h"
#include "audit.h"
#include "avc_ss.h"
+#include "ima.h"
#define SELINUX_INODE_INIT_XATTRS 1
@@ -1336,11 +1338,11 @@ static int selinux_genfs_get_sid(struct dentry *dentry,
struct super_block *sb = dentry->d_sb;
char *buffer, *path;
- buffer = (char *)__get_free_page(GFP_KERNEL);
+ buffer = kmalloc(PATH_MAX, GFP_KERNEL);
if (!buffer)
return -ENOMEM;
- path = dentry_path_raw(dentry, buffer, PAGE_SIZE);
+ path = dentry_path_raw(dentry, buffer, PATH_MAX);
if (IS_ERR(path))
rc = PTR_ERR(path);
else {
@@ -1361,7 +1363,7 @@ static int selinux_genfs_get_sid(struct dentry *dentry,
rc = 0;
}
}
- free_page((unsigned long)buffer);
+ kfree(buffer);
return rc;
}
@@ -6296,12 +6298,17 @@ static int selinux_netlink_send(struct sock *sk, struct sk_buff *skb)
return rc;
} else if (rc == -EINVAL) {
/* -EINVAL is a missing msg/perm mapping */
- pr_warn_ratelimited("SELinux: unrecognized netlink"
- " message: protocol=%hu nlmsg_type=%hu sclass=%s"
- " pid=%d comm=%s\n",
- sk->sk_protocol, nlh->nlmsg_type,
- secclass_map[sclass - 1].name,
- task_pid_nr(current), current->comm);
+ if (sclass == SECCLASS_NETLINK_TCPDIAG_SOCKET &&
+ nlh->nlmsg_type == DCCPDIAG_GETSOCK)
+ pr_warn_once("SELinux: DCCP has been removed, pid=%d comm=%s\n",
+ task_pid_nr(current), current->comm);
+ else
+ pr_warn_ratelimited("SELinux: unrecognized netlink"
+ " message: protocol=%hu nlmsg_type=%hu sclass=%s"
+ " pid=%d comm=%s\n",
+ sk->sk_protocol, nlh->nlmsg_type,
+ secclass_map[sclass - 1].name,
+ task_pid_nr(current), current->comm);
if (enforcing_enabled() &&
!security_get_allow_unknown())
return rc;
@@ -7874,6 +7881,8 @@ static __init int selinux_init(void)
hashtab_cache_init();
+ selinux_ima_config_len_init();
+
security_add_hooks(selinux_hooks, ARRAY_SIZE(selinux_hooks),
&selinux_lsmid);
diff --git a/security/selinux/ima.c b/security/selinux/ima.c
index aa34da9b0aeb..cda68122e032 100644
--- a/security/selinux/ima.c
+++ b/security/selinux/ima.c
@@ -9,9 +9,31 @@
*/
#include <linux/vmalloc.h>
#include <linux/ima.h>
+#include <linux/seq_buf.h>
#include "security.h"
#include "ima.h"
+static int selinux_ima_config_len __ro_after_init;
+
+/*
+ * selinux_ima_config_len_init - Compute the configuration settings string length
+ *
+ * The string is fixed text plus one digit per setting, so its length
+ * is known at boot.
+ */
+void __init selinux_ima_config_len_init(void)
+{
+ int buf_len, suffix_len, i;
+
+ buf_len = strlen("initialized=0;enforcing=0;checkreqprot=0;") + 1;
+ suffix_len = strlen("=0;");
+
+ for (i = 0; i < __POLICYDB_CAP_MAX; i++)
+ buf_len += strlen(selinux_policycap_names[i]) + suffix_len;
+
+ selinux_ima_config_len = buf_len;
+}
+
/*
* selinux_ima_collect_state - Read selinux configuration settings
*
@@ -20,46 +42,25 @@
*/
static char *selinux_ima_collect_state(void)
{
- const char *on = "=1;", *off = "=0;";
+ struct seq_buf s;
char *buf;
- int buf_len, len, i, rc;
-
- buf_len = strlen("initialized=0;enforcing=0;checkreqprot=0;") + 1;
+ int i;
- len = strlen(on);
- for (i = 0; i < __POLICYDB_CAP_MAX; i++)
- buf_len += strlen(selinux_policycap_names[i]) + len;
-
- buf = kzalloc(buf_len, GFP_KERNEL);
+ buf = kzalloc(selinux_ima_config_len, GFP_KERNEL);
if (!buf)
return NULL;
- rc = strscpy(buf, "initialized", buf_len);
- WARN_ON(rc < 0);
-
- rc = strlcat(buf, selinux_initialized() ? on : off, buf_len);
- WARN_ON(rc >= buf_len);
+ seq_buf_init(&s, buf, selinux_ima_config_len);
- rc = strlcat(buf, "enforcing", buf_len);
- WARN_ON(rc >= buf_len);
+ seq_buf_printf(&s, "initialized=%d;enforcing=%d;checkreqprot=%d;",
+ selinux_initialized(), enforcing_enabled(),
+ checkreqprot_get());
- rc = strlcat(buf, enforcing_enabled() ? on : off, buf_len);
- WARN_ON(rc >= buf_len);
-
- rc = strlcat(buf, "checkreqprot", buf_len);
- WARN_ON(rc >= buf_len);
-
- rc = strlcat(buf, checkreqprot_get() ? on : off, buf_len);
- WARN_ON(rc >= buf_len);
-
- for (i = 0; i < __POLICYDB_CAP_MAX; i++) {
- rc = strlcat(buf, selinux_policycap_names[i], buf_len);
- WARN_ON(rc >= buf_len);
+ for (i = 0; i < __POLICYDB_CAP_MAX; i++)
+ seq_buf_printf(&s, "%s=%d;", selinux_policycap_names[i],
+ selinux_state.policycap[i]);
- rc = strlcat(buf, selinux_state.policycap[i] ? on : off,
- buf_len);
- WARN_ON(rc >= buf_len);
- }
+ WARN_ON(seq_buf_has_overflowed(&s));
return buf;
}
diff --git a/security/selinux/include/ima.h b/security/selinux/include/ima.h
index 38ab302f5946..d7d18f030d3d 100644
--- a/security/selinux/include/ima.h
+++ b/security/selinux/include/ima.h
@@ -14,9 +14,13 @@
#include "security.h"
#ifdef CONFIG_IMA
+void __init selinux_ima_config_len_init(void);
extern void selinux_ima_measure_state(void);
extern void selinux_ima_measure_state_locked(void);
#else
+static inline void selinux_ima_config_len_init(void)
+{
+}
static inline void selinux_ima_measure_state(void)
{
}
diff --git a/security/selinux/selinuxfs.c b/security/selinux/selinuxfs.c
index 5aaaf69410bb..c7d91476971c 100644
--- a/security/selinux/selinuxfs.c
+++ b/security/selinux/selinuxfs.c
@@ -1984,17 +1984,15 @@ int __init init_sel_fs(void)
return err;
err = register_filesystem(&sel_fs_type);
- if (err) {
- sysfs_remove_mount_point(fs_kobj, "selinux");
- return err;
- }
+ if (err)
+ goto err_remove_mount_point;
selinux_null.mnt = kern_mount(&sel_fs_type);
if (IS_ERR(selinux_null.mnt)) {
pr_err("selinuxfs: could not mount!\n");
err = PTR_ERR(selinux_null.mnt);
selinux_null.mnt = NULL;
- return err;
+ goto err_unregister_fs;
}
selinux_null.dentry = try_lookup_noperm(&null_name,
@@ -2003,7 +2001,7 @@ int __init init_sel_fs(void)
pr_err("selinuxfs: could not lookup null!\n");
err = PTR_ERR(selinux_null.dentry);
selinux_null.dentry = NULL;
- return err;
+ goto err_unmount;
}
/*
@@ -2012,5 +2010,14 @@ int __init init_sel_fs(void)
*/
(void) selinux_kernel_status_page();
+ return 0;
+
+err_unmount:
+ kern_unmount(selinux_null.mnt);
+ selinux_null.mnt = NULL;
+err_unregister_fs:
+ unregister_filesystem(&sel_fs_type);
+err_remove_mount_point:
+ sysfs_remove_mount_point(fs_kobj, "selinux");
return err;
}
diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c
index 8a32666c0ba2..b75c977c6673 100644
--- a/security/selinux/ss/policydb.c
+++ b/security/selinux/ss/policydb.c
@@ -604,10 +604,15 @@ static int type_index(void *key, void *datum, void *datap)
typdatum = datum;
p = datap;
+ if (!typdatum->value || typdatum->value > p->p_types.nprim ||
+ typdatum->bounds > p->p_types.nprim) {
+ pr_err("SELinux: type %s had value %u bounds %u nprim %u\n",
+ (char *)key, typdatum->value, typdatum->bounds,
+ p->p_types.nprim);
+ return -EINVAL;
+ }
+
if (typdatum->primary) {
- if (!typdatum->value || typdatum->value > p->p_types.nprim ||
- typdatum->bounds > p->p_types.nprim)
- return -EINVAL;
p->sym_val_to_name[SYM_TYPES][typdatum->value - 1] = key;
p->type_val_to_struct[typdatum->value - 1] = typdatum;
}
@@ -1398,6 +1403,27 @@ static int read_cons_helper(struct policydb *p, struct constraint_node **nodep,
if (depth == (CEXPR_MAXDEPTH - 1))
return -EINVAL;
depth++;
+ switch (e->attr) {
+ case CEXPR_USER:
+ case CEXPR_TYPE:
+ if (e->op != CEXPR_EQ &&
+ e->op != CEXPR_NEQ)
+ return -EINVAL;
+ break;
+ case CEXPR_ROLE:
+ case CEXPR_L1L2:
+ case CEXPR_L1H2:
+ case CEXPR_H1L2:
+ case CEXPR_H1H2:
+ case CEXPR_L1H1:
+ case CEXPR_L2H2:
+ if (e->op < CEXPR_EQ ||
+ e->op > CEXPR_INCOMP)
+ return -EINVAL;
+ break;
+ default:
+ return -EINVAL;
+ }
break;
case CEXPR_NAMES:
if (!allowxtarget && (e->attr & CEXPR_XTARGET))
@@ -1405,6 +1431,20 @@ static int read_cons_helper(struct policydb *p, struct constraint_node **nodep,
if (depth == (CEXPR_MAXDEPTH - 1))
return -EINVAL;
depth++;
+ switch (e->attr &
+ ~(CEXPR_TARGET|CEXPR_XTARGET)) {
+ case CEXPR_USER:
+ case CEXPR_ROLE:
+ case CEXPR_TYPE:
+ break;
+ default:
+ return -EINVAL;
+ }
+ if ((e->attr & (CEXPR_TARGET|CEXPR_XTARGET)) ==
+ (CEXPR_TARGET|CEXPR_XTARGET))
+ return -EINVAL;
+ if (e->op != CEXPR_EQ && e->op != CEXPR_NEQ)
+ return -EINVAL;
rc = ebitmap_read(&e->names, fp);
if (rc)
return rc;
diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
index 7afce975436e..da77ad769c83 100644
--- a/security/selinux/ss/services.c
+++ b/security/selinux/ss/services.c
@@ -1355,8 +1355,8 @@ const char *security_get_initial_sid_context(u32 sid)
}
static int security_sid_to_context_core(u32 sid, char **scontext,
- u32 *scontext_len, int force,
- int only_invalid)
+ u32 *scontext_len, bool force,
+ bool only_invalid)
{
struct selinux_policy *policy;
struct policydb *policydb;
@@ -1439,14 +1439,14 @@ out_unlock:
int security_sid_to_context(u32 sid, char **scontext, u32 *scontext_len)
{
return security_sid_to_context_core(sid, scontext,
- scontext_len, 0, 0);
+ scontext_len, false, false);
}
int security_sid_to_context_force(u32 sid,
char **scontext, u32 *scontext_len)
{
return security_sid_to_context_core(sid, scontext,
- scontext_len, 1, 0);
+ scontext_len, true, false);
}
/**
@@ -1466,7 +1466,7 @@ int security_sid_to_context_inval(u32 sid,
char **scontext, u32 *scontext_len)
{
return security_sid_to_context_core(sid, scontext,
- scontext_len, 1, 1);
+ scontext_len, true, true);
}
/*
@@ -1552,7 +1552,7 @@ out:
static int security_context_to_sid_core(const char *scontext, u32 scontext_len,
u32 *sid, u32 def_sid, gfp_t gfp_flags,
- int force)
+ bool force)
{
struct selinux_policy *policy;
struct policydb *policydb;
@@ -1641,7 +1641,7 @@ int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid,
gfp_t gfp)
{
return security_context_to_sid_core(scontext, scontext_len,
- sid, SECSID_NULL, gfp, 0);
+ sid, SECSID_NULL, gfp, false);
}
int security_context_str_to_sid(const char *scontext, u32 *sid, gfp_t gfp)
@@ -1673,14 +1673,14 @@ int security_context_to_sid_default(const char *scontext, u32 scontext_len,
u32 *sid, u32 def_sid, gfp_t gfp_flags)
{
return security_context_to_sid_core(scontext, scontext_len,
- sid, def_sid, gfp_flags, 1);
+ sid, def_sid, gfp_flags, true);
}
int security_context_to_sid_force(const char *scontext, u32 scontext_len,
u32 *sid)
{
return security_context_to_sid_core(scontext, scontext_len,
- sid, SECSID_NULL, GFP_KERNEL, 1);
+ sid, SECSID_NULL, GFP_KERNEL, true);
}
static int compute_sid_handle_invalid_context(