selinux/stable-6.10 PR 20240513

-----BEGIN PGP SIGNATURE-----
 
 iQJIBAABCAAyFiEES0KozwfymdVUl37v6iDy2pc3iXMFAmZCWd4UHHBhdWxAcGF1
 bC1tb29yZS5jb20ACgkQ6iDy2pc3iXMFMQ/8DlQhbe+NzeAjBg2O7RqNKoE/UU2l
 JAkzgQ7h35/sgsfDIEhPv0VOzq2cwLSaw5/qSGGrQDWR4AKz55HvBSJQDElgzPo2
 wtL2lozjJ03+P391aeXEHdkqzgp2F3c6oNthIcFvRmi3EVcWr7eqnjWU+bJzFtMA
 z4IgX01yiUF6EMdTJcWjSLclk3dOqHWPV657RadYyp2pr3u9rc9gqgxichs0dQW0
 X/vexUBg81TdSeHS+u9Jgrz+TCsQdP3CHSFibXDv1rX89bqCbG9wYNTyTBHH9f0j
 LPpV2bKaesxIZV6dZyIKKSqCtHGBcjcJEjUbl7JFkQOS/a8NPMDH2ZYkHqbyq4BH
 SX+kRhthmXZiZ2IWhMRikaE4FBIWI7JAC4riKB2Dd0RzJrNEgaawU0wM+evKai9F
 s3GCk/P7wnTT4GlDHSkYEiiRF9c3DNkfVb9mqG78PRMR4X+z/0dsX5iaJTwlyMxo
 69JSoTNzMxVdDtvD+K89V7GCm8NmGFjLwQUqb282L/6ibzC/5CCUQXn8ZWvNRPql
 IUoQhKbveCWR3m9vAMeGpE61oNgFp0mHj3Zb/vE5Yu7HxOn2y1lFv2XGxR6bGyTF
 T53AaHM15uFomhqhG+iM3b4FDhNIJpbUc4MJsq3iMgFC941n1ceXyeBEgf31+Z2x
 k1ZlxqLAWn05auA=
 =2Wbi
 -----END PGP SIGNATURE-----

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

Pull selinux updates from Paul Moore:

 - Attempt to pre-allocate the SELinux status page so it doesn't appear
   to userspace that we are skipping SELinux policy sequence numbers

 - Reject invalid SELinux policy bitmaps with an error at policy load
   time

 - Consistently use the same type, u32, for ebitmap offsets

 - Improve the "symhash" hash function for better distribution on common
   policies

 - Correct a number of printk format specifiers in the ebitmap code

 - Improved error checking in sel_write_load()

 - Ensure we have a proper return code in the
   filename_trans_read_helper_compat() function

 - Make better use of the current_sid() helper function

 - Allow for more hash table statistics when debugging is enabled

 - Migrate from printk_ratelimit() to pr_warn_ratelimited()

 - Miscellaneous cleanups and tweaks to selinux_lsm_getattr()

 - More consitification work in the conditional policy space

* tag 'selinux-pr-20240513' of git://git.kernel.org/pub/scm/linux/kernel/git/pcmoore/selinux:
  selinux: constify source policy in cond_policydb_dup()
  selinux: avoid printk_ratelimit()
  selinux: pre-allocate the status page
  selinux: clarify return code in filename_trans_read_helper_compat()
  selinux: use u32 as bit position type in ebitmap code
  selinux: improve symtab string hashing
  selinux: dump statistics for more hash tables
  selinux: make more use of current_sid()
  selinux: update numeric format specifiers for ebitmaps
  selinux: improve error checking in sel_write_load()
  selinux: cleanup selinux_lsm_getattr()
  selinux: reject invalid ebitmaps
This commit is contained in:
Linus Torvalds 2024-05-15 08:36:30 -07:00
commit ccae19c623
12 changed files with 145 additions and 125 deletions

View file

@ -2961,7 +2961,7 @@ static int selinux_inode_init_security_anon(struct inode *inode,
const struct qstr *name, const struct qstr *name,
const struct inode *context_inode) const struct inode *context_inode)
{ {
const struct task_security_struct *tsec = selinux_cred(current_cred()); u32 sid = current_sid();
struct common_audit_data ad; struct common_audit_data ad;
struct inode_security_struct *isec; struct inode_security_struct *isec;
int rc; int rc;
@ -2990,7 +2990,7 @@ static int selinux_inode_init_security_anon(struct inode *inode,
} else { } else {
isec->sclass = SECCLASS_ANON_INODE; isec->sclass = SECCLASS_ANON_INODE;
rc = security_transition_sid( rc = security_transition_sid(
tsec->sid, tsec->sid, sid, sid,
isec->sclass, name, &isec->sid); isec->sclass, name, &isec->sid);
if (rc) if (rc)
return rc; return rc;
@ -3005,7 +3005,7 @@ static int selinux_inode_init_security_anon(struct inode *inode,
ad.type = LSM_AUDIT_DATA_ANONINODE; ad.type = LSM_AUDIT_DATA_ANONINODE;
ad.u.anonclass = name ? (const char *)name->name : "?"; ad.u.anonclass = name ? (const char *)name->name : "?";
return avc_has_perm(tsec->sid, return avc_has_perm(sid,
isec->sid, isec->sid,
isec->sclass, isec->sclass,
FILE__CREATE, FILE__CREATE,
@ -3063,14 +3063,12 @@ static int selinux_inode_readlink(struct dentry *dentry)
static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode, static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
bool rcu) bool rcu)
{ {
const struct cred *cred = current_cred();
struct common_audit_data ad; struct common_audit_data ad;
struct inode_security_struct *isec; struct inode_security_struct *isec;
u32 sid; u32 sid = current_sid();
ad.type = LSM_AUDIT_DATA_DENTRY; ad.type = LSM_AUDIT_DATA_DENTRY;
ad.u.dentry = dentry; ad.u.dentry = dentry;
sid = cred_sid(cred);
isec = inode_security_rcu(inode, rcu); isec = inode_security_rcu(inode, rcu);
if (IS_ERR(isec)) if (IS_ERR(isec))
return PTR_ERR(isec); return PTR_ERR(isec);
@ -3094,12 +3092,11 @@ static noinline int audit_inode_permission(struct inode *inode,
static int selinux_inode_permission(struct inode *inode, int mask) static int selinux_inode_permission(struct inode *inode, int mask)
{ {
const struct cred *cred = current_cred();
u32 perms; u32 perms;
bool from_access; bool from_access;
bool no_block = mask & MAY_NOT_BLOCK; bool no_block = mask & MAY_NOT_BLOCK;
struct inode_security_struct *isec; struct inode_security_struct *isec;
u32 sid; u32 sid = current_sid();
struct av_decision avd; struct av_decision avd;
int rc, rc2; int rc, rc2;
u32 audited, denied; u32 audited, denied;
@ -3116,7 +3113,6 @@ static int selinux_inode_permission(struct inode *inode, int mask)
perms = file_mask_to_av(inode->i_mode, mask); perms = file_mask_to_av(inode->i_mode, mask);
sid = cred_sid(cred);
isec = inode_security_rcu(inode, no_block); isec = inode_security_rcu(inode, no_block);
if (IS_ERR(isec)) if (IS_ERR(isec))
return PTR_ERR(isec); return PTR_ERR(isec);
@ -5564,13 +5560,7 @@ static void selinux_inet_conn_established(struct sock *sk, struct sk_buff *skb)
static int selinux_secmark_relabel_packet(u32 sid) static int selinux_secmark_relabel_packet(u32 sid)
{ {
const struct task_security_struct *tsec; return avc_has_perm(current_sid(), sid, SECCLASS_PACKET, PACKET__RELABELTO,
u32 tsid;
tsec = selinux_cred(current_cred());
tsid = tsec->sid;
return avc_has_perm(tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO,
NULL); NULL);
} }
@ -6348,55 +6338,55 @@ static void selinux_d_instantiate(struct dentry *dentry, struct inode *inode)
static int selinux_lsm_getattr(unsigned int attr, struct task_struct *p, static int selinux_lsm_getattr(unsigned int attr, struct task_struct *p,
char **value) char **value)
{ {
const struct task_security_struct *__tsec; const struct task_security_struct *tsec;
u32 sid;
int error; int error;
unsigned len; u32 sid;
u32 len;
rcu_read_lock(); rcu_read_lock();
__tsec = selinux_cred(__task_cred(p)); tsec = selinux_cred(__task_cred(p));
if (p != current) {
if (current != p) { error = avc_has_perm(current_sid(), tsec->sid,
error = avc_has_perm(current_sid(), __tsec->sid,
SECCLASS_PROCESS, PROCESS__GETATTR, NULL); SECCLASS_PROCESS, PROCESS__GETATTR, NULL);
if (error) if (error)
goto bad; goto err_unlock;
} }
switch (attr) { switch (attr) {
case LSM_ATTR_CURRENT: case LSM_ATTR_CURRENT:
sid = __tsec->sid; sid = tsec->sid;
break; break;
case LSM_ATTR_PREV: case LSM_ATTR_PREV:
sid = __tsec->osid; sid = tsec->osid;
break; break;
case LSM_ATTR_EXEC: case LSM_ATTR_EXEC:
sid = __tsec->exec_sid; sid = tsec->exec_sid;
break; break;
case LSM_ATTR_FSCREATE: case LSM_ATTR_FSCREATE:
sid = __tsec->create_sid; sid = tsec->create_sid;
break; break;
case LSM_ATTR_KEYCREATE: case LSM_ATTR_KEYCREATE:
sid = __tsec->keycreate_sid; sid = tsec->keycreate_sid;
break; break;
case LSM_ATTR_SOCKCREATE: case LSM_ATTR_SOCKCREATE:
sid = __tsec->sockcreate_sid; sid = tsec->sockcreate_sid;
break; break;
default: default:
error = -EOPNOTSUPP; error = -EOPNOTSUPP;
goto bad; goto err_unlock;
} }
rcu_read_unlock(); rcu_read_unlock();
if (!sid) if (sid == SECSID_NULL) {
*value = NULL;
return 0; return 0;
}
error = security_sid_to_context(sid, value, &len); error = security_sid_to_context(sid, value, &len);
if (error) if (error)
return error; return error;
return len; return len;
bad: err_unlock:
rcu_read_unlock(); rcu_read_unlock();
return error; return error;
} }

View file

@ -571,11 +571,18 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
size_t count, loff_t *ppos) size_t count, loff_t *ppos)
{ {
struct selinux_fs_info *fsi = file_inode(file)->i_sb->s_fs_info; struct selinux_fs_info *fsi;
struct selinux_load_state load_state; struct selinux_load_state load_state;
ssize_t length; ssize_t length;
void *data = NULL; void *data = NULL;
/* no partial writes */
if (*ppos)
return -EINVAL;
/* no empty policies */
if (!count)
return -EINVAL;
mutex_lock(&selinux_state.policy_mutex); mutex_lock(&selinux_state.policy_mutex);
length = avc_has_perm(current_sid(), SECINITSID_SECURITY, length = avc_has_perm(current_sid(), SECINITSID_SECURITY,
@ -583,26 +590,22 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
if (length) if (length)
goto out; goto out;
/* No partial writes. */
length = -EINVAL;
if (*ppos != 0)
goto out;
length = -ENOMEM;
data = vmalloc(count); data = vmalloc(count);
if (!data) if (!data) {
length = -ENOMEM;
goto out; goto out;
}
length = -EFAULT; if (copy_from_user(data, buf, count) != 0) {
if (copy_from_user(data, buf, count) != 0) length = -EFAULT;
goto out; goto out;
}
length = security_load_policy(data, count, &load_state); length = security_load_policy(data, count, &load_state);
if (length) { if (length) {
pr_warn_ratelimited("SELinux: failed to load policy\n"); pr_warn_ratelimited("SELinux: failed to load policy\n");
goto out; goto out;
} }
fsi = file_inode(file)->i_sb->s_fs_info;
length = sel_make_policy_nodes(fsi, load_state.policy); length = sel_make_policy_nodes(fsi, load_state.policy);
if (length) { if (length) {
pr_warn_ratelimited("SELinux: failed to initialize selinuxfs\n"); pr_warn_ratelimited("SELinux: failed to initialize selinuxfs\n");
@ -611,13 +614,12 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
} }
selinux_policy_commit(&load_state); selinux_policy_commit(&load_state);
length = count; length = count;
audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_POLICY_LOAD, audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,
"auid=%u ses=%u lsm=selinux res=1", "auid=%u ses=%u lsm=selinux res=1",
from_kuid(&init_user_ns, audit_get_loginuid(current)), from_kuid(&init_user_ns, audit_get_loginuid(current)),
audit_get_sessionid(current)); audit_get_sessionid(current));
out: out:
mutex_unlock(&selinux_state.policy_mutex); mutex_unlock(&selinux_state.policy_mutex);
vfree(data); vfree(data);
@ -2161,6 +2163,12 @@ static int __init init_sel_fs(void)
return err; return err;
} }
/*
* Try to pre-allocate the status page, so the sequence number of the
* initial policy load can be stored.
*/
(void) selinux_kernel_status_page();
return err; return err;
} }

View file

@ -169,6 +169,9 @@ int cond_init_bool_indexes(struct policydb *p)
p->p_bools.nprim, sizeof(*p->bool_val_to_struct), GFP_KERNEL); p->p_bools.nprim, sizeof(*p->bool_val_to_struct), GFP_KERNEL);
if (!p->bool_val_to_struct) if (!p->bool_val_to_struct)
return -ENOMEM; return -ENOMEM;
avtab_hash_eval(&p->te_cond_avtab, "conditional_rules");
return 0; return 0;
} }
@ -600,7 +603,8 @@ void cond_compute_av(struct avtab *ctab, struct avtab_key *key,
} }
} }
static int cond_dup_av_list(struct cond_av_list *new, struct cond_av_list *orig, static int cond_dup_av_list(struct cond_av_list *new,
const struct cond_av_list *orig,
struct avtab *avtab) struct avtab *avtab)
{ {
u32 i; u32 i;
@ -623,7 +627,7 @@ static int cond_dup_av_list(struct cond_av_list *new, struct cond_av_list *orig,
} }
static int duplicate_policydb_cond_list(struct policydb *newp, static int duplicate_policydb_cond_list(struct policydb *newp,
struct policydb *origp) const struct policydb *origp)
{ {
int rc; int rc;
u32 i; u32 i;
@ -640,7 +644,7 @@ static int duplicate_policydb_cond_list(struct policydb *newp,
for (i = 0; i < origp->cond_list_len; i++) { for (i = 0; i < origp->cond_list_len; i++) {
struct cond_node *newn = &newp->cond_list[i]; struct cond_node *newn = &newp->cond_list[i];
struct cond_node *orign = &origp->cond_list[i]; const struct cond_node *orign = &origp->cond_list[i];
newp->cond_list_len++; newp->cond_list_len++;
@ -680,8 +684,8 @@ static int cond_bools_destroy(void *key, void *datum, void *args)
return 0; return 0;
} }
static int cond_bools_copy(struct hashtab_node *new, struct hashtab_node *orig, static int cond_bools_copy(struct hashtab_node *new,
void *args) const struct hashtab_node *orig, void *args)
{ {
struct cond_bool_datum *datum; struct cond_bool_datum *datum;
@ -707,7 +711,7 @@ static int cond_bools_index(void *key, void *datum, void *args)
} }
static int duplicate_policydb_bools(struct policydb *newdb, static int duplicate_policydb_bools(struct policydb *newdb,
struct policydb *orig) const struct policydb *orig)
{ {
struct cond_bool_datum **cond_bool_array; struct cond_bool_datum **cond_bool_array;
int rc; int rc;
@ -740,7 +744,7 @@ void cond_policydb_destroy_dup(struct policydb *p)
cond_policydb_destroy(p); cond_policydb_destroy(p);
} }
int cond_policydb_dup(struct policydb *new, struct policydb *orig) int cond_policydb_dup(struct policydb *new, const struct policydb *orig)
{ {
cond_policydb_init(new); cond_policydb_init(new);

View file

@ -79,6 +79,6 @@ void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key,
struct extended_perms_decision *xpermd); struct extended_perms_decision *xpermd);
void evaluate_cond_nodes(struct policydb *p); void evaluate_cond_nodes(struct policydb *p);
void cond_policydb_destroy_dup(struct policydb *p); void cond_policydb_destroy_dup(struct policydb *p);
int cond_policydb_dup(struct policydb *new, struct policydb *orig); int cond_policydb_dup(struct policydb *new, const struct policydb *orig);
#endif /* _CONDITIONAL_H_ */ #endif /* _CONDITIONAL_H_ */

View file

@ -21,7 +21,7 @@
#include "ebitmap.h" #include "ebitmap.h"
#include "policydb.h" #include "policydb.h"
#define BITS_PER_U64 (sizeof(u64) * 8) #define BITS_PER_U64 ((u32)(sizeof(u64) * 8))
static struct kmem_cache *ebitmap_node_cachep __ro_after_init; static struct kmem_cache *ebitmap_node_cachep __ro_after_init;
@ -79,7 +79,8 @@ int ebitmap_and(struct ebitmap *dst, const struct ebitmap *e1,
const struct ebitmap *e2) const struct ebitmap *e2)
{ {
struct ebitmap_node *n; struct ebitmap_node *n;
int bit, rc; u32 bit;
int rc;
ebitmap_init(dst); ebitmap_init(dst);
@ -256,7 +257,7 @@ int ebitmap_contains(const struct ebitmap *e1, const struct ebitmap *e2,
return 1; return 1;
} }
int ebitmap_get_bit(const struct ebitmap *e, unsigned long bit) int ebitmap_get_bit(const struct ebitmap *e, u32 bit)
{ {
const struct ebitmap_node *n; const struct ebitmap_node *n;
@ -273,7 +274,7 @@ int ebitmap_get_bit(const struct ebitmap *e, unsigned long bit)
return 0; return 0;
} }
int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value) int ebitmap_set_bit(struct ebitmap *e, u32 bit, int value)
{ {
struct ebitmap_node *n, *prev, *new; struct ebitmap_node *n, *prev, *new;
@ -284,7 +285,7 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
if (value) { if (value) {
ebitmap_node_set_bit(n, bit); ebitmap_node_set_bit(n, bit);
} else { } else {
unsigned int s; u32 s;
ebitmap_node_clr_bit(n, bit); ebitmap_node_clr_bit(n, bit);
@ -362,12 +363,12 @@ void ebitmap_destroy(struct ebitmap *e)
int ebitmap_read(struct ebitmap *e, void *fp) int ebitmap_read(struct ebitmap *e, void *fp)
{ {
struct ebitmap_node *n = NULL; struct ebitmap_node *n = NULL;
u32 mapunit, count, startbit, index; u32 mapunit, count, startbit, index, i;
__le32 ebitmap_start; __le32 ebitmap_start;
u64 map; u64 map;
__le64 mapbits; __le64 mapbits;
__le32 buf[3]; __le32 buf[3];
int rc, i; int rc;
ebitmap_init(e); ebitmap_init(e);
@ -381,7 +382,7 @@ int ebitmap_read(struct ebitmap *e, void *fp)
if (mapunit != BITS_PER_U64) { if (mapunit != BITS_PER_U64) {
pr_err("SELinux: ebitmap: map size %u does not " pr_err("SELinux: ebitmap: map size %u does not "
"match my size %zd (high bit was %d)\n", "match my size %u (high bit was %u)\n",
mapunit, BITS_PER_U64, e->highbit); mapunit, BITS_PER_U64, e->highbit);
goto bad; goto bad;
} }
@ -407,13 +408,13 @@ int ebitmap_read(struct ebitmap *e, void *fp)
startbit = le32_to_cpu(ebitmap_start); startbit = le32_to_cpu(ebitmap_start);
if (startbit & (mapunit - 1)) { if (startbit & (mapunit - 1)) {
pr_err("SELinux: ebitmap start bit (%d) is " pr_err("SELinux: ebitmap start bit (%u) is "
"not a multiple of the map unit size (%u)\n", "not a multiple of the map unit size (%u)\n",
startbit, mapunit); startbit, mapunit);
goto bad; goto bad;
} }
if (startbit > e->highbit - mapunit) { if (startbit > e->highbit - mapunit) {
pr_err("SELinux: ebitmap start bit (%d) is " pr_err("SELinux: ebitmap start bit (%u) is "
"beyond the end of the bitmap (%u)\n", "beyond the end of the bitmap (%u)\n",
startbit, (e->highbit - mapunit)); startbit, (e->highbit - mapunit));
goto bad; goto bad;
@ -436,8 +437,8 @@ int ebitmap_read(struct ebitmap *e, void *fp)
e->node = tmp; e->node = tmp;
n = tmp; n = tmp;
} else if (startbit <= n->startbit) { } else if (startbit <= n->startbit) {
pr_err("SELinux: ebitmap: start bit %d" pr_err("SELinux: ebitmap: start bit %u"
" comes after start bit %d\n", " comes after start bit %u\n",
startbit, n->startbit); startbit, n->startbit);
goto bad; goto bad;
} }
@ -448,6 +449,10 @@ int ebitmap_read(struct ebitmap *e, void *fp)
goto bad; goto bad;
} }
map = le64_to_cpu(mapbits); map = le64_to_cpu(mapbits);
if (!map) {
pr_err("SELinux: ebitmap: empty map\n");
goto bad;
}
index = (startbit - n->startbit) / EBITMAP_UNIT_SIZE; index = (startbit - n->startbit) / EBITMAP_UNIT_SIZE;
while (map) { while (map) {
@ -455,6 +460,13 @@ int ebitmap_read(struct ebitmap *e, void *fp)
map = EBITMAP_SHIFT_UNIT_SIZE(map); map = EBITMAP_SHIFT_UNIT_SIZE(map);
} }
} }
if (n && n->startbit + EBITMAP_SIZE != e->highbit) {
pr_err("SELinux: ebitmap: high bit %u is not equal to the expected value %zu\n",
e->highbit, n->startbit + EBITMAP_SIZE);
goto bad;
}
ok: ok:
rc = 0; rc = 0;
out: out:
@ -469,19 +481,20 @@ int ebitmap_read(struct ebitmap *e, void *fp)
int ebitmap_write(const struct ebitmap *e, void *fp) int ebitmap_write(const struct ebitmap *e, void *fp)
{ {
struct ebitmap_node *n; struct ebitmap_node *n;
u32 count; u32 bit, count, last_bit, last_startbit;
__le32 buf[3]; __le32 buf[3];
u64 map; u64 map;
int bit, last_bit, last_startbit, rc; int rc;
buf[0] = cpu_to_le32(BITS_PER_U64); buf[0] = cpu_to_le32(BITS_PER_U64);
count = 0; count = 0;
last_bit = 0; last_bit = 0;
last_startbit = -1; last_startbit = U32_MAX;
ebitmap_for_each_positive_bit(e, n, bit) ebitmap_for_each_positive_bit(e, n, bit)
{ {
if (rounddown(bit, (int)BITS_PER_U64) > last_startbit) { if (last_startbit == U32_MAX ||
rounddown(bit, BITS_PER_U64) > last_startbit) {
count++; count++;
last_startbit = rounddown(bit, BITS_PER_U64); last_startbit = rounddown(bit, BITS_PER_U64);
} }
@ -495,10 +508,11 @@ int ebitmap_write(const struct ebitmap *e, void *fp)
return rc; return rc;
map = 0; map = 0;
last_startbit = INT_MIN; last_startbit = U32_MAX;
ebitmap_for_each_positive_bit(e, n, bit) ebitmap_for_each_positive_bit(e, n, bit)
{ {
if (rounddown(bit, (int)BITS_PER_U64) > last_startbit) { if (last_startbit == U32_MAX ||
rounddown(bit, BITS_PER_U64) > last_startbit) {
__le64 buf64[1]; __le64 buf64[1];
/* this is the very first bit */ /* this is the very first bit */

View file

@ -46,10 +46,10 @@ struct ebitmap {
#define ebitmap_length(e) ((e)->highbit) #define ebitmap_length(e) ((e)->highbit)
static inline unsigned int ebitmap_start_positive(const struct ebitmap *e, static inline u32 ebitmap_start_positive(const struct ebitmap *e,
struct ebitmap_node **n) struct ebitmap_node **n)
{ {
unsigned int ofs; u32 ofs;
for (*n = e->node; *n; *n = (*n)->next) { for (*n = e->node; *n; *n = (*n)->next) {
ofs = find_first_bit((*n)->maps, EBITMAP_SIZE); ofs = find_first_bit((*n)->maps, EBITMAP_SIZE);
@ -64,11 +64,10 @@ static inline void ebitmap_init(struct ebitmap *e)
memset(e, 0, sizeof(*e)); memset(e, 0, sizeof(*e));
} }
static inline unsigned int ebitmap_next_positive(const struct ebitmap *e, static inline u32 ebitmap_next_positive(const struct ebitmap *e,
struct ebitmap_node **n, struct ebitmap_node **n, u32 bit)
unsigned int bit)
{ {
unsigned int ofs; u32 ofs;
ofs = find_next_bit((*n)->maps, EBITMAP_SIZE, bit - (*n)->startbit + 1); ofs = find_next_bit((*n)->maps, EBITMAP_SIZE, bit - (*n)->startbit + 1);
if (ofs < EBITMAP_SIZE) if (ofs < EBITMAP_SIZE)
@ -87,11 +86,10 @@ static inline unsigned int ebitmap_next_positive(const struct ebitmap *e,
#define EBITMAP_NODE_OFFSET(node, bit) \ #define EBITMAP_NODE_OFFSET(node, bit) \
(((bit) - (node)->startbit) % EBITMAP_UNIT_SIZE) (((bit) - (node)->startbit) % EBITMAP_UNIT_SIZE)
static inline int ebitmap_node_get_bit(const struct ebitmap_node *n, static inline int ebitmap_node_get_bit(const struct ebitmap_node *n, u32 bit)
unsigned int bit)
{ {
unsigned int index = EBITMAP_NODE_INDEX(n, bit); u32 index = EBITMAP_NODE_INDEX(n, bit);
unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit); u32 ofs = EBITMAP_NODE_OFFSET(n, bit);
BUG_ON(index >= EBITMAP_UNIT_NUMS); BUG_ON(index >= EBITMAP_UNIT_NUMS);
if ((n->maps[index] & (EBITMAP_BIT << ofs))) if ((n->maps[index] & (EBITMAP_BIT << ofs)))
@ -99,21 +97,19 @@ static inline int ebitmap_node_get_bit(const struct ebitmap_node *n,
return 0; return 0;
} }
static inline void ebitmap_node_set_bit(struct ebitmap_node *n, static inline void ebitmap_node_set_bit(struct ebitmap_node *n, u32 bit)
unsigned int bit)
{ {
unsigned int index = EBITMAP_NODE_INDEX(n, bit); u32 index = EBITMAP_NODE_INDEX(n, bit);
unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit); u32 ofs = EBITMAP_NODE_OFFSET(n, bit);
BUG_ON(index >= EBITMAP_UNIT_NUMS); BUG_ON(index >= EBITMAP_UNIT_NUMS);
n->maps[index] |= (EBITMAP_BIT << ofs); n->maps[index] |= (EBITMAP_BIT << ofs);
} }
static inline void ebitmap_node_clr_bit(struct ebitmap_node *n, static inline void ebitmap_node_clr_bit(struct ebitmap_node *n, u32 bit)
unsigned int bit)
{ {
unsigned int index = EBITMAP_NODE_INDEX(n, bit); u32 index = EBITMAP_NODE_INDEX(n, bit);
unsigned int ofs = EBITMAP_NODE_OFFSET(n, bit); u32 ofs = EBITMAP_NODE_OFFSET(n, bit);
BUG_ON(index >= EBITMAP_UNIT_NUMS); BUG_ON(index >= EBITMAP_UNIT_NUMS);
n->maps[index] &= ~(EBITMAP_BIT << ofs); n->maps[index] &= ~(EBITMAP_BIT << ofs);
@ -130,8 +126,8 @@ int ebitmap_and(struct ebitmap *dst, const struct ebitmap *e1,
const struct ebitmap *e2); const struct ebitmap *e2);
int ebitmap_contains(const struct ebitmap *e1, const struct ebitmap *e2, int ebitmap_contains(const struct ebitmap *e1, const struct ebitmap *e2,
u32 last_e2bit); u32 last_e2bit);
int ebitmap_get_bit(const struct ebitmap *e, unsigned long bit); int ebitmap_get_bit(const struct ebitmap *e, u32 bit);
int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value); int ebitmap_set_bit(struct ebitmap *e, u32 bit, int value);
void ebitmap_destroy(struct ebitmap *e); void ebitmap_destroy(struct ebitmap *e);
int ebitmap_read(struct ebitmap *e, void *fp); int ebitmap_read(struct ebitmap *e, void *fp);
int ebitmap_write(const struct ebitmap *e, void *fp); int ebitmap_write(const struct ebitmap *e, void *fp);

View file

@ -136,11 +136,12 @@ void hashtab_stat(struct hashtab *h, struct hashtab_info *info)
} }
#endif /* CONFIG_SECURITY_SELINUX_DEBUG */ #endif /* CONFIG_SECURITY_SELINUX_DEBUG */
int hashtab_duplicate(struct hashtab *new, struct hashtab *orig, int hashtab_duplicate(struct hashtab *new, const struct hashtab *orig,
int (*copy)(struct hashtab_node *new, int (*copy)(struct hashtab_node *new,
struct hashtab_node *orig, void *args), const struct hashtab_node *orig, void *args),
int (*destroy)(void *k, void *d, void *args), void *args) int (*destroy)(void *k, void *d, void *args), void *args)
{ {
const struct hashtab_node *orig_cur;
struct hashtab_node *cur, *tmp, *tail; struct hashtab_node *cur, *tmp, *tail;
u32 i; u32 i;
int rc; int rc;
@ -155,12 +156,13 @@ int hashtab_duplicate(struct hashtab *new, struct hashtab *orig,
for (i = 0; i < orig->size; i++) { for (i = 0; i < orig->size; i++) {
tail = NULL; tail = NULL;
for (cur = orig->htable[i]; cur; cur = cur->next) { for (orig_cur = orig->htable[i]; orig_cur;
orig_cur = orig_cur->next) {
tmp = kmem_cache_zalloc(hashtab_node_cachep, tmp = kmem_cache_zalloc(hashtab_node_cachep,
GFP_KERNEL); GFP_KERNEL);
if (!tmp) if (!tmp)
goto error; goto error;
rc = copy(tmp, cur, args); rc = copy(tmp, orig_cur, args);
if (rc) { if (rc) {
kmem_cache_free(hashtab_node_cachep, tmp); kmem_cache_free(hashtab_node_cachep, tmp);
goto error; goto error;

View file

@ -136,9 +136,9 @@ void hashtab_destroy(struct hashtab *h);
int hashtab_map(struct hashtab *h, int (*apply)(void *k, void *d, void *args), int hashtab_map(struct hashtab *h, int (*apply)(void *k, void *d, void *args),
void *args); void *args);
int hashtab_duplicate(struct hashtab *new, struct hashtab *orig, int hashtab_duplicate(struct hashtab *new, const struct hashtab *orig,
int (*copy)(struct hashtab_node *new, int (*copy)(struct hashtab_node *new,
struct hashtab_node *orig, void *args), const struct hashtab_node *orig, void *args),
int (*destroy)(void *k, void *d, void *args), void *args); int (*destroy)(void *k, void *d, void *args), void *args);
#ifdef CONFIG_SECURITY_SELINUX_DEBUG #ifdef CONFIG_SECURITY_SELINUX_DEBUG

View file

@ -672,14 +672,16 @@ static int (*const index_f[SYM_NUM])(void *key, void *datum, void *datap) = {
/* clang-format on */ /* clang-format on */
#ifdef CONFIG_SECURITY_SELINUX_DEBUG #ifdef CONFIG_SECURITY_SELINUX_DEBUG
static void hash_eval(struct hashtab *h, const char *hash_name) static void hash_eval(struct hashtab *h, const char *hash_name,
const char *hash_details)
{ {
struct hashtab_info info; struct hashtab_info info;
hashtab_stat(h, &info); hashtab_stat(h, &info);
pr_debug( pr_debug(
"SELinux: %s: %d entries and %d/%d buckets used, longest chain length %d, sum of chain length^2 %llu\n", "SELinux: %s%s%s: %d entries and %d/%d buckets used, longest chain length %d, sum of chain length^2 %llu\n",
hash_name, h->nel, info.slots_used, h->size, info.max_chain_len, hash_name, hash_details ? "@" : "", hash_details ?: "", h->nel,
info.slots_used, h->size, info.max_chain_len,
info.chain2_len_sum); info.chain2_len_sum);
} }
@ -688,11 +690,12 @@ static void symtab_hash_eval(struct symtab *s)
int i; int i;
for (i = 0; i < SYM_NUM; i++) for (i = 0; i < SYM_NUM; i++)
hash_eval(&s[i].table, symtab_name[i]); hash_eval(&s[i].table, symtab_name[i], NULL);
} }
#else #else
static inline void hash_eval(struct hashtab *h, const char *hash_name) static inline void hash_eval(struct hashtab *h, const char *hash_name,
const char *hash_details)
{ {
} }
static inline void symtab_hash_eval(struct symtab *s) static inline void symtab_hash_eval(struct symtab *s)
@ -1178,6 +1181,8 @@ static int common_read(struct policydb *p, struct symtab *s, void *fp)
goto bad; goto bad;
} }
hash_eval(&comdatum->permissions.table, "common_permissions", key);
rc = symtab_insert(s, key, comdatum); rc = symtab_insert(s, key, comdatum);
if (rc) if (rc)
goto bad; goto bad;
@ -1358,6 +1363,8 @@ static int class_read(struct policydb *p, struct symtab *s, void *fp)
goto bad; goto bad;
} }
hash_eval(&cladatum->permissions.table, "class_permissions", key);
rc = read_cons_helper(p, &cladatum->constraints, ncons, 0, fp); rc = read_cons_helper(p, &cladatum->constraints, ncons, 0, fp);
if (rc) if (rc)
goto bad; goto bad;
@ -1898,7 +1905,7 @@ static int range_read(struct policydb *p, void *fp)
rt = NULL; rt = NULL;
r = NULL; r = NULL;
} }
hash_eval(&p->range_tr, "rangetr"); hash_eval(&p->range_tr, "rangetr", NULL);
rc = 0; rc = 0;
out: out:
kfree(rt); kfree(rt);
@ -1943,6 +1950,7 @@ static int filename_trans_read_helper_compat(struct policydb *p, void *fp)
if (unlikely(ebitmap_get_bit(&datum->stypes, stype - 1))) { if (unlikely(ebitmap_get_bit(&datum->stypes, stype - 1))) {
/* conflicting/duplicate rules are ignored */ /* conflicting/duplicate rules are ignored */
datum = NULL; datum = NULL;
rc = 0;
goto out; goto out;
} }
if (likely(datum->otype == otype)) if (likely(datum->otype == otype))
@ -2116,7 +2124,7 @@ static int filename_trans_read(struct policydb *p, void *fp)
return rc; return rc;
} }
} }
hash_eval(&p->filename_trans, "filenametr"); hash_eval(&p->filename_trans, "filenametr", NULL);
return 0; return 0;
} }
@ -2649,6 +2657,8 @@ int policydb_read(struct policydb *p, void *fp)
rtd = NULL; rtd = NULL;
} }
hash_eval(&p->role_tr, "roletr", NULL);
rc = next_entry(buf, fp, sizeof(u32)); rc = next_entry(buf, fp, sizeof(u32));
if (rc) if (rc)
goto bad; goto bad;

View file

@ -633,8 +633,7 @@ static void context_struct_compute_av(struct policydb *policydb,
} }
if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) { if (unlikely(!tclass || tclass > policydb->p_classes.nprim)) {
if (printk_ratelimit()) pr_warn_ratelimited("SELinux: Invalid class %u\n", tclass);
pr_warn("SELinux: Invalid class %hu\n", tclass);
return; return;
} }

View file

@ -12,17 +12,17 @@
static unsigned int symhash(const void *key) static unsigned int symhash(const void *key)
{ {
const char *p, *keyp; /*
unsigned int size; * djb2a
unsigned int val; * Public domain from cdb v0.75
*/
unsigned int hash = 5381;
unsigned char c;
val = 0; while ((c = *(const unsigned char *)key++))
keyp = key; hash = ((hash << 5) + hash) ^ c;
size = strlen(keyp);
for (p = keyp; (p - keyp) < size; p++) return hash;
val = (val << 4 | (val >> (8 * sizeof(unsigned int) - 4))) ^
(*p);
return val;
} }
static int symcmp(const void *key1, const void *key2) static int symcmp(const void *key1, const void *key2)

View file

@ -76,7 +76,6 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
gfp_t gfp) gfp_t gfp)
{ {
int rc; int rc;
const struct task_security_struct *tsec = selinux_cred(current_cred());
struct xfrm_sec_ctx *ctx = NULL; struct xfrm_sec_ctx *ctx = NULL;
u32 str_len; u32 str_len;
@ -103,7 +102,7 @@ static int selinux_xfrm_alloc_user(struct xfrm_sec_ctx **ctxp,
if (rc) if (rc)
goto err; goto err;
rc = avc_has_perm(tsec->sid, ctx->ctx_sid, rc = avc_has_perm(current_sid(), ctx->ctx_sid,
SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, NULL); SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, NULL);
if (rc) if (rc)
goto err; goto err;
@ -134,12 +133,10 @@ static void selinux_xfrm_free(struct xfrm_sec_ctx *ctx)
*/ */
static int selinux_xfrm_delete(struct xfrm_sec_ctx *ctx) static int selinux_xfrm_delete(struct xfrm_sec_ctx *ctx)
{ {
const struct task_security_struct *tsec = selinux_cred(current_cred());
if (!ctx) if (!ctx)
return 0; return 0;
return avc_has_perm(tsec->sid, ctx->ctx_sid, return avc_has_perm(current_sid(), ctx->ctx_sid,
SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT, SECCLASS_ASSOCIATION, ASSOCIATION__SETCONTEXT,
NULL); NULL);
} }