Commit e67b7985 authored by Stephen Smalley's avatar Stephen Smalley Committed by Paul Moore
Browse files

selinux: stop passing selinux_state pointers and their offspring



Linus observed that the pervasive passing of selinux_state pointers
introduced by me in commit aa8e712c ("selinux: wrap global selinux
state") adds overhead and complexity without providing any
benefit. The original idea was to pave the way for SELinux namespaces
but those have not yet been implemented and there isn't currently
a concrete plan to do so. Remove the passing of the selinux_state
pointers, reverting to direct use of the single global selinux_state,
and likewise remove passing of child pointers like the selinux_avc.
The selinux_policy pointer remains as it is needed for atomic switching
of policies.

Suggested-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
Reported-by: default avatarkernel test robot <lkp@intel.com>
Link: https://lore.kernel.org/oe-kbuild-all/202303101057.mZ3Gv5fK-lkp@intel.com/


Signed-off-by: default avatarStephen Smalley <stephen.smalley.work@gmail.com>
Signed-off-by: default avatarPaul Moore <paul@paul-moore.com>
parent f62ca0b6
Loading
Loading
Loading
Loading
+86 −111
Original line number Diff line number Diff line
@@ -93,7 +93,7 @@ struct selinux_avc {

static struct selinux_avc selinux_avc;

void selinux_avc_init(struct selinux_avc **avc)
void selinux_avc_init(void)
{
	int i;

@@ -104,18 +104,16 @@ void selinux_avc_init(struct selinux_avc **avc)
	}
	atomic_set(&selinux_avc.avc_cache.active_nodes, 0);
	atomic_set(&selinux_avc.avc_cache.lru_hint, 0);
	*avc = &selinux_avc;
}

unsigned int avc_get_cache_threshold(struct selinux_avc *avc)
unsigned int avc_get_cache_threshold(void)
{
	return avc->avc_cache_threshold;
	return selinux_avc.avc_cache_threshold;
}

void avc_set_cache_threshold(struct selinux_avc *avc,
			     unsigned int cache_threshold)
void avc_set_cache_threshold(unsigned int cache_threshold)
{
	avc->avc_cache_threshold = cache_threshold;
	selinux_avc.avc_cache_threshold = cache_threshold;
}

static struct avc_callback_node *avc_callbacks __ro_after_init;
@@ -150,7 +148,7 @@ void __init avc_init(void)
					0, SLAB_PANIC, NULL);
}

int avc_get_hash_stats(struct selinux_avc *avc, char *page)
int avc_get_hash_stats(char *page)
{
	int i, chain_len, max_chain_len, slots_used;
	struct avc_node *node;
@@ -161,7 +159,7 @@ int avc_get_hash_stats(struct selinux_avc *avc, char *page)
	slots_used = 0;
	max_chain_len = 0;
	for (i = 0; i < AVC_CACHE_SLOTS; i++) {
		head = &avc->avc_cache.slots[i];
		head = &selinux_avc.avc_cache.slots[i];
		if (!hlist_empty(head)) {
			slots_used++;
			chain_len = 0;
@@ -176,7 +174,7 @@ int avc_get_hash_stats(struct selinux_avc *avc, char *page)

	return scnprintf(page, PAGE_SIZE, "entries: %d\nbuckets used: %d/%d\n"
			 "longest chain: %d\n",
			 atomic_read(&avc->avc_cache.active_nodes),
			 atomic_read(&selinux_avc.avc_cache.active_nodes),
			 slots_used, AVC_CACHE_SLOTS, max_chain_len);
}

@@ -414,8 +412,7 @@ static inline u32 avc_xperms_audit_required(u32 requested,
	return audited;
}

static inline int avc_xperms_audit(struct selinux_state *state,
				   u32 ssid, u32 tsid, u16 tclass,
static inline int avc_xperms_audit(u32 ssid, u32 tsid, u16 tclass,
				   u32 requested, struct av_decision *avd,
				   struct extended_perms_decision *xpd,
				   u8 perm, int result,
@@ -427,7 +424,7 @@ static inline int avc_xperms_audit(struct selinux_state *state,
			requested, avd, xpd, perm, result, &denied);
	if (likely(!audited))
		return 0;
	return slow_avc_audit(state, ssid, tsid, tclass, requested,
	return slow_avc_audit(ssid, tsid, tclass, requested,
			audited, denied, result, ad);
}

@@ -439,30 +436,29 @@ static void avc_node_free(struct rcu_head *rhead)
	avc_cache_stats_incr(frees);
}

static void avc_node_delete(struct selinux_avc *avc, struct avc_node *node)
static void avc_node_delete(struct avc_node *node)
{
	hlist_del_rcu(&node->list);
	call_rcu(&node->rhead, avc_node_free);
	atomic_dec(&avc->avc_cache.active_nodes);
	atomic_dec(&selinux_avc.avc_cache.active_nodes);
}

static void avc_node_kill(struct selinux_avc *avc, struct avc_node *node)
static void avc_node_kill(struct avc_node *node)
{
	avc_xperms_free(node->ae.xp_node);
	kmem_cache_free(avc_node_cachep, node);
	avc_cache_stats_incr(frees);
	atomic_dec(&avc->avc_cache.active_nodes);
	atomic_dec(&selinux_avc.avc_cache.active_nodes);
}

static void avc_node_replace(struct selinux_avc *avc,
			     struct avc_node *new, struct avc_node *old)
static void avc_node_replace(struct avc_node *new, struct avc_node *old)
{
	hlist_replace_rcu(&old->list, &new->list);
	call_rcu(&old->rhead, avc_node_free);
	atomic_dec(&avc->avc_cache.active_nodes);
	atomic_dec(&selinux_avc.avc_cache.active_nodes);
}

static inline int avc_reclaim_node(struct selinux_avc *avc)
static inline int avc_reclaim_node(void)
{
	struct avc_node *node;
	int hvalue, try, ecx;
@@ -471,17 +467,17 @@ static inline int avc_reclaim_node(struct selinux_avc *avc)
	spinlock_t *lock;

	for (try = 0, ecx = 0; try < AVC_CACHE_SLOTS; try++) {
		hvalue = atomic_inc_return(&avc->avc_cache.lru_hint) &
		hvalue = atomic_inc_return(&selinux_avc.avc_cache.lru_hint) &
			(AVC_CACHE_SLOTS - 1);
		head = &avc->avc_cache.slots[hvalue];
		lock = &avc->avc_cache.slots_lock[hvalue];
		head = &selinux_avc.avc_cache.slots[hvalue];
		lock = &selinux_avc.avc_cache.slots_lock[hvalue];

		if (!spin_trylock_irqsave(lock, flags))
			continue;

		rcu_read_lock();
		hlist_for_each_entry(node, head, list) {
			avc_node_delete(avc, node);
			avc_node_delete(node);
			avc_cache_stats_incr(reclaims);
			ecx++;
			if (ecx >= AVC_CACHE_RECLAIM) {
@@ -497,7 +493,7 @@ static inline int avc_reclaim_node(struct selinux_avc *avc)
	return ecx;
}

static struct avc_node *avc_alloc_node(struct selinux_avc *avc)
static struct avc_node *avc_alloc_node(void)
{
	struct avc_node *node;

@@ -508,9 +504,9 @@ static struct avc_node *avc_alloc_node(struct selinux_avc *avc)
	INIT_HLIST_NODE(&node->list);
	avc_cache_stats_incr(allocations);

	if (atomic_inc_return(&avc->avc_cache.active_nodes) >
	    avc->avc_cache_threshold)
		avc_reclaim_node(avc);
	if (atomic_inc_return(&selinux_avc.avc_cache.active_nodes) >
	    selinux_avc.avc_cache_threshold)
		avc_reclaim_node();

out:
	return node;
@@ -524,15 +520,14 @@ static void avc_node_populate(struct avc_node *node, u32 ssid, u32 tsid, u16 tcl
	memcpy(&node->ae.avd, avd, sizeof(node->ae.avd));
}

static inline struct avc_node *avc_search_node(struct selinux_avc *avc,
					       u32 ssid, u32 tsid, u16 tclass)
static inline struct avc_node *avc_search_node(u32 ssid, u32 tsid, u16 tclass)
{
	struct avc_node *node, *ret = NULL;
	int hvalue;
	struct hlist_head *head;

	hvalue = avc_hash(ssid, tsid, tclass);
	head = &avc->avc_cache.slots[hvalue];
	head = &selinux_avc.avc_cache.slots[hvalue];
	hlist_for_each_entry_rcu(node, head, list) {
		if (ssid == node->ae.ssid &&
		    tclass == node->ae.tclass &&
@@ -547,7 +542,6 @@ static inline struct avc_node *avc_search_node(struct selinux_avc *avc,

/**
 * avc_lookup - Look up an AVC entry.
 * @avc: the access vector cache
 * @ssid: source security identifier
 * @tsid: target security identifier
 * @tclass: target security class
@@ -558,13 +552,12 @@ static inline struct avc_node *avc_search_node(struct selinux_avc *avc,
 * then this function returns the avc_node.
 * Otherwise, this function returns NULL.
 */
static struct avc_node *avc_lookup(struct selinux_avc *avc,
				   u32 ssid, u32 tsid, u16 tclass)
static struct avc_node *avc_lookup(u32 ssid, u32 tsid, u16 tclass)
{
	struct avc_node *node;

	avc_cache_stats_incr(lookups);
	node = avc_search_node(avc, ssid, tsid, tclass);
	node = avc_search_node(ssid, tsid, tclass);

	if (node)
		return node;
@@ -573,8 +566,7 @@ static struct avc_node *avc_lookup(struct selinux_avc *avc,
	return NULL;
}

static int avc_latest_notif_update(struct selinux_avc *avc,
				   int seqno, int is_insert)
static int avc_latest_notif_update(int seqno, int is_insert)
{
	int ret = 0;
	static DEFINE_SPINLOCK(notif_lock);
@@ -582,14 +574,14 @@ static int avc_latest_notif_update(struct selinux_avc *avc,

	spin_lock_irqsave(&notif_lock, flag);
	if (is_insert) {
		if (seqno < avc->avc_cache.latest_notif) {
		if (seqno < selinux_avc.avc_cache.latest_notif) {
			pr_warn("SELinux: avc:  seqno %d < latest_notif %d\n",
			       seqno, avc->avc_cache.latest_notif);
			       seqno, selinux_avc.avc_cache.latest_notif);
			ret = -EAGAIN;
		}
	} else {
		if (seqno > avc->avc_cache.latest_notif)
			avc->avc_cache.latest_notif = seqno;
		if (seqno > selinux_avc.avc_cache.latest_notif)
			selinux_avc.avc_cache.latest_notif = seqno;
	}
	spin_unlock_irqrestore(&notif_lock, flag);

@@ -598,7 +590,6 @@ static int avc_latest_notif_update(struct selinux_avc *avc,

/**
 * avc_insert - Insert an AVC entry.
 * @avc: the access vector cache
 * @ssid: source security identifier
 * @tsid: target security identifier
 * @tclass: target security class
@@ -615,8 +606,7 @@ static int avc_latest_notif_update(struct selinux_avc *avc,
 * the access vectors into a cache entry, returns
 * avc_node inserted. Otherwise, this function returns NULL.
 */
static struct avc_node *avc_insert(struct selinux_avc *avc,
				   u32 ssid, u32 tsid, u16 tclass,
static struct avc_node *avc_insert(u32 ssid, u32 tsid, u16 tclass,
				   struct av_decision *avd,
				   struct avc_xperms_node *xp_node)
{
@@ -626,28 +616,28 @@ static struct avc_node *avc_insert(struct selinux_avc *avc,
	spinlock_t *lock;
	struct hlist_head *head;

	if (avc_latest_notif_update(avc, avd->seqno, 1))
	if (avc_latest_notif_update(avd->seqno, 1))
		return NULL;

	node = avc_alloc_node(avc);
	node = avc_alloc_node();
	if (!node)
		return NULL;

	avc_node_populate(node, ssid, tsid, tclass, avd);
	if (avc_xperms_populate(node, xp_node)) {
		avc_node_kill(avc, node);
		avc_node_kill(node);
		return NULL;
	}

	hvalue = avc_hash(ssid, tsid, tclass);
	head = &avc->avc_cache.slots[hvalue];
	lock = &avc->avc_cache.slots_lock[hvalue];
	head = &selinux_avc.avc_cache.slots[hvalue];
	lock = &selinux_avc.avc_cache.slots_lock[hvalue];
	spin_lock_irqsave(lock, flag);
	hlist_for_each_entry(pos, head, list) {
		if (pos->ae.ssid == ssid &&
			pos->ae.tsid == tsid &&
			pos->ae.tclass == tclass) {
			avc_node_replace(avc, node, pos);
			avc_node_replace(node, pos);
			goto found;
		}
	}
@@ -715,14 +705,14 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
	u32 tcontext_len;
	int rc;

	rc = security_sid_to_context(sad->state, sad->ssid, &scontext,
	rc = security_sid_to_context(sad->ssid, &scontext,
				     &scontext_len);
	if (rc)
		audit_log_format(ab, " ssid=%d", sad->ssid);
	else
		audit_log_format(ab, " scontext=%s", scontext);

	rc = security_sid_to_context(sad->state, sad->tsid, &tcontext,
	rc = security_sid_to_context(sad->tsid, &tcontext,
				     &tcontext_len);
	if (rc)
		audit_log_format(ab, " tsid=%d", sad->tsid);
@@ -740,7 +730,7 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
	kfree(scontext);

	/* in case of invalid context report also the actual context string */
	rc = security_sid_to_context_inval(sad->state, sad->ssid, &scontext,
	rc = security_sid_to_context_inval(sad->ssid, &scontext,
					   &scontext_len);
	if (!rc && scontext) {
		if (scontext_len && scontext[scontext_len - 1] == '\0')
@@ -750,7 +740,7 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
		kfree(scontext);
	}

	rc = security_sid_to_context_inval(sad->state, sad->tsid, &scontext,
	rc = security_sid_to_context_inval(sad->tsid, &scontext,
					   &scontext_len);
	if (!rc && scontext) {
		if (scontext_len && scontext[scontext_len - 1] == '\0')
@@ -766,8 +756,7 @@ static void avc_audit_post_callback(struct audit_buffer *ab, void *a)
 * Note that it is non-blocking and can be called from under
 * rcu_read_lock().
 */
noinline int slow_avc_audit(struct selinux_state *state,
			    u32 ssid, u32 tsid, u16 tclass,
noinline int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
			    u32 requested, u32 audited, u32 denied, int result,
			    struct common_audit_data *a)
{
@@ -789,7 +778,6 @@ noinline int slow_avc_audit(struct selinux_state *state,
	sad.audited = audited;
	sad.denied = denied;
	sad.result = result;
	sad.state = state;

	a->selinux_audit_data = &sad;

@@ -827,7 +815,6 @@ int __init avc_add_callback(int (*callback)(u32 event), u32 events)

/**
 * avc_update_node - Update an AVC entry
 * @avc: the access vector cache
 * @event : Updating event
 * @perms : Permission mask bits
 * @driver: xperm driver information
@@ -844,8 +831,7 @@ int __init avc_add_callback(int (*callback)(u32 event), u32 events)
 * otherwise, this function updates the AVC entry. The original AVC-entry object
 * will release later by RCU.
 */
static int avc_update_node(struct selinux_avc *avc,
			   u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid,
static int avc_update_node(u32 event, u32 perms, u8 driver, u8 xperm, u32 ssid,
			   u32 tsid, u16 tclass, u32 seqno,
			   struct extended_perms_decision *xpd,
			   u32 flags)
@@ -856,7 +842,7 @@ static int avc_update_node(struct selinux_avc *avc,
	struct hlist_head *head;
	spinlock_t *lock;

	node = avc_alloc_node(avc);
	node = avc_alloc_node();
	if (!node) {
		rc = -ENOMEM;
		goto out;
@@ -865,8 +851,8 @@ static int avc_update_node(struct selinux_avc *avc,
	/* Lock the target slot */
	hvalue = avc_hash(ssid, tsid, tclass);

	head = &avc->avc_cache.slots[hvalue];
	lock = &avc->avc_cache.slots_lock[hvalue];
	head = &selinux_avc.avc_cache.slots[hvalue];
	lock = &selinux_avc.avc_cache.slots_lock[hvalue];

	spin_lock_irqsave(lock, flag);

@@ -882,7 +868,7 @@ static int avc_update_node(struct selinux_avc *avc,

	if (!orig) {
		rc = -ENOENT;
		avc_node_kill(avc, node);
		avc_node_kill(node);
		goto out_unlock;
	}

@@ -895,7 +881,7 @@ static int avc_update_node(struct selinux_avc *avc,
	if (orig->ae.xp_node) {
		rc = avc_xperms_populate(node, orig->ae.xp_node);
		if (rc) {
			avc_node_kill(avc, node);
			avc_node_kill(node);
			goto out_unlock;
		}
	}
@@ -926,7 +912,7 @@ static int avc_update_node(struct selinux_avc *avc,
		avc_add_xperms_decision(node, xpd);
		break;
	}
	avc_node_replace(avc, node, orig);
	avc_node_replace(node, orig);
out_unlock:
	spin_unlock_irqrestore(lock, flag);
out:
@@ -935,9 +921,8 @@ static int avc_update_node(struct selinux_avc *avc,

/**
 * avc_flush - Flush the cache
 * @avc: the access vector cache
 */
static void avc_flush(struct selinux_avc *avc)
static void avc_flush(void)
{
	struct hlist_head *head;
	struct avc_node *node;
@@ -946,8 +931,8 @@ static void avc_flush(struct selinux_avc *avc)
	int i;

	for (i = 0; i < AVC_CACHE_SLOTS; i++) {
		head = &avc->avc_cache.slots[i];
		lock = &avc->avc_cache.slots_lock[i];
		head = &selinux_avc.avc_cache.slots[i];
		lock = &selinux_avc.avc_cache.slots_lock[i];

		spin_lock_irqsave(lock, flag);
		/*
@@ -956,7 +941,7 @@ static void avc_flush(struct selinux_avc *avc)
		 */
		rcu_read_lock();
		hlist_for_each_entry(node, head, list)
			avc_node_delete(avc, node);
			avc_node_delete(node);
		rcu_read_unlock();
		spin_unlock_irqrestore(lock, flag);
	}
@@ -964,15 +949,14 @@ static void avc_flush(struct selinux_avc *avc)

/**
 * avc_ss_reset - Flush the cache and revalidate migrated permissions.
 * @avc: the access vector cache
 * @seqno: policy sequence number
 */
int avc_ss_reset(struct selinux_avc *avc, u32 seqno)
int avc_ss_reset(u32 seqno)
{
	struct avc_callback_node *c;
	int rc = 0, tmprc;

	avc_flush(avc);
	avc_flush();

	for (c = avc_callbacks; c; c = c->next) {
		if (c->events & AVC_CALLBACK_RESET) {
@@ -984,13 +968,12 @@ int avc_ss_reset(struct selinux_avc *avc, u32 seqno)
		}
	}

	avc_latest_notif_update(avc, seqno, 0);
	avc_latest_notif_update(seqno, 0);
	return rc;
}

/**
 * avc_compute_av - Add an entry to the AVC based on the security policy
 * @state: SELinux state pointer
 * @ssid: subject
 * @tsid: object/target
 * @tclass: object class
@@ -1001,18 +984,16 @@ int avc_ss_reset(struct selinux_avc *avc, u32 seqno)
 * fails.  Don't inline this, since it's the slow-path and just results in a
 * bigger stack frame.
 */
static noinline struct avc_node *avc_compute_av(struct selinux_state *state,
						u32 ssid, u32 tsid, u16 tclass,
static noinline struct avc_node *avc_compute_av(u32 ssid, u32 tsid, u16 tclass,
						struct av_decision *avd,
						struct avc_xperms_node *xp_node)
{
	INIT_LIST_HEAD(&xp_node->xpd_head);
	security_compute_av(state, ssid, tsid, tclass, avd, &xp_node->xp);
	return avc_insert(state->avc, ssid, tsid, tclass, avd, xp_node);
	security_compute_av(ssid, tsid, tclass, avd, &xp_node->xp);
	return avc_insert(ssid, tsid, tclass, avd, xp_node);
}

static noinline int avc_denied(struct selinux_state *state,
			       u32 ssid, u32 tsid,
static noinline int avc_denied(u32 ssid, u32 tsid,
			       u16 tclass, u32 requested,
			       u8 driver, u8 xperm, unsigned int flags,
			       struct av_decision *avd)
@@ -1020,11 +1001,11 @@ static noinline int avc_denied(struct selinux_state *state,
	if (flags & AVC_STRICT)
		return -EACCES;

	if (enforcing_enabled(state) &&
	if (enforcing_enabled() &&
	    !(avd->flags & AVD_FLAGS_PERMISSIVE))
		return -EACCES;

	avc_update_node(state->avc, AVC_CALLBACK_GRANT, requested, driver,
	avc_update_node(AVC_CALLBACK_GRANT, requested, driver,
			xperm, ssid, tsid, tclass, avd->seqno, NULL, flags);
	return 0;
}
@@ -1036,8 +1017,7 @@ static noinline int avc_denied(struct selinux_state *state,
 * as-is the case with ioctls, then multiple may be chained together and the
 * driver field is used to specify which set contains the permission.
 */
int avc_has_extended_perms(struct selinux_state *state,
			   u32 ssid, u32 tsid, u16 tclass, u32 requested,
int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
			   u8 driver, u8 xperm, struct common_audit_data *ad)
{
	struct avc_node *node;
@@ -1058,9 +1038,9 @@ int avc_has_extended_perms(struct selinux_state *state,

	rcu_read_lock();

	node = avc_lookup(state->avc, ssid, tsid, tclass);
	node = avc_lookup(ssid, tsid, tclass);
	if (unlikely(!node)) {
		avc_compute_av(state, ssid, tsid, tclass, &avd, xp_node);
		avc_compute_av(ssid, tsid, tclass, &avd, xp_node);
	} else {
		memcpy(&avd, &node->ae.avd, sizeof(avd));
		xp_node = node->ae.xp_node;
@@ -1084,10 +1064,10 @@ int avc_has_extended_perms(struct selinux_state *state,
			goto decision;
		}
		rcu_read_unlock();
		security_compute_xperms_decision(state, ssid, tsid, tclass,
		security_compute_xperms_decision(ssid, tsid, tclass,
						 driver, &local_xpd);
		rcu_read_lock();
		avc_update_node(state->avc, AVC_CALLBACK_ADD_XPERMS, requested,
		avc_update_node(AVC_CALLBACK_ADD_XPERMS, requested,
				driver, xperm, ssid, tsid, tclass, avd.seqno,
				&local_xpd, 0);
	} else {
@@ -1101,12 +1081,12 @@ int avc_has_extended_perms(struct selinux_state *state,
decision:
	denied = requested & ~(avd.allowed);
	if (unlikely(denied))
		rc = avc_denied(state, ssid, tsid, tclass, requested,
		rc = avc_denied(ssid, tsid, tclass, requested,
				driver, xperm, AVC_EXTENDED_PERMS, &avd);

	rcu_read_unlock();

	rc2 = avc_xperms_audit(state, ssid, tsid, tclass, requested,
	rc2 = avc_xperms_audit(ssid, tsid, tclass, requested,
			&avd, xpd, xperm, rc, ad);
	if (rc2)
		return rc2;
@@ -1115,7 +1095,6 @@ int avc_has_extended_perms(struct selinux_state *state,

/**
 * avc_perm_nonode - Add an entry to the AVC
 * @state: SELinux state pointer
 * @ssid: subject
 * @tsid: object/target
 * @tclass: object class
@@ -1127,25 +1106,23 @@ int avc_has_extended_perms(struct selinux_state *state,
 * unlikely and needs extra stack space for the new node that we generate, so
 * don't inline it.
 */
static noinline int avc_perm_nonode(struct selinux_state *state,
				    u32 ssid, u32 tsid, u16 tclass,
static noinline int avc_perm_nonode(u32 ssid, u32 tsid, u16 tclass,
				    u32 requested, unsigned int flags,
				    struct av_decision *avd)
{
	u32 denied;
	struct avc_xperms_node xp_node;

	avc_compute_av(state, ssid, tsid, tclass, avd, &xp_node);
	avc_compute_av(ssid, tsid, tclass, avd, &xp_node);
	denied = requested & ~(avd->allowed);
	if (unlikely(denied))
		return avc_denied(state, ssid, tsid, tclass, requested, 0, 0,
		return avc_denied(ssid, tsid, tclass, requested, 0, 0,
				  flags, avd);
	return 0;
}

/**
 * avc_has_perm_noaudit - Check permissions but perform no auditing.
 * @state: SELinux state
 * @ssid: source security identifier
 * @tsid: target security identifier
 * @tclass: target security class
@@ -1164,8 +1141,7 @@ static noinline int avc_perm_nonode(struct selinux_state *state,
 * auditing, e.g. in cases where a lock must be held for the check but
 * should be released for the auditing.
 */
inline int avc_has_perm_noaudit(struct selinux_state *state,
				u32 ssid, u32 tsid,
inline int avc_has_perm_noaudit(u32 ssid, u32 tsid,
				u16 tclass, u32 requested,
				unsigned int flags,
				struct av_decision *avd)
@@ -1177,10 +1153,10 @@ inline int avc_has_perm_noaudit(struct selinux_state *state,
		return -EACCES;

	rcu_read_lock();
	node = avc_lookup(state->avc, ssid, tsid, tclass);
	node = avc_lookup(ssid, tsid, tclass);
	if (unlikely(!node)) {
		rcu_read_unlock();
		return avc_perm_nonode(state, ssid, tsid, tclass, requested,
		return avc_perm_nonode(ssid, tsid, tclass, requested,
				       flags, avd);
	}
	denied = requested & ~node->ae.avd.allowed;
@@ -1188,14 +1164,13 @@ inline int avc_has_perm_noaudit(struct selinux_state *state,
	rcu_read_unlock();

	if (unlikely(denied))
		return avc_denied(state, ssid, tsid, tclass, requested, 0, 0,
		return avc_denied(ssid, tsid, tclass, requested, 0, 0,
				  flags, avd);
	return 0;
}

/**
 * avc_has_perm - Check permissions and perform any appropriate auditing.
 * @state: SELinux state
 * @ssid: source security identifier
 * @tsid: target security identifier
 * @tclass: target security class
@@ -1210,25 +1185,25 @@ inline int avc_has_perm_noaudit(struct selinux_state *state,
 * permissions are granted, -%EACCES if any permissions are denied, or
 * another -errno upon other errors.
 */
int avc_has_perm(struct selinux_state *state, u32 ssid, u32 tsid, u16 tclass,
int avc_has_perm(u32 ssid, u32 tsid, u16 tclass,
		 u32 requested, struct common_audit_data *auditdata)
{
	struct av_decision avd;
	int rc, rc2;

	rc = avc_has_perm_noaudit(state, ssid, tsid, tclass, requested, 0,
	rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0,
				  &avd);

	rc2 = avc_audit(state, ssid, tsid, tclass, requested, &avd, rc,
	rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc,
			auditdata);
	if (rc2)
		return rc2;
	return rc;
}

u32 avc_policy_seqno(struct selinux_state *state)
u32 avc_policy_seqno(void)
{
	return state->avc->avc_cache.latest_notif;
	return selinux_avc.avc_cache.latest_notif;
}

void avc_disable(void)
@@ -1245,7 +1220,7 @@ void avc_disable(void)
	 * the cache and get that memory back.
	 */
	if (avc_node_cachep) {
		avc_flush(selinux_state.avc);
		avc_flush();
		/* kmem_cache_destroy(avc_node_cachep); */
	}
}
+208 −341

File changed.

Preview size limit exceeded, changes collapsed.

+1 −1
Original line number Diff line number Diff line
@@ -141,7 +141,7 @@ static int sel_ib_pkey_sid_slow(u64 subnet_prefix, u16 pkey_num, u32 *sid)
		return 0;
	}

	ret = security_ib_pkey_sid(&selinux_state, subnet_prefix, pkey_num,
	ret = security_ib_pkey_sid(subnet_prefix, pkey_num,
				   sid);
	if (ret)
		goto out;
+16 −21
Original line number Diff line number Diff line
@@ -15,12 +15,10 @@
/*
 * selinux_ima_collect_state - Read selinux configuration settings
 *
 * @state: selinux_state
 *
 * On success returns the configuration settings string.
 * On error, returns NULL.
 */
static char *selinux_ima_collect_state(struct selinux_state *state)
static char *selinux_ima_collect_state(void)
{
	const char *on = "=1;", *off = "=0;";
	char *buf;
@@ -39,26 +37,27 @@ static char *selinux_ima_collect_state(struct selinux_state *state)
	rc = strscpy(buf, "initialized", buf_len);
	WARN_ON(rc < 0);

	rc = strlcat(buf, selinux_initialized(state) ? on : off, buf_len);
	rc = strlcat(buf, selinux_initialized() ? on : off, buf_len);
	WARN_ON(rc >= buf_len);

	rc = strlcat(buf, "enforcing", buf_len);
	WARN_ON(rc >= buf_len);

	rc = strlcat(buf, enforcing_enabled(state) ? on : off, buf_len);
	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(state) ? on : off, 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, state->policycap[i] ? on : off, buf_len);
		rc = strlcat(buf, selinux_state.policycap[i] ? on : off,
			buf_len);
		WARN_ON(rc >= buf_len);
	}

@@ -67,19 +66,17 @@ static char *selinux_ima_collect_state(struct selinux_state *state)

/*
 * selinux_ima_measure_state_locked - Measure SELinux state and hash of policy
 *
 * @state: selinux state struct
 */
void selinux_ima_measure_state_locked(struct selinux_state *state)
void selinux_ima_measure_state_locked(void)
{
	char *state_str = NULL;
	void *policy = NULL;
	size_t policy_len;
	int rc = 0;

	lockdep_assert_held(&state->policy_mutex);
	lockdep_assert_held(&selinux_state.policy_mutex);

	state_str = selinux_ima_collect_state(state);
	state_str = selinux_ima_collect_state();
	if (!state_str) {
		pr_err("SELinux: %s: failed to read state.\n", __func__);
		return;
@@ -94,10 +91,10 @@ void selinux_ima_measure_state_locked(struct selinux_state *state)
	/*
	 * Measure SELinux policy only after initialization is completed.
	 */
	if (!selinux_initialized(state))
	if (!selinux_initialized())
		return;

	rc = security_read_state_kernel(state, &policy, &policy_len);
	rc = security_read_state_kernel(&policy, &policy_len);
	if (rc) {
		pr_err("SELinux: %s: failed to read policy %d.\n", __func__, rc);
		return;
@@ -112,14 +109,12 @@ void selinux_ima_measure_state_locked(struct selinux_state *state)

/*
 * selinux_ima_measure_state - Measure SELinux state and hash of policy
 *
 * @state: selinux state struct
 */
void selinux_ima_measure_state(struct selinux_state *state)
void selinux_ima_measure_state(void)
{
	lockdep_assert_not_held(&state->policy_mutex);
	lockdep_assert_not_held(&selinux_state.policy_mutex);

	mutex_lock(&state->policy_mutex);
	selinux_ima_measure_state_locked(state);
	mutex_unlock(&state->policy_mutex);
	mutex_lock(&selinux_state.policy_mutex);
	selinux_ima_measure_state_locked();
	mutex_unlock(&selinux_state.policy_mutex);
}
+10 −19
Original line number Diff line number Diff line
@@ -52,7 +52,6 @@ struct selinux_audit_data {
	u32 audited;
	u32 denied;
	int result;
	struct selinux_state *state;
} __randomize_layout;

/*
@@ -97,14 +96,12 @@ static inline u32 avc_audit_required(u32 requested,
	return audited;
}

int slow_avc_audit(struct selinux_state *state,
		   u32 ssid, u32 tsid, u16 tclass,
int slow_avc_audit(u32 ssid, u32 tsid, u16 tclass,
		   u32 requested, u32 audited, u32 denied, int result,
		   struct common_audit_data *a);

/**
 * avc_audit - Audit the granting or denial of permissions.
 * @state: SELinux state
 * @ssid: source security identifier
 * @tsid: target security identifier
 * @tclass: target security class
@@ -122,8 +119,7 @@ int slow_avc_audit(struct selinux_state *state,
 * be performed under a lock, to allow the lock to be released
 * before calling the auditing code.
 */
static inline int avc_audit(struct selinux_state *state,
			    u32 ssid, u32 tsid,
static inline int avc_audit(u32 ssid, u32 tsid,
			    u16 tclass, u32 requested,
			    struct av_decision *avd,
			    int result,
@@ -133,30 +129,27 @@ static inline int avc_audit(struct selinux_state *state,
	audited = avc_audit_required(requested, avd, result, 0, &denied);
	if (likely(!audited))
		return 0;
	return slow_avc_audit(state, ssid, tsid, tclass,
	return slow_avc_audit(ssid, tsid, tclass,
			      requested, audited, denied, result,
			      a);
}

#define AVC_STRICT 1 /* Ignore permissive mode. */
#define AVC_EXTENDED_PERMS 2	/* update extended permissions */
int avc_has_perm_noaudit(struct selinux_state *state,
			 u32 ssid, u32 tsid,
int avc_has_perm_noaudit(u32 ssid, u32 tsid,
			 u16 tclass, u32 requested,
			 unsigned flags,
			 struct av_decision *avd);

int avc_has_perm(struct selinux_state *state,
		 u32 ssid, u32 tsid,
int avc_has_perm(u32 ssid, u32 tsid,
		 u16 tclass, u32 requested,
		 struct common_audit_data *auditdata);

int avc_has_extended_perms(struct selinux_state *state,
			   u32 ssid, u32 tsid, u16 tclass, u32 requested,
int avc_has_extended_perms(u32 ssid, u32 tsid, u16 tclass, u32 requested,
			   u8 driver, u8 perm, struct common_audit_data *ad);


u32 avc_policy_seqno(struct selinux_state *state);
u32 avc_policy_seqno(void);

#define AVC_CALLBACK_GRANT		1
#define AVC_CALLBACK_TRY_REVOKE		2
@@ -171,11 +164,9 @@ u32 avc_policy_seqno(struct selinux_state *state);
int avc_add_callback(int (*callback)(u32 event), u32 events);

/* Exported to selinuxfs */
struct selinux_avc;
int avc_get_hash_stats(struct selinux_avc *avc, char *page);
unsigned int avc_get_cache_threshold(struct selinux_avc *avc);
void avc_set_cache_threshold(struct selinux_avc *avc,
			     unsigned int cache_threshold);
int avc_get_hash_stats(char *page);
unsigned int avc_get_cache_threshold(void);
void avc_set_cache_threshold(unsigned int cache_threshold);

/* Attempt to free avc node cache */
void avc_disable(void);
Loading