diff options
Diffstat (limited to 'security/selinux/ss/avtab.c')
| -rw-r--r-- | security/selinux/ss/avtab.c | 101 | 
1 files changed, 33 insertions, 68 deletions
| diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c index 6dcb6aa4db7f..75df32906055 100644 --- a/security/selinux/ss/avtab.c +++ b/security/selinux/ss/avtab.c @@ -109,7 +109,7 @@ static int avtab_insert(struct avtab *h, struct avtab_key *key, struct avtab_dat  	struct avtab_node *prev, *cur, *newnode;  	u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); -	if (!h) +	if (!h || !h->nslot)  		return -EINVAL;  	hvalue = avtab_hash(key, h->mask); @@ -154,7 +154,7 @@ avtab_insert_nonunique(struct avtab *h, struct avtab_key *key, struct avtab_datu  	struct avtab_node *prev, *cur;  	u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); -	if (!h) +	if (!h || !h->nslot)  		return NULL;  	hvalue = avtab_hash(key, h->mask);  	for (prev = NULL, cur = h->htable[hvalue]; @@ -184,7 +184,7 @@ struct avtab_datum *avtab_search(struct avtab *h, struct avtab_key *key)  	struct avtab_node *cur;  	u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); -	if (!h) +	if (!h || !h->nslot)  		return NULL;  	hvalue = avtab_hash(key, h->mask); @@ -220,7 +220,7 @@ avtab_search_node(struct avtab *h, struct avtab_key *key)  	struct avtab_node *cur;  	u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD); -	if (!h) +	if (!h || !h->nslot)  		return NULL;  	hvalue = avtab_hash(key, h->mask); @@ -295,6 +295,7 @@ void avtab_destroy(struct avtab *h)  	}  	kvfree(h->htable);  	h->htable = NULL; +	h->nel = 0;  	h->nslot = 0;  	h->mask = 0;  } @@ -303,88 +304,52 @@ void avtab_init(struct avtab *h)  {  	h->htable = NULL;  	h->nel = 0; +	h->nslot = 0; +	h->mask = 0;  } -int avtab_alloc(struct avtab *h, u32 nrules) +static int avtab_alloc_common(struct avtab *h, u32 nslot)  { -	u32 mask = 0; -	u32 shift = 0; -	u32 work = nrules; -	u32 nslot = 0; - -	if (nrules == 0) -		goto avtab_alloc_out; - -	while (work) { -		work  = work >> 1; -		shift++; -	} -	if (shift > 2) -		shift = shift - 2; -	nslot = 1 << shift; -	if (nslot > MAX_AVTAB_HASH_BUCKETS) -		nslot = MAX_AVTAB_HASH_BUCKETS; -	mask = nslot - 1; +	if (!nslot) +		return 0;  	h->htable = kvcalloc(nslot, sizeof(void *), GFP_KERNEL);  	if (!h->htable)  		return -ENOMEM; - avtab_alloc_out: -	h->nel = 0;  	h->nslot = nslot; -	h->mask = mask; -	pr_debug("SELinux: %d avtab hash slots, %d rules.\n", -	       h->nslot, nrules); +	h->mask = nslot - 1;  	return 0;  } -int avtab_duplicate(struct avtab *new, struct avtab *orig) +int avtab_alloc(struct avtab *h, u32 nrules)  { -	int i; -	struct avtab_node *node, *tmp, *tail; - -	memset(new, 0, sizeof(*new)); +	int rc; +	u32 nslot = 0; -	new->htable = kvcalloc(orig->nslot, sizeof(void *), GFP_KERNEL); -	if (!new->htable) -		return -ENOMEM; -	new->nslot = orig->nslot; -	new->mask = orig->mask; - -	for (i = 0; i < orig->nslot; i++) { -		tail = NULL; -		for (node = orig->htable[i]; node; node = node->next) { -			tmp = kmem_cache_zalloc(avtab_node_cachep, GFP_KERNEL); -			if (!tmp) -				goto error; -			tmp->key = node->key; -			if (tmp->key.specified & AVTAB_XPERMS) { -				tmp->datum.u.xperms = -					kmem_cache_zalloc(avtab_xperms_cachep, -							GFP_KERNEL); -				if (!tmp->datum.u.xperms) { -					kmem_cache_free(avtab_node_cachep, tmp); -					goto error; -				} -				tmp->datum.u.xperms = node->datum.u.xperms; -			} else -				tmp->datum.u.data = node->datum.u.data; - -			if (tail) -				tail->next = tmp; -			else -				new->htable[i] = tmp; - -			tail = tmp; -			new->nel++; +	if (nrules != 0) { +		u32 shift = 1; +		u32 work = nrules >> 3; +		while (work) { +			work >>= 1; +			shift++;  		} +		nslot = 1 << shift; +		if (nslot > MAX_AVTAB_HASH_BUCKETS) +			nslot = MAX_AVTAB_HASH_BUCKETS; + +		rc = avtab_alloc_common(h, nslot); +		if (rc) +			return rc;  	} +	pr_debug("SELinux: %d avtab hash slots, %d rules.\n", nslot, nrules);  	return 0; -error: -	avtab_destroy(new); -	return -ENOMEM; +} + +int avtab_alloc_dup(struct avtab *new, const struct avtab *orig) +{ +	return avtab_alloc_common(new, orig->nslot);  }  void avtab_hash_eval(struct avtab *h, char *tag) |