This commit is contained in:
Mark Brown
2026-07-31 15:26:32 +01:00
7 changed files with 136 additions and 61 deletions
+1 -2
View File
@@ -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;
}
+18 -9
View File
@@ -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);
+33 -32
View File
@@ -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;
int i;
buf_len = strlen("initialized=0;enforcing=0;checkreqprot=0;") + 1;
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);
seq_buf_init(&s, buf, selinux_ima_config_len);
rc = strlcat(buf, selinux_initialized() ? on : off, 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", 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, 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);
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;
}
+4
View File
@@ -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)
{
}
+13 -6
View File
@@ -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;
}
+58 -3
View File
@@ -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;
}
@@ -1175,6 +1180,9 @@ static int perm_read(struct policydb *p, struct symtab *s, struct policy_file *f
rc = -EINVAL;
if (perdatum->value < 1 || perdatum->value > SEL_VEC_MAX)
goto bad;
/* indexes an nprim-sized array in security_get_permissions() */
if (perdatum->value > s->nprim)
goto bad;
rc = str_read(&key, GFP_KERNEL, fp, len);
if (rc)
@@ -1327,6 +1335,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))
@@ -1334,6 +1363,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;
@@ -1419,6 +1462,18 @@ static int class_read(struct policydb *p, struct symtab *s, struct policy_file *
cladatum->comkey);
goto bad;
}
/*
* security_get_permissions() maps the common's permissions
* into an array sized by this class's nprim, so a class must
* declare at least as many as the common it inherits.
*/
if (cladatum->permissions.nprim <
cladatum->comdatum->permissions.nprim) {
pr_err("SELinux: class %s has fewer permissions than common %s\n",
key, cladatum->comkey);
goto bad;
}
}
for (i = 0; i < nel; i++) {
rc = perm_read(p, &cladatum->permissions, fp);
+9 -9
View File
@@ -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(