Re: [RFC PATCH v2] selinux: convert policy read-write lock to RCU

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On 8/19/20 12:17 AM, Stephen Smalley wrote:
> Convert the policy read-write lock to RCU.  This is significantly
> simplified by the earlier work to encapsulate the policy data
> structures and refactor the policy load and boolean setting logic.
> Move the latest_granting sequence number into the selinux_policy
> structure so that it can be updated atomically with the policy.
> Since the removal of the policy rwlock and this move of
> latest_granting reduces the selinux_ss structure to nothing more than
> a wrapper around the selinux_policy pointer, get rid of the extra
> layer of indirection.
>
> At present this change merely passes a hardcoded 1 to
> rcu_dereference_check() in the cases where we know we do not need to
> take rcu_read_lock(), with the preceding comment explaining why.
> Alternatively we could pass fsi->mutex down from selinuxfs and
> apply a lockdep check on it instead.
>
> This change does not specifically do anything special with respect
> to the sidtab live convert; I am unclear as to whether it is safe
> as a result.  Comments welcome.
>
> Based in part on earlier attempts to convert the policy rwlock
> to RCU by Kaigai Kohei [1] and by Peter Enderborg [2].
>
> [1] https://urldefense.proofpoint.com/v2/url?u=https-3A__lore.kernel.org_selinux_6e2f9128-2De191-2Debb3-2D0e87-2D74bfccb0767f-40tycho.nsa.gov_&d=DwIDAg&c=fP4tf--1dS0biCFlB0saz0I0kjO5v7-GLPtvShAo4cc&r=oO5HuGEGxznA2F3djiiYxmxxWQonw0h6Sks-BEoB4ys&m=_kM-X4solVxqaxB8a9pa3-yQIHOpIAWFGk3hl2dC4MM&s=h9lpEA-9HTA9-cthBzr1fCMSAEsPTF0_ZIGMOgnSJOU&e= 
> [2] https://urldefense.proofpoint.com/v2/url?u=https-3A__lore.kernel.org_selinux_20180530141104.28569-2D1-2Dpeter.enderborg-40sony.com_&d=DwIDAg&c=fP4tf--1dS0biCFlB0saz0I0kjO5v7-GLPtvShAo4cc&r=oO5HuGEGxznA2F3djiiYxmxxWQonw0h6Sks-BEoB4ys&m=_kM-X4solVxqaxB8a9pa3-yQIHOpIAWFGk3hl2dC4MM&s=BUPrJpavIz18sxwineNiV0T57bIXVQlhFTwl2f7CfR8&e= 
>
> Signed-off-by: Stephen Smalley <stephen.smalley.work@xxxxxxxxx>
> ---
> v2 switches to synchronize_rcu() and moves latest_granting into selinux_policy,
> removing the need for a separate selinux_ss struct altogether.  Open questions
> remain about what to pass to rcu_dereference_check() and whether sidtab live
> convert is safe after this change.
>
>  security/selinux/hooks.c            |   1 -
>  security/selinux/include/security.h |   5 +-
>  security/selinux/ss/services.c      | 436 ++++++++++++++++------------
>  security/selinux/ss/services.h      |   5 -
>  4 files changed, 256 insertions(+), 191 deletions(-)
>
> diff --git a/security/selinux/hooks.c b/security/selinux/hooks.c
> index ca901025802a..102292f96b0f 100644
> --- a/security/selinux/hooks.c
> +++ b/security/selinux/hooks.c
> @@ -7232,7 +7232,6 @@ static __init int selinux_init(void)
>  	memset(&selinux_state, 0, sizeof(selinux_state));
>  	enforcing_set(&selinux_state, selinux_enforcing_boot);
>  	selinux_state.checkreqprot = selinux_checkreqprot_boot;
> -	selinux_ss_init(&selinux_state.ss);
>  	selinux_avc_init(&selinux_state.avc);
>  	mutex_init(&selinux_state.status_lock);
>  
> diff --git a/security/selinux/include/security.h b/security/selinux/include/security.h
> index c68ed2beadff..1b6a67a66a7e 100644
> --- a/security/selinux/include/security.h
> +++ b/security/selinux/include/security.h
> @@ -13,6 +13,7 @@
>  #include <linux/dcache.h>
>  #include <linux/magic.h>
>  #include <linux/types.h>
> +#include <linux/rcupdate.h>
>  #include <linux/refcount.h>
>  #include <linux/workqueue.h>
>  #include "flask.h"
> @@ -84,7 +85,6 @@ extern int selinux_enabled_boot;
>  #define POLICYDB_BOUNDS_MAXDEPTH	4
>  
>  struct selinux_avc;
> -struct selinux_ss;
>  struct selinux_policy;
>  
>  struct selinux_state {
> @@ -102,10 +102,9 @@ struct selinux_state {
>  	struct mutex status_lock;
>  
>  	struct selinux_avc *avc;
> -	struct selinux_ss *ss;
> +	struct selinux_policy *policy __rcu;
>  } __randomize_layout;
>  
> -void selinux_ss_init(struct selinux_ss **ss);
>  void selinux_avc_init(struct selinux_avc **avc);
>  
>  extern struct selinux_state selinux_state;
> diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c
> index f6f78c65f53f..ba9347517e5b 100644
> --- a/security/selinux/ss/services.c
> +++ b/security/selinux/ss/services.c
> @@ -66,14 +66,6 @@
>  #include "audit.h"
>  #include "policycap_names.h"
>  
> -static struct selinux_ss selinux_ss;
> -
> -void selinux_ss_init(struct selinux_ss **ss)
> -{
> -	rwlock_init(&selinux_ss.policy_rwlock);
> -	*ss = &selinux_ss;
> -}
> -
>  /* Forward declaration. */
>  static int context_struct_to_string(struct policydb *policydb,
>  				    struct context *context,
> @@ -239,13 +231,15 @@ static void map_decision(struct selinux_map *map,
>  int security_mls_enabled(struct selinux_state *state)
>  {
>  	int mls_enabled;
> +	struct selinux_policy *policy;
>  
>  	if (!selinux_initialized(state))
>  		return 0;
>  
> -	read_lock(&state->ss->policy_rwlock);
> -	mls_enabled = state->ss->policy->policydb.mls_enabled;
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_lock();
> +	policy = rcu_dereference(state->policy);
> +	mls_enabled = policy->policydb.mls_enabled;
> +	rcu_read_unlock();
>  	return mls_enabled;
>  }
>  
> @@ -722,8 +716,9 @@ static int security_validtrans_handle_fail(struct selinux_state *state,
>  					   struct sidtab_entry *tentry,
>  					   u16 tclass)
>  {
> -	struct policydb *p = &state->ss->policy->policydb;
> -	struct sidtab *sidtab = state->ss->policy->sidtab;
> +	struct selinux_policy *policy = rcu_dereference(state->policy);
> +	struct policydb *p = &policy->policydb;
> +	struct sidtab *sidtab = policy->sidtab;
>  	char *o = NULL, *n = NULL, *t = NULL;
>  	u32 olen, nlen, tlen;
>  
> @@ -751,6 +746,7 @@ static int security_compute_validatetrans(struct selinux_state *state,
>  					  u32 oldsid, u32 newsid, u32 tasksid,
>  					  u16 orig_tclass, bool user)
>  {
> +	struct selinux_policy *policy;
>  	struct policydb *policydb;
>  	struct sidtab *sidtab;
>  	struct sidtab_entry *oentry;
> @@ -765,13 +761,14 @@ static int security_compute_validatetrans(struct selinux_state *state,
>  	if (!selinux_initialized(state))
>  		return 0;
>  
> -	read_lock(&state->ss->policy_rwlock);
> +	rcu_read_lock();
>  
> -	policydb = &state->ss->policy->policydb;
> -	sidtab = state->ss->policy->sidtab;
> +	policy = rcu_dereference(state->policy);
> +	policydb = &policy->policydb;
> +	sidtab = policy->sidtab;
>  
>  	if (!user)
> -		tclass = unmap_class(&state->ss->policy->map, orig_tclass);
> +		tclass = unmap_class(&policy->map, orig_tclass);
>  	else
>  		tclass = orig_tclass;
>  
> @@ -824,7 +821,7 @@ static int security_compute_validatetrans(struct selinux_state *state,
>  	}
>  
>  out:
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_unlock();
>  	return rc;
>  }
>  
> @@ -856,6 +853,7 @@ int security_validate_transition(struct selinux_state *state,
>  int security_bounded_transition(struct selinux_state *state,
>  				u32 old_sid, u32 new_sid)
>  {
> +	struct selinux_policy *policy;
>  	struct policydb *policydb;
>  	struct sidtab *sidtab;
>  	struct sidtab_entry *old_entry, *new_entry;
> @@ -866,10 +864,10 @@ int security_bounded_transition(struct selinux_state *state,
>  	if (!selinux_initialized(state))
>  		return 0;
>  
> -	read_lock(&state->ss->policy_rwlock);
> -
> -	policydb = &state->ss->policy->policydb;
> -	sidtab = state->ss->policy->sidtab;
> +	rcu_read_lock();
> +	policy = rcu_dereference(state->policy);
> +	policydb = &policy->policydb;
> +	sidtab = policy->sidtab;
>  
>  	rc = -EINVAL;
>  	old_entry = sidtab_search_entry(sidtab, old_sid);
> @@ -930,17 +928,20 @@ int security_bounded_transition(struct selinux_state *state,
>  		kfree(old_name);
>  	}
>  out:
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_unlock();
>  
>  	return rc;
>  }
>  
> -static void avd_init(struct selinux_state *state, struct av_decision *avd)
> +static void avd_init(struct selinux_policy *policy, struct av_decision *avd)
>  {
>  	avd->allowed = 0;
>  	avd->auditallow = 0;
>  	avd->auditdeny = 0xffffffff;
> -	avd->seqno = state->ss->latest_granting;
> +	if (policy)
> +		avd->seqno = policy->latest_granting;
> +	else
> +		avd->seqno = 0;
>  	avd->flags = 0;
>  }
>  
> @@ -1005,6 +1006,7 @@ void security_compute_xperms_decision(struct selinux_state *state,
>  				      u8 driver,
>  				      struct extended_perms_decision *xpermd)
>  {
> +	struct selinux_policy *policy;
>  	struct policydb *policydb;
>  	struct sidtab *sidtab;
>  	u16 tclass;
> @@ -1021,12 +1023,13 @@ void security_compute_xperms_decision(struct selinux_state *state,
>  	memset(xpermd->auditallow->p, 0, sizeof(xpermd->auditallow->p));
>  	memset(xpermd->dontaudit->p, 0, sizeof(xpermd->dontaudit->p));
>  
> -	read_lock(&state->ss->policy_rwlock);
> +	rcu_read_lock();
>  	if (!selinux_initialized(state))
>  		goto allow;
>  
> -	policydb = &state->ss->policy->policydb;
> -	sidtab = state->ss->policy->sidtab;
> +	policy = rcu_dereference(state->policy);
> +	policydb = &policy->policydb;
> +	sidtab = policy->sidtab;
>  
>  	scontext = sidtab_search(sidtab, ssid);
>  	if (!scontext) {
> @@ -1042,7 +1045,7 @@ void security_compute_xperms_decision(struct selinux_state *state,
>  		goto out;
>  	}
>  
> -	tclass = unmap_class(&state->ss->policy->map, orig_tclass);
> +	tclass = unmap_class(&policy->map, orig_tclass);
>  	if (unlikely(orig_tclass && !tclass)) {
>  		if (policydb->allow_unknown)
>  			goto allow;
> @@ -1074,7 +1077,7 @@ void security_compute_xperms_decision(struct selinux_state *state,
>  		}
>  	}
>  out:
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_unlock();
>  	return;
>  allow:
>  	memset(xpermd->allowed->p, 0xff, sizeof(xpermd->allowed->p));
> @@ -1099,19 +1102,21 @@ void security_compute_av(struct selinux_state *state,
>  			 struct av_decision *avd,
>  			 struct extended_perms *xperms)
>  {
> +	struct selinux_policy *policy;
>  	struct policydb *policydb;
>  	struct sidtab *sidtab;
>  	u16 tclass;
>  	struct context *scontext = NULL, *tcontext = NULL;
>  
> -	read_lock(&state->ss->policy_rwlock);
> -	avd_init(state, avd);
> +	rcu_read_lock();
> +	policy = rcu_dereference(state->policy);
> +	avd_init(policy, avd);
>  	xperms->len = 0;
>  	if (!selinux_initialized(state))
>  		goto allow;
>  
> -	policydb = &state->ss->policy->policydb;
> -	sidtab = state->ss->policy->sidtab;
> +	policydb = &policy->policydb;
> +	sidtab = policy->sidtab;
>  
>  	scontext = sidtab_search(sidtab, ssid);
>  	if (!scontext) {
> @@ -1131,7 +1136,7 @@ void security_compute_av(struct selinux_state *state,
>  		goto out;
>  	}
>  
> -	tclass = unmap_class(&state->ss->policy->map, orig_tclass);
> +	tclass = unmap_class(&policy->map, orig_tclass);
>  	if (unlikely(orig_tclass && !tclass)) {
>  		if (policydb->allow_unknown)
>  			goto allow;
> @@ -1139,10 +1144,10 @@ void security_compute_av(struct selinux_state *state,
>  	}
>  	context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
>  				  xperms);
> -	map_decision(&state->ss->policy->map, orig_tclass, avd,
> +	map_decision(&policy->map, orig_tclass, avd,
>  		     policydb->allow_unknown);
>  out:
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_unlock();
>  	return;
>  allow:
>  	avd->allowed = 0xffffffff;
> @@ -1155,17 +1160,19 @@ void security_compute_av_user(struct selinux_state *state,
>  			      u16 tclass,
>  			      struct av_decision *avd)
>  {
> +	struct selinux_policy *policy;
>  	struct policydb *policydb;
>  	struct sidtab *sidtab;
>  	struct context *scontext = NULL, *tcontext = NULL;
>  
> -	read_lock(&state->ss->policy_rwlock);
> -	avd_init(state, avd);
> +	rcu_read_lock();
> +	policy = rcu_dereference(state->policy);
> +	avd_init(policy, avd);
>  	if (!selinux_initialized(state))
>  		goto allow;
>  
> -	policydb = &state->ss->policy->policydb;
> -	sidtab = state->ss->policy->sidtab;
> +	policydb = &policy->policydb;
> +	sidtab = policy->sidtab;
>  
>  	scontext = sidtab_search(sidtab, ssid);
>  	if (!scontext) {
> @@ -1194,7 +1201,7 @@ void security_compute_av_user(struct selinux_state *state,
>  	context_struct_compute_av(policydb, scontext, tcontext, tclass, avd,
>  				  NULL);
>   out:
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_unlock();
>  	return;
>  allow:
>  	avd->allowed = 0xffffffff;
> @@ -1279,6 +1286,7 @@ static int sidtab_entry_to_string(struct policydb *p,
>  
>  int security_sidtab_hash_stats(struct selinux_state *state, char *page)
>  {
> +	struct selinux_policy *policy;
>  	int rc;
>  
>  	if (!selinux_initialized(state)) {
> @@ -1287,9 +1295,10 @@ int security_sidtab_hash_stats(struct selinux_state *state, char *page)
>  		return -EINVAL;
>  	}
>  
> -	read_lock(&state->ss->policy_rwlock);
> -	rc = sidtab_hash_stats(state->ss->policy->sidtab, page);
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_lock();
> +	policy = rcu_dereference(state->policy);
> +	rc = sidtab_hash_stats(policy->sidtab, page);
> +	rcu_read_unlock();
>  
>  	return rc;
>  }
> @@ -1306,6 +1315,7 @@ static int security_sid_to_context_core(struct selinux_state *state,
>  					u32 *scontext_len, int force,
>  					int only_invalid)
>  {
> +	struct selinux_policy *policy;
>  	struct policydb *policydb;
>  	struct sidtab *sidtab;
>  	struct sidtab_entry *entry;
> @@ -1335,9 +1345,10 @@ static int security_sid_to_context_core(struct selinux_state *state,
>  		       "load_policy on unknown SID %d\n", __func__, sid);
>  		return -EINVAL;
>  	}
> -	read_lock(&state->ss->policy_rwlock);
> -	policydb = &state->ss->policy->policydb;
> -	sidtab = state->ss->policy->sidtab;
> +	rcu_read_lock();
> +	policy = rcu_dereference(state->policy);
> +	policydb = &policy->policydb;
> +	sidtab = policy->sidtab;
>  
>  	if (force)
>  		entry = sidtab_search_entry_force(sidtab, sid);
> @@ -1356,7 +1367,7 @@ static int security_sid_to_context_core(struct selinux_state *state,
>  				    scontext_len);
>  
>  out_unlock:
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_unlock();
>  	return rc;
>  
>  }
> @@ -1491,6 +1502,7 @@ static int security_context_to_sid_core(struct selinux_state *state,
>  					u32 *sid, u32 def_sid, gfp_t gfp_flags,
>  					int force)
>  {
> +	struct selinux_policy *policy;
>  	struct policydb *policydb;
>  	struct sidtab *sidtab;
>  	char *scontext2, *str = NULL;
> @@ -1529,9 +1541,10 @@ static int security_context_to_sid_core(struct selinux_state *state,
>  		if (!str)
>  			goto out;
>  	}
> -	read_lock(&state->ss->policy_rwlock);
> -	policydb = &state->ss->policy->policydb;
> -	sidtab = state->ss->policy->sidtab;
> +	rcu_read_lock();
> +	policy = rcu_dereference(state->policy);
> +	policydb = &policy->policydb;
> +	sidtab = policy->sidtab;
>  	rc = string_to_context_struct(policydb, sidtab, scontext2,
>  				      &context, def_sid);
>  	if (rc == -EINVAL && force) {
> @@ -1543,7 +1556,7 @@ static int security_context_to_sid_core(struct selinux_state *state,
>  	rc = sidtab_context_to_sid(sidtab, &context, sid);
>  	context_destroy(&context);
>  out_unlock:
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_unlock();
>  out:
>  	kfree(scontext2);
>  	kfree(str);
> @@ -1618,8 +1631,9 @@ static int compute_sid_handle_invalid_context(
>  	u16 tclass,
>  	struct context *newcontext)
>  {
> -	struct policydb *policydb = &state->ss->policy->policydb;
> -	struct sidtab *sidtab = state->ss->policy->sidtab;
> +	struct selinux_policy *policy = rcu_dereference(state->policy);
> +	struct policydb *policydb = &policy->policydb;
> +	struct sidtab *sidtab = policy->sidtab;
>  	char *s = NULL, *t = NULL, *n = NULL;
>  	u32 slen, tlen, nlen;
>  	struct audit_buffer *ab;
> @@ -1686,6 +1700,7 @@ static int security_compute_sid(struct selinux_state *state,
>  				u32 *out_sid,
>  				bool kern)
>  {
> +	struct selinux_policy *policy;
>  	struct policydb *policydb;
>  	struct sidtab *sidtab;
>  	struct class_datum *cladatum = NULL;
> @@ -1712,19 +1727,21 @@ static int security_compute_sid(struct selinux_state *state,
>  
>  	context_init(&newcontext);
>  
> -	read_lock(&state->ss->policy_rwlock);
> +	rcu_read_lock();
> +
> +	policy = rcu_dereference(state->policy);
>  
>  	if (kern) {
> -		tclass = unmap_class(&state->ss->policy->map, orig_tclass);
> +		tclass = unmap_class(&policy->map, orig_tclass);
>  		sock = security_is_socket_class(orig_tclass);
>  	} else {
>  		tclass = orig_tclass;
> -		sock = security_is_socket_class(map_class(&state->ss->policy->map,
> +		sock = security_is_socket_class(map_class(&policy->map,
>  							  tclass));
>  	}
>  
> -	policydb = &state->ss->policy->policydb;
> -	sidtab = state->ss->policy->sidtab;
> +	policydb = &policy->policydb;
> +	sidtab = policy->sidtab;
>  
>  	sentry = sidtab_search_entry(sidtab, ssid);
>  	if (!sentry) {
> @@ -1852,7 +1869,7 @@ static int security_compute_sid(struct selinux_state *state,
>  	/* Obtain the sid for the context. */
>  	rc = sidtab_context_to_sid(sidtab, &newcontext, out_sid);
>  out_unlock:
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_unlock();
>  	context_destroy(&newcontext);
>  out:
>  	return rc;
> @@ -1941,7 +1958,8 @@ static inline int convert_context_handle_invalid_context(
>  	struct selinux_state *state,
>  	struct context *context)
>  {
> -	struct policydb *policydb = &state->ss->policy->policydb;
> +	struct selinux_policy *policy = rcu_dereference(state->policy);
> +	struct policydb *policydb = &policy->policydb;
>  	char *s;
>  	u32 len;
>  
> @@ -2094,13 +2112,16 @@ static int convert_context(struct context *oldc, struct context *newc, void *p)
>  
>  static void security_load_policycaps(struct selinux_state *state)
>  {
> +	struct selinux_policy *policy;
>  	struct policydb *p;
>  	unsigned int i;
>  	struct ebitmap_node *node;
>  
> -	read_lock(&state->ss->policy_rwlock);
> +	rcu_read_lock();
>  
> -	p = &state->ss->policy->policydb;
> +	policy = rcu_dereference(state->policy);
> +
> +	p = &policy->policydb;
>  
>  	for (i = 0; i < ARRAY_SIZE(state->policycap); i++)
>  		state->policycap[i] = ebitmap_get_bit(&p->policycaps, i);
> @@ -2116,7 +2137,7 @@ static void security_load_policycaps(struct selinux_state *state)
>  				i);
>  	}
>  
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_unlock();
>  }
>  
>  static int security_preserve_bools(struct selinux_state *state,
> @@ -2134,10 +2155,21 @@ static void selinux_policy_free(struct selinux_policy *policy)
>  	kfree(policy);
>  }
>  
> +static void selinux_policy_cond_free(struct selinux_policy *policy)
> +{
> +	cond_policydb_destroy_dup(&policy->policydb);
> +	kfree(policy);
> +}
> +
>  void selinux_policy_cancel(struct selinux_state *state,
>  			struct selinux_policy *policy)
>  {
> -	sidtab_cancel_convert(state->ss->policy->sidtab);
> +	struct selinux_policy *oldpolicy;
> +
> +	rcu_read_lock();
> +	oldpolicy = rcu_dereference(state->policy);
> +	sidtab_cancel_convert(oldpolicy->sidtab);
> +	rcu_read_unlock();
>  	selinux_policy_free(policy);
>  }
>  
> @@ -2159,14 +2191,14 @@ void selinux_policy_commit(struct selinux_state *state,
>  	u32 seqno;
>  
>  	/*
> -	 * NOTE: We do not need to take the policy read-lock
> +	 * NOTE: We do not need to take the rcu read lock
>  	 * around the code below because other policy-modifying
>  	 * operations are already excluded by selinuxfs via
>  	 * fsi->mutex.
>  	 */
> +	oldpolicy = rcu_dereference_check(state->policy, 1);
>  
>  	/* If switching between different policy types, log MLS status */
> -	oldpolicy = state->ss->policy;
>  	if (oldpolicy) {
>  		if (oldpolicy->policydb.mls_enabled && !newpolicy->policydb.mls_enabled)
>  			pr_info("SELinux: Disabling MLS support...\n");
> @@ -2174,11 +2206,16 @@ void selinux_policy_commit(struct selinux_state *state,
>  			pr_info("SELinux: Enabling MLS support...\n");
>  	}
>  
> +
> +	/* Set latest granting seqno for new policy. */
> +	if (oldpolicy)
> +		newpolicy->latest_granting = oldpolicy->latest_granting + 1;
> +	else
> +		newpolicy->latest_granting = 1;
> +	seqno = newpolicy->latest_granting;
> +
>  	/* Install the new policy. */
> -	write_lock_irq(&state->ss->policy_rwlock);
> -	state->ss->policy = newpolicy;
> -	seqno = ++state->ss->latest_granting;
> -	write_unlock_irq(&state->ss->policy_rwlock);
> +	rcu_assign_pointer(state->policy, newpolicy);
>  
>  	/* Load the policycaps from the new policy */
>  	security_load_policycaps(state);
> @@ -2194,6 +2231,7 @@ void selinux_policy_commit(struct selinux_state *state,
>  	}
>  
>  	/* Free the old policy */
> +	synchronize_rcu();


I tested this with call_rcu(), it is good way to get it fast. However im not sure if call_rcu is right
for this huge free task.  I think synchronize_rcu() is safe with cond_resched().

Added Paul E. McKenney for his view on call_rcu or not for this case. I think he suggested that some time.


>  	selinux_policy_free(oldpolicy);
>  
>  	/* Notify others of the policy change */
> @@ -2213,7 +2251,7 @@ void selinux_policy_commit(struct selinux_state *state,
>  int security_load_policy(struct selinux_state *state, void *data, size_t len,
>  			struct selinux_policy **newpolicyp)
>  {
> -	struct selinux_policy *newpolicy;
> +	struct selinux_policy *newpolicy, *oldpolicy;
>  	struct sidtab_convert_params convert_params;
>  	struct convert_context_args args;
>  	int rc = 0;
> @@ -2261,20 +2299,22 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len,
>  	 * Convert the internal representations of contexts
>  	 * in the new SID table.
>  	 *
> -	 * NOTE: We do not need to take the policy read-lock
> +	 * NOTE: We do not need to take the rcu read lock
>  	 * around the code below because other policy-modifying
>  	 * operations are already excluded by selinuxfs via
>  	 * fsi->mutex.
>  	 */
> +	oldpolicy = rcu_dereference_check(state->policy, 1);
> +
>  	args.state = state;
> -	args.oldp = &state->ss->policy->policydb;
> +	args.oldp = &oldpolicy->policydb;
>  	args.newp = &newpolicy->policydb;
>  
>  	convert_params.func = convert_context;
>  	convert_params.args = &args;
>  	convert_params.target = newpolicy->sidtab;
>  
> -	rc = sidtab_convert(state->ss->policy->sidtab, &convert_params);
> +	rc = sidtab_convert(oldpolicy->sidtab, &convert_params);
>  	if (rc) {
>  		pr_err("SELinux:  unable to convert the internal"
>  			" representation of contexts in the new SID"
> @@ -2291,11 +2331,13 @@ int security_load_policy(struct selinux_state *state, void *data, size_t len,
>  
>  size_t security_policydb_len(struct selinux_state *state)
>  {
> +	struct selinux_policy *policy;
>  	size_t len;
>  
> -	read_lock(&state->ss->policy_rwlock);
> -	len = state->ss->policy->policydb.len;
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_lock();
> +	policy = rcu_dereference(state->policy);
> +	len = policy->policydb.len;
> +	rcu_read_unlock();
>  
>  	return len;
>  }
> @@ -2309,15 +2351,16 @@ size_t security_policydb_len(struct selinux_state *state)
>  int security_port_sid(struct selinux_state *state,
>  		      u8 protocol, u16 port, u32 *out_sid)
>  {
> +	struct selinux_policy *policy;
>  	struct policydb *policydb;
>  	struct sidtab *sidtab;
>  	struct ocontext *c;
>  	int rc = 0;
>  
> -	read_lock(&state->ss->policy_rwlock);
> -
> -	policydb = &state->ss->policy->policydb;
> -	sidtab = state->ss->policy->sidtab;
> +	rcu_read_lock();
> +	policy = rcu_dereference(state->policy);
> +	policydb = &policy->policydb;
> +	sidtab = policy->sidtab;
>  
>  	c = policydb->ocontexts[OCON_PORT];
>  	while (c) {
> @@ -2341,7 +2384,7 @@ int security_port_sid(struct selinux_state *state,
>  	}
>  
>  out:
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_unlock();
>  	return rc;
>  }
>  
> @@ -2354,15 +2397,16 @@ int security_port_sid(struct selinux_state *state,
>  int security_ib_pkey_sid(struct selinux_state *state,
>  			 u64 subnet_prefix, u16 pkey_num, u32 *out_sid)
>  {
> +	struct selinux_policy *policy;
>  	struct policydb *policydb;
>  	struct sidtab *sidtab;
>  	struct ocontext *c;
>  	int rc = 0;
>  
> -	read_lock(&state->ss->policy_rwlock);
> -
> -	policydb = &state->ss->policy->policydb;
> -	sidtab = state->ss->policy->sidtab;
> +	rcu_read_lock();
> +	policy = rcu_dereference(state->policy);
> +	policydb = &policy->policydb;
> +	sidtab = policy->sidtab;
>  
>  	c = policydb->ocontexts[OCON_IBPKEY];
>  	while (c) {
> @@ -2387,7 +2431,7 @@ int security_ib_pkey_sid(struct selinux_state *state,
>  		*out_sid = SECINITSID_UNLABELED;
>  
>  out:
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_unlock();
>  	return rc;
>  }
>  
> @@ -2400,15 +2444,16 @@ int security_ib_pkey_sid(struct selinux_state *state,
>  int security_ib_endport_sid(struct selinux_state *state,
>  			    const char *dev_name, u8 port_num, u32 *out_sid)
>  {
> +	struct selinux_policy *policy;
>  	struct policydb *policydb;
>  	struct sidtab *sidtab;
>  	struct ocontext *c;
>  	int rc = 0;
>  
> -	read_lock(&state->ss->policy_rwlock);
> -
> -	policydb = &state->ss->policy->policydb;
> -	sidtab = state->ss->policy->sidtab;
> +	rcu_read_lock();
> +	policy = rcu_dereference(state->policy);
> +	policydb = &policy->policydb;
> +	sidtab = policy->sidtab;
>  
>  	c = policydb->ocontexts[OCON_IBENDPORT];
>  	while (c) {
> @@ -2433,7 +2478,7 @@ int security_ib_endport_sid(struct selinux_state *state,
>  		*out_sid = SECINITSID_UNLABELED;
>  
>  out:
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_unlock();
>  	return rc;
>  }
>  
> @@ -2445,15 +2490,16 @@ int security_ib_endport_sid(struct selinux_state *state,
>  int security_netif_sid(struct selinux_state *state,
>  		       char *name, u32 *if_sid)
>  {
> +	struct selinux_policy *policy;
>  	struct policydb *policydb;
>  	struct sidtab *sidtab;
>  	int rc = 0;
>  	struct ocontext *c;
>  
> -	read_lock(&state->ss->policy_rwlock);
> -
> -	policydb = &state->ss->policy->policydb;
> -	sidtab = state->ss->policy->sidtab;
> +	rcu_read_lock();
> +	policy = rcu_dereference(state->policy);
> +	policydb = &policy->policydb;
> +	sidtab = policy->sidtab;
>  
>  	c = policydb->ocontexts[OCON_NETIF];
>  	while (c) {
> @@ -2478,7 +2524,7 @@ int security_netif_sid(struct selinux_state *state,
>  		*if_sid = SECINITSID_NETIF;
>  
>  out:
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_unlock();
>  	return rc;
>  }
>  
> @@ -2508,15 +2554,16 @@ int security_node_sid(struct selinux_state *state,
>  		      u32 addrlen,
>  		      u32 *out_sid)
>  {
> +	struct selinux_policy *policy;
>  	struct policydb *policydb;
>  	struct sidtab *sidtab;
>  	int rc;
>  	struct ocontext *c;
>  
> -	read_lock(&state->ss->policy_rwlock);
> -
> -	policydb = &state->ss->policy->policydb;
> -	sidtab = state->ss->policy->sidtab;
> +	rcu_read_lock();
> +	policy = rcu_dereference(state->policy);
> +	policydb = &policy->policydb;
> +	sidtab = policy->sidtab;
>  
>  	switch (domain) {
>  	case AF_INET: {
> @@ -2571,7 +2618,7 @@ int security_node_sid(struct selinux_state *state,
>  
>  	rc = 0;
>  out:
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_unlock();
>  	return rc;
>  }
>  
> @@ -2597,6 +2644,7 @@ int security_get_user_sids(struct selinux_state *state,
>  			   u32 **sids,
>  			   u32 *nel)
>  {
> +	struct selinux_policy *policy;
>  	struct policydb *policydb;
>  	struct sidtab *sidtab;
>  	struct context *fromcon, usercon;
> @@ -2613,10 +2661,10 @@ int security_get_user_sids(struct selinux_state *state,
>  	if (!selinux_initialized(state))
>  		goto out;
>  
> -	read_lock(&state->ss->policy_rwlock);
> -
> -	policydb = &state->ss->policy->policydb;
> -	sidtab = state->ss->policy->sidtab;
> +	rcu_read_lock();
> +	policy = rcu_dereference(state->policy);
> +	policydb = &policy->policydb;
> +	sidtab = policy->sidtab;
>  
>  	context_init(&usercon);
>  
> @@ -2667,7 +2715,7 @@ int security_get_user_sids(struct selinux_state *state,
>  	}
>  	rc = 0;
>  out_unlock:
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_unlock();
>  	if (rc || !mynel) {
>  		kfree(mysids);
>  		goto out;
> @@ -2778,12 +2826,14 @@ int security_genfs_sid(struct selinux_state *state,
>  		       u16 orig_sclass,
>  		       u32 *sid)
>  {
> +	struct selinux_policy *policy;
>  	int retval;
>  
> -	read_lock(&state->ss->policy_rwlock);
> -	retval = __security_genfs_sid(state->ss->policy,
> +	rcu_read_lock();
> +	policy = rcu_dereference(state->policy);
> +	retval = __security_genfs_sid(policy,
>  				fstype, path, orig_sclass, sid);
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_unlock();
>  	return retval;
>  }
>  
> @@ -2803,6 +2853,7 @@ int selinux_policy_genfs_sid(struct selinux_policy *policy,
>   */
>  int security_fs_use(struct selinux_state *state, struct super_block *sb)
>  {
> +	struct selinux_policy *policy;
>  	struct policydb *policydb;
>  	struct sidtab *sidtab;
>  	int rc = 0;
> @@ -2810,10 +2861,10 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb)
>  	struct superblock_security_struct *sbsec = sb->s_security;
>  	const char *fstype = sb->s_type->name;
>  
> -	read_lock(&state->ss->policy_rwlock);
> -
> -	policydb = &state->ss->policy->policydb;
> -	sidtab = state->ss->policy->sidtab;
> +	rcu_read_lock();
> +	policy = rcu_dereference(state->policy);
> +	policydb = &policy->policydb;
> +	sidtab = policy->sidtab;
>  
>  	c = policydb->ocontexts[OCON_FSUSE];
>  	while (c) {
> @@ -2832,7 +2883,7 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb)
>  		}
>  		sbsec->sid = c->sid[0];
>  	} else {
> -		rc = __security_genfs_sid(state->ss->policy, fstype, "/",
> +		rc = __security_genfs_sid(policy, fstype, "/",
>  					SECCLASS_DIR, &sbsec->sid);
>  		if (rc) {
>  			sbsec->behavior = SECURITY_FS_USE_NONE;
> @@ -2843,7 +2894,7 @@ int security_fs_use(struct selinux_state *state, struct super_block *sb)
>  	}
>  
>  out:
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_unlock();
>  	return rc;
>  }
>  
> @@ -2906,24 +2957,26 @@ int security_set_bools(struct selinux_state *state, u32 len, int *values)
>  	int rc;
>  	u32 i, seqno = 0;
>  
> +	if (!selinux_initialized(state))
> +		return -EINVAL;
> +
>  	/*
> -	 * NOTE: We do not need to take the policy read-lock
> +	 * NOTE: We do not need to take the rcu read lock
>  	 * around the code below because other policy-modifying
>  	 * operations are already excluded by selinuxfs via
>  	 * fsi->mutex.
>  	 */
>  
> +	oldpolicy = rcu_dereference_check(state->policy, 1);
> +
>  	/* Consistency check on number of booleans, should never fail */
> -	if (WARN_ON(len != state->ss->policy->policydb.p_bools.nprim))
> +	if (WARN_ON(len != oldpolicy->policydb.p_bools.nprim))
>  		return -EINVAL;
>  
> -	newpolicy = kmemdup(state->ss->policy, sizeof(*newpolicy),
> -			GFP_KERNEL);
> +	newpolicy = kmemdup(oldpolicy, sizeof(*newpolicy), GFP_KERNEL);
>  	if (!newpolicy)
>  		return -ENOMEM;
>  
> -	oldpolicy = state->ss->policy;
> -
>  	/*
>  	 * Deep copy only the parts of the policydb that might be
>  	 * modified as a result of changing booleans.
> @@ -2955,20 +3008,20 @@ int security_set_bools(struct selinux_state *state, u32 len, int *values)
>  	/* Re-evaluate the conditional rules in the copy */
>  	evaluate_cond_nodes(&newpolicy->policydb);
>  
> +	/* Set latest granting seqno for new policy */
> +	newpolicy->latest_granting = oldpolicy->latest_granting + 1;
> +	seqno = newpolicy->latest_granting;
> +
>  	/* Install the new policy */
> -	write_lock_irq(&state->ss->policy_rwlock);
> -	state->ss->policy = newpolicy;
> -	seqno = ++state->ss->latest_granting;
> -	write_unlock_irq(&state->ss->policy_rwlock);
> +	rcu_assign_pointer(state->policy, newpolicy);
>  
>  	/*
>  	 * Free the conditional portions of the old policydb
> -	 * that were copied for the new policy.
> +	 * that were copied for the new policy, and the oldpolicy
> +	 * structure itself but not what it references.
>  	 */
> -	cond_policydb_destroy_dup(&oldpolicy->policydb);
> -
> -	/* Free the old policy structure but not what it references. */
> -	kfree(oldpolicy);
> +	synchronize_rcu();
> +	selinux_policy_cond_free(oldpolicy);
>  
>  	/* Notify others of the policy change */
>  	selinux_notify_policy_change(state, seqno);
> @@ -2978,13 +3031,14 @@ int security_set_bools(struct selinux_state *state, u32 len, int *values)
>  int security_get_bool_value(struct selinux_state *state,
>  			    u32 index)
>  {
> +	struct selinux_policy *policy;
>  	struct policydb *policydb;
>  	int rc;
>  	u32 len;
>  
> -	read_lock(&state->ss->policy_rwlock);
> -
> -	policydb = &state->ss->policy->policydb;
> +	rcu_read_lock();
> +	policy = state->policy;
> +	policydb = &policy->policydb;
>  
>  	rc = -EFAULT;
>  	len = policydb->p_bools.nprim;
> @@ -2993,21 +3047,23 @@ int security_get_bool_value(struct selinux_state *state,
>  
>  	rc = policydb->bool_val_to_struct[index]->state;
>  out:
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_unlock();
>  	return rc;
>  }
>  
>  static int security_preserve_bools(struct selinux_state *state,
>  				   struct policydb *policydb)
>  {
> +	struct selinux_policy *policy;
>  	int rc, *bvalues = NULL;
>  	char **bnames = NULL;
>  	struct cond_bool_datum *booldatum;
>  	u32 i, nbools = 0;
>  
> -	read_lock(&state->ss->policy_rwlock);
> -	rc = security_get_bools(state->ss->policy, &nbools, &bnames, &bvalues);
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_lock();
> +	policy = state->policy;
> +	rc = security_get_bools(policy, &nbools, &bnames, &bvalues);
> +	rcu_read_unlock();
>  	if (rc)
>  		goto out;
>  	for (i = 0; i < nbools; i++) {
> @@ -3034,6 +3090,7 @@ static int security_preserve_bools(struct selinux_state *state,
>  int security_sid_mls_copy(struct selinux_state *state,
>  			  u32 sid, u32 mls_sid, u32 *new_sid)
>  {
> +	struct selinux_policy *policy;
>  	struct policydb *policydb;
>  	struct sidtab *sidtab;
>  	struct context *context1;
> @@ -3051,10 +3108,10 @@ int security_sid_mls_copy(struct selinux_state *state,
>  
>  	context_init(&newcon);
>  
> -	read_lock(&state->ss->policy_rwlock);
> -
> -	policydb = &state->ss->policy->policydb;
> -	sidtab = state->ss->policy->sidtab;
> +	rcu_read_lock();
> +	policy = rcu_dereference(state->policy);
> +	policydb = &policy->policydb;
> +	sidtab = policy->sidtab;
>  
>  	if (!policydb->mls_enabled) {
>  		*new_sid = sid;
> @@ -3107,7 +3164,7 @@ int security_sid_mls_copy(struct selinux_state *state,
>  	}
>  	rc = sidtab_context_to_sid(sidtab, &newcon, new_sid);
>  out_unlock:
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_unlock();
>  	context_destroy(&newcon);
>  out:
>  	return rc;
> @@ -3138,6 +3195,7 @@ int security_net_peersid_resolve(struct selinux_state *state,
>  				 u32 xfrm_sid,
>  				 u32 *peer_sid)
>  {
> +	struct selinux_policy *policy;
>  	struct policydb *policydb;
>  	struct sidtab *sidtab;
>  	int rc;
> @@ -3161,10 +3219,10 @@ int security_net_peersid_resolve(struct selinux_state *state,
>  		return 0;
>  	}
>  
> -	read_lock(&state->ss->policy_rwlock);
> -
> -	policydb = &state->ss->policy->policydb;
> -	sidtab = state->ss->policy->sidtab;
> +	rcu_read_lock();
> +	policy = rcu_dereference(state->policy);
> +	policydb = &policy->policydb;
> +	sidtab = policy->sidtab;
>  
>  	/*
>  	 * We don't need to check initialized here since the only way both
> @@ -3201,7 +3259,7 @@ int security_net_peersid_resolve(struct selinux_state *state,
>  	 * expressive */
>  	*peer_sid = xfrm_sid;
>  out:
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_unlock();
>  	return rc;
>  }
>  
> @@ -3305,21 +3363,25 @@ int security_get_permissions(struct selinux_policy *policy,
>  
>  int security_get_reject_unknown(struct selinux_state *state)
>  {
> +	struct selinux_policy *policy;
>  	int value;
>  
> -	read_lock(&state->ss->policy_rwlock);
> -	value = state->ss->policy->policydb.reject_unknown;
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_lock();
> +	policy = rcu_dereference(state->policy);
> +	value = policy->policydb.reject_unknown;
> +	rcu_read_unlock();
>  	return value;
>  }
>  
>  int security_get_allow_unknown(struct selinux_state *state)
>  {
> +	struct selinux_policy *policy;
>  	int value;
>  
> -	read_lock(&state->ss->policy_rwlock);
> -	value = state->ss->policy->policydb.allow_unknown;
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_lock();
> +	policy = rcu_dereference(state->policy);
> +	value = policy->policydb.allow_unknown;
> +	rcu_read_unlock();
>  	return value;
>  }
>  
> @@ -3336,11 +3398,13 @@ int security_get_allow_unknown(struct selinux_state *state)
>  int security_policycap_supported(struct selinux_state *state,
>  				 unsigned int req_cap)
>  {
> +	struct selinux_policy *policy;
>  	int rc;
>  
> -	read_lock(&state->ss->policy_rwlock);
> -	rc = ebitmap_get_bit(&state->ss->policy->policydb.policycaps, req_cap);
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_lock();
> +	policy = rcu_dereference(state->policy);
> +	rc = ebitmap_get_bit(&policy->policydb.policycaps, req_cap);
> +	rcu_read_unlock();
>  
>  	return rc;
>  }
> @@ -3363,6 +3427,7 @@ void selinux_audit_rule_free(void *vrule)
>  int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
>  {
>  	struct selinux_state *state = &selinux_state;
> +	struct selinux_policy *policy;
>  	struct policydb *policydb;
>  	struct selinux_audit_rule *tmprule;
>  	struct role_datum *roledatum;
> @@ -3406,11 +3471,11 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
>  
>  	context_init(&tmprule->au_ctxt);
>  
> -	read_lock(&state->ss->policy_rwlock);
> -
> -	policydb = &state->ss->policy->policydb;
> +	rcu_read_lock();
> +	policy = rcu_dereference(state->policy);
> +	policydb = &policy->policydb;
>  
> -	tmprule->au_seqno = state->ss->latest_granting;
> +	tmprule->au_seqno = policy->latest_granting;
>  
>  	switch (field) {
>  	case AUDIT_SUBJ_USER:
> @@ -3449,7 +3514,7 @@ int selinux_audit_rule_init(u32 field, u32 op, char *rulestr, void **vrule)
>  	}
>  	rc = 0;
>  out:
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_unlock();
>  
>  	if (rc) {
>  		selinux_audit_rule_free(tmprule);
> @@ -3489,6 +3554,7 @@ int selinux_audit_rule_known(struct audit_krule *rule)
>  int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
>  {
>  	struct selinux_state *state = &selinux_state;
> +	struct selinux_policy *policy;
>  	struct context *ctxt;
>  	struct mls_level *level;
>  	struct selinux_audit_rule *rule = vrule;
> @@ -3499,14 +3565,16 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
>  		return -ENOENT;
>  	}
>  
> -	read_lock(&state->ss->policy_rwlock);
> +	rcu_read_lock();
> +
> +	policy = rcu_dereference(state->policy);
>  
> -	if (rule->au_seqno < state->ss->latest_granting) {
> +	if (rule->au_seqno < policy->latest_granting) {
>  		match = -ESTALE;
>  		goto out;
>  	}
>  
> -	ctxt = sidtab_search(state->ss->policy->sidtab, sid);
> +	ctxt = sidtab_search(policy->sidtab, sid);
>  	if (unlikely(!ctxt)) {
>  		WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n",
>  			  sid);
> @@ -3590,7 +3658,7 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule)
>  	}
>  
>  out:
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_unlock();
>  	return match;
>  }
>  
> @@ -3668,6 +3736,7 @@ int security_netlbl_secattr_to_sid(struct selinux_state *state,
>  				   struct netlbl_lsm_secattr *secattr,
>  				   u32 *sid)
>  {
> +	struct selinux_policy *policy;
>  	struct policydb *policydb;
>  	struct sidtab *sidtab;
>  	int rc;
> @@ -3679,10 +3748,10 @@ int security_netlbl_secattr_to_sid(struct selinux_state *state,
>  		return 0;
>  	}
>  
> -	read_lock(&state->ss->policy_rwlock);
> -
> -	policydb = &state->ss->policy->policydb;
> -	sidtab = state->ss->policy->sidtab;
> +	rcu_read_lock();
> +	policy = rcu_dereference(state->policy);
> +	policydb = &policy->policydb;
> +	sidtab = policy->sidtab;
>  
>  	if (secattr->flags & NETLBL_SECATTR_CACHE)
>  		*sid = *(u32 *)secattr->cache->data;
> @@ -3718,12 +3787,12 @@ int security_netlbl_secattr_to_sid(struct selinux_state *state,
>  	} else
>  		*sid = SECSID_NULL;
>  
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_unlock();
>  	return 0;
>  out_free:
>  	ebitmap_destroy(&ctx_new.range.level[0].cat);
>  out:
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_unlock();
>  	return rc;
>  }
>  
> @@ -3740,6 +3809,7 @@ int security_netlbl_secattr_to_sid(struct selinux_state *state,
>  int security_netlbl_sid_to_secattr(struct selinux_state *state,
>  				   u32 sid, struct netlbl_lsm_secattr *secattr)
>  {
> +	struct selinux_policy *policy;
>  	struct policydb *policydb;
>  	int rc;
>  	struct context *ctx;
> @@ -3747,12 +3817,12 @@ int security_netlbl_sid_to_secattr(struct selinux_state *state,
>  	if (!selinux_initialized(state))
>  		return 0;
>  
> -	read_lock(&state->ss->policy_rwlock);
> -
> -	policydb = &state->ss->policy->policydb;
> +	rcu_read_lock();
> +	policy = rcu_dereference(state->policy);
> +	policydb = &policy->policydb;
>  
>  	rc = -ENOENT;
> -	ctx = sidtab_search(state->ss->policy->sidtab, sid);
> +	ctx = sidtab_search(policy->sidtab, sid);
>  	if (ctx == NULL)
>  		goto out;
>  
> @@ -3767,7 +3837,7 @@ int security_netlbl_sid_to_secattr(struct selinux_state *state,
>  	mls_export_netlbl_lvl(policydb, ctx, secattr);
>  	rc = mls_export_netlbl_cat(policydb, ctx, secattr);
>  out:
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_unlock();
>  	return rc;
>  }
>  #endif /* CONFIG_NETLABEL */
> @@ -3781,6 +3851,7 @@ int security_netlbl_sid_to_secattr(struct selinux_state *state,
>  int security_read_policy(struct selinux_state *state,
>  			 void **data, size_t *len)
>  {
> +	struct selinux_policy *policy;
>  	int rc;
>  	struct policy_file fp;
>  
> @@ -3796,9 +3867,10 @@ int security_read_policy(struct selinux_state *state,
>  	fp.data = *data;
>  	fp.len = *len;
>  
> -	read_lock(&state->ss->policy_rwlock);
> -	rc = policydb_write(&state->ss->policy->policydb, &fp);
> -	read_unlock(&state->ss->policy_rwlock);
> +	rcu_read_lock();
> +	policy = rcu_dereference(state->policy);
> +	rc = policydb_write(&policy->policydb, &fp);
> +	rcu_read_unlock();
>  
>  	if (rc)
>  		return rc;
> diff --git a/security/selinux/ss/services.h b/security/selinux/ss/services.h
> index 06931e34cb24..9555ad074303 100644
> --- a/security/selinux/ss/services.h
> +++ b/security/selinux/ss/services.h
> @@ -26,12 +26,7 @@ struct selinux_policy {
>  	struct sidtab *sidtab;
>  	struct policydb policydb;
>  	struct selinux_map map;
> -};
> -
> -struct selinux_ss {
> -	rwlock_t policy_rwlock;
>  	u32 latest_granting;
> -	struct selinux_policy *policy;
>  } __randomize_layout;
>  
>  void services_compute_xperms_drivers(struct extended_perms *xperms,





[Index of Archives]     [Selinux Refpolicy]     [Linux SGX]     [Fedora Users]     [Fedora Desktop]     [Yosemite Photos]     [Yosemite Camping]     [Yosemite Campsites]     [KDE Users]     [Gnome Users]

  Powered by Linux