selinux/stable-7.4 PR 20261015

-----BEGIN PGP SIGNATURE-----
 
 iQJIBAABCgAyFiEES0KozwfymdVUl37v6iDy2pc3iXMFAmrRAQIUHHBhdWxAcGF1
 bC1tb29yZS5jb20ACgkQ6iDy2pc3iXPjzBAAhBwzyxD47NquFO6w6dHj95wol7t/
 sxiWyNMLIPHsXr5RjbqS/EIkCS9OM0ZPRSKFAY/x1ddTJRr2KIQiaUPI1cf+VsMG
 QeGYd9p5Kp00jopa8Mj+2No9TvJZoNMTEyNYgtBQWCNUwF+dnYV0/c42IoHNeuOm
 5+BvqAIL32sEHHEtDeyconNJq4SLhsh75jC0jZtGSIbk3Y33a8q+4WkLc6nLzE7f
 AY5G4BDgt4z+Y7isMjDf1ApItyvDeHm4HP5gzu/YKUEF0D25UPiI+/eQhBAKdIEW
 +Y6v2NkN/0bYFGX/tKcKBAUb4OdYPcqA4B+H+5y03m/BuUxkqX3q5b3n4uPuL5Bl
 2nKVHtie/jjBEKTLlmP/bdivDPpf8V7Ljy/9baqrRuQSoUtxU9dd/dV+Ae08iKY4
 m1l6Kw2SjxoDNRRwaXJAA0oYCfl5T0OY3ZSaZCUnBLv7sNw3AZzop1c1FFRaLeeJ
 KGYju9cB+XsvOWTdkV7xGj6JFJpazcMSm6HPwkEEoXHpnuA842ErBpjozPpaTPsR
 i7EW1a/ohx2PXwWBxttYUY6IC8IW/d7vMTmR4hxkzILq3L0IMhdBnKvGsUWfvlrf
 5kqUEvxN+6SbhRhg2Jm9MRtW7/Tt2w8Ev2smb8B6zO1VcYDzEAgojtlymoS+itYK
 psYNddDIrkfSkpw=
 =pp5e
 -----END PGP SIGNATURE-----

Merge tag 'selinux-pr-20261015' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux

Pull selinux updates from Paul Moore:

 - Continue to improve the load time validation of SELinux policies

   While SELinux policy loading remains a privileged operation, we
   continue the recent trend of hardening the policy parsing and
   validation code in the kernel to ensure that invalid, or poorly
   formatted policies are rejected at load time.

 - Correctly incorporate "neveraudit" into the xperms code

   This change aligns the xperms neveraudit handling with the
   conventional permission handling code, exiting early from the SELinux
   auditing code when neveraudit is enabled for the domain.

 - Mark the selinuxfs "status" and "policy" files immutable

   These are read-only kernel/userspace interfaces that could
   successfully be opened at the VFS layer through the use of
   CAP_DAC_OVERRIDE. With this pull request we are marking these two
   files as immutable so that the requests to open these file with write
   permissions now fail at the VFS layer. This also allows us to drop
   some of our mmap() checks around write permissions as the VFS will
   now also handle this for us.

   The existing SELinux permissions checks remain untouched.

 - Convert the selinuxfs inode numbers to u64

   Bring selinuxfs current with other filesystems in using u64 for inode
   numbering as opposed to the architecture dependent unsigned long.

 - Constify a number of the SELinux AVC function parameters

 - Remove a SELinux MLS function that was no longer used

* tag 'selinux-pr-20261015' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux:
  selinux: validate permissive and neveraudit map types at load
  selinux: validate user MLS range and default level at load
  selinux: bounds-check role and user membership bitmaps at load
  selinux: check neveraudit in avc_xperms_audit_required()
  selinux: bounds-check filename transition source types at load
  selinux: reject duplicate symbol values during policy load
  selinux: reject a policy that both rejects and allows unknown classes
  selinux: constify avc function parameters
  selinux: avoid 64-bit division of inode numbers
  selinux: mark status and policy inodes as immutable, drop status mmap write checks
  selinux: remove unused mls_setup_user_range()
  selinux: convert selinuxfs inode numbers from unsigned long to u64
  selinux: tighten policydb_context_isvalid() checks
This commit is contained in:
Linus Torvalds 2026-10-20 19:42:14 -10:00
commit 331eadd85f
7 changed files with 183 additions and 101 deletions

View File

@ -190,8 +190,8 @@ avc_xperms_decision_lookup(u8 driver, u8 base_perm,
}
static inline unsigned int
avc_xperms_has_perm(struct extended_perms_decision *xpd,
u8 perm, u8 which)
avc_xperms_has_perm(const struct extended_perms_decision *xpd,
u8 perm, u8 which)
{
unsigned int rc = 0;
@ -247,7 +247,7 @@ static void avc_xperms_free(struct avc_xperms_node *xp_node)
}
static void avc_copy_xperms_decision(struct extended_perms_decision *dest,
struct extended_perms_decision *src)
const struct extended_perms_decision *src)
{
dest->base_perm = src->base_perm;
dest->driver = src->driver;
@ -269,7 +269,7 @@ static void avc_copy_xperms_decision(struct extended_perms_decision *dest,
*/
static inline void avc_quick_copy_xperms_decision(u8 perm,
struct extended_perms_decision *dest,
struct extended_perms_decision *src)
const struct extended_perms_decision *src)
{
/*
* compute index of the u32 of the 256 bits (8 u32s) that contain this
@ -323,7 +323,7 @@ static struct avc_xperms_decision_node
}
static int avc_add_xperms_decision(struct avc_node *node,
struct extended_perms_decision *src)
const struct extended_perms_decision *src)
{
struct avc_xperms_decision_node *dest_xpd;
@ -348,7 +348,7 @@ static struct avc_xperms_node *avc_xperms_alloc(void)
}
static int avc_xperms_populate(struct avc_node *node,
struct avc_xperms_node *src)
const struct avc_xperms_node *src)
{
struct avc_xperms_node *dest;
struct avc_xperms_decision_node *dest_xpd;
@ -381,14 +381,17 @@ static int avc_xperms_populate(struct avc_node *node,
}
static inline u32 avc_xperms_audit_required(u32 requested,
struct av_decision *avd,
struct extended_perms_decision *xpd,
u8 perm,
int result,
u32 *deniedp)
const struct av_decision *avd,
const struct extended_perms_decision *xpd,
u8 perm,
int result,
u32 *deniedp)
{
u32 denied, audited;
if (avd->flags & AVD_FLAGS_NEVERAUDIT)
return 0;
denied = requested & ~avd->allowed;
if (unlikely(denied)) {
audited = denied & avd->auditdeny;
@ -411,8 +414,8 @@ static inline u32 avc_xperms_audit_required(u32 requested,
}
static inline int avc_xperms_audit(u32 ssid, u32 tsid, u16 tclass,
u32 requested, struct av_decision *avd,
struct extended_perms_decision *xpd,
u32 requested, const struct av_decision *avd,
const struct extended_perms_decision *xpd,
u8 perm, int result,
struct common_audit_data *ad)
{
@ -509,7 +512,8 @@ static struct avc_node *avc_alloc_node(void)
return node;
}
static void avc_node_populate(struct avc_node *node, u32 ssid, u32 tsid, u16 tclass, struct av_decision *avd)
static void avc_node_populate(struct avc_node *node, u32 ssid, u32 tsid,
u16 tclass, const struct av_decision *avd)
{
node->ae.ssid = ssid;
node->ae.tsid = tsid;
@ -603,7 +607,8 @@ static int avc_latest_notif_update(u32 seqno, int is_insert)
* the access vectors into a cache entry.
*/
static void avc_insert(u32 ssid, u32 tsid, u16 tclass,
struct av_decision *avd, struct avc_xperms_node *xp_node)
const struct av_decision *avd,
const struct avc_xperms_node *xp_node)
{
struct avc_node *pos, *node = NULL;
u32 hvalue;
@ -828,7 +833,7 @@ int __init avc_add_callback(int (*callback)(u32 event), u32 events)
*/
static int avc_update_node(u32 event, u32 perms, u8 driver, u8 base_perm,
u8 xperm, u32 ssid, u32 tsid, u16 tclass, u32 seqno,
struct extended_perms_decision *xpd, u32 flags)
const struct extended_perms_decision *xpd, u32 flags)
{
u32 hvalue;
int rc = 0;

View File

@ -61,8 +61,9 @@ struct selinux_audit_data {
void __init avc_init(void);
static inline u32 avc_audit_required(u32 requested, struct av_decision *avd,
int result, u32 auditdeny, u32 *deniedp)
static inline u32 avc_audit_required(u32 requested,
const struct av_decision *avd, int result,
u32 auditdeny, u32 *deniedp)
{
u32 denied, audited;
@ -121,7 +122,7 @@ int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested, u32 audited,
* before calling the auditing code.
*/
static inline int avc_audit(u32 ssid, u32 tsid, u16 tclass, u32 requested,
struct av_decision *avd, int result,
const struct av_decision *avd, int result,
struct common_audit_data *a)
{
u32 audited, denied;

View File

@ -75,8 +75,8 @@ struct selinux_fs_info {
char **bool_pending_names;
int *bool_pending_values;
struct dentry *class_dir;
unsigned long last_class_ino;
unsigned long last_ino;
u64 last_class_ino;
u64 last_ino;
struct super_block *sb;
};
@ -247,11 +247,6 @@ static int sel_mmap_handle_status(struct file *filp,
/* only allows one page from the head */
if (vma->vm_pgoff > 0 || size != PAGE_SIZE)
return -EIO;
/* disallow writable mapping */
if (vma->vm_flags & VM_WRITE)
return -EPERM;
/* disallow mprotect() turns it into writable */
vm_flags_clear(vma, VM_MAYWRITE);
return remap_pfn_range(vma, vma->vm_start,
page_to_pfn(status),
@ -304,15 +299,14 @@ static int sel_make_bools(struct selinux_policy *newpolicy, struct dentry *bool_
int **bool_pending_values);
static int sel_make_classes(struct selinux_policy *newpolicy,
struct dentry *class_dir,
unsigned long *last_class_ino);
u64 *last_class_ino);
/* declaration for sel_make_class_dirs */
static struct dentry *sel_make_dir(struct dentry *dir, const char *name,
unsigned long *ino);
u64 *ino);
/* declaration for sel_make_policy_nodes */
static struct dentry *sel_make_swapover_dir(struct super_block *sb,
unsigned long *ino);
static struct dentry *sel_make_swapover_dir(struct super_block *sb, u64 *ino);
static ssize_t sel_read_mls(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
@ -467,7 +461,7 @@ static int sel_make_policy_nodes(struct selinux_fs_info *fsi,
unsigned int bool_num = 0;
char **bool_names = NULL;
int *bool_values = NULL;
unsigned long tmp_ino = fsi->last_ino; /* Don't increment last_ino in this function */
u64 tmp_ino = fsi->last_ino; /* Don't increment last_ino in this function */
tmp_parent = sel_make_swapover_dir(fsi->sb, &tmp_ino);
if (IS_ERR(tmp_parent))
@ -1568,30 +1562,32 @@ static int sel_make_initcon_files(struct dentry *dir)
return err;
}
static inline unsigned long sel_class_to_ino(u16 class)
static inline u64 sel_class_to_ino(u16 class)
{
return (class * (SEL_VEC_MAX + 1)) | SEL_CLASS_INO_OFFSET;
}
static inline u16 sel_ino_to_class(unsigned long ino)
static inline u16 sel_ino_to_class(u64 ino)
{
return (ino & SEL_INO_MASK) / (SEL_VEC_MAX + 1);
u32 ino_masked = ino & SEL_INO_MASK;
return ino_masked / (SEL_VEC_MAX + 1);
}
static inline unsigned long sel_perm_to_ino(u16 class, u32 perm)
static inline u64 sel_perm_to_ino(u16 class, u32 perm)
{
return (class * (SEL_VEC_MAX + 1) + perm) | SEL_CLASS_INO_OFFSET;
}
static inline u32 sel_ino_to_perm(unsigned long ino)
static inline u32 sel_ino_to_perm(u64 ino)
{
return (ino & SEL_INO_MASK) % (SEL_VEC_MAX + 1);
u32 ino_masked = ino & SEL_INO_MASK;
return ino_masked % (SEL_VEC_MAX + 1);
}
static ssize_t sel_read_class(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
unsigned long ino = file_inode(file)->i_ino;
u64 ino = file_inode(file)->i_ino;
char res[TMPBUFLEN];
ssize_t len = scnprintf(res, sizeof(res), "%d", sel_ino_to_class(ino));
return simple_read_from_buffer(buf, count, ppos, res, len);
@ -1605,7 +1601,7 @@ static const struct file_operations sel_class_ops = {
static ssize_t sel_read_perm(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
unsigned long ino = file_inode(file)->i_ino;
u64 ino = file_inode(file)->i_ino;
char res[TMPBUFLEN];
ssize_t len = scnprintf(res, sizeof(res), "%d", sel_ino_to_perm(ino));
return simple_read_from_buffer(buf, count, ppos, res, len);
@ -1622,7 +1618,7 @@ static ssize_t sel_read_policycap(struct file *file, char __user *buf,
int value;
char tmpbuf[TMPBUFLEN];
ssize_t length;
unsigned long i_ino = file_inode(file)->i_ino;
u64 i_ino = file_inode(file)->i_ino;
value = security_policycap_supported(i_ino & SEL_INO_MASK);
length = scnprintf(tmpbuf, TMPBUFLEN, "%d", value);
@ -1698,7 +1694,7 @@ static int sel_make_class_dir_entries(struct selinux_policy *newpolicy,
static int sel_make_classes(struct selinux_policy *newpolicy,
struct dentry *class_dir,
unsigned long *last_class_ino)
u64 *last_class_ino)
{
u32 i, nclasses;
int rc;
@ -1763,7 +1759,7 @@ static int sel_make_policycap(struct dentry *dir)
}
static struct dentry *sel_make_dir(struct dentry *dir, const char *name,
unsigned long *ino)
u64 *ino)
{
struct inode *inode;
@ -1792,8 +1788,7 @@ static const struct inode_operations swapover_dir_inode_operations = {
.permission = reject_all,
};
static struct dentry *sel_make_swapover_dir(struct super_block *sb,
unsigned long *ino)
static struct dentry *sel_make_swapover_dir(struct super_block *sb, u64 *ino)
{
struct dentry *dentry;
struct inode *inode;
@ -1820,6 +1815,17 @@ static struct dentry *sel_make_swapover_dir(struct super_block *sb,
#define NULL_FILE_NAME "null"
static void sel_mark_immutable(struct dentry *root, const char *name)
{
struct qstr q = QSTR(name);
struct dentry *dentry = try_lookup_noperm(&q, root);
if (!IS_ERR_OR_NULL(dentry)) {
d_inode(dentry)->i_flags |= S_IMMUTABLE;
dput(dentry);
}
}
static int sel_fill_super(struct super_block *sb, struct fs_context *fc)
{
struct selinux_fs_info *fsi;
@ -1859,6 +1865,9 @@ static int sel_fill_super(struct super_block *sb, struct fs_context *fc)
if (ret)
goto err;
sel_mark_immutable(sb->s_root, "status");
sel_mark_immutable(sb->s_root, "policy");
fsi = sb->s_fs_info;
fsi->bool_dir = sel_make_dir(sb->s_root, BOOL_DIR_NAME, &fsi->last_ino);
if (IS_ERR(fsi->bool_dir)) {

View File

@ -400,44 +400,6 @@ int mls_range_set(struct context *context, struct mls_range *range)
return rc;
}
int mls_setup_user_range(struct policydb *p, struct context *fromcon,
struct user_datum *user, struct context *usercon)
{
if (p->mls_enabled) {
struct mls_level *fromcon_sen = &(fromcon->range.level[0]);
struct mls_level *fromcon_clr = &(fromcon->range.level[1]);
struct mls_level *user_low = &(user->range.level[0]);
struct mls_level *user_clr = &(user->range.level[1]);
struct mls_level *user_def = &(user->dfltlevel);
struct mls_level *usercon_sen = &(usercon->range.level[0]);
struct mls_level *usercon_clr = &(usercon->range.level[1]);
/* Honor the user's default level if we can */
if (mls_level_between(user_def, fromcon_sen, fromcon_clr))
*usercon_sen = *user_def;
else if (mls_level_between(fromcon_sen, user_def, user_clr))
*usercon_sen = *fromcon_sen;
else if (mls_level_between(fromcon_clr, user_low, user_def))
*usercon_sen = *user_low;
else
return -EINVAL;
/* Lower the clearance of available contexts
if the clearance of "fromcon" is lower than
that of the user's default clearance (but
only if the "fromcon" clearance dominates
the user's computed sensitivity level) */
if (mls_level_dom(user_clr, fromcon_clr))
*usercon_clr = *fromcon_clr;
else if (mls_level_dom(fromcon_clr, user_clr))
*usercon_clr = *user_clr;
else
return -EINVAL;
}
return 0;
}
/*
* Convert the MLS fields in the security context
* structure `oldc' from the values specified in the

View File

@ -46,9 +46,6 @@ int mls_compute_sid(struct policydb *p, struct context *scontext,
struct context *tcontext, u16 tclass, u32 specified,
struct context *newcontext, bool sock);
int mls_setup_user_range(struct policydb *p, struct context *fromcon,
struct user_datum *user, struct context *usercon);
#ifdef CONFIG_NETLABEL
void mls_export_netlbl_lvl(struct policydb *p, struct context *context,
struct netlbl_lsm_secattr *secattr);

View File

@ -42,9 +42,6 @@ static inline int mls_level_dom(const struct mls_level *l1,
#define mls_level_incomp(l1, l2) \
(!mls_level_dom((l1), (l2)) && !mls_level_dom((l2), (l1)))
#define mls_level_between(l1, l2, l3) \
(mls_level_dom((l1), (l2)) && mls_level_dom((l3), (l1)))
#define mls_range_contains(r1, r2) \
(mls_level_dom(&(r2).level[0], &(r1).level[0]) && \
mls_level_dom(&(r1).level[1], &(r2).level[1]))

View File

@ -560,6 +560,9 @@ static int common_index(void *key, void *datum, void *datap)
if (!comdatum->value || comdatum->value > p->p_commons.nprim)
return -EINVAL;
if (p->sym_val_to_name[SYM_COMMONS][comdatum->value - 1])
return -EINVAL;
p->sym_val_to_name[SYM_COMMONS][comdatum->value - 1] = key;
return 0;
@ -575,6 +578,9 @@ static int class_index(void *key, void *datum, void *datap)
if (!cladatum->value || cladatum->value > p->p_classes.nprim)
return -EINVAL;
if (p->class_val_to_struct[cladatum->value - 1])
return -EINVAL;
p->sym_val_to_name[SYM_CLASSES][cladatum->value - 1] = key;
p->class_val_to_struct[cladatum->value - 1] = cladatum;
return 0;
@ -591,6 +597,9 @@ static int role_index(void *key, void *datum, void *datap)
role->bounds > p->p_roles.nprim)
return -EINVAL;
if (p->role_val_to_struct[role->value - 1])
return -EINVAL;
p->sym_val_to_name[SYM_ROLES][role->value - 1] = key;
p->role_val_to_struct[role->value - 1] = role;
return 0;
@ -613,6 +622,8 @@ static int type_index(void *key, void *datum, void *datap)
}
if (typdatum->primary) {
if (p->type_val_to_struct[typdatum->value - 1])
return -EINVAL;
p->sym_val_to_name[SYM_TYPES][typdatum->value - 1] = key;
p->type_val_to_struct[typdatum->value - 1] = typdatum;
}
@ -631,6 +642,9 @@ static int user_index(void *key, void *datum, void *datap)
usrdatum->bounds > p->p_users.nprim)
return -EINVAL;
if (p->user_val_to_struct[usrdatum->value - 1])
return -EINVAL;
p->sym_val_to_name[SYM_USERS][usrdatum->value - 1] = key;
p->user_val_to_struct[usrdatum->value - 1] = usrdatum;
return 0;
@ -647,8 +661,11 @@ static int sens_index(void *key, void *datum, void *datap)
if (!levdatum->level.sens || levdatum->level.sens > p->p_levels.nprim)
return -EINVAL;
if (!levdatum->isalias)
if (!levdatum->isalias) {
if (p->sym_val_to_name[SYM_LEVELS][levdatum->level.sens - 1])
return -EINVAL;
p->sym_val_to_name[SYM_LEVELS][levdatum->level.sens - 1] = key;
}
return 0;
}
@ -664,8 +681,11 @@ static int cat_index(void *key, void *datum, void *datap)
if (!catdatum->value || catdatum->value > p->p_cats.nprim)
return -EINVAL;
if (!catdatum->isalias)
if (!catdatum->isalias) {
if (p->sym_val_to_name[SYM_CATS][catdatum->value - 1])
return -EINVAL;
p->sym_val_to_name[SYM_CATS][catdatum->value - 1] = key;
}
return 0;
}
@ -687,6 +707,64 @@ static int sens_cat_index_check(void *key, void *datum, void *datap)
return 0;
}
static int role_index_check(void *key, void *datum, void *datap)
{
const struct policydb *p = datap;
const struct role_datum *role = datum;
struct ebitmap_node *node;
u32 bit;
ebitmap_for_each_positive_bit(&role->dominates, node, bit) {
if (!policydb_role_isvalid(p, bit + 1)) {
pr_err("SELinux: role %s declares dominance on undefined role %u\n",
(const char *)key, bit + 1);
return -EINVAL;
}
}
ebitmap_for_each_positive_bit(&role->types, node, bit) {
if (!policydb_type_isvalid(p, bit + 1)) {
pr_err("SELinux: role %s authorizes undefined type %u\n",
(const char *)key, bit + 1);
return -EINVAL;
}
}
return 0;
}
static int user_index_check(void *key, void *datum, void *datap)
{
const struct policydb *p = datap;
const struct user_datum *usr = datum;
struct ebitmap_node *node;
u32 bit;
ebitmap_for_each_positive_bit(&usr->roles, node, bit) {
if (!policydb_role_isvalid(p, bit + 1)) {
pr_err("SELinux: user %s authorizes undefined role %u\n",
(const char *)key, bit + 1);
return -EINVAL;
}
}
if (p->mls_enabled) {
if (!mls_range_isvalid(p, &usr->range)) {
pr_err("SELinux: user %s has an invalid MLS range\n",
(const char *)key);
return -EINVAL;
}
if (!mls_level_isvalid(p, &usr->dfltlevel)) {
pr_err("SELinux: user %s has an invalid MLS default level\n",
(const char *)key);
return -EINVAL;
}
}
return 0;
}
/* clang-format off */
static int (*const index_f[SYM_NUM])(void *key, void *datum, void *datap) = {
common_index,
@ -740,8 +818,9 @@ static inline void symtab_hash_eval(struct symtab *s)
*/
static int policydb_index(struct policydb *p)
{
struct ebitmap_node *node;
int i, rc;
u32 v;
u32 bit, v;
if (p->mls_enabled)
pr_debug(
@ -816,6 +895,31 @@ static int policydb_index(struct policydb *p)
goto out;
}
rc = hashtab_map(&p->p_roles.table, role_index_check, p);
if (rc)
goto out;
rc = hashtab_map(&p->p_users.table, user_index_check, p);
if (rc)
goto out;
ebitmap_for_each_positive_bit(&p->permissive_map, node, bit) {
if (!policydb_simpletype_isvalid(p, bit)) {
pr_err("SELinux: permissive map refers to invalid type %u\n",
bit);
rc = -EINVAL;
goto out;
}
}
ebitmap_for_each_positive_bit(&p->neveraudit_map, node, bit) {
if (!policydb_simpletype_isvalid(p, bit)) {
pr_err("SELinux: neveraudit map refers to invalid type %u\n",
bit);
rc = -EINVAL;
goto out;
}
}
rc = 0;
out:
return rc;
@ -1037,13 +1141,13 @@ bool policydb_context_isvalid(const struct policydb *p, const struct context *c)
const struct role_datum *role;
const struct user_datum *usrdatum;
if (!c->role || c->role > p->p_roles.nprim)
if (!policydb_role_isvalid(p, c->role))
return false;
if (!c->user || c->user > p->p_users.nprim)
if (!policydb_user_isvalid(p, c->user))
return false;
if (!c->type || c->type > p->p_types.nprim)
if (!policydb_simpletype_isvalid(p, c->type))
return false;
if (c->role != OBJECT_R_VAL) {
@ -1051,7 +1155,7 @@ bool policydb_context_isvalid(const struct policydb *p, const struct context *c)
* Role must be authorized for the type.
*/
role = p->role_val_to_struct[c->role - 1];
if (!role || !ebitmap_get_bit(&role->types, c->type - 1))
if (!ebitmap_get_bit(&role->types, c->type - 1))
/* role may not be associated with type */
return false;
@ -1059,9 +1163,6 @@ bool policydb_context_isvalid(const struct policydb *p, const struct context *c)
* User must be authorized for the role.
*/
usrdatum = p->user_val_to_struct[c->user - 1];
if (!usrdatum)
return false;
if (!ebitmap_get_bit(&usrdatum->roles, c->role - 1))
/* user may not be associated with role */
return false;
@ -2350,6 +2451,10 @@ static int filename_trans_read_helper(struct policydb *p, struct policy_file *fp
if (rc)
goto out;
rc = -EINVAL;
if (ebitmap_get_highest_set_bit(&datum->stypes) >= p->p_types.nprim)
goto out;
rc = next_entry(buf, fp, sizeof(u32));
if (rc)
goto out;
@ -2847,7 +2952,8 @@ int policydb_read(struct policydb *p, struct policy_file *fp)
goto bad;
}
if ((le32_to_cpu(buf[1]) & POLICYDB_CONFIG_MLS)) {
val = le32_to_cpu(buf[1]);
if (val & POLICYDB_CONFIG_MLS) {
p->mls_enabled = 1;
rc = -EINVAL;
@ -2858,8 +2964,13 @@ int policydb_read(struct policydb *p, struct policy_file *fp)
goto bad;
}
}
p->reject_unknown = !!(le32_to_cpu(buf[1]) & REJECT_UNKNOWN);
p->allow_unknown = !!(le32_to_cpu(buf[1]) & ALLOW_UNKNOWN);
rc = -EINVAL;
if ((val & (REJECT_UNKNOWN | ALLOW_UNKNOWN)) == (REJECT_UNKNOWN | ALLOW_UNKNOWN)) {
pr_err("SELinux: policydb configuration both rejects and allows unknown classes and permissions\n");
goto bad;
}
p->reject_unknown = !!(val & REJECT_UNKNOWN);
p->allow_unknown = !!(val & ALLOW_UNKNOWN);
if (p->policyvers >= POLICYDB_VERSION_POLCAP) {
rc = ebitmap_read(&p->policycaps, fp);