Re: [PATCH 2/4] selinux: refactor avtab_node comparisons

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

 



On Sep 29, 2023 Jacob Satterfield <jsatterfield.linux@xxxxxxxxx> wrote:
> 
> In four separate functions within avtab, the same comparison logic is
> used. The only difference is how the result is handled or whether there
> is a unique specifier value to be checked for or used.
> 
> Extracting this functionality into the avtab_node_cmp() function unifies
> the comparison logic between searching and insertion and gets rid of
> duplicative code so that the implementation is easier to maintain.
> 
> Signed-off-by: Jacob Satterfield <jsatterfield.linux@xxxxxxxxx>
> Reviewed-by: Stephen Smalley <stephen.smalley.work@xxxxxxxxx>
> ---
>  security/selinux/ss/avtab.c | 101 +++++++++++++++---------------------
>  1 file changed, 41 insertions(+), 60 deletions(-)

Thanks for doing this.  I've got a few small nits (below), but overall
I think this is a nice improvement.

> diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c
> index 8751a602ead2..1cd4fed30bf7 100644
> --- a/security/selinux/ss/avtab.c
> +++ b/security/selinux/ss/avtab.c
> @@ -96,12 +96,34 @@ avtab_insert_node(struct avtab *h, struct avtab_node **dst,
>  	return newnode;
>  }
>  
> +static int avtab_node_cmp(const struct avtab_key *key1,
> +			  const struct avtab_key *key2)
> +{
> +	u16 specified = key1->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
> +
> +	if (key1->source_type == key2->source_type &&
> +		key1->target_type == key2->target_type &&
> +		key1->target_class == key2->target_class &&
> +		(specified & key2->specified))
> +		return 0;

Normally I'd be a nice guy and fix this up during the merge, but
since I'd like a respin for other reasons I'm going to mention
this so you can fix it yourself, and learn a bit for next time ;)

Please don't needlessly indent multi-line if-conditionals.  As an
example, here is what I would have preferred to see for the above
if-statement:

  if (key1->source_type == key2->source_type &&
      key1->target_type == key2->target_type &&
      key1->target_class == key2->target_class &&
      (specified & key2->specified))
          return 0;

At some point in the future (hopefully soon, but my review backlog
is daunting at the moment) we'll have some automated tools to help
identify problems like this, but we're not there quite yet.

> +	if (key1->source_type < key2->source_type)
> +		return -1;
> +	if (key1->source_type == key2->source_type &&
> +		key1->target_type < key2->target_type)
> +		return -1;
> +	if (key1->source_type == key2->source_type &&
> +		key1->target_type == key2->target_type &&
> +		key1->target_class < key2->target_class)
> +		return -1;
> +	return 1;
> +}
> +
>  static int avtab_insert(struct avtab *h, const struct avtab_key *key,
>  			const struct avtab_datum *datum)
>  {
>  	u32 hvalue;
>  	struct avtab_node *prev, *cur, *newnode;
> -	u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
> +	int cmp;
>  
>  	if (!h || !h->nslot || h->nel == U32_MAX)
>  		return -EINVAL;
> @@ -110,23 +132,11 @@ static int avtab_insert(struct avtab *h, const struct avtab_key *key,
>  	for (prev = NULL, cur = h->htable[hvalue];
>  	     cur;
>  	     prev = cur, cur = cur->next) {
> -		if (key->source_type == cur->key.source_type &&
> -		    key->target_type == cur->key.target_type &&
> -		    key->target_class == cur->key.target_class &&
> -		    (specified & cur->key.specified)) {
> -			/* extended perms may not be unique */
> -			if (specified & AVTAB_XPERMS)
> -				break;
> +		cmp = avtab_node_cmp(key, &cur->key);
> +		/* extended perms may not be unique */
> +		if (unlikely(cmp == 0 && !(key->specified & AVTAB_XPERMS)))
>  			return -EEXIST;
> -		}

I'm generally not a big fan of the unlikely()/likely() macros unless
it is a rather extreme case, please don't add one here.

> -		if (key->source_type < cur->key.source_type)
> -			break;
> -		if (key->source_type == cur->key.source_type &&
> -		    key->target_type < cur->key.target_type)
> -			break;
> -		if (key->source_type == cur->key.source_type &&
> -		    key->target_type == cur->key.target_type &&
> -		    key->target_class < cur->key.target_class)
> +		if (cmp <= 0)
>  			break;

I wonder if we should put the `cmp <= 0` (no match) check first since
that will probably the more common case, right?  Or am I thinking of
this backwards?

>  	}
>  
> @@ -148,7 +158,7 @@ struct avtab_node *avtab_insert_nonunique(struct avtab *h,
>  {
>  	u32 hvalue;
>  	struct avtab_node *prev, *cur;
> -	u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
> +	int cmp;
>  
>  	if (!h || !h->nslot || h->nel == U32_MAX)
>  		return NULL;
> @@ -156,19 +166,8 @@ struct avtab_node *avtab_insert_nonunique(struct avtab *h,
>  	for (prev = NULL, cur = h->htable[hvalue];
>  	     cur;
>  	     prev = cur, cur = cur->next) {
> -		if (key->source_type == cur->key.source_type &&
> -		    key->target_type == cur->key.target_type &&
> -		    key->target_class == cur->key.target_class &&
> -		    (specified & cur->key.specified))
> -			break;
> -		if (key->source_type < cur->key.source_type)
> -			break;
> -		if (key->source_type == cur->key.source_type &&
> -		    key->target_type < cur->key.target_type)
> -			break;
> -		if (key->source_type == cur->key.source_type &&
> -		    key->target_type == cur->key.target_type &&
> -		    key->target_class < cur->key.target_class)
> +		cmp = avtab_node_cmp(key, &cur->key);
> +		if (cmp <= 0)
>  			break;
>  	}
>  	return avtab_insert_node(h, prev ? &prev->next : &h->htable[hvalue],
> @@ -183,7 +182,7 @@ struct avtab_node *avtab_search_node(struct avtab *h,
>  {
>  	u32 hvalue;
>  	struct avtab_node *cur;
> -	u16 specified = key->specified & ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
> +	int cmp;
>  
>  	if (!h || !h->nslot)
>  		return NULL;
> @@ -191,20 +190,10 @@ struct avtab_node *avtab_search_node(struct avtab *h,
>  	hvalue = avtab_hash(key, h->mask);
>  	for (cur = h->htable[hvalue]; cur;
>  	     cur = cur->next) {
> -		if (key->source_type == cur->key.source_type &&
> -		    key->target_type == cur->key.target_type &&
> -		    key->target_class == cur->key.target_class &&
> -		    (specified & cur->key.specified))
> +		cmp = avtab_node_cmp(key, &cur->key);
> +		if (cmp == 0)
>  			return cur;
> -
> -		if (key->source_type < cur->key.source_type)
> -			break;
> -		if (key->source_type == cur->key.source_type &&
> -		    key->target_type < cur->key.target_type)
> -			break;
> -		if (key->source_type == cur->key.source_type &&
> -		    key->target_type == cur->key.target_type &&
> -		    key->target_class < cur->key.target_class)
> +		if (cmp < 0)
>  			break;

See the ordering comment/question above in avtab_insert().  I'm
reasonably confident in the search case there will be more misses
than hits.

>  	}
>  	return NULL;
> @@ -213,27 +202,19 @@ struct avtab_node *avtab_search_node(struct avtab *h,
>  struct avtab_node*
>  avtab_search_node_next(struct avtab_node *node, u16 specified)
>  {
> +	struct avtab_key tmp_key;
>  	struct avtab_node *cur;
> +	int cmp;
>  
>  	if (!node)
>  		return NULL;
> -
> -	specified &= ~(AVTAB_ENABLED|AVTAB_ENABLED_OLD);
> +	tmp_key = node->key;
> +	tmp_key.specified = specified;
>  	for (cur = node->next; cur; cur = cur->next) {
> -		if (node->key.source_type == cur->key.source_type &&
> -		    node->key.target_type == cur->key.target_type &&
> -		    node->key.target_class == cur->key.target_class &&
> -		    (specified & cur->key.specified))
> +		cmp = avtab_node_cmp(&tmp_key, &cur->key);
> +		if (cmp == 0)
>  			return cur;
> -
> -		if (node->key.source_type < cur->key.source_type)
> -			break;
> -		if (node->key.source_type == cur->key.source_type &&
> -		    node->key.target_type < cur->key.target_type)
> -			break;
> -		if (node->key.source_type == cur->key.source_type &&
> -		    node->key.target_type == cur->key.target_type &&
> -		    node->key.target_class < cur->key.target_class)
> +		if (cmp < 0)
>  			break;

Another ordering spot.

>  	}
>  	return NULL;
> -- 
> 2.41.0

--
paul-moore.com



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

  Powered by Linux