Commit ccae19c6 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
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
parents 4cd4e4b8 581646c3
Loading
Loading
Loading
Loading
+24 −34
Original line number Diff line number Diff line
@@ -2961,7 +2961,7 @@ static int selinux_inode_init_security_anon(struct inode *inode,
					    const struct qstr *name,
					    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 inode_security_struct *isec;
	int rc;
@@ -2990,7 +2990,7 @@ static int selinux_inode_init_security_anon(struct inode *inode,
	} else {
		isec->sclass = SECCLASS_ANON_INODE;
		rc = security_transition_sid(
			tsec->sid, tsec->sid,
			sid, sid,
			isec->sclass, name, &isec->sid);
		if (rc)
			return rc;
@@ -3005,7 +3005,7 @@ static int selinux_inode_init_security_anon(struct inode *inode,
	ad.type = LSM_AUDIT_DATA_ANONINODE;
	ad.u.anonclass = name ? (const char *)name->name : "?";

	return avc_has_perm(tsec->sid,
	return avc_has_perm(sid,
			    isec->sid,
			    isec->sclass,
			    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,
				     bool rcu)
{
	const struct cred *cred = current_cred();
	struct common_audit_data ad;
	struct inode_security_struct *isec;
	u32 sid;
	u32 sid = current_sid();

	ad.type = LSM_AUDIT_DATA_DENTRY;
	ad.u.dentry = dentry;
	sid = cred_sid(cred);
	isec = inode_security_rcu(inode, rcu);
	if (IS_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)
{
	const struct cred *cred = current_cred();
	u32 perms;
	bool from_access;
	bool no_block = mask & MAY_NOT_BLOCK;
	struct inode_security_struct *isec;
	u32 sid;
	u32 sid = current_sid();
	struct av_decision avd;
	int rc, rc2;
	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);

	sid = cred_sid(cred);
	isec = inode_security_rcu(inode, no_block);
	if (IS_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)
{
	const struct task_security_struct *tsec;
	u32 tsid;

	tsec = selinux_cred(current_cred());
	tsid = tsec->sid;

	return avc_has_perm(tsid, sid, SECCLASS_PACKET, PACKET__RELABELTO,
	return avc_has_perm(current_sid(), sid, SECCLASS_PACKET, PACKET__RELABELTO,
			    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,
			       char **value)
{
	const struct task_security_struct *__tsec;
	u32 sid;
	const struct task_security_struct *tsec;
	int error;
	unsigned len;
	u32 sid;
	u32 len;

	rcu_read_lock();
	__tsec = selinux_cred(__task_cred(p));

	if (current != p) {
		error = avc_has_perm(current_sid(), __tsec->sid,
	tsec = selinux_cred(__task_cred(p));
	if (p != current) {
		error = avc_has_perm(current_sid(), tsec->sid,
				     SECCLASS_PROCESS, PROCESS__GETATTR, NULL);
		if (error)
			goto bad;
			goto err_unlock;
	}

	switch (attr) {
	case LSM_ATTR_CURRENT:
		sid = __tsec->sid;
		sid = tsec->sid;
		break;
	case LSM_ATTR_PREV:
		sid = __tsec->osid;
		sid = tsec->osid;
		break;
	case LSM_ATTR_EXEC:
		sid = __tsec->exec_sid;
		sid = tsec->exec_sid;
		break;
	case LSM_ATTR_FSCREATE:
		sid = __tsec->create_sid;
		sid = tsec->create_sid;
		break;
	case LSM_ATTR_KEYCREATE:
		sid = __tsec->keycreate_sid;
		sid = tsec->keycreate_sid;
		break;
	case LSM_ATTR_SOCKCREATE:
		sid = __tsec->sockcreate_sid;
		sid = tsec->sockcreate_sid;
		break;
	default:
		error = -EOPNOTSUPP;
		goto bad;
		goto err_unlock;
	}
	rcu_read_unlock();

	if (!sid)
	if (sid == SECSID_NULL) {
		*value = NULL;
		return 0;
	}

	error = security_sid_to_context(sid, value, &len);
	if (error)
		return error;
	return len;

bad:
err_unlock:
	rcu_read_unlock();
	return error;
}
+22 −14
Original line number Diff line number Diff line
@@ -571,11 +571,18 @@ static ssize_t sel_write_load(struct file *file, const char __user *buf,
			      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;
	ssize_t length;
	void *data = NULL;

	/* no partial writes */
	if (*ppos)
		return -EINVAL;
	/* no empty policies */
	if (!count)
		return -EINVAL;

	mutex_lock(&selinux_state.policy_mutex);

	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)
		goto out;

	/* No partial writes. */
	length = -EINVAL;
	if (*ppos != 0)
		goto out;

	length = -ENOMEM;
	data = vmalloc(count);
	if (!data)
	if (!data) {
		length = -ENOMEM;
		goto out;

	}
	if (copy_from_user(data, buf, count) != 0) {
		length = -EFAULT;
	if (copy_from_user(data, buf, count) != 0)
		goto out;
	}

	length = security_load_policy(data, count, &load_state);
	if (length) {
		pr_warn_ratelimited("SELinux: failed to load policy\n");
		goto out;
	}

	fsi = file_inode(file)->i_sb->s_fs_info;
	length = sel_make_policy_nodes(fsi, load_state.policy);
	if (length) {
		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);

	length = count;

	audit_log(audit_context(), GFP_KERNEL, AUDIT_MAC_POLICY_LOAD,
		"auid=%u ses=%u lsm=selinux res=1",
		from_kuid(&init_user_ns, audit_get_loginuid(current)),
		audit_get_sessionid(current));

out:
	mutex_unlock(&selinux_state.policy_mutex);
	vfree(data);
@@ -2161,6 +2163,12 @@ static int __init init_sel_fs(void)
		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;
}

+11 −7
Original line number Diff line number Diff line
@@ -169,6 +169,9 @@ int cond_init_bool_indexes(struct policydb *p)
		p->p_bools.nprim, sizeof(*p->bool_val_to_struct), GFP_KERNEL);
	if (!p->bool_val_to_struct)
		return -ENOMEM;

	avtab_hash_eval(&p->te_cond_avtab, "conditional_rules");

	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)
{
	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,
					struct policydb *origp)
					const struct policydb *origp)
{
	int rc;
	u32 i;
@@ -640,7 +644,7 @@ static int duplicate_policydb_cond_list(struct policydb *newp,

	for (i = 0; i < origp->cond_list_len; 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++;

@@ -680,8 +684,8 @@ static int cond_bools_destroy(void *key, void *datum, void *args)
	return 0;
}

static int cond_bools_copy(struct hashtab_node *new, struct hashtab_node *orig,
			   void *args)
static int cond_bools_copy(struct hashtab_node *new,
			   const struct hashtab_node *orig, void *args)
{
	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,
				    struct policydb *orig)
				    const struct policydb *orig)
{
	struct cond_bool_datum **cond_bool_array;
	int rc;
@@ -740,7 +744,7 @@ void cond_policydb_destroy_dup(struct policydb *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);

+1 −1
Original line number Diff line number Diff line
@@ -79,6 +79,6 @@ void cond_compute_xperms(struct avtab *ctab, struct avtab_key *key,
			 struct extended_perms_decision *xpermd);
void evaluate_cond_nodes(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_ */
+32 −18
Original line number Diff line number Diff line
@@ -21,7 +21,7 @@
#include "ebitmap.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;

@@ -79,7 +79,8 @@ int ebitmap_and(struct ebitmap *dst, const struct ebitmap *e1,
		const struct ebitmap *e2)
{
	struct ebitmap_node *n;
	int bit, rc;
	u32 bit;
	int rc;

	ebitmap_init(dst);

@@ -256,7 +257,7 @@ int ebitmap_contains(const struct ebitmap *e1, const struct ebitmap *e2,
	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;

@@ -273,7 +274,7 @@ int ebitmap_get_bit(const struct ebitmap *e, unsigned long bit)
	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;

@@ -284,7 +285,7 @@ int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value)
			if (value) {
				ebitmap_node_set_bit(n, bit);
			} else {
				unsigned int s;
				u32 s;

				ebitmap_node_clr_bit(n, bit);

@@ -362,12 +363,12 @@ void ebitmap_destroy(struct ebitmap *e)
int ebitmap_read(struct ebitmap *e, void *fp)
{
	struct ebitmap_node *n = NULL;
	u32 mapunit, count, startbit, index;
	u32 mapunit, count, startbit, index, i;
	__le32 ebitmap_start;
	u64 map;
	__le64 mapbits;
	__le32 buf[3];
	int rc, i;
	int rc;

	ebitmap_init(e);

@@ -381,7 +382,7 @@ int ebitmap_read(struct ebitmap *e, void *fp)

	if (mapunit != BITS_PER_U64) {
		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);
		goto bad;
	}
@@ -407,13 +408,13 @@ int ebitmap_read(struct ebitmap *e, void *fp)
		startbit = le32_to_cpu(ebitmap_start);

		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",
			       startbit, mapunit);
			goto bad;
		}
		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",
			       startbit, (e->highbit - mapunit));
			goto bad;
@@ -436,8 +437,8 @@ int ebitmap_read(struct ebitmap *e, void *fp)
				e->node = tmp;
			n = tmp;
		} else if (startbit <= n->startbit) {
			pr_err("SELinux: ebitmap: start bit %d"
			       " comes after start bit %d\n",
			pr_err("SELinux: ebitmap: start bit %u"
			       " comes after start bit %u\n",
			       startbit, n->startbit);
			goto bad;
		}
@@ -448,6 +449,10 @@ int ebitmap_read(struct ebitmap *e, void *fp)
			goto bad;
		}
		map = le64_to_cpu(mapbits);
		if (!map) {
			pr_err("SELinux: ebitmap: empty map\n");
			goto bad;
		}

		index = (startbit - n->startbit) / EBITMAP_UNIT_SIZE;
		while (map) {
@@ -455,6 +460,13 @@ int ebitmap_read(struct ebitmap *e, void *fp)
			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:
	rc = 0;
out:
@@ -469,19 +481,20 @@ int ebitmap_read(struct ebitmap *e, void *fp)
int ebitmap_write(const struct ebitmap *e, void *fp)
{
	struct ebitmap_node *n;
	u32 count;
	u32 bit, count, last_bit, last_startbit;
	__le32 buf[3];
	u64 map;
	int bit, last_bit, last_startbit, rc;
	int rc;

	buf[0] = cpu_to_le32(BITS_PER_U64);

	count = 0;
	last_bit = 0;
	last_startbit = -1;
	last_startbit = U32_MAX;
	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++;
			last_startbit = rounddown(bit, BITS_PER_U64);
		}
@@ -495,10 +508,11 @@ int ebitmap_write(const struct ebitmap *e, void *fp)
		return rc;

	map = 0;
	last_startbit = INT_MIN;
	last_startbit = U32_MAX;
	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];

			/* this is the very first bit */
Loading