diff options
Diffstat (limited to 'security/selinux/ss')
| -rw-r--r-- | security/selinux/ss/constraint.h | 1 | ||||
| -rw-r--r-- | security/selinux/ss/ebitmap.c | 20 | ||||
| -rw-r--r-- | security/selinux/ss/ebitmap.h | 10 | ||||
| -rw-r--r-- | security/selinux/ss/hashtab.c | 3 | ||||
| -rw-r--r-- | security/selinux/ss/mls.c | 24 | ||||
| -rw-r--r-- | security/selinux/ss/mls_types.h | 2 | ||||
| -rw-r--r-- | security/selinux/ss/policydb.c | 121 | ||||
| -rw-r--r-- | security/selinux/ss/policydb.h | 11 | ||||
| -rw-r--r-- | security/selinux/ss/services.c | 100 | 
9 files changed, 212 insertions, 80 deletions
diff --git a/security/selinux/ss/constraint.h b/security/selinux/ss/constraint.h index 149dda731fd..96fd947c494 100644 --- a/security/selinux/ss/constraint.h +++ b/security/selinux/ss/constraint.h @@ -48,6 +48,7 @@ struct constraint_expr {  	u32 op;			/* operator */  	struct ebitmap names;	/* names */ +	struct type_set *type_names;  	struct constraint_expr *next;   /* next expression */  }; diff --git a/security/selinux/ss/ebitmap.c b/security/selinux/ss/ebitmap.c index 30f119b1d1e..820313a04d4 100644 --- a/security/selinux/ss/ebitmap.c +++ b/security/selinux/ss/ebitmap.c @@ -213,7 +213,12 @@ netlbl_import_failure:  }  #endif /* CONFIG_NETLABEL */ -int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2) +/* + * Check to see if all the bits set in e2 are also set in e1. Optionally, + * if last_e2bit is non-zero, the highest set bit in e2 cannot exceed + * last_e2bit. + */ +int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2, u32 last_e2bit)  {  	struct ebitmap_node *n1, *n2;  	int i; @@ -223,14 +228,25 @@ int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2)  	n1 = e1->node;  	n2 = e2->node; +  	while (n1 && n2 && (n1->startbit <= n2->startbit)) {  		if (n1->startbit < n2->startbit) {  			n1 = n1->next;  			continue;  		} -		for (i = 0; i < EBITMAP_UNIT_NUMS; i++) { +		for (i = EBITMAP_UNIT_NUMS - 1; (i >= 0) && !n2->maps[i]; ) +			i--;	/* Skip trailing NULL map entries */ +		if (last_e2bit && (i >= 0)) { +			u32 lastsetbit = n2->startbit + i * EBITMAP_UNIT_SIZE + +					 __fls(n2->maps[i]); +			if (lastsetbit > last_e2bit) +				return 0; +		} + +		while (i >= 0) {  			if ((n1->maps[i] & n2->maps[i]) != n2->maps[i])  				return 0; +			i--;  		}  		n1 = n1->next; diff --git a/security/selinux/ss/ebitmap.h b/security/selinux/ss/ebitmap.h index 922f8afa89d..712c8a7b8e8 100644 --- a/security/selinux/ss/ebitmap.h +++ b/security/selinux/ss/ebitmap.h @@ -16,7 +16,13 @@  #include <net/netlabel.h> -#define EBITMAP_UNIT_NUMS	((32 - sizeof(void *) - sizeof(u32))	\ +#ifdef CONFIG_64BIT +#define	EBITMAP_NODE_SIZE	64 +#else +#define	EBITMAP_NODE_SIZE	32 +#endif + +#define EBITMAP_UNIT_NUMS	((EBITMAP_NODE_SIZE-sizeof(void *)-sizeof(u32))\  					/ sizeof(unsigned long))  #define EBITMAP_UNIT_SIZE	BITS_PER_LONG  #define EBITMAP_SIZE		(EBITMAP_UNIT_NUMS * EBITMAP_UNIT_SIZE) @@ -117,7 +123,7 @@ static inline void ebitmap_node_clr_bit(struct ebitmap_node *n,  int ebitmap_cmp(struct ebitmap *e1, struct ebitmap *e2);  int ebitmap_cpy(struct ebitmap *dst, struct ebitmap *src); -int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2); +int ebitmap_contains(struct ebitmap *e1, struct ebitmap *e2, u32 last_e2bit);  int ebitmap_get_bit(struct ebitmap *e, unsigned long bit);  int ebitmap_set_bit(struct ebitmap *e, unsigned long bit, int value);  void ebitmap_destroy(struct ebitmap *e); diff --git a/security/selinux/ss/hashtab.c b/security/selinux/ss/hashtab.c index 933e735bb18..2cc49614984 100644 --- a/security/selinux/ss/hashtab.c +++ b/security/selinux/ss/hashtab.c @@ -6,6 +6,7 @@  #include <linux/kernel.h>  #include <linux/slab.h>  #include <linux/errno.h> +#include <linux/sched.h>  #include "hashtab.h"  struct hashtab *hashtab_create(u32 (*hash_value)(struct hashtab *h, const void *key), @@ -40,6 +41,8 @@ int hashtab_insert(struct hashtab *h, void *key, void *datum)  	u32 hvalue;  	struct hashtab_node *prev, *cur, *newnode; +	cond_resched(); +  	if (!h || h->nel == HASHTAB_MAX_NODES)  		return -EINVAL; diff --git a/security/selinux/ss/mls.c b/security/selinux/ss/mls.c index 40de8d3f208..d307b37ddc2 100644 --- a/security/selinux/ss/mls.c +++ b/security/selinux/ss/mls.c @@ -160,8 +160,6 @@ void mls_sid_to_context(struct context *context,  int mls_level_isvalid(struct policydb *p, struct mls_level *l)  {  	struct level_datum *levdatum; -	struct ebitmap_node *node; -	int i;  	if (!l->sens || l->sens > p->p_levels.nprim)  		return 0; @@ -170,19 +168,13 @@ int mls_level_isvalid(struct policydb *p, struct mls_level *l)  	if (!levdatum)  		return 0; -	ebitmap_for_each_positive_bit(&l->cat, node, i) { -		if (i > p->p_cats.nprim) -			return 0; -		if (!ebitmap_get_bit(&levdatum->level->cat, i)) { -			/* -			 * Category may not be associated with -			 * sensitivity. -			 */ -			return 0; -		} -	} - -	return 1; +	/* +	 * Return 1 iff all the bits set in l->cat are also be set in +	 * levdatum->level->cat and no bit in l->cat is larger than +	 * p->p_cats.nprim. +	 */ +	return ebitmap_contains(&levdatum->level->cat, &l->cat, +				p->p_cats.nprim);  }  int mls_range_isvalid(struct policydb *p, struct mls_range *r) @@ -500,6 +492,8 @@ int mls_convert_context(struct policydb *oldp,  			rc = ebitmap_set_bit(&bitmap, catdatum->value - 1, 1);  			if (rc)  				return rc; + +			cond_resched();  		}  		ebitmap_destroy(&c->range.level[l].cat);  		c->range.level[l].cat = bitmap; diff --git a/security/selinux/ss/mls_types.h b/security/selinux/ss/mls_types.h index 03bed52a805..e9364877413 100644 --- a/security/selinux/ss/mls_types.h +++ b/security/selinux/ss/mls_types.h @@ -35,7 +35,7 @@ static inline int mls_level_eq(struct mls_level *l1, struct mls_level *l2)  static inline int mls_level_dom(struct mls_level *l1, struct mls_level *l2)  {  	return ((l1->sens >= l2->sens) && -		ebitmap_contains(&l1->cat, &l2->cat)); +		ebitmap_contains(&l1->cat, &l2->cat, 0));  }  #define mls_level_incomp(l1, l2) \ diff --git a/security/selinux/ss/policydb.c b/security/selinux/ss/policydb.c index c8adde3aff8..9c5cdc2caae 100644 --- a/security/selinux/ss/policydb.c +++ b/security/selinux/ss/policydb.c @@ -143,6 +143,11 @@ static struct policydb_compat_info policydb_compat[] = {  		.sym_num	= SYM_NUM,  		.ocon_num	= OCON_NUM,  	}, +	{ +		.version	= POLICYDB_VERSION_CONSTRAINT_NAMES, +		.sym_num	= SYM_NUM, +		.ocon_num	= OCON_NUM, +	},  };  static struct policydb_compat_info *policydb_lookup_compat(int version) @@ -613,6 +618,19 @@ static int common_destroy(void *key, void *datum, void *p)  	return 0;  } +static void constraint_expr_destroy(struct constraint_expr *expr) +{ +	if (expr) { +		ebitmap_destroy(&expr->names); +		if (expr->type_names) { +			ebitmap_destroy(&expr->type_names->types); +			ebitmap_destroy(&expr->type_names->negset); +			kfree(expr->type_names); +		} +		kfree(expr); +	} +} +  static int cls_destroy(void *key, void *datum, void *p)  {  	struct class_datum *cladatum; @@ -628,10 +646,9 @@ static int cls_destroy(void *key, void *datum, void *p)  		while (constraint) {  			e = constraint->expr;  			while (e) { -				ebitmap_destroy(&e->names);  				etmp = e;  				e = e->next; -				kfree(etmp); +				constraint_expr_destroy(etmp);  			}  			ctemp = constraint;  			constraint = constraint->next; @@ -642,16 +659,14 @@ static int cls_destroy(void *key, void *datum, void *p)  		while (constraint) {  			e = constraint->expr;  			while (e) { -				ebitmap_destroy(&e->names);  				etmp = e;  				e = e->next; -				kfree(etmp); +				constraint_expr_destroy(etmp);  			}  			ctemp = constraint;  			constraint = constraint->next;  			kfree(ctemp);  		} -  		kfree(cladatum->comkey);  	}  	kfree(datum); @@ -1156,8 +1171,34 @@ bad:  	return rc;  } -static int read_cons_helper(struct constraint_node **nodep, int ncons, -			    int allowxtarget, void *fp) +static void type_set_init(struct type_set *t) +{ +	ebitmap_init(&t->types); +	ebitmap_init(&t->negset); +} + +static int type_set_read(struct type_set *t, void *fp) +{ +	__le32 buf[1]; +	int rc; + +	if (ebitmap_read(&t->types, fp)) +		return -EINVAL; +	if (ebitmap_read(&t->negset, fp)) +		return -EINVAL; + +	rc = next_entry(buf, fp, sizeof(u32)); +	if (rc < 0) +		return -EINVAL; +	t->flags = le32_to_cpu(buf[0]); + +	return 0; +} + + +static int read_cons_helper(struct policydb *p, +				struct constraint_node **nodep, +				int ncons, int allowxtarget, void *fp)  {  	struct constraint_node *c, *lc;  	struct constraint_expr *e, *le; @@ -1225,6 +1266,18 @@ static int read_cons_helper(struct constraint_node **nodep, int ncons,  				rc = ebitmap_read(&e->names, fp);  				if (rc)  					return rc; +				if (p->policyvers >= +					POLICYDB_VERSION_CONSTRAINT_NAMES) { +						e->type_names = kzalloc(sizeof +						(*e->type_names), +						GFP_KERNEL); +					if (!e->type_names) +						return -ENOMEM; +					type_set_init(e->type_names); +					rc = type_set_read(e->type_names, fp); +					if (rc) +						return rc; +				}  				break;  			default:  				return -EINVAL; @@ -1301,7 +1354,7 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)  			goto bad;  	} -	rc = read_cons_helper(&cladatum->constraints, ncons, 0, fp); +	rc = read_cons_helper(p, &cladatum->constraints, ncons, 0, fp);  	if (rc)  		goto bad; @@ -1311,7 +1364,8 @@ static int class_read(struct policydb *p, struct hashtab *h, void *fp)  		if (rc)  			goto bad;  		ncons = le32_to_cpu(buf[0]); -		rc = read_cons_helper(&cladatum->validatetrans, ncons, 1, fp); +		rc = read_cons_helper(p, &cladatum->validatetrans, +				ncons, 1, fp);  		if (rc)  			goto bad;  	} @@ -1941,7 +1995,19 @@ static int filename_trans_read(struct policydb *p, void *fp)  		if (rc)  			goto out; -		hashtab_insert(p->filename_trans, ft, otype); +		rc = hashtab_insert(p->filename_trans, ft, otype); +		if (rc) { +			/* +			 * Do not return -EEXIST to the caller, or the system +			 * will not boot. +			 */ +			if (rc != -EEXIST) +				goto out; +			/* But free memory to avoid memory leak. */ +			kfree(ft); +			kfree(name); +			kfree(otype); +		}  	}  	hash_eval(p->filename_trans, "filenametr");  	return 0; @@ -2753,6 +2819,24 @@ static int common_write(void *vkey, void *datum, void *ptr)  	return 0;  } +static int type_set_write(struct type_set *t, void *fp) +{ +	int rc; +	__le32 buf[1]; + +	if (ebitmap_write(&t->types, fp)) +		return -EINVAL; +	if (ebitmap_write(&t->negset, fp)) +		return -EINVAL; + +	buf[0] = cpu_to_le32(t->flags); +	rc = put_entry(buf, sizeof(u32), 1, fp); +	if (rc) +		return -EINVAL; + +	return 0; +} +  static int write_cons_helper(struct policydb *p, struct constraint_node *node,  			     void *fp)  { @@ -2784,6 +2868,12 @@ static int write_cons_helper(struct policydb *p, struct constraint_node *node,  				rc = ebitmap_write(&e->names, fp);  				if (rc)  					return rc; +				if (p->policyvers >= +					POLICYDB_VERSION_CONSTRAINT_NAMES) { +					rc = type_set_write(e->type_names, fp); +					if (rc) +						return rc; +				}  				break;  			default:  				break; @@ -3203,9 +3293,8 @@ static int range_write_helper(void *key, void *data, void *ptr)  static int range_write(struct policydb *p, void *fp)  { -	size_t nel;  	__le32 buf[1]; -	int rc; +	int rc, nel;  	struct policy_data pd;  	pd.p = p; @@ -3249,10 +3338,10 @@ static int filename_write_helper(void *key, void *data, void *ptr)  	if (rc)  		return rc; -	buf[0] = ft->stype; -	buf[1] = ft->ttype; -	buf[2] = ft->tclass; -	buf[3] = otype->otype; +	buf[0] = cpu_to_le32(ft->stype); +	buf[1] = cpu_to_le32(ft->ttype); +	buf[2] = cpu_to_le32(ft->tclass); +	buf[3] = cpu_to_le32(otype->otype);  	rc = put_entry(buf, sizeof(u32), 4, fp);  	if (rc) diff --git a/security/selinux/ss/policydb.h b/security/selinux/ss/policydb.h index da637471d4c..725d5945a97 100644 --- a/security/selinux/ss/policydb.h +++ b/security/selinux/ss/policydb.h @@ -154,6 +154,17 @@ struct cond_bool_datum {  struct cond_node;  /* + * type set preserves data needed to determine constraint info from + * policy source. This is not used by the kernel policy but allows + * utilities such as audit2allow to determine constraint denials. + */ +struct type_set { +	struct ebitmap types; +	struct ebitmap negset; +	u32 flags; +}; + +/*   * The configuration data includes security contexts for   * initial SIDs, unlabeled file systems, TCP and UDP port numbers,   * network interfaces, and nodes.  This structure stores the diff --git a/security/selinux/ss/services.c b/security/selinux/ss/services.c index b4feecc3fe0..4bca49414a4 100644 --- a/security/selinux/ss/services.c +++ b/security/selinux/ss/services.c @@ -72,6 +72,7 @@  int selinux_policycap_netpeer;  int selinux_policycap_openperm; +int selinux_policycap_alwaysnetwork;  static DEFINE_RWLOCK(policy_rwlock); @@ -1231,6 +1232,10 @@ static int security_context_to_sid_core(const char *scontext, u32 scontext_len,  	struct context context;  	int rc = 0; +	/* An empty security context is never valid. */ +	if (!scontext_len) +		return -EINVAL; +  	if (!ss_initialized) {  		int i; @@ -1284,16 +1289,18 @@ out:   * @scontext: security context   * @scontext_len: length in bytes   * @sid: security identifier, SID + * @gfp: context for the allocation   *   * Obtains a SID associated with the security context that   * has the string representation specified by @scontext.   * Returns -%EINVAL if the context is invalid, -%ENOMEM if insufficient   * memory is available, or 0 on success.   */ -int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid) +int security_context_to_sid(const char *scontext, u32 scontext_len, u32 *sid, +			    gfp_t gfp)  {  	return security_context_to_sid_core(scontext, scontext_len, -					    sid, SECSID_NULL, GFP_KERNEL, 0); +					    sid, SECSID_NULL, gfp, 0);  }  /** @@ -1812,6 +1819,8 @@ static void security_load_policycaps(void)  						  POLICYDB_CAPABILITY_NETPEER);  	selinux_policycap_openperm = ebitmap_get_bit(&policydb.policycaps,  						  POLICYDB_CAPABILITY_OPENPERM); +	selinux_policycap_alwaysnetwork = ebitmap_get_bit(&policydb.policycaps, +						  POLICYDB_CAPABILITY_ALWAYSNETWORK);  }  static int security_preserve_bools(struct policydb *p); @@ -1828,7 +1837,7 @@ static int security_preserve_bools(struct policydb *p);   */  int security_load_policy(void *data, size_t len)  { -	struct policydb oldpolicydb, newpolicydb; +	struct policydb *oldpolicydb, *newpolicydb;  	struct sidtab oldsidtab, newsidtab;  	struct selinux_mapping *oldmap, *map = NULL;  	struct convert_context_args args; @@ -1837,12 +1846,19 @@ int security_load_policy(void *data, size_t len)  	int rc = 0;  	struct policy_file file = { data, len }, *fp = &file; +	oldpolicydb = kzalloc(2 * sizeof(*oldpolicydb), GFP_KERNEL); +	if (!oldpolicydb) { +		rc = -ENOMEM; +		goto out; +	} +	newpolicydb = oldpolicydb + 1; +  	if (!ss_initialized) {  		avtab_cache_init();  		rc = policydb_read(&policydb, fp);  		if (rc) {  			avtab_cache_destroy(); -			return rc; +			goto out;  		}  		policydb.len = len; @@ -1852,14 +1868,14 @@ int security_load_policy(void *data, size_t len)  		if (rc) {  			policydb_destroy(&policydb);  			avtab_cache_destroy(); -			return rc; +			goto out;  		}  		rc = policydb_load_isids(&policydb, &sidtab);  		if (rc) {  			policydb_destroy(&policydb);  			avtab_cache_destroy(); -			return rc; +			goto out;  		}  		security_load_policycaps(); @@ -1871,36 +1887,36 @@ int security_load_policy(void *data, size_t len)  		selinux_status_update_policyload(seqno);  		selinux_netlbl_cache_invalidate();  		selinux_xfrm_notify_policyload(); -		return 0; +		goto out;  	}  #if 0  	sidtab_hash_eval(&sidtab, "sids");  #endif -	rc = policydb_read(&newpolicydb, fp); +	rc = policydb_read(newpolicydb, fp);  	if (rc) -		return rc; +		goto out; -	newpolicydb.len = len; +	newpolicydb->len = len;  	/* If switching between different policy types, log MLS status */ -	if (policydb.mls_enabled && !newpolicydb.mls_enabled) +	if (policydb.mls_enabled && !newpolicydb->mls_enabled)  		printk(KERN_INFO "SELinux: Disabling MLS support...\n"); -	else if (!policydb.mls_enabled && newpolicydb.mls_enabled) +	else if (!policydb.mls_enabled && newpolicydb->mls_enabled)  		printk(KERN_INFO "SELinux: Enabling MLS support...\n"); -	rc = policydb_load_isids(&newpolicydb, &newsidtab); +	rc = policydb_load_isids(newpolicydb, &newsidtab);  	if (rc) {  		printk(KERN_ERR "SELinux:  unable to load the initial SIDs\n"); -		policydb_destroy(&newpolicydb); -		return rc; +		policydb_destroy(newpolicydb); +		goto out;  	} -	rc = selinux_set_mapping(&newpolicydb, secclass_map, &map, &map_size); +	rc = selinux_set_mapping(newpolicydb, secclass_map, &map, &map_size);  	if (rc)  		goto err; -	rc = security_preserve_bools(&newpolicydb); +	rc = security_preserve_bools(newpolicydb);  	if (rc) {  		printk(KERN_ERR "SELinux:  unable to preserve booleans\n");  		goto err; @@ -1918,7 +1934,7 @@ int security_load_policy(void *data, size_t len)  	 * in the new SID table.  	 */  	args.oldp = &policydb; -	args.newp = &newpolicydb; +	args.newp = newpolicydb;  	rc = sidtab_map(&newsidtab, convert_context, &args);  	if (rc) {  		printk(KERN_ERR "SELinux:  unable to convert the internal" @@ -1928,12 +1944,12 @@ int security_load_policy(void *data, size_t len)  	}  	/* Save the old policydb and SID table to free later. */ -	memcpy(&oldpolicydb, &policydb, sizeof policydb); +	memcpy(oldpolicydb, &policydb, sizeof(policydb));  	sidtab_set(&oldsidtab, &sidtab);  	/* Install the new policydb and SID table. */  	write_lock_irq(&policy_rwlock); -	memcpy(&policydb, &newpolicydb, sizeof policydb); +	memcpy(&policydb, newpolicydb, sizeof(policydb));  	sidtab_set(&sidtab, &newsidtab);  	security_load_policycaps();  	oldmap = current_mapping; @@ -1943,7 +1959,7 @@ int security_load_policy(void *data, size_t len)  	write_unlock_irq(&policy_rwlock);  	/* Free the old policydb and SID table. */ -	policydb_destroy(&oldpolicydb); +	policydb_destroy(oldpolicydb);  	sidtab_destroy(&oldsidtab);  	kfree(oldmap); @@ -1953,14 +1969,17 @@ int security_load_policy(void *data, size_t len)  	selinux_netlbl_cache_invalidate();  	selinux_xfrm_notify_policyload(); -	return 0; +	rc = 0; +	goto out;  err:  	kfree(map);  	sidtab_destroy(&newsidtab); -	policydb_destroy(&newpolicydb); -	return rc; +	policydb_destroy(newpolicydb); +out: +	kfree(oldpolicydb); +	return rc;  }  size_t security_policydb_len(void) @@ -2323,17 +2342,14 @@ out:  /**   * security_fs_use - Determine how to handle labeling for a filesystem. - * @fstype: filesystem type - * @behavior: labeling behavior - * @sid: SID for filesystem (superblock) + * @sb: superblock in question   */ -int security_fs_use( -	const char *fstype, -	unsigned int *behavior, -	u32 *sid) +int security_fs_use(struct super_block *sb)  {  	int rc = 0;  	struct ocontext *c; +	struct superblock_security_struct *sbsec = sb->s_security; +	const char *fstype = sb->s_type->name;  	read_lock(&policy_rwlock); @@ -2345,21 +2361,21 @@ int security_fs_use(  	}  	if (c) { -		*behavior = c->v.behavior; +		sbsec->behavior = c->v.behavior;  		if (!c->sid[0]) {  			rc = sidtab_context_to_sid(&sidtab, &c->context[0],  						   &c->sid[0]);  			if (rc)  				goto out;  		} -		*sid = c->sid[0]; +		sbsec->sid = c->sid[0];  	} else { -		rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, sid); +		rc = security_genfs_sid(fstype, "/", SECCLASS_DIR, &sbsec->sid);  		if (rc) { -			*behavior = SECURITY_FS_USE_NONE; +			sbsec->behavior = SECURITY_FS_USE_NONE;  			rc = 0;  		} else { -			*behavior = SECURITY_FS_USE_GENFS; +			sbsec->behavior = SECURITY_FS_USE_GENFS;  		}  	} @@ -2938,25 +2954,21 @@ int selinux_audit_rule_match(u32 sid, u32 field, u32 op, void *vrule,  	struct selinux_audit_rule *rule = vrule;  	int match = 0; -	if (!rule) { -		audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, -			  "selinux_audit_rule_match: missing rule\n"); +	if (unlikely(!rule)) { +		WARN_ONCE(1, "selinux_audit_rule_match: missing rule\n");  		return -ENOENT;  	}  	read_lock(&policy_rwlock);  	if (rule->au_seqno < latest_granting) { -		audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, -			  "selinux_audit_rule_match: stale rule\n");  		match = -ESTALE;  		goto out;  	}  	ctxt = sidtab_search(&sidtab, sid); -	if (!ctxt) { -		audit_log(actx, GFP_ATOMIC, AUDIT_SELINUX_ERR, -			  "selinux_audit_rule_match: unrecognized SID %d\n", +	if (unlikely(!ctxt)) { +		WARN_ONCE(1, "selinux_audit_rule_match: unrecognized SID %d\n",  			  sid);  		match = -ENOENT;  		goto out;  | 
