diff mbox

[1/1] libsepol/cil: Improve processing of context rules

Message ID 20180329200649.30211-1-jwcart2@tycho.nsa.gov (mailing list archive)
State Not Applicable
Headers show

Commit Message

James Carter March 29, 2018, 8:06 p.m. UTC
Improve the processing of netifcon, genfscon, ibpkeycon, ibendportcon,
portcon, nodecon, fsuse, filecon, iomemcon, ioportcon, pcidevicecon,
and devicetreecon rules.

If the multiple-decls option is not used then report errors if duplicate
context rules are found. If it is used then remove duplicate context rules
and report errors when two rules are identical except for the context.

This also changes the ordering of portcon and filecon rules. The protocol
of portcon rules will be compared if the port numbers are the same and the
path strings of filecon rules will be compared if the number of meta
characters, the stem length, string length and file types are the same.

Based on an initial patch by Pierre-Hugues Husson (phh@phh.me)

Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
---
 libsepol/cil/src/cil_post.c | 331 ++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 318 insertions(+), 13 deletions(-)

Comments

James Carter March 29, 2018, 8:14 p.m. UTC | #1
Pierre-Hugues Husson, I've tested and everything seems to work as I expect it, 
but does this meet your needs?

Jim

On 03/29/2018 04:06 PM, James Carter wrote:
> Improve the processing of netifcon, genfscon, ibpkeycon, ibendportcon,
> portcon, nodecon, fsuse, filecon, iomemcon, ioportcon, pcidevicecon,
> and devicetreecon rules.
> 
> If the multiple-decls option is not used then report errors if duplicate
> context rules are found. If it is used then remove duplicate context rules
> and report errors when two rules are identical except for the context.
> 
> This also changes the ordering of portcon and filecon rules. The protocol
> of portcon rules will be compared if the port numbers are the same and the
> path strings of filecon rules will be compared if the number of meta
> characters, the stem length, string length and file types are the same.
> 
> Based on an initial patch by Pierre-Hugues Husson (phh@phh.me)
> 
> Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
> ---
>   libsepol/cil/src/cil_post.c | 331 ++++++++++++++++++++++++++++++++++++++++++--
>   1 file changed, 318 insertions(+), 13 deletions(-)
> 
> diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c
> index a2122454..0b09cecc 100644
> --- a/libsepol/cil/src/cil_post.c
> +++ b/libsepol/cil/src/cil_post.c
> @@ -53,6 +53,83 @@
>   static int __cil_expr_to_bitmap(struct cil_list *expr, ebitmap_t *out, int max, struct cil_db *db);
>   static int __cil_expr_list_to_bitmap(struct cil_list *expr_list, ebitmap_t *out, int max, struct cil_db *db);
>   
> +static int cats_compare(struct cil_cats *a, struct cil_cats *b)
> +{
> +	struct cil_list_item *i, *j;
> +	int rc;
> +
> +	if (a == b) return 0;
> +	if (!a) return -1;
> +	if (!b) return 1;
> +
> +	/* Expects cat expression to have been evaluated */
> +	cil_list_for_each(i, a->datum_expr) {
> +		cil_list_for_each(j, b->datum_expr) {
> +			rc = strcmp(DATUM(i->data)->fqn, DATUM(j->data)->fqn);
> +			if (!rc) return rc;
> +		}
> +	}
> +	return 0;
> +}
> +
> +static int level_compare(struct cil_level *a, struct cil_level *b)
> +{
> +	int rc;
> +
> +	if (a == b) return 0;
> +	if (!a) return -1;
> +	if (!b) return 1;
> +
> +	if (a->sens != b->sens) {
> +		rc = strcmp(DATUM(a->sens)->fqn, DATUM(b->sens)->fqn);
> +		if (rc != 0) return rc;
> +	}
> +	if (a->cats != b->cats) {
> +		return cats_compare(a->cats, b->cats);
> +	}
> +	return 0;
> +}
> +
> +static int range_compare(struct cil_levelrange *a, struct cil_levelrange *b)
> +{
> +	int rc;
> +
> +	if (a == b) return 0;
> +	if (!a) return -1;
> +	if (!b) return 1;
> +
> +	if (a->low != b->low) {
> +		rc = level_compare(a->low, b->low);
> +		if (rc != 0) return rc;
> +	}
> +	if (a->high != b->high) {
> +		return level_compare(a->high, b->high);
> +	}
> +	return 0;
> +}
> +
> +static int context_compare(struct cil_context *a, struct cil_context *b)
> +{
> +	int rc;
> +
> +	if (a->user != b->user) {
> +		rc = strcmp(DATUM(a->user)->fqn, DATUM(b->user)->fqn);
> +		if (rc != 0) return rc;
> +	}
> +	if (a->role != b->role) {
> +		rc = strcmp(DATUM(a->role)->fqn, DATUM(b->role)->fqn);
> +		if (rc != 0) return rc;
> +	}
> +	if (a->type != b->type) {
> +		rc = strcmp(DATUM(a->type)->fqn, DATUM(b->type)->fqn);
> +		if (rc != 0) return rc;
> +	}
> +	if (a->range != b->range) {
> +		return range_compare(a->range, b->range);
> +	}
> +	return 0;
> +}
> +
>   static int cil_verify_is_list(struct cil_list *list, enum cil_flavor flavor)
>   {
>   	struct cil_list_item *curr;
> @@ -145,6 +222,8 @@ int cil_post_filecon_compare(const void *a, const void *b)
>   		rc = -1;
>   	} else if (b_filecon->type < a_filecon->type) {
>   		rc = 1;
> +	} else {
> +		rc = strcmp(a_filecon->path_str, b_filecon->path_str);
>   	}
>   
>   	free(a_path);
> @@ -190,6 +269,10 @@ int cil_post_portcon_compare(const void *a, const void *b)
>   			rc = -1;
>   		} else if (bportcon->port_low < aportcon->port_low) {
>   			rc = 1;
> +		} else if (aportcon->proto < bportcon->proto) {
> +			rc = -1;
> +		} else if (aportcon->proto > bportcon->proto) {
> +			rc = 1;
>   		}
>   	}
>   
> @@ -369,6 +452,102 @@ int cil_post_fsuse_compare(const void *a, const void *b)
>   	return rc;
>   }
>   
> +int cil_post_filecon_context_compare(const void *a, const void *b)
> +{
> +	struct cil_filecon *a_filecon = *(struct cil_filecon**)a;
> +	struct cil_filecon *b_filecon = *(struct cil_filecon**)b;
> +	return context_compare(a_filecon->context, b_filecon->context);
> +}
> +
> +int cil_post_ibpkeycon_context_compare(const void *a, const void *b)
> +{
> +	struct cil_ibpkeycon *a_ibpkeycon = *(struct cil_ibpkeycon **)a;
> +	struct cil_ibpkeycon *b_ibpkeycon = *(struct cil_ibpkeycon **)b;
> +	return context_compare(a_ibpkeycon->context, b_ibpkeycon->context);
> +}
> +
> +int cil_post_portcon_context_compare(const void *a, const void *b)
> +{
> +	struct cil_portcon *a_portcon = *(struct cil_portcon**)a;
> +	struct cil_portcon *b_portcon = *(struct cil_portcon**)b;
> +	return context_compare(a_portcon->context, b_portcon->context);
> +}
> +
> +int cil_post_genfscon_context_compare(const void *a, const void *b)
> +{
> +	struct cil_genfscon *a_genfscon = *(struct cil_genfscon**)a;
> +	struct cil_genfscon *b_genfscon = *(struct cil_genfscon**)b;
> +	return context_compare(a_genfscon->context, b_genfscon->context);
> +}
> +
> +int cil_post_netifcon_context_compare(const void *a, const void *b)
> +{
> +	int rc;
> +	struct cil_netifcon *a_netifcon = *(struct cil_netifcon**)a;
> +	struct cil_netifcon *b_netifcon = *(struct cil_netifcon**)b;
> +	rc = context_compare(a_netifcon->if_context, b_netifcon->if_context);
> +	if (rc != 0) {
> +		return rc;
> +	}
> +	return context_compare(a_netifcon->packet_context, b_netifcon->packet_context);
> +}
> +
> +int cil_post_ibendportcon_context_compare(const void *a, const void *b)
> +{
> +	struct cil_ibendportcon *a_ibendportcon = *(struct cil_ibendportcon **)a;
> +	struct cil_ibendportcon *b_ibendportcon = *(struct cil_ibendportcon **)b;
> +	return context_compare(a_ibendportcon->context, b_ibendportcon->context);
> +}
> +
> +int cil_post_nodecon_context_compare(const void *a, const void *b)
> +{
> +	struct cil_nodecon *a_nodecon = *(struct cil_nodecon **)a;
> +	struct cil_nodecon *b_nodecon = *(struct cil_nodecon **)b;
> +	return context_compare(a_nodecon->context, b_nodecon->context);
> +}
> +
> +int cil_post_pirqcon_context_compare(const void *a, const void *b)
> +{
> +	struct cil_pirqcon *a_pirqcon = *(struct cil_pirqcon**)a;
> +	struct cil_pirqcon *b_pirqcon = *(struct cil_pirqcon**)b;
> +	return context_compare(a_pirqcon->context, b_pirqcon->context);
> +}
> +
> +int cil_post_iomemcon_context_compare(const void *a, const void *b)
> +{
> +	struct cil_iomemcon *a_iomemcon = *(struct cil_iomemcon**)a;
> +	struct cil_iomemcon *b_iomemcon = *(struct cil_iomemcon**)b;
> +	return context_compare(a_iomemcon->context, b_iomemcon->context);
> +}
> +
> +int cil_post_ioportcon_context_compare(const void *a, const void *b)
> +{
> +	struct cil_ioportcon *a_ioportcon = *(struct cil_ioportcon**)a;
> +	struct cil_ioportcon *b_ioportcon = *(struct cil_ioportcon**)b;
> +	return context_compare(a_ioportcon->context, b_ioportcon->context);
> +}
> +
> +int cil_post_pcidevicecon_context_compare(const void *a, const void *b)
> +{
> +	struct cil_pcidevicecon *a_pcidevicecon = *(struct cil_pcidevicecon**)a;
> +	struct cil_pcidevicecon *b_pcidevicecon = *(struct cil_pcidevicecon**)b;
> +	return context_compare(a_pcidevicecon->context, b_pcidevicecon->context);
> +}
> +
> +int cil_post_devicetreecon_context_compare(const void *a, const void *b)
> +{
> +	struct cil_devicetreecon *a_devicetreecon = *(struct cil_devicetreecon**)a;
> +	struct cil_devicetreecon *b_devicetreecon = *(struct cil_devicetreecon**)b;
> +	return context_compare(a_devicetreecon->context, b_devicetreecon->context);
> +}
> +
> +int cil_post_fsuse_context_compare(const void *a, const void *b)
> +{
> +	struct cil_fsuse *a_fsuse = *(struct cil_fsuse**)a;
> +	struct cil_fsuse *b_fsuse = *(struct cil_fsuse**)b;
> +	return context_compare(a_fsuse->context, b_fsuse->context);
> +}
> +
>   static int __cil_post_db_count_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
>   {
>   	struct cil_db *db = extra_args;
> @@ -2064,6 +2243,74 @@ exit:
>   	return rc;
>   }
>   
> +static int __cil_post_report_conflict(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
> +{
> +	struct cil_list_item *li = extra_args;
> +
> +	if (node->flavor == CIL_BLOCK) {
> +		struct cil_block *blk = node->data;
> +		if (blk->is_abstract == CIL_TRUE) {
> +			*finished = CIL_TREE_SKIP_HEAD;
> +		}
> +	} else if (node->flavor == CIL_MACRO) {
> +		*finished = CIL_TREE_SKIP_HEAD;
> +	} else if (node->flavor == li->flavor) {
> +		if (node->data == li->data) {
> +			char *path = cil_tree_get_cil_path(node);
> +			cil_log(CIL_WARN, "  at %s:%d\n", path, node->line);
> +		}
> +	}
> +	return SEPOL_OK;
> +}
> +
> +static int __cil_post_process_context_rules(struct cil_sort *sort, int (*compar)(const void *, const void *), int (*concompar)(const void *, const void *), struct cil_db *db, enum cil_flavor flavor, const char *flavor_str)
> +{
> +	uint32_t count = sort->count;
> +	uint32_t i, j = 0, removed = 0;
> +	int rc = SEPOL_OK;
> +
> +	if (count < 2) {
> +		return SEPOL_OK;
> +	}
> +
> +	qsort(sort->array, sort->count, sizeof(sort->array), compar);
> +
> +	for (i=1; i<count; i++) {
> +		if (compar(&sort->array[i], &sort->array[j]) != 0) {
> +			j++;
> +		} else {
> +			removed++;
> +			if (!db->multiple_decls ||
> +			   concompar(&sort->array[i], &sort->array[j]) != 0) {
> +				struct cil_list_item li;
> +				int rc2;
> +				cil_log(CIL_WARN, "Found conflicting %s rules\n",
> +					flavor_str);
> +				rc = SEPOL_ERR;
> +				li.flavor = flavor;
> +				li.data = sort->array[i];
> +				rc2 = cil_tree_walk(db->ast->root,
> +						    __cil_post_report_conflict,
> +						    NULL, NULL, &li);
> +				if (rc2 != SEPOL_OK) goto exit;
> +				li.data = sort->array[j];
> +				rc2 = cil_tree_walk(db->ast->root,
> +						    __cil_post_report_conflict,
> +						    NULL, NULL, &li);
> +				if (rc2 != SEPOL_OK) goto exit;
> +			}
> +		}
> +		if (i != j) {
> +			sort->array[j] = sort->array[i];
> +		}
> +	}
> +
> +	sort->count = count - removed;
> +
> +exit:
> +	return rc;
> +}
> +
>   static int cil_post_db(struct cil_db *db)
>   {
>   	int rc = SEPOL_ERR;
> @@ -2116,19 +2363,77 @@ static int cil_post_db(struct cil_db *db)
>   		goto exit;
>   	}
>   
> -	qsort(db->netifcon->array, db->netifcon->count, sizeof(db->netifcon->array), cil_post_netifcon_compare);
> -	qsort(db->genfscon->array, db->genfscon->count, sizeof(db->genfscon->array), cil_post_genfscon_compare);
> -	qsort(db->ibpkeycon->array, db->ibpkeycon->count, sizeof(db->ibpkeycon->array), cil_post_ibpkeycon_compare);
> -	qsort(db->ibendportcon->array, db->ibendportcon->count, sizeof(db->ibendportcon->array), cil_post_ibendportcon_compare);
> -	qsort(db->portcon->array, db->portcon->count, sizeof(db->portcon->array), cil_post_portcon_compare);
> -	qsort(db->nodecon->array, db->nodecon->count, sizeof(db->nodecon->array), cil_post_nodecon_compare);
> -	qsort(db->fsuse->array, db->fsuse->count, sizeof(db->fsuse->array), cil_post_fsuse_compare);
> -	qsort(db->filecon->array, db->filecon->count, sizeof(db->filecon->array), cil_post_filecon_compare);
> -	qsort(db->pirqcon->array, db->pirqcon->count, sizeof(db->pirqcon->array), cil_post_pirqcon_compare);
> -	qsort(db->iomemcon->array, db->iomemcon->count, sizeof(db->iomemcon->array), cil_post_iomemcon_compare);
> -	qsort(db->ioportcon->array, db->ioportcon->count, sizeof(db->ioportcon->array), cil_post_ioportcon_compare);
> -	qsort(db->pcidevicecon->array, db->pcidevicecon->count, sizeof(db->pcidevicecon->array), cil_post_pcidevicecon_compare);
> -	qsort(db->devicetreecon->array, db->devicetreecon->count, sizeof(db->devicetreecon->array), cil_post_devicetreecon_compare);
> +	rc = __cil_post_process_context_rules(db->netifcon, cil_post_netifcon_compare, cil_post_netifcon_context_compare, db, CIL_NETIFCON, CIL_KEY_NETIFCON);
> +	if (rc != SEPOL_OK) {
> +		cil_log(CIL_ERR, "Problems processing netifcon rules\n");
> +		goto exit;
> +	}
> +
> +	rc = __cil_post_process_context_rules(db->genfscon, cil_post_genfscon_compare, cil_post_genfscon_context_compare, db, CIL_GENFSCON, CIL_KEY_GENFSCON);
> +	if (rc != SEPOL_OK) {
> +		cil_log(CIL_ERR, "Problems processing genfscon rules\n");
> +		goto exit;
> +	}
> +
> +	rc = __cil_post_process_context_rules(db->ibpkeycon, cil_post_ibpkeycon_compare, cil_post_ibpkeycon_context_compare, db, CIL_IBPKEYCON, CIL_KEY_IBPKEYCON);
> +	if (rc != SEPOL_OK) {
> +		cil_log(CIL_ERR, "Problems processing ibpkeycon rules\n");
> +		goto exit;
> +	}
> +
> +	rc = __cil_post_process_context_rules(db->ibendportcon, cil_post_ibendportcon_compare, cil_post_ibendportcon_context_compare, db, CIL_IBENDPORTCON, CIL_KEY_IBENDPORTCON);
> +	if (rc != SEPOL_OK) {
> +		cil_log(CIL_ERR, "Problems processing ibendportcon rules\n");
> +		goto exit;
> +	}
> +
> +	rc = __cil_post_process_context_rules(db->portcon, cil_post_portcon_compare, cil_post_portcon_context_compare, db, CIL_PORTCON, CIL_KEY_PORTCON);
> +	if (rc != SEPOL_OK) {
> +		cil_log(CIL_ERR, "Problems processing portcon rules\n");
> +		goto exit;
> +	}
> +
> +	rc = __cil_post_process_context_rules(db->nodecon, cil_post_nodecon_compare, cil_post_nodecon_context_compare, db, CIL_NODECON, CIL_KEY_NODECON);
> +	if (rc != SEPOL_OK) {
> +		cil_log(CIL_ERR, "Problems processing nodecon rules\n");
> +		goto exit;
> +	}
> +
> +	rc = __cil_post_process_context_rules(db->fsuse, cil_post_fsuse_compare, cil_post_fsuse_context_compare, db, CIL_FSUSE, CIL_KEY_FSUSE);
> +	if (rc != SEPOL_OK) {
> +		cil_log(CIL_ERR, "Problems processing fsuse rules\n");
> +		goto exit;
> +	}
> +
> +	rc = __cil_post_process_context_rules(db->filecon, cil_post_filecon_compare, cil_post_filecon_context_compare, db, CIL_FILECON, CIL_KEY_FILECON);
> +	if (rc != SEPOL_OK) {
> +		cil_log(CIL_ERR, "Problems processing filecon rules\n");
> +		goto exit;
> +	}
> +
> +	rc = __cil_post_process_context_rules(db->iomemcon, cil_post_iomemcon_compare, cil_post_iomemcon_context_compare, db, CIL_IOMEMCON, CIL_KEY_IOMEMCON);
> +	if (rc != SEPOL_OK) {
> +		cil_log(CIL_ERR, "Problems processing iomemcon rules\n");
> +		goto exit;
> +	}
> +
> +	rc = __cil_post_process_context_rules(db->ioportcon, cil_post_ioportcon_compare, cil_post_ioportcon_context_compare, db, CIL_IOPORTCON, CIL_KEY_IOPORTCON);
> +	if (rc != SEPOL_OK) {
> +		cil_log(CIL_ERR, "Problems processing ioportcon rules\n");
> +		goto exit;
> +	}
> +
> +	rc = __cil_post_process_context_rules(db->pcidevicecon, cil_post_pcidevicecon_compare, cil_post_pcidevicecon_context_compare, db, CIL_PCIDEVICECON, CIL_KEY_PCIDEVICECON);
> +	if (rc != SEPOL_OK) {
> +		cil_log(CIL_ERR, "Problems processing pcidevicecon rules\n");
> +		goto exit;
> +	}
> +
> +	rc = __cil_post_process_context_rules(db->devicetreecon, cil_post_devicetreecon_compare, cil_post_devicetreecon_context_compare, db, CIL_DEVICETREECON, CIL_KEY_DEVICETREECON);
> +	if (rc != SEPOL_OK) {
> +		cil_log(CIL_ERR, "Problems processing devicetreecon rules\n");
> +		goto exit;
> +	}
>   
>   exit:
>   	return rc;
>
Pierre-Hugues Husson March 29, 2018, 8:32 p.m. UTC | #2
The commit message and the code match my needs, and the few tests (not
unit tests at all though) I have are passing.
I'll test it on real devices, and I'll report back if anything seem wrong.

Just as a reminder, the only problems I hit for the moment are on
genfscon, so that's the only thing I've checked.

Thanks!

2018-03-29 22:14 GMT+02:00 jwcart2 <jwcart2@tycho.nsa.gov>:
> Pierre-Hugues Husson, I've tested and everything seems to work as I expect
> it, but does this meet your needs?
>
> Jim
>
>
> On 03/29/2018 04:06 PM, James Carter wrote:
>>
>> Improve the processing of netifcon, genfscon, ibpkeycon, ibendportcon,
>> portcon, nodecon, fsuse, filecon, iomemcon, ioportcon, pcidevicecon,
>> and devicetreecon rules.
>>
>> If the multiple-decls option is not used then report errors if duplicate
>> context rules are found. If it is used then remove duplicate context rules
>> and report errors when two rules are identical except for the context.
>>
>> This also changes the ordering of portcon and filecon rules. The protocol
>> of portcon rules will be compared if the port numbers are the same and the
>> path strings of filecon rules will be compared if the number of meta
>> characters, the stem length, string length and file types are the same.
>>
>> Based on an initial patch by Pierre-Hugues Husson (phh@phh.me)
>>
>> Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
>> ---
>>   libsepol/cil/src/cil_post.c | 331
>> ++++++++++++++++++++++++++++++++++++++++++--
>>   1 file changed, 318 insertions(+), 13 deletions(-)
>>
>> diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c
>> index a2122454..0b09cecc 100644
>> --- a/libsepol/cil/src/cil_post.c
>> +++ b/libsepol/cil/src/cil_post.c
>> @@ -53,6 +53,83 @@
>>   static int __cil_expr_to_bitmap(struct cil_list *expr, ebitmap_t *out,
>> int max, struct cil_db *db);
>>   static int __cil_expr_list_to_bitmap(struct cil_list *expr_list,
>> ebitmap_t *out, int max, struct cil_db *db);
>>   +static int cats_compare(struct cil_cats *a, struct cil_cats *b)
>> +{
>> +       struct cil_list_item *i, *j;
>> +       int rc;
>> +
>> +       if (a == b) return 0;
>> +       if (!a) return -1;
>> +       if (!b) return 1;
>> +
>> +       /* Expects cat expression to have been evaluated */
>> +       cil_list_for_each(i, a->datum_expr) {
>> +               cil_list_for_each(j, b->datum_expr) {
>> +                       rc = strcmp(DATUM(i->data)->fqn,
>> DATUM(j->data)->fqn);
>> +                       if (!rc) return rc;
>> +               }
>> +       }
>> +       return 0;
>> +}
>> +
>> +static int level_compare(struct cil_level *a, struct cil_level *b)
>> +{
>> +       int rc;
>> +
>> +       if (a == b) return 0;
>> +       if (!a) return -1;
>> +       if (!b) return 1;
>> +
>> +       if (a->sens != b->sens) {
>> +               rc = strcmp(DATUM(a->sens)->fqn, DATUM(b->sens)->fqn);
>> +               if (rc != 0) return rc;
>> +       }
>> +       if (a->cats != b->cats) {
>> +               return cats_compare(a->cats, b->cats);
>> +       }
>> +       return 0;
>> +}
>> +
>> +static int range_compare(struct cil_levelrange *a, struct cil_levelrange
>> *b)
>> +{
>> +       int rc;
>> +
>> +       if (a == b) return 0;
>> +       if (!a) return -1;
>> +       if (!b) return 1;
>> +
>> +       if (a->low != b->low) {
>> +               rc = level_compare(a->low, b->low);
>> +               if (rc != 0) return rc;
>> +       }
>> +       if (a->high != b->high) {
>> +               return level_compare(a->high, b->high);
>> +       }
>> +       return 0;
>> +}
>> +
>> +static int context_compare(struct cil_context *a, struct cil_context *b)
>> +{
>> +       int rc;
>> +
>> +       if (a->user != b->user) {
>> +               rc = strcmp(DATUM(a->user)->fqn, DATUM(b->user)->fqn);
>> +               if (rc != 0) return rc;
>> +       }
>> +       if (a->role != b->role) {
>> +               rc = strcmp(DATUM(a->role)->fqn, DATUM(b->role)->fqn);
>> +               if (rc != 0) return rc;
>> +       }
>> +       if (a->type != b->type) {
>> +               rc = strcmp(DATUM(a->type)->fqn, DATUM(b->type)->fqn);
>> +               if (rc != 0) return rc;
>> +       }
>> +       if (a->range != b->range) {
>> +               return range_compare(a->range, b->range);
>> +       }
>> +       return 0;
>> +}
>> +
>>   static int cil_verify_is_list(struct cil_list *list, enum cil_flavor
>> flavor)
>>   {
>>         struct cil_list_item *curr;
>> @@ -145,6 +222,8 @@ int cil_post_filecon_compare(const void *a, const void
>> *b)
>>                 rc = -1;
>>         } else if (b_filecon->type < a_filecon->type) {
>>                 rc = 1;
>> +       } else {
>> +               rc = strcmp(a_filecon->path_str, b_filecon->path_str);
>>         }
>>         free(a_path);
>> @@ -190,6 +269,10 @@ int cil_post_portcon_compare(const void *a, const
>> void *b)
>>                         rc = -1;
>>                 } else if (bportcon->port_low < aportcon->port_low) {
>>                         rc = 1;
>> +               } else if (aportcon->proto < bportcon->proto) {
>> +                       rc = -1;
>> +               } else if (aportcon->proto > bportcon->proto) {
>> +                       rc = 1;
>>                 }
>>         }
>>   @@ -369,6 +452,102 @@ int cil_post_fsuse_compare(const void *a, const
>> void *b)
>>         return rc;
>>   }
>>   +int cil_post_filecon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_filecon *a_filecon = *(struct cil_filecon**)a;
>> +       struct cil_filecon *b_filecon = *(struct cil_filecon**)b;
>> +       return context_compare(a_filecon->context, b_filecon->context);
>> +}
>> +
>> +int cil_post_ibpkeycon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_ibpkeycon *a_ibpkeycon = *(struct cil_ibpkeycon **)a;
>> +       struct cil_ibpkeycon *b_ibpkeycon = *(struct cil_ibpkeycon **)b;
>> +       return context_compare(a_ibpkeycon->context,
>> b_ibpkeycon->context);
>> +}
>> +
>> +int cil_post_portcon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_portcon *a_portcon = *(struct cil_portcon**)a;
>> +       struct cil_portcon *b_portcon = *(struct cil_portcon**)b;
>> +       return context_compare(a_portcon->context, b_portcon->context);
>> +}
>> +
>> +int cil_post_genfscon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_genfscon *a_genfscon = *(struct cil_genfscon**)a;
>> +       struct cil_genfscon *b_genfscon = *(struct cil_genfscon**)b;
>> +       return context_compare(a_genfscon->context, b_genfscon->context);
>> +}
>> +
>> +int cil_post_netifcon_context_compare(const void *a, const void *b)
>> +{
>> +       int rc;
>> +       struct cil_netifcon *a_netifcon = *(struct cil_netifcon**)a;
>> +       struct cil_netifcon *b_netifcon = *(struct cil_netifcon**)b;
>> +       rc = context_compare(a_netifcon->if_context,
>> b_netifcon->if_context);
>> +       if (rc != 0) {
>> +               return rc;
>> +       }
>> +       return context_compare(a_netifcon->packet_context,
>> b_netifcon->packet_context);
>> +}
>> +
>> +int cil_post_ibendportcon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_ibendportcon *a_ibendportcon = *(struct
>> cil_ibendportcon **)a;
>> +       struct cil_ibendportcon *b_ibendportcon = *(struct
>> cil_ibendportcon **)b;
>> +       return context_compare(a_ibendportcon->context,
>> b_ibendportcon->context);
>> +}
>> +
>> +int cil_post_nodecon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_nodecon *a_nodecon = *(struct cil_nodecon **)a;
>> +       struct cil_nodecon *b_nodecon = *(struct cil_nodecon **)b;
>> +       return context_compare(a_nodecon->context, b_nodecon->context);
>> +}
>> +
>> +int cil_post_pirqcon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_pirqcon *a_pirqcon = *(struct cil_pirqcon**)a;
>> +       struct cil_pirqcon *b_pirqcon = *(struct cil_pirqcon**)b;
>> +       return context_compare(a_pirqcon->context, b_pirqcon->context);
>> +}
>> +
>> +int cil_post_iomemcon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_iomemcon *a_iomemcon = *(struct cil_iomemcon**)a;
>> +       struct cil_iomemcon *b_iomemcon = *(struct cil_iomemcon**)b;
>> +       return context_compare(a_iomemcon->context, b_iomemcon->context);
>> +}
>> +
>> +int cil_post_ioportcon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_ioportcon *a_ioportcon = *(struct cil_ioportcon**)a;
>> +       struct cil_ioportcon *b_ioportcon = *(struct cil_ioportcon**)b;
>> +       return context_compare(a_ioportcon->context,
>> b_ioportcon->context);
>> +}
>> +
>> +int cil_post_pcidevicecon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_pcidevicecon *a_pcidevicecon = *(struct
>> cil_pcidevicecon**)a;
>> +       struct cil_pcidevicecon *b_pcidevicecon = *(struct
>> cil_pcidevicecon**)b;
>> +       return context_compare(a_pcidevicecon->context,
>> b_pcidevicecon->context);
>> +}
>> +
>> +int cil_post_devicetreecon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_devicetreecon *a_devicetreecon = *(struct
>> cil_devicetreecon**)a;
>> +       struct cil_devicetreecon *b_devicetreecon = *(struct
>> cil_devicetreecon**)b;
>> +       return context_compare(a_devicetreecon->context,
>> b_devicetreecon->context);
>> +}
>> +
>> +int cil_post_fsuse_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_fsuse *a_fsuse = *(struct cil_fsuse**)a;
>> +       struct cil_fsuse *b_fsuse = *(struct cil_fsuse**)b;
>> +       return context_compare(a_fsuse->context, b_fsuse->context);
>> +}
>> +
>>   static int __cil_post_db_count_helper(struct cil_tree_node *node,
>> uint32_t *finished, void *extra_args)
>>   {
>>         struct cil_db *db = extra_args;
>> @@ -2064,6 +2243,74 @@ exit:
>>         return rc;
>>   }
>>   +static int __cil_post_report_conflict(struct cil_tree_node *node,
>> uint32_t *finished, void *extra_args)
>> +{
>> +       struct cil_list_item *li = extra_args;
>> +
>> +       if (node->flavor == CIL_BLOCK) {
>> +               struct cil_block *blk = node->data;
>> +               if (blk->is_abstract == CIL_TRUE) {
>> +                       *finished = CIL_TREE_SKIP_HEAD;
>> +               }
>> +       } else if (node->flavor == CIL_MACRO) {
>> +               *finished = CIL_TREE_SKIP_HEAD;
>> +       } else if (node->flavor == li->flavor) {
>> +               if (node->data == li->data) {
>> +                       char *path = cil_tree_get_cil_path(node);
>> +                       cil_log(CIL_WARN, "  at %s:%d\n", path,
>> node->line);
>> +               }
>> +       }
>> +       return SEPOL_OK;
>> +}
>> +
>> +static int __cil_post_process_context_rules(struct cil_sort *sort, int
>> (*compar)(const void *, const void *), int (*concompar)(const void *, const
>> void *), struct cil_db *db, enum cil_flavor flavor, const char *flavor_str)
>> +{
>> +       uint32_t count = sort->count;
>> +       uint32_t i, j = 0, removed = 0;
>> +       int rc = SEPOL_OK;
>> +
>> +       if (count < 2) {
>> +               return SEPOL_OK;
>> +       }
>> +
>> +       qsort(sort->array, sort->count, sizeof(sort->array), compar);
>> +
>> +       for (i=1; i<count; i++) {
>> +               if (compar(&sort->array[i], &sort->array[j]) != 0) {
>> +                       j++;
>> +               } else {
>> +                       removed++;
>> +                       if (!db->multiple_decls ||
>> +                          concompar(&sort->array[i], &sort->array[j]) !=
>> 0) {
>> +                               struct cil_list_item li;
>> +                               int rc2;
>> +                               cil_log(CIL_WARN, "Found conflicting %s
>> rules\n",
>> +                                       flavor_str);
>> +                               rc = SEPOL_ERR;
>> +                               li.flavor = flavor;
>> +                               li.data = sort->array[i];
>> +                               rc2 = cil_tree_walk(db->ast->root,
>> +
>> __cil_post_report_conflict,
>> +                                                   NULL, NULL, &li);
>> +                               if (rc2 != SEPOL_OK) goto exit;
>> +                               li.data = sort->array[j];
>> +                               rc2 = cil_tree_walk(db->ast->root,
>> +
>> __cil_post_report_conflict,
>> +                                                   NULL, NULL, &li);
>> +                               if (rc2 != SEPOL_OK) goto exit;
>> +                       }
>> +               }
>> +               if (i != j) {
>> +                       sort->array[j] = sort->array[i];
>> +               }
>> +       }
>> +
>> +       sort->count = count - removed;
>> +
>> +exit:
>> +       return rc;
>> +}
>> +
>>   static int cil_post_db(struct cil_db *db)
>>   {
>>         int rc = SEPOL_ERR;
>> @@ -2116,19 +2363,77 @@ static int cil_post_db(struct cil_db *db)
>>                 goto exit;
>>         }
>>   -     qsort(db->netifcon->array, db->netifcon->count,
>> sizeof(db->netifcon->array), cil_post_netifcon_compare);
>> -       qsort(db->genfscon->array, db->genfscon->count,
>> sizeof(db->genfscon->array), cil_post_genfscon_compare);
>> -       qsort(db->ibpkeycon->array, db->ibpkeycon->count,
>> sizeof(db->ibpkeycon->array), cil_post_ibpkeycon_compare);
>> -       qsort(db->ibendportcon->array, db->ibendportcon->count,
>> sizeof(db->ibendportcon->array), cil_post_ibendportcon_compare);
>> -       qsort(db->portcon->array, db->portcon->count,
>> sizeof(db->portcon->array), cil_post_portcon_compare);
>> -       qsort(db->nodecon->array, db->nodecon->count,
>> sizeof(db->nodecon->array), cil_post_nodecon_compare);
>> -       qsort(db->fsuse->array, db->fsuse->count,
>> sizeof(db->fsuse->array), cil_post_fsuse_compare);
>> -       qsort(db->filecon->array, db->filecon->count,
>> sizeof(db->filecon->array), cil_post_filecon_compare);
>> -       qsort(db->pirqcon->array, db->pirqcon->count,
>> sizeof(db->pirqcon->array), cil_post_pirqcon_compare);
>> -       qsort(db->iomemcon->array, db->iomemcon->count,
>> sizeof(db->iomemcon->array), cil_post_iomemcon_compare);
>> -       qsort(db->ioportcon->array, db->ioportcon->count,
>> sizeof(db->ioportcon->array), cil_post_ioportcon_compare);
>> -       qsort(db->pcidevicecon->array, db->pcidevicecon->count,
>> sizeof(db->pcidevicecon->array), cil_post_pcidevicecon_compare);
>> -       qsort(db->devicetreecon->array, db->devicetreecon->count,
>> sizeof(db->devicetreecon->array), cil_post_devicetreecon_compare);
>> +       rc = __cil_post_process_context_rules(db->netifcon,
>> cil_post_netifcon_compare, cil_post_netifcon_context_compare, db,
>> CIL_NETIFCON, CIL_KEY_NETIFCON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing netifcon rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->genfscon,
>> cil_post_genfscon_compare, cil_post_genfscon_context_compare, db,
>> CIL_GENFSCON, CIL_KEY_GENFSCON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing genfscon rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->ibpkeycon,
>> cil_post_ibpkeycon_compare, cil_post_ibpkeycon_context_compare, db,
>> CIL_IBPKEYCON, CIL_KEY_IBPKEYCON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing ibpkeycon rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->ibendportcon,
>> cil_post_ibendportcon_compare, cil_post_ibendportcon_context_compare, db,
>> CIL_IBENDPORTCON, CIL_KEY_IBENDPORTCON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing ibendportcon
>> rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->portcon,
>> cil_post_portcon_compare, cil_post_portcon_context_compare, db, CIL_PORTCON,
>> CIL_KEY_PORTCON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing portcon rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->nodecon,
>> cil_post_nodecon_compare, cil_post_nodecon_context_compare, db, CIL_NODECON,
>> CIL_KEY_NODECON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing nodecon rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->fsuse,
>> cil_post_fsuse_compare, cil_post_fsuse_context_compare, db, CIL_FSUSE,
>> CIL_KEY_FSUSE);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing fsuse rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->filecon,
>> cil_post_filecon_compare, cil_post_filecon_context_compare, db, CIL_FILECON,
>> CIL_KEY_FILECON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing filecon rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->iomemcon,
>> cil_post_iomemcon_compare, cil_post_iomemcon_context_compare, db,
>> CIL_IOMEMCON, CIL_KEY_IOMEMCON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing iomemcon rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->ioportcon,
>> cil_post_ioportcon_compare, cil_post_ioportcon_context_compare, db,
>> CIL_IOPORTCON, CIL_KEY_IOPORTCON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing ioportcon rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->pcidevicecon,
>> cil_post_pcidevicecon_compare, cil_post_pcidevicecon_context_compare, db,
>> CIL_PCIDEVICECON, CIL_KEY_PCIDEVICECON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing pcidevicecon
>> rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->devicetreecon,
>> cil_post_devicetreecon_compare, cil_post_devicetreecon_context_compare, db,
>> CIL_DEVICETREECON, CIL_KEY_DEVICETREECON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing devicetreecon
>> rules\n");
>> +               goto exit;
>> +       }
>>     exit:
>>         return rc;
>>
>
>
> --
> James Carter <jwcart2@tycho.nsa.gov>
> National Security Agency
Tri Vo March 30, 2018, 12:59 a.m. UTC | #3
In Android we have a problem when .cil files from different partitions with
duplicate genfscon statements are built together. I've checked that this commit
fixes the problem.

Thank you!

On Thu, Mar 29, 2018 at 1:14 PM, jwcart2 <jwcart2@tycho.nsa.gov> wrote:
> Pierre-Hugues Husson, I've tested and everything seems to work as I expect
> it, but does this meet your needs?
>
> Jim
>
>
> On 03/29/2018 04:06 PM, James Carter wrote:
>>
>> Improve the processing of netifcon, genfscon, ibpkeycon, ibendportcon,
>> portcon, nodecon, fsuse, filecon, iomemcon, ioportcon, pcidevicecon,
>> and devicetreecon rules.
>>
>> If the multiple-decls option is not used then report errors if duplicate
>> context rules are found. If it is used then remove duplicate context rules
>> and report errors when two rules are identical except for the context.
>>
>> This also changes the ordering of portcon and filecon rules. The protocol
>> of portcon rules will be compared if the port numbers are the same and the
>> path strings of filecon rules will be compared if the number of meta
>> characters, the stem length, string length and file types are the same.
>>
>> Based on an initial patch by Pierre-Hugues Husson (phh@phh.me)
>>
>> Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
>> ---
>>   libsepol/cil/src/cil_post.c | 331
>> ++++++++++++++++++++++++++++++++++++++++++--
>>   1 file changed, 318 insertions(+), 13 deletions(-)
>>
>> diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c
>> index a2122454..0b09cecc 100644
>> --- a/libsepol/cil/src/cil_post.c
>> +++ b/libsepol/cil/src/cil_post.c
>> @@ -53,6 +53,83 @@
>>   static int __cil_expr_to_bitmap(struct cil_list *expr, ebitmap_t *out,
>> int max, struct cil_db *db);
>>   static int __cil_expr_list_to_bitmap(struct cil_list *expr_list,
>> ebitmap_t *out, int max, struct cil_db *db);
>>   +static int cats_compare(struct cil_cats *a, struct cil_cats *b)
>> +{
>> +       struct cil_list_item *i, *j;
>> +       int rc;
>> +
>> +       if (a == b) return 0;
>> +       if (!a) return -1;
>> +       if (!b) return 1;
>> +
>> +       /* Expects cat expression to have been evaluated */
>> +       cil_list_for_each(i, a->datum_expr) {
>> +               cil_list_for_each(j, b->datum_expr) {
>> +                       rc = strcmp(DATUM(i->data)->fqn,
>> DATUM(j->data)->fqn);
>> +                       if (!rc) return rc;
>> +               }
>> +       }
>> +       return 0;
>> +}
>> +
>> +static int level_compare(struct cil_level *a, struct cil_level *b)
>> +{
>> +       int rc;
>> +
>> +       if (a == b) return 0;
>> +       if (!a) return -1;
>> +       if (!b) return 1;
>> +
>> +       if (a->sens != b->sens) {
>> +               rc = strcmp(DATUM(a->sens)->fqn, DATUM(b->sens)->fqn);
>> +               if (rc != 0) return rc;
>> +       }
>> +       if (a->cats != b->cats) {
>> +               return cats_compare(a->cats, b->cats);
>> +       }
>> +       return 0;
>> +}
>> +
>> +static int range_compare(struct cil_levelrange *a, struct cil_levelrange
>> *b)
>> +{
>> +       int rc;
>> +
>> +       if (a == b) return 0;
>> +       if (!a) return -1;
>> +       if (!b) return 1;
>> +
>> +       if (a->low != b->low) {
>> +               rc = level_compare(a->low, b->low);
>> +               if (rc != 0) return rc;
>> +       }
>> +       if (a->high != b->high) {
>> +               return level_compare(a->high, b->high);
>> +       }
>> +       return 0;
>> +}
>> +
>> +static int context_compare(struct cil_context *a, struct cil_context *b)
>> +{
>> +       int rc;
>> +
>> +       if (a->user != b->user) {
>> +               rc = strcmp(DATUM(a->user)->fqn, DATUM(b->user)->fqn);
>> +               if (rc != 0) return rc;
>> +       }
>> +       if (a->role != b->role) {
>> +               rc = strcmp(DATUM(a->role)->fqn, DATUM(b->role)->fqn);
>> +               if (rc != 0) return rc;
>> +       }
>> +       if (a->type != b->type) {
>> +               rc = strcmp(DATUM(a->type)->fqn, DATUM(b->type)->fqn);
>> +               if (rc != 0) return rc;
>> +       }
>> +       if (a->range != b->range) {
>> +               return range_compare(a->range, b->range);
>> +       }
>> +       return 0;
>> +}
>> +
>>   static int cil_verify_is_list(struct cil_list *list, enum cil_flavor
>> flavor)
>>   {
>>         struct cil_list_item *curr;
>> @@ -145,6 +222,8 @@ int cil_post_filecon_compare(const void *a, const void
>> *b)
>>                 rc = -1;
>>         } else if (b_filecon->type < a_filecon->type) {
>>                 rc = 1;
>> +       } else {
>> +               rc = strcmp(a_filecon->path_str, b_filecon->path_str);
>>         }
>>         free(a_path);
>> @@ -190,6 +269,10 @@ int cil_post_portcon_compare(const void *a, const
>> void *b)
>>                         rc = -1;
>>                 } else if (bportcon->port_low < aportcon->port_low) {
>>                         rc = 1;
>> +               } else if (aportcon->proto < bportcon->proto) {
>> +                       rc = -1;
>> +               } else if (aportcon->proto > bportcon->proto) {
>> +                       rc = 1;
>>                 }
>>         }
>>   @@ -369,6 +452,102 @@ int cil_post_fsuse_compare(const void *a, const
>> void *b)
>>         return rc;
>>   }
>>   +int cil_post_filecon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_filecon *a_filecon = *(struct cil_filecon**)a;
>> +       struct cil_filecon *b_filecon = *(struct cil_filecon**)b;
>> +       return context_compare(a_filecon->context, b_filecon->context);
>> +}
>> +
>> +int cil_post_ibpkeycon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_ibpkeycon *a_ibpkeycon = *(struct cil_ibpkeycon **)a;
>> +       struct cil_ibpkeycon *b_ibpkeycon = *(struct cil_ibpkeycon **)b;
>> +       return context_compare(a_ibpkeycon->context,
>> b_ibpkeycon->context);
>> +}
>> +
>> +int cil_post_portcon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_portcon *a_portcon = *(struct cil_portcon**)a;
>> +       struct cil_portcon *b_portcon = *(struct cil_portcon**)b;
>> +       return context_compare(a_portcon->context, b_portcon->context);
>> +}
>> +
>> +int cil_post_genfscon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_genfscon *a_genfscon = *(struct cil_genfscon**)a;
>> +       struct cil_genfscon *b_genfscon = *(struct cil_genfscon**)b;
>> +       return context_compare(a_genfscon->context, b_genfscon->context);
>> +}
>> +
>> +int cil_post_netifcon_context_compare(const void *a, const void *b)
>> +{
>> +       int rc;
>> +       struct cil_netifcon *a_netifcon = *(struct cil_netifcon**)a;
>> +       struct cil_netifcon *b_netifcon = *(struct cil_netifcon**)b;
>> +       rc = context_compare(a_netifcon->if_context,
>> b_netifcon->if_context);
>> +       if (rc != 0) {
>> +               return rc;
>> +       }
>> +       return context_compare(a_netifcon->packet_context,
>> b_netifcon->packet_context);
>> +}
>> +
>> +int cil_post_ibendportcon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_ibendportcon *a_ibendportcon = *(struct
>> cil_ibendportcon **)a;
>> +       struct cil_ibendportcon *b_ibendportcon = *(struct
>> cil_ibendportcon **)b;
>> +       return context_compare(a_ibendportcon->context,
>> b_ibendportcon->context);
>> +}
>> +
>> +int cil_post_nodecon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_nodecon *a_nodecon = *(struct cil_nodecon **)a;
>> +       struct cil_nodecon *b_nodecon = *(struct cil_nodecon **)b;
>> +       return context_compare(a_nodecon->context, b_nodecon->context);
>> +}
>> +
>> +int cil_post_pirqcon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_pirqcon *a_pirqcon = *(struct cil_pirqcon**)a;
>> +       struct cil_pirqcon *b_pirqcon = *(struct cil_pirqcon**)b;
>> +       return context_compare(a_pirqcon->context, b_pirqcon->context);
>> +}
>> +
>> +int cil_post_iomemcon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_iomemcon *a_iomemcon = *(struct cil_iomemcon**)a;
>> +       struct cil_iomemcon *b_iomemcon = *(struct cil_iomemcon**)b;
>> +       return context_compare(a_iomemcon->context, b_iomemcon->context);
>> +}
>> +
>> +int cil_post_ioportcon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_ioportcon *a_ioportcon = *(struct cil_ioportcon**)a;
>> +       struct cil_ioportcon *b_ioportcon = *(struct cil_ioportcon**)b;
>> +       return context_compare(a_ioportcon->context,
>> b_ioportcon->context);
>> +}
>> +
>> +int cil_post_pcidevicecon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_pcidevicecon *a_pcidevicecon = *(struct
>> cil_pcidevicecon**)a;
>> +       struct cil_pcidevicecon *b_pcidevicecon = *(struct
>> cil_pcidevicecon**)b;
>> +       return context_compare(a_pcidevicecon->context,
>> b_pcidevicecon->context);
>> +}
>> +
>> +int cil_post_devicetreecon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_devicetreecon *a_devicetreecon = *(struct
>> cil_devicetreecon**)a;
>> +       struct cil_devicetreecon *b_devicetreecon = *(struct
>> cil_devicetreecon**)b;
>> +       return context_compare(a_devicetreecon->context,
>> b_devicetreecon->context);
>> +}
>> +
>> +int cil_post_fsuse_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_fsuse *a_fsuse = *(struct cil_fsuse**)a;
>> +       struct cil_fsuse *b_fsuse = *(struct cil_fsuse**)b;
>> +       return context_compare(a_fsuse->context, b_fsuse->context);
>> +}
>> +
>>   static int __cil_post_db_count_helper(struct cil_tree_node *node,
>> uint32_t *finished, void *extra_args)
>>   {
>>         struct cil_db *db = extra_args;
>> @@ -2064,6 +2243,74 @@ exit:
>>         return rc;
>>   }
>>   +static int __cil_post_report_conflict(struct cil_tree_node *node,
>> uint32_t *finished, void *extra_args)
>> +{
>> +       struct cil_list_item *li = extra_args;
>> +
>> +       if (node->flavor == CIL_BLOCK) {
>> +               struct cil_block *blk = node->data;
>> +               if (blk->is_abstract == CIL_TRUE) {
>> +                       *finished = CIL_TREE_SKIP_HEAD;
>> +               }
>> +       } else if (node->flavor == CIL_MACRO) {
>> +               *finished = CIL_TREE_SKIP_HEAD;
>> +       } else if (node->flavor == li->flavor) {
>> +               if (node->data == li->data) {
>> +                       char *path = cil_tree_get_cil_path(node);
>> +                       cil_log(CIL_WARN, "  at %s:%d\n", path,
>> node->line);
>> +               }
>> +       }
>> +       return SEPOL_OK;
>> +}
>> +
>> +static int __cil_post_process_context_rules(struct cil_sort *sort, int
>> (*compar)(const void *, const void *), int (*concompar)(const void *, const
>> void *), struct cil_db *db, enum cil_flavor flavor, const char *flavor_str)
>> +{
>> +       uint32_t count = sort->count;
>> +       uint32_t i, j = 0, removed = 0;
>> +       int rc = SEPOL_OK;
>> +
>> +       if (count < 2) {
>> +               return SEPOL_OK;
>> +       }
>> +
>> +       qsort(sort->array, sort->count, sizeof(sort->array), compar);
>> +
>> +       for (i=1; i<count; i++) {
>> +               if (compar(&sort->array[i], &sort->array[j]) != 0) {
>> +                       j++;
>> +               } else {
>> +                       removed++;
>> +                       if (!db->multiple_decls ||
>> +                          concompar(&sort->array[i], &sort->array[j]) !=
>> 0) {
>> +                               struct cil_list_item li;
>> +                               int rc2;
>> +                               cil_log(CIL_WARN, "Found conflicting %s
>> rules\n",
>> +                                       flavor_str);
>> +                               rc = SEPOL_ERR;
>> +                               li.flavor = flavor;
>> +                               li.data = sort->array[i];
>> +                               rc2 = cil_tree_walk(db->ast->root,
>> +
>> __cil_post_report_conflict,
>> +                                                   NULL, NULL, &li);
>> +                               if (rc2 != SEPOL_OK) goto exit;
>> +                               li.data = sort->array[j];
>> +                               rc2 = cil_tree_walk(db->ast->root,
>> +
>> __cil_post_report_conflict,
>> +                                                   NULL, NULL, &li);
>> +                               if (rc2 != SEPOL_OK) goto exit;
>> +                       }
>> +               }
>> +               if (i != j) {
>> +                       sort->array[j] = sort->array[i];
>> +               }
>> +       }
>> +
>> +       sort->count = count - removed;
>> +
>> +exit:
>> +       return rc;
>> +}
>> +
>>   static int cil_post_db(struct cil_db *db)
>>   {
>>         int rc = SEPOL_ERR;
>> @@ -2116,19 +2363,77 @@ static int cil_post_db(struct cil_db *db)
>>                 goto exit;
>>         }
>>   -     qsort(db->netifcon->array, db->netifcon->count,
>> sizeof(db->netifcon->array), cil_post_netifcon_compare);
>> -       qsort(db->genfscon->array, db->genfscon->count,
>> sizeof(db->genfscon->array), cil_post_genfscon_compare);
>> -       qsort(db->ibpkeycon->array, db->ibpkeycon->count,
>> sizeof(db->ibpkeycon->array), cil_post_ibpkeycon_compare);
>> -       qsort(db->ibendportcon->array, db->ibendportcon->count,
>> sizeof(db->ibendportcon->array), cil_post_ibendportcon_compare);
>> -       qsort(db->portcon->array, db->portcon->count,
>> sizeof(db->portcon->array), cil_post_portcon_compare);
>> -       qsort(db->nodecon->array, db->nodecon->count,
>> sizeof(db->nodecon->array), cil_post_nodecon_compare);
>> -       qsort(db->fsuse->array, db->fsuse->count,
>> sizeof(db->fsuse->array), cil_post_fsuse_compare);
>> -       qsort(db->filecon->array, db->filecon->count,
>> sizeof(db->filecon->array), cil_post_filecon_compare);
>> -       qsort(db->pirqcon->array, db->pirqcon->count,
>> sizeof(db->pirqcon->array), cil_post_pirqcon_compare);
>> -       qsort(db->iomemcon->array, db->iomemcon->count,
>> sizeof(db->iomemcon->array), cil_post_iomemcon_compare);
>> -       qsort(db->ioportcon->array, db->ioportcon->count,
>> sizeof(db->ioportcon->array), cil_post_ioportcon_compare);
>> -       qsort(db->pcidevicecon->array, db->pcidevicecon->count,
>> sizeof(db->pcidevicecon->array), cil_post_pcidevicecon_compare);
>> -       qsort(db->devicetreecon->array, db->devicetreecon->count,
>> sizeof(db->devicetreecon->array), cil_post_devicetreecon_compare);
>> +       rc = __cil_post_process_context_rules(db->netifcon,
>> cil_post_netifcon_compare, cil_post_netifcon_context_compare, db,
>> CIL_NETIFCON, CIL_KEY_NETIFCON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing netifcon rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->genfscon,
>> cil_post_genfscon_compare, cil_post_genfscon_context_compare, db,
>> CIL_GENFSCON, CIL_KEY_GENFSCON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing genfscon rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->ibpkeycon,
>> cil_post_ibpkeycon_compare, cil_post_ibpkeycon_context_compare, db,
>> CIL_IBPKEYCON, CIL_KEY_IBPKEYCON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing ibpkeycon rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->ibendportcon,
>> cil_post_ibendportcon_compare, cil_post_ibendportcon_context_compare, db,
>> CIL_IBENDPORTCON, CIL_KEY_IBENDPORTCON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing ibendportcon
>> rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->portcon,
>> cil_post_portcon_compare, cil_post_portcon_context_compare, db, CIL_PORTCON,
>> CIL_KEY_PORTCON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing portcon rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->nodecon,
>> cil_post_nodecon_compare, cil_post_nodecon_context_compare, db, CIL_NODECON,
>> CIL_KEY_NODECON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing nodecon rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->fsuse,
>> cil_post_fsuse_compare, cil_post_fsuse_context_compare, db, CIL_FSUSE,
>> CIL_KEY_FSUSE);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing fsuse rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->filecon,
>> cil_post_filecon_compare, cil_post_filecon_context_compare, db, CIL_FILECON,
>> CIL_KEY_FILECON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing filecon rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->iomemcon,
>> cil_post_iomemcon_compare, cil_post_iomemcon_context_compare, db,
>> CIL_IOMEMCON, CIL_KEY_IOMEMCON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing iomemcon rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->ioportcon,
>> cil_post_ioportcon_compare, cil_post_ioportcon_context_compare, db,
>> CIL_IOPORTCON, CIL_KEY_IOPORTCON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing ioportcon rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->pcidevicecon,
>> cil_post_pcidevicecon_compare, cil_post_pcidevicecon_context_compare, db,
>> CIL_PCIDEVICECON, CIL_KEY_PCIDEVICECON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing pcidevicecon
>> rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->devicetreecon,
>> cil_post_devicetreecon_compare, cil_post_devicetreecon_context_compare, db,
>> CIL_DEVICETREECON, CIL_KEY_DEVICETREECON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing devicetreecon
>> rules\n");
>> +               goto exit;
>> +       }
>>     exit:
>>         return rc;
>>
>
>
> --
> James Carter <jwcart2@tycho.nsa.gov>
> National Security Agency
Jann Horn via Selinux March 30, 2018, 5:33 p.m. UTC | #4
On Thu, Mar 29, 2018 at 1:06 PM, James Carter <jwcart2@tycho.nsa.gov> wrote:
> Improve the processing of netifcon, genfscon, ibpkeycon, ibendportcon,
> portcon, nodecon, fsuse, filecon, iomemcon, ioportcon, pcidevicecon,
> and devicetreecon rules.
>
> If the multiple-decls option is not used then report errors if duplicate
> context rules are found. If it is used then remove duplicate context rules
> and report errors when two rules are identical except for the context.
>
> This also changes the ordering of portcon and filecon rules. The protocol
> of portcon rules will be compared if the port numbers are the same and the
> path strings of filecon rules will be compared if the number of meta
> characters, the stem length, string length and file types are the same.
>
> Based on an initial patch by Pierre-Hugues Husson (phh@phh.me)
>
> Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>

Acked-by: Jeff Vander Stoep <jeffv@google.com>

> ---
>  libsepol/cil/src/cil_post.c | 331 ++++++++++++++++++++++++++++++++++++++++++--
>  1 file changed, 318 insertions(+), 13 deletions(-)
>
> diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c
> index a2122454..0b09cecc 100644
> --- a/libsepol/cil/src/cil_post.c
> +++ b/libsepol/cil/src/cil_post.c
> @@ -53,6 +53,83 @@
>  static int __cil_expr_to_bitmap(struct cil_list *expr, ebitmap_t *out, int max, struct cil_db *db);
>  static int __cil_expr_list_to_bitmap(struct cil_list *expr_list, ebitmap_t *out, int max, struct cil_db *db);
>
> +static int cats_compare(struct cil_cats *a, struct cil_cats *b)
> +{
> +       struct cil_list_item *i, *j;
> +       int rc;
> +
> +       if (a == b) return 0;
> +       if (!a) return -1;
> +       if (!b) return 1;
> +
> +       /* Expects cat expression to have been evaluated */
> +       cil_list_for_each(i, a->datum_expr) {
> +               cil_list_for_each(j, b->datum_expr) {
> +                       rc = strcmp(DATUM(i->data)->fqn, DATUM(j->data)->fqn);
> +                       if (!rc) return rc;
> +               }
> +       }
> +       return 0;
> +}
> +
> +static int level_compare(struct cil_level *a, struct cil_level *b)
> +{
> +       int rc;
> +
> +       if (a == b) return 0;
> +       if (!a) return -1;
> +       if (!b) return 1;
> +
> +       if (a->sens != b->sens) {
> +               rc = strcmp(DATUM(a->sens)->fqn, DATUM(b->sens)->fqn);
> +               if (rc != 0) return rc;
> +       }
> +       if (a->cats != b->cats) {
> +               return cats_compare(a->cats, b->cats);
> +       }
> +       return 0;
> +}
> +
> +static int range_compare(struct cil_levelrange *a, struct cil_levelrange *b)
> +{
> +       int rc;
> +
> +       if (a == b) return 0;
> +       if (!a) return -1;
> +       if (!b) return 1;
> +
> +       if (a->low != b->low) {
> +               rc = level_compare(a->low, b->low);
> +               if (rc != 0) return rc;
> +       }
> +       if (a->high != b->high) {
> +               return level_compare(a->high, b->high);
> +       }
> +       return 0;
> +}
> +
> +static int context_compare(struct cil_context *a, struct cil_context *b)
> +{
> +       int rc;
> +
> +       if (a->user != b->user) {
> +               rc = strcmp(DATUM(a->user)->fqn, DATUM(b->user)->fqn);
> +               if (rc != 0) return rc;
> +       }
> +       if (a->role != b->role) {
> +               rc = strcmp(DATUM(a->role)->fqn, DATUM(b->role)->fqn);
> +               if (rc != 0) return rc;
> +       }
> +       if (a->type != b->type) {
> +               rc = strcmp(DATUM(a->type)->fqn, DATUM(b->type)->fqn);
> +               if (rc != 0) return rc;
> +       }
> +       if (a->range != b->range) {
> +               return range_compare(a->range, b->range);
> +       }
> +       return 0;
> +}
> +
>  static int cil_verify_is_list(struct cil_list *list, enum cil_flavor flavor)
>  {
>         struct cil_list_item *curr;
> @@ -145,6 +222,8 @@ int cil_post_filecon_compare(const void *a, const void *b)
>                 rc = -1;
>         } else if (b_filecon->type < a_filecon->type) {
>                 rc = 1;
> +       } else {
> +               rc = strcmp(a_filecon->path_str, b_filecon->path_str);
>         }
>
>         free(a_path);
> @@ -190,6 +269,10 @@ int cil_post_portcon_compare(const void *a, const void *b)
>                         rc = -1;
>                 } else if (bportcon->port_low < aportcon->port_low) {
>                         rc = 1;
> +               } else if (aportcon->proto < bportcon->proto) {
> +                       rc = -1;
> +               } else if (aportcon->proto > bportcon->proto) {
> +                       rc = 1;
>                 }
>         }
>
> @@ -369,6 +452,102 @@ int cil_post_fsuse_compare(const void *a, const void *b)
>         return rc;
>  }
>
> +int cil_post_filecon_context_compare(const void *a, const void *b)
> +{
> +       struct cil_filecon *a_filecon = *(struct cil_filecon**)a;
> +       struct cil_filecon *b_filecon = *(struct cil_filecon**)b;
> +       return context_compare(a_filecon->context, b_filecon->context);
> +}
> +
> +int cil_post_ibpkeycon_context_compare(const void *a, const void *b)
> +{
> +       struct cil_ibpkeycon *a_ibpkeycon = *(struct cil_ibpkeycon **)a;
> +       struct cil_ibpkeycon *b_ibpkeycon = *(struct cil_ibpkeycon **)b;
> +       return context_compare(a_ibpkeycon->context, b_ibpkeycon->context);
> +}
> +
> +int cil_post_portcon_context_compare(const void *a, const void *b)
> +{
> +       struct cil_portcon *a_portcon = *(struct cil_portcon**)a;
> +       struct cil_portcon *b_portcon = *(struct cil_portcon**)b;
> +       return context_compare(a_portcon->context, b_portcon->context);
> +}
> +
> +int cil_post_genfscon_context_compare(const void *a, const void *b)
> +{
> +       struct cil_genfscon *a_genfscon = *(struct cil_genfscon**)a;
> +       struct cil_genfscon *b_genfscon = *(struct cil_genfscon**)b;
> +       return context_compare(a_genfscon->context, b_genfscon->context);
> +}
> +
> +int cil_post_netifcon_context_compare(const void *a, const void *b)
> +{
> +       int rc;
> +       struct cil_netifcon *a_netifcon = *(struct cil_netifcon**)a;
> +       struct cil_netifcon *b_netifcon = *(struct cil_netifcon**)b;
> +       rc = context_compare(a_netifcon->if_context, b_netifcon->if_context);
> +       if (rc != 0) {
> +               return rc;
> +       }
> +       return context_compare(a_netifcon->packet_context, b_netifcon->packet_context);
> +}
> +
> +int cil_post_ibendportcon_context_compare(const void *a, const void *b)
> +{
> +       struct cil_ibendportcon *a_ibendportcon = *(struct cil_ibendportcon **)a;
> +       struct cil_ibendportcon *b_ibendportcon = *(struct cil_ibendportcon **)b;
> +       return context_compare(a_ibendportcon->context, b_ibendportcon->context);
> +}
> +
> +int cil_post_nodecon_context_compare(const void *a, const void *b)
> +{
> +       struct cil_nodecon *a_nodecon = *(struct cil_nodecon **)a;
> +       struct cil_nodecon *b_nodecon = *(struct cil_nodecon **)b;
> +       return context_compare(a_nodecon->context, b_nodecon->context);
> +}
> +
> +int cil_post_pirqcon_context_compare(const void *a, const void *b)
> +{
> +       struct cil_pirqcon *a_pirqcon = *(struct cil_pirqcon**)a;
> +       struct cil_pirqcon *b_pirqcon = *(struct cil_pirqcon**)b;
> +       return context_compare(a_pirqcon->context, b_pirqcon->context);
> +}
> +
> +int cil_post_iomemcon_context_compare(const void *a, const void *b)
> +{
> +       struct cil_iomemcon *a_iomemcon = *(struct cil_iomemcon**)a;
> +       struct cil_iomemcon *b_iomemcon = *(struct cil_iomemcon**)b;
> +       return context_compare(a_iomemcon->context, b_iomemcon->context);
> +}
> +
> +int cil_post_ioportcon_context_compare(const void *a, const void *b)
> +{
> +       struct cil_ioportcon *a_ioportcon = *(struct cil_ioportcon**)a;
> +       struct cil_ioportcon *b_ioportcon = *(struct cil_ioportcon**)b;
> +       return context_compare(a_ioportcon->context, b_ioportcon->context);
> +}
> +
> +int cil_post_pcidevicecon_context_compare(const void *a, const void *b)
> +{
> +       struct cil_pcidevicecon *a_pcidevicecon = *(struct cil_pcidevicecon**)a;
> +       struct cil_pcidevicecon *b_pcidevicecon = *(struct cil_pcidevicecon**)b;
> +       return context_compare(a_pcidevicecon->context, b_pcidevicecon->context);
> +}
> +
> +int cil_post_devicetreecon_context_compare(const void *a, const void *b)
> +{
> +       struct cil_devicetreecon *a_devicetreecon = *(struct cil_devicetreecon**)a;
> +       struct cil_devicetreecon *b_devicetreecon = *(struct cil_devicetreecon**)b;
> +       return context_compare(a_devicetreecon->context, b_devicetreecon->context);
> +}
> +
> +int cil_post_fsuse_context_compare(const void *a, const void *b)
> +{
> +       struct cil_fsuse *a_fsuse = *(struct cil_fsuse**)a;
> +       struct cil_fsuse *b_fsuse = *(struct cil_fsuse**)b;
> +       return context_compare(a_fsuse->context, b_fsuse->context);
> +}
> +
>  static int __cil_post_db_count_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
>  {
>         struct cil_db *db = extra_args;
> @@ -2064,6 +2243,74 @@ exit:
>         return rc;
>  }
>
> +static int __cil_post_report_conflict(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
> +{
> +       struct cil_list_item *li = extra_args;
> +
> +       if (node->flavor == CIL_BLOCK) {
> +               struct cil_block *blk = node->data;
> +               if (blk->is_abstract == CIL_TRUE) {
> +                       *finished = CIL_TREE_SKIP_HEAD;
> +               }
> +       } else if (node->flavor == CIL_MACRO) {
> +               *finished = CIL_TREE_SKIP_HEAD;
> +       } else if (node->flavor == li->flavor) {
> +               if (node->data == li->data) {
> +                       char *path = cil_tree_get_cil_path(node);
> +                       cil_log(CIL_WARN, "  at %s:%d\n", path, node->line);
> +               }
> +       }
> +       return SEPOL_OK;
> +}
> +
> +static int __cil_post_process_context_rules(struct cil_sort *sort, int (*compar)(const void *, const void *), int (*concompar)(const void *, const void *), struct cil_db *db, enum cil_flavor flavor, const char *flavor_str)
> +{
> +       uint32_t count = sort->count;
> +       uint32_t i, j = 0, removed = 0;
> +       int rc = SEPOL_OK;
> +
> +       if (count < 2) {
> +               return SEPOL_OK;
> +       }
> +
> +       qsort(sort->array, sort->count, sizeof(sort->array), compar);
> +
> +       for (i=1; i<count; i++) {
> +               if (compar(&sort->array[i], &sort->array[j]) != 0) {
> +                       j++;
> +               } else {
> +                       removed++;
> +                       if (!db->multiple_decls ||
> +                          concompar(&sort->array[i], &sort->array[j]) != 0) {
> +                               struct cil_list_item li;
> +                               int rc2;
> +                               cil_log(CIL_WARN, "Found conflicting %s rules\n",
> +                                       flavor_str);
> +                               rc = SEPOL_ERR;
> +                               li.flavor = flavor;
> +                               li.data = sort->array[i];
> +                               rc2 = cil_tree_walk(db->ast->root,
> +                                                   __cil_post_report_conflict,
> +                                                   NULL, NULL, &li);
> +                               if (rc2 != SEPOL_OK) goto exit;
> +                               li.data = sort->array[j];
> +                               rc2 = cil_tree_walk(db->ast->root,
> +                                                   __cil_post_report_conflict,
> +                                                   NULL, NULL, &li);
> +                               if (rc2 != SEPOL_OK) goto exit;
> +                       }
> +               }
> +               if (i != j) {
> +                       sort->array[j] = sort->array[i];
> +               }
> +       }
> +
> +       sort->count = count - removed;
> +
> +exit:
> +       return rc;
> +}
> +
>  static int cil_post_db(struct cil_db *db)
>  {
>         int rc = SEPOL_ERR;
> @@ -2116,19 +2363,77 @@ static int cil_post_db(struct cil_db *db)
>                 goto exit;
>         }
>
> -       qsort(db->netifcon->array, db->netifcon->count, sizeof(db->netifcon->array), cil_post_netifcon_compare);
> -       qsort(db->genfscon->array, db->genfscon->count, sizeof(db->genfscon->array), cil_post_genfscon_compare);
> -       qsort(db->ibpkeycon->array, db->ibpkeycon->count, sizeof(db->ibpkeycon->array), cil_post_ibpkeycon_compare);
> -       qsort(db->ibendportcon->array, db->ibendportcon->count, sizeof(db->ibendportcon->array), cil_post_ibendportcon_compare);
> -       qsort(db->portcon->array, db->portcon->count, sizeof(db->portcon->array), cil_post_portcon_compare);
> -       qsort(db->nodecon->array, db->nodecon->count, sizeof(db->nodecon->array), cil_post_nodecon_compare);
> -       qsort(db->fsuse->array, db->fsuse->count, sizeof(db->fsuse->array), cil_post_fsuse_compare);
> -       qsort(db->filecon->array, db->filecon->count, sizeof(db->filecon->array), cil_post_filecon_compare);
> -       qsort(db->pirqcon->array, db->pirqcon->count, sizeof(db->pirqcon->array), cil_post_pirqcon_compare);
> -       qsort(db->iomemcon->array, db->iomemcon->count, sizeof(db->iomemcon->array), cil_post_iomemcon_compare);
> -       qsort(db->ioportcon->array, db->ioportcon->count, sizeof(db->ioportcon->array), cil_post_ioportcon_compare);
> -       qsort(db->pcidevicecon->array, db->pcidevicecon->count, sizeof(db->pcidevicecon->array), cil_post_pcidevicecon_compare);
> -       qsort(db->devicetreecon->array, db->devicetreecon->count, sizeof(db->devicetreecon->array), cil_post_devicetreecon_compare);
> +       rc = __cil_post_process_context_rules(db->netifcon, cil_post_netifcon_compare, cil_post_netifcon_context_compare, db, CIL_NETIFCON, CIL_KEY_NETIFCON);
> +       if (rc != SEPOL_OK) {
> +               cil_log(CIL_ERR, "Problems processing netifcon rules\n");
> +               goto exit;
> +       }
> +
> +       rc = __cil_post_process_context_rules(db->genfscon, cil_post_genfscon_compare, cil_post_genfscon_context_compare, db, CIL_GENFSCON, CIL_KEY_GENFSCON);
> +       if (rc != SEPOL_OK) {
> +               cil_log(CIL_ERR, "Problems processing genfscon rules\n");
> +               goto exit;
> +       }
> +
> +       rc = __cil_post_process_context_rules(db->ibpkeycon, cil_post_ibpkeycon_compare, cil_post_ibpkeycon_context_compare, db, CIL_IBPKEYCON, CIL_KEY_IBPKEYCON);
> +       if (rc != SEPOL_OK) {
> +               cil_log(CIL_ERR, "Problems processing ibpkeycon rules\n");
> +               goto exit;
> +       }
> +
> +       rc = __cil_post_process_context_rules(db->ibendportcon, cil_post_ibendportcon_compare, cil_post_ibendportcon_context_compare, db, CIL_IBENDPORTCON, CIL_KEY_IBENDPORTCON);
> +       if (rc != SEPOL_OK) {
> +               cil_log(CIL_ERR, "Problems processing ibendportcon rules\n");
> +               goto exit;
> +       }
> +
> +       rc = __cil_post_process_context_rules(db->portcon, cil_post_portcon_compare, cil_post_portcon_context_compare, db, CIL_PORTCON, CIL_KEY_PORTCON);
> +       if (rc != SEPOL_OK) {
> +               cil_log(CIL_ERR, "Problems processing portcon rules\n");
> +               goto exit;
> +       }
> +
> +       rc = __cil_post_process_context_rules(db->nodecon, cil_post_nodecon_compare, cil_post_nodecon_context_compare, db, CIL_NODECON, CIL_KEY_NODECON);
> +       if (rc != SEPOL_OK) {
> +               cil_log(CIL_ERR, "Problems processing nodecon rules\n");
> +               goto exit;
> +       }
> +
> +       rc = __cil_post_process_context_rules(db->fsuse, cil_post_fsuse_compare, cil_post_fsuse_context_compare, db, CIL_FSUSE, CIL_KEY_FSUSE);
> +       if (rc != SEPOL_OK) {
> +               cil_log(CIL_ERR, "Problems processing fsuse rules\n");
> +               goto exit;
> +       }
> +
> +       rc = __cil_post_process_context_rules(db->filecon, cil_post_filecon_compare, cil_post_filecon_context_compare, db, CIL_FILECON, CIL_KEY_FILECON);
> +       if (rc != SEPOL_OK) {
> +               cil_log(CIL_ERR, "Problems processing filecon rules\n");
> +               goto exit;
> +       }
> +
> +       rc = __cil_post_process_context_rules(db->iomemcon, cil_post_iomemcon_compare, cil_post_iomemcon_context_compare, db, CIL_IOMEMCON, CIL_KEY_IOMEMCON);
> +       if (rc != SEPOL_OK) {
> +               cil_log(CIL_ERR, "Problems processing iomemcon rules\n");
> +               goto exit;
> +       }
> +
> +       rc = __cil_post_process_context_rules(db->ioportcon, cil_post_ioportcon_compare, cil_post_ioportcon_context_compare, db, CIL_IOPORTCON, CIL_KEY_IOPORTCON);
> +       if (rc != SEPOL_OK) {
> +               cil_log(CIL_ERR, "Problems processing ioportcon rules\n");
> +               goto exit;
> +       }
> +
> +       rc = __cil_post_process_context_rules(db->pcidevicecon, cil_post_pcidevicecon_compare, cil_post_pcidevicecon_context_compare, db, CIL_PCIDEVICECON, CIL_KEY_PCIDEVICECON);
> +       if (rc != SEPOL_OK) {
> +               cil_log(CIL_ERR, "Problems processing pcidevicecon rules\n");
> +               goto exit;
> +       }
> +
> +       rc = __cil_post_process_context_rules(db->devicetreecon, cil_post_devicetreecon_compare, cil_post_devicetreecon_context_compare, db, CIL_DEVICETREECON, CIL_KEY_DEVICETREECON);
> +       if (rc != SEPOL_OK) {
> +               cil_log(CIL_ERR, "Problems processing devicetreecon rules\n");
> +               goto exit;
> +       }
>
>  exit:
>         return rc;
> --
> 2.13.6
>
James Carter April 3, 2018, 12:43 p.m. UTC | #5
On 03/30/2018 01:33 PM, Jeffrey Vander Stoep wrote:
> On Thu, Mar 29, 2018 at 1:06 PM, James Carter <jwcart2@tycho.nsa.gov> wrote:
>> Improve the processing of netifcon, genfscon, ibpkeycon, ibendportcon,
>> portcon, nodecon, fsuse, filecon, iomemcon, ioportcon, pcidevicecon,
>> and devicetreecon rules.
>>
>> If the multiple-decls option is not used then report errors if duplicate
>> context rules are found. If it is used then remove duplicate context rules
>> and report errors when two rules are identical except for the context.
>>
>> This also changes the ordering of portcon and filecon rules. The protocol
>> of portcon rules will be compared if the port numbers are the same and the
>> path strings of filecon rules will be compared if the number of meta
>> characters, the stem length, string length and file types are the same.
>>
>> Based on an initial patch by Pierre-Hugues Husson (phh@phh.me)
>>
>> Signed-off-by: James Carter <jwcart2@tycho.nsa.gov>
> 
> Acked-by: Jeff Vander Stoep <jeffv@google.com>
> 

This has been applied.

Jim

>> ---
>>   libsepol/cil/src/cil_post.c | 331 ++++++++++++++++++++++++++++++++++++++++++--
>>   1 file changed, 318 insertions(+), 13 deletions(-)
>>
>> diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c
>> index a2122454..0b09cecc 100644
>> --- a/libsepol/cil/src/cil_post.c
>> +++ b/libsepol/cil/src/cil_post.c
>> @@ -53,6 +53,83 @@
>>   static int __cil_expr_to_bitmap(struct cil_list *expr, ebitmap_t *out, int max, struct cil_db *db);
>>   static int __cil_expr_list_to_bitmap(struct cil_list *expr_list, ebitmap_t *out, int max, struct cil_db *db);
>>
>> +static int cats_compare(struct cil_cats *a, struct cil_cats *b)
>> +{
>> +       struct cil_list_item *i, *j;
>> +       int rc;
>> +
>> +       if (a == b) return 0;
>> +       if (!a) return -1;
>> +       if (!b) return 1;
>> +
>> +       /* Expects cat expression to have been evaluated */
>> +       cil_list_for_each(i, a->datum_expr) {
>> +               cil_list_for_each(j, b->datum_expr) {
>> +                       rc = strcmp(DATUM(i->data)->fqn, DATUM(j->data)->fqn);
>> +                       if (!rc) return rc;
>> +               }
>> +       }
>> +       return 0;
>> +}
>> +
>> +static int level_compare(struct cil_level *a, struct cil_level *b)
>> +{
>> +       int rc;
>> +
>> +       if (a == b) return 0;
>> +       if (!a) return -1;
>> +       if (!b) return 1;
>> +
>> +       if (a->sens != b->sens) {
>> +               rc = strcmp(DATUM(a->sens)->fqn, DATUM(b->sens)->fqn);
>> +               if (rc != 0) return rc;
>> +       }
>> +       if (a->cats != b->cats) {
>> +               return cats_compare(a->cats, b->cats);
>> +       }
>> +       return 0;
>> +}
>> +
>> +static int range_compare(struct cil_levelrange *a, struct cil_levelrange *b)
>> +{
>> +       int rc;
>> +
>> +       if (a == b) return 0;
>> +       if (!a) return -1;
>> +       if (!b) return 1;
>> +
>> +       if (a->low != b->low) {
>> +               rc = level_compare(a->low, b->low);
>> +               if (rc != 0) return rc;
>> +       }
>> +       if (a->high != b->high) {
>> +               return level_compare(a->high, b->high);
>> +       }
>> +       return 0;
>> +}
>> +
>> +static int context_compare(struct cil_context *a, struct cil_context *b)
>> +{
>> +       int rc;
>> +
>> +       if (a->user != b->user) {
>> +               rc = strcmp(DATUM(a->user)->fqn, DATUM(b->user)->fqn);
>> +               if (rc != 0) return rc;
>> +       }
>> +       if (a->role != b->role) {
>> +               rc = strcmp(DATUM(a->role)->fqn, DATUM(b->role)->fqn);
>> +               if (rc != 0) return rc;
>> +       }
>> +       if (a->type != b->type) {
>> +               rc = strcmp(DATUM(a->type)->fqn, DATUM(b->type)->fqn);
>> +               if (rc != 0) return rc;
>> +       }
>> +       if (a->range != b->range) {
>> +               return range_compare(a->range, b->range);
>> +       }
>> +       return 0;
>> +}
>> +
>>   static int cil_verify_is_list(struct cil_list *list, enum cil_flavor flavor)
>>   {
>>          struct cil_list_item *curr;
>> @@ -145,6 +222,8 @@ int cil_post_filecon_compare(const void *a, const void *b)
>>                  rc = -1;
>>          } else if (b_filecon->type < a_filecon->type) {
>>                  rc = 1;
>> +       } else {
>> +               rc = strcmp(a_filecon->path_str, b_filecon->path_str);
>>          }
>>
>>          free(a_path);
>> @@ -190,6 +269,10 @@ int cil_post_portcon_compare(const void *a, const void *b)
>>                          rc = -1;
>>                  } else if (bportcon->port_low < aportcon->port_low) {
>>                          rc = 1;
>> +               } else if (aportcon->proto < bportcon->proto) {
>> +                       rc = -1;
>> +               } else if (aportcon->proto > bportcon->proto) {
>> +                       rc = 1;
>>                  }
>>          }
>>
>> @@ -369,6 +452,102 @@ int cil_post_fsuse_compare(const void *a, const void *b)
>>          return rc;
>>   }
>>
>> +int cil_post_filecon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_filecon *a_filecon = *(struct cil_filecon**)a;
>> +       struct cil_filecon *b_filecon = *(struct cil_filecon**)b;
>> +       return context_compare(a_filecon->context, b_filecon->context);
>> +}
>> +
>> +int cil_post_ibpkeycon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_ibpkeycon *a_ibpkeycon = *(struct cil_ibpkeycon **)a;
>> +       struct cil_ibpkeycon *b_ibpkeycon = *(struct cil_ibpkeycon **)b;
>> +       return context_compare(a_ibpkeycon->context, b_ibpkeycon->context);
>> +}
>> +
>> +int cil_post_portcon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_portcon *a_portcon = *(struct cil_portcon**)a;
>> +       struct cil_portcon *b_portcon = *(struct cil_portcon**)b;
>> +       return context_compare(a_portcon->context, b_portcon->context);
>> +}
>> +
>> +int cil_post_genfscon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_genfscon *a_genfscon = *(struct cil_genfscon**)a;
>> +       struct cil_genfscon *b_genfscon = *(struct cil_genfscon**)b;
>> +       return context_compare(a_genfscon->context, b_genfscon->context);
>> +}
>> +
>> +int cil_post_netifcon_context_compare(const void *a, const void *b)
>> +{
>> +       int rc;
>> +       struct cil_netifcon *a_netifcon = *(struct cil_netifcon**)a;
>> +       struct cil_netifcon *b_netifcon = *(struct cil_netifcon**)b;
>> +       rc = context_compare(a_netifcon->if_context, b_netifcon->if_context);
>> +       if (rc != 0) {
>> +               return rc;
>> +       }
>> +       return context_compare(a_netifcon->packet_context, b_netifcon->packet_context);
>> +}
>> +
>> +int cil_post_ibendportcon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_ibendportcon *a_ibendportcon = *(struct cil_ibendportcon **)a;
>> +       struct cil_ibendportcon *b_ibendportcon = *(struct cil_ibendportcon **)b;
>> +       return context_compare(a_ibendportcon->context, b_ibendportcon->context);
>> +}
>> +
>> +int cil_post_nodecon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_nodecon *a_nodecon = *(struct cil_nodecon **)a;
>> +       struct cil_nodecon *b_nodecon = *(struct cil_nodecon **)b;
>> +       return context_compare(a_nodecon->context, b_nodecon->context);
>> +}
>> +
>> +int cil_post_pirqcon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_pirqcon *a_pirqcon = *(struct cil_pirqcon**)a;
>> +       struct cil_pirqcon *b_pirqcon = *(struct cil_pirqcon**)b;
>> +       return context_compare(a_pirqcon->context, b_pirqcon->context);
>> +}
>> +
>> +int cil_post_iomemcon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_iomemcon *a_iomemcon = *(struct cil_iomemcon**)a;
>> +       struct cil_iomemcon *b_iomemcon = *(struct cil_iomemcon**)b;
>> +       return context_compare(a_iomemcon->context, b_iomemcon->context);
>> +}
>> +
>> +int cil_post_ioportcon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_ioportcon *a_ioportcon = *(struct cil_ioportcon**)a;
>> +       struct cil_ioportcon *b_ioportcon = *(struct cil_ioportcon**)b;
>> +       return context_compare(a_ioportcon->context, b_ioportcon->context);
>> +}
>> +
>> +int cil_post_pcidevicecon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_pcidevicecon *a_pcidevicecon = *(struct cil_pcidevicecon**)a;
>> +       struct cil_pcidevicecon *b_pcidevicecon = *(struct cil_pcidevicecon**)b;
>> +       return context_compare(a_pcidevicecon->context, b_pcidevicecon->context);
>> +}
>> +
>> +int cil_post_devicetreecon_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_devicetreecon *a_devicetreecon = *(struct cil_devicetreecon**)a;
>> +       struct cil_devicetreecon *b_devicetreecon = *(struct cil_devicetreecon**)b;
>> +       return context_compare(a_devicetreecon->context, b_devicetreecon->context);
>> +}
>> +
>> +int cil_post_fsuse_context_compare(const void *a, const void *b)
>> +{
>> +       struct cil_fsuse *a_fsuse = *(struct cil_fsuse**)a;
>> +       struct cil_fsuse *b_fsuse = *(struct cil_fsuse**)b;
>> +       return context_compare(a_fsuse->context, b_fsuse->context);
>> +}
>> +
>>   static int __cil_post_db_count_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
>>   {
>>          struct cil_db *db = extra_args;
>> @@ -2064,6 +2243,74 @@ exit:
>>          return rc;
>>   }
>>
>> +static int __cil_post_report_conflict(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
>> +{
>> +       struct cil_list_item *li = extra_args;
>> +
>> +       if (node->flavor == CIL_BLOCK) {
>> +               struct cil_block *blk = node->data;
>> +               if (blk->is_abstract == CIL_TRUE) {
>> +                       *finished = CIL_TREE_SKIP_HEAD;
>> +               }
>> +       } else if (node->flavor == CIL_MACRO) {
>> +               *finished = CIL_TREE_SKIP_HEAD;
>> +       } else if (node->flavor == li->flavor) {
>> +               if (node->data == li->data) {
>> +                       char *path = cil_tree_get_cil_path(node);
>> +                       cil_log(CIL_WARN, "  at %s:%d\n", path, node->line);
>> +               }
>> +       }
>> +       return SEPOL_OK;
>> +}
>> +
>> +static int __cil_post_process_context_rules(struct cil_sort *sort, int (*compar)(const void *, const void *), int (*concompar)(const void *, const void *), struct cil_db *db, enum cil_flavor flavor, const char *flavor_str)
>> +{
>> +       uint32_t count = sort->count;
>> +       uint32_t i, j = 0, removed = 0;
>> +       int rc = SEPOL_OK;
>> +
>> +       if (count < 2) {
>> +               return SEPOL_OK;
>> +       }
>> +
>> +       qsort(sort->array, sort->count, sizeof(sort->array), compar);
>> +
>> +       for (i=1; i<count; i++) {
>> +               if (compar(&sort->array[i], &sort->array[j]) != 0) {
>> +                       j++;
>> +               } else {
>> +                       removed++;
>> +                       if (!db->multiple_decls ||
>> +                          concompar(&sort->array[i], &sort->array[j]) != 0) {
>> +                               struct cil_list_item li;
>> +                               int rc2;
>> +                               cil_log(CIL_WARN, "Found conflicting %s rules\n",
>> +                                       flavor_str);
>> +                               rc = SEPOL_ERR;
>> +                               li.flavor = flavor;
>> +                               li.data = sort->array[i];
>> +                               rc2 = cil_tree_walk(db->ast->root,
>> +                                                   __cil_post_report_conflict,
>> +                                                   NULL, NULL, &li);
>> +                               if (rc2 != SEPOL_OK) goto exit;
>> +                               li.data = sort->array[j];
>> +                               rc2 = cil_tree_walk(db->ast->root,
>> +                                                   __cil_post_report_conflict,
>> +                                                   NULL, NULL, &li);
>> +                               if (rc2 != SEPOL_OK) goto exit;
>> +                       }
>> +               }
>> +               if (i != j) {
>> +                       sort->array[j] = sort->array[i];
>> +               }
>> +       }
>> +
>> +       sort->count = count - removed;
>> +
>> +exit:
>> +       return rc;
>> +}
>> +
>>   static int cil_post_db(struct cil_db *db)
>>   {
>>          int rc = SEPOL_ERR;
>> @@ -2116,19 +2363,77 @@ static int cil_post_db(struct cil_db *db)
>>                  goto exit;
>>          }
>>
>> -       qsort(db->netifcon->array, db->netifcon->count, sizeof(db->netifcon->array), cil_post_netifcon_compare);
>> -       qsort(db->genfscon->array, db->genfscon->count, sizeof(db->genfscon->array), cil_post_genfscon_compare);
>> -       qsort(db->ibpkeycon->array, db->ibpkeycon->count, sizeof(db->ibpkeycon->array), cil_post_ibpkeycon_compare);
>> -       qsort(db->ibendportcon->array, db->ibendportcon->count, sizeof(db->ibendportcon->array), cil_post_ibendportcon_compare);
>> -       qsort(db->portcon->array, db->portcon->count, sizeof(db->portcon->array), cil_post_portcon_compare);
>> -       qsort(db->nodecon->array, db->nodecon->count, sizeof(db->nodecon->array), cil_post_nodecon_compare);
>> -       qsort(db->fsuse->array, db->fsuse->count, sizeof(db->fsuse->array), cil_post_fsuse_compare);
>> -       qsort(db->filecon->array, db->filecon->count, sizeof(db->filecon->array), cil_post_filecon_compare);
>> -       qsort(db->pirqcon->array, db->pirqcon->count, sizeof(db->pirqcon->array), cil_post_pirqcon_compare);
>> -       qsort(db->iomemcon->array, db->iomemcon->count, sizeof(db->iomemcon->array), cil_post_iomemcon_compare);
>> -       qsort(db->ioportcon->array, db->ioportcon->count, sizeof(db->ioportcon->array), cil_post_ioportcon_compare);
>> -       qsort(db->pcidevicecon->array, db->pcidevicecon->count, sizeof(db->pcidevicecon->array), cil_post_pcidevicecon_compare);
>> -       qsort(db->devicetreecon->array, db->devicetreecon->count, sizeof(db->devicetreecon->array), cil_post_devicetreecon_compare);
>> +       rc = __cil_post_process_context_rules(db->netifcon, cil_post_netifcon_compare, cil_post_netifcon_context_compare, db, CIL_NETIFCON, CIL_KEY_NETIFCON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing netifcon rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->genfscon, cil_post_genfscon_compare, cil_post_genfscon_context_compare, db, CIL_GENFSCON, CIL_KEY_GENFSCON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing genfscon rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->ibpkeycon, cil_post_ibpkeycon_compare, cil_post_ibpkeycon_context_compare, db, CIL_IBPKEYCON, CIL_KEY_IBPKEYCON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing ibpkeycon rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->ibendportcon, cil_post_ibendportcon_compare, cil_post_ibendportcon_context_compare, db, CIL_IBENDPORTCON, CIL_KEY_IBENDPORTCON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing ibendportcon rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->portcon, cil_post_portcon_compare, cil_post_portcon_context_compare, db, CIL_PORTCON, CIL_KEY_PORTCON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing portcon rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->nodecon, cil_post_nodecon_compare, cil_post_nodecon_context_compare, db, CIL_NODECON, CIL_KEY_NODECON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing nodecon rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->fsuse, cil_post_fsuse_compare, cil_post_fsuse_context_compare, db, CIL_FSUSE, CIL_KEY_FSUSE);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing fsuse rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->filecon, cil_post_filecon_compare, cil_post_filecon_context_compare, db, CIL_FILECON, CIL_KEY_FILECON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing filecon rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->iomemcon, cil_post_iomemcon_compare, cil_post_iomemcon_context_compare, db, CIL_IOMEMCON, CIL_KEY_IOMEMCON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing iomemcon rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->ioportcon, cil_post_ioportcon_compare, cil_post_ioportcon_context_compare, db, CIL_IOPORTCON, CIL_KEY_IOPORTCON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing ioportcon rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->pcidevicecon, cil_post_pcidevicecon_compare, cil_post_pcidevicecon_context_compare, db, CIL_PCIDEVICECON, CIL_KEY_PCIDEVICECON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing pcidevicecon rules\n");
>> +               goto exit;
>> +       }
>> +
>> +       rc = __cil_post_process_context_rules(db->devicetreecon, cil_post_devicetreecon_compare, cil_post_devicetreecon_context_compare, db, CIL_DEVICETREECON, CIL_KEY_DEVICETREECON);
>> +       if (rc != SEPOL_OK) {
>> +               cil_log(CIL_ERR, "Problems processing devicetreecon rules\n");
>> +               goto exit;
>> +       }
>>
>>   exit:
>>          return rc;
>> --
>> 2.13.6
>>
> 
>
diff mbox

Patch

diff --git a/libsepol/cil/src/cil_post.c b/libsepol/cil/src/cil_post.c
index a2122454..0b09cecc 100644
--- a/libsepol/cil/src/cil_post.c
+++ b/libsepol/cil/src/cil_post.c
@@ -53,6 +53,83 @@ 
 static int __cil_expr_to_bitmap(struct cil_list *expr, ebitmap_t *out, int max, struct cil_db *db);
 static int __cil_expr_list_to_bitmap(struct cil_list *expr_list, ebitmap_t *out, int max, struct cil_db *db);
 
+static int cats_compare(struct cil_cats *a, struct cil_cats *b)
+{
+	struct cil_list_item *i, *j;
+	int rc;
+
+	if (a == b) return 0;
+	if (!a) return -1;
+	if (!b) return 1;
+
+	/* Expects cat expression to have been evaluated */
+	cil_list_for_each(i, a->datum_expr) {
+		cil_list_for_each(j, b->datum_expr) {
+			rc = strcmp(DATUM(i->data)->fqn, DATUM(j->data)->fqn);
+			if (!rc) return rc;
+		}
+	}
+	return 0;
+}
+
+static int level_compare(struct cil_level *a, struct cil_level *b)
+{
+	int rc;
+
+	if (a == b) return 0;
+	if (!a) return -1;
+	if (!b) return 1;
+
+	if (a->sens != b->sens) {
+		rc = strcmp(DATUM(a->sens)->fqn, DATUM(b->sens)->fqn);
+		if (rc != 0) return rc;
+	}
+	if (a->cats != b->cats) {
+		return cats_compare(a->cats, b->cats);
+	}
+	return 0;
+}
+
+static int range_compare(struct cil_levelrange *a, struct cil_levelrange *b)
+{
+	int rc;
+
+	if (a == b) return 0;
+	if (!a) return -1;
+	if (!b) return 1;
+
+	if (a->low != b->low) {
+		rc = level_compare(a->low, b->low);
+		if (rc != 0) return rc;
+	}
+	if (a->high != b->high) {
+		return level_compare(a->high, b->high);
+	}
+	return 0;
+}
+
+static int context_compare(struct cil_context *a, struct cil_context *b)
+{
+	int rc;
+
+	if (a->user != b->user) {
+		rc = strcmp(DATUM(a->user)->fqn, DATUM(b->user)->fqn);
+		if (rc != 0) return rc;
+	}
+	if (a->role != b->role) {
+		rc = strcmp(DATUM(a->role)->fqn, DATUM(b->role)->fqn);
+		if (rc != 0) return rc;
+	}
+	if (a->type != b->type) {
+		rc = strcmp(DATUM(a->type)->fqn, DATUM(b->type)->fqn);
+		if (rc != 0) return rc;
+	}
+	if (a->range != b->range) {
+		return range_compare(a->range, b->range);
+	}
+	return 0;
+}
+
 static int cil_verify_is_list(struct cil_list *list, enum cil_flavor flavor)
 {
 	struct cil_list_item *curr;
@@ -145,6 +222,8 @@  int cil_post_filecon_compare(const void *a, const void *b)
 		rc = -1;
 	} else if (b_filecon->type < a_filecon->type) {
 		rc = 1;
+	} else {
+		rc = strcmp(a_filecon->path_str, b_filecon->path_str);
 	}
 
 	free(a_path);
@@ -190,6 +269,10 @@  int cil_post_portcon_compare(const void *a, const void *b)
 			rc = -1;
 		} else if (bportcon->port_low < aportcon->port_low) {
 			rc = 1;
+		} else if (aportcon->proto < bportcon->proto) {
+			rc = -1;
+		} else if (aportcon->proto > bportcon->proto) {
+			rc = 1;
 		}
 	}
 
@@ -369,6 +452,102 @@  int cil_post_fsuse_compare(const void *a, const void *b)
 	return rc;
 }
 
+int cil_post_filecon_context_compare(const void *a, const void *b)
+{
+	struct cil_filecon *a_filecon = *(struct cil_filecon**)a;
+	struct cil_filecon *b_filecon = *(struct cil_filecon**)b;
+	return context_compare(a_filecon->context, b_filecon->context);
+}
+
+int cil_post_ibpkeycon_context_compare(const void *a, const void *b)
+{
+	struct cil_ibpkeycon *a_ibpkeycon = *(struct cil_ibpkeycon **)a;
+	struct cil_ibpkeycon *b_ibpkeycon = *(struct cil_ibpkeycon **)b;
+	return context_compare(a_ibpkeycon->context, b_ibpkeycon->context);
+}
+
+int cil_post_portcon_context_compare(const void *a, const void *b)
+{
+	struct cil_portcon *a_portcon = *(struct cil_portcon**)a;
+	struct cil_portcon *b_portcon = *(struct cil_portcon**)b;
+	return context_compare(a_portcon->context, b_portcon->context);
+}
+
+int cil_post_genfscon_context_compare(const void *a, const void *b)
+{
+	struct cil_genfscon *a_genfscon = *(struct cil_genfscon**)a;
+	struct cil_genfscon *b_genfscon = *(struct cil_genfscon**)b;
+	return context_compare(a_genfscon->context, b_genfscon->context);
+}
+
+int cil_post_netifcon_context_compare(const void *a, const void *b)
+{
+	int rc;
+	struct cil_netifcon *a_netifcon = *(struct cil_netifcon**)a;
+	struct cil_netifcon *b_netifcon = *(struct cil_netifcon**)b;
+	rc = context_compare(a_netifcon->if_context, b_netifcon->if_context);
+	if (rc != 0) {
+		return rc;
+	}
+	return context_compare(a_netifcon->packet_context, b_netifcon->packet_context);
+}
+
+int cil_post_ibendportcon_context_compare(const void *a, const void *b)
+{
+	struct cil_ibendportcon *a_ibendportcon = *(struct cil_ibendportcon **)a;
+	struct cil_ibendportcon *b_ibendportcon = *(struct cil_ibendportcon **)b;
+	return context_compare(a_ibendportcon->context, b_ibendportcon->context);
+}
+
+int cil_post_nodecon_context_compare(const void *a, const void *b)
+{
+	struct cil_nodecon *a_nodecon = *(struct cil_nodecon **)a;
+	struct cil_nodecon *b_nodecon = *(struct cil_nodecon **)b;
+	return context_compare(a_nodecon->context, b_nodecon->context);
+}
+
+int cil_post_pirqcon_context_compare(const void *a, const void *b)
+{
+	struct cil_pirqcon *a_pirqcon = *(struct cil_pirqcon**)a;
+	struct cil_pirqcon *b_pirqcon = *(struct cil_pirqcon**)b;
+	return context_compare(a_pirqcon->context, b_pirqcon->context);
+}
+
+int cil_post_iomemcon_context_compare(const void *a, const void *b)
+{
+	struct cil_iomemcon *a_iomemcon = *(struct cil_iomemcon**)a;
+	struct cil_iomemcon *b_iomemcon = *(struct cil_iomemcon**)b;
+	return context_compare(a_iomemcon->context, b_iomemcon->context);
+}
+
+int cil_post_ioportcon_context_compare(const void *a, const void *b)
+{
+	struct cil_ioportcon *a_ioportcon = *(struct cil_ioportcon**)a;
+	struct cil_ioportcon *b_ioportcon = *(struct cil_ioportcon**)b;
+	return context_compare(a_ioportcon->context, b_ioportcon->context);
+}
+
+int cil_post_pcidevicecon_context_compare(const void *a, const void *b)
+{
+	struct cil_pcidevicecon *a_pcidevicecon = *(struct cil_pcidevicecon**)a;
+	struct cil_pcidevicecon *b_pcidevicecon = *(struct cil_pcidevicecon**)b;
+	return context_compare(a_pcidevicecon->context, b_pcidevicecon->context);
+}
+
+int cil_post_devicetreecon_context_compare(const void *a, const void *b)
+{
+	struct cil_devicetreecon *a_devicetreecon = *(struct cil_devicetreecon**)a;
+	struct cil_devicetreecon *b_devicetreecon = *(struct cil_devicetreecon**)b;
+	return context_compare(a_devicetreecon->context, b_devicetreecon->context);
+}
+
+int cil_post_fsuse_context_compare(const void *a, const void *b)
+{
+	struct cil_fsuse *a_fsuse = *(struct cil_fsuse**)a;
+	struct cil_fsuse *b_fsuse = *(struct cil_fsuse**)b;
+	return context_compare(a_fsuse->context, b_fsuse->context);
+}
+
 static int __cil_post_db_count_helper(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
 {
 	struct cil_db *db = extra_args;
@@ -2064,6 +2243,74 @@  exit:
 	return rc;
 }
 
+static int __cil_post_report_conflict(struct cil_tree_node *node, uint32_t *finished, void *extra_args)
+{
+	struct cil_list_item *li = extra_args;
+
+	if (node->flavor == CIL_BLOCK) {
+		struct cil_block *blk = node->data;
+		if (blk->is_abstract == CIL_TRUE) {
+			*finished = CIL_TREE_SKIP_HEAD;
+		}
+	} else if (node->flavor == CIL_MACRO) {
+		*finished = CIL_TREE_SKIP_HEAD;
+	} else if (node->flavor == li->flavor) {
+		if (node->data == li->data) {
+			char *path = cil_tree_get_cil_path(node);
+			cil_log(CIL_WARN, "  at %s:%d\n", path, node->line);
+		}
+	}
+	return SEPOL_OK;
+}
+
+static int __cil_post_process_context_rules(struct cil_sort *sort, int (*compar)(const void *, const void *), int (*concompar)(const void *, const void *), struct cil_db *db, enum cil_flavor flavor, const char *flavor_str)
+{
+	uint32_t count = sort->count;
+	uint32_t i, j = 0, removed = 0;
+	int rc = SEPOL_OK;
+
+	if (count < 2) {
+		return SEPOL_OK;
+	}
+
+	qsort(sort->array, sort->count, sizeof(sort->array), compar);
+
+	for (i=1; i<count; i++) {
+		if (compar(&sort->array[i], &sort->array[j]) != 0) {
+			j++;
+		} else {
+			removed++;
+			if (!db->multiple_decls ||
+			   concompar(&sort->array[i], &sort->array[j]) != 0) {
+				struct cil_list_item li;
+				int rc2;
+				cil_log(CIL_WARN, "Found conflicting %s rules\n",
+					flavor_str);
+				rc = SEPOL_ERR;
+				li.flavor = flavor;
+				li.data = sort->array[i];
+				rc2 = cil_tree_walk(db->ast->root,
+						    __cil_post_report_conflict,
+						    NULL, NULL, &li);
+				if (rc2 != SEPOL_OK) goto exit;
+				li.data = sort->array[j];
+				rc2 = cil_tree_walk(db->ast->root,
+						    __cil_post_report_conflict,
+						    NULL, NULL, &li);
+				if (rc2 != SEPOL_OK) goto exit;
+			}
+		}
+		if (i != j) {
+			sort->array[j] = sort->array[i];
+		}
+	}
+
+	sort->count = count - removed;
+
+exit:
+	return rc;
+}
+
 static int cil_post_db(struct cil_db *db)
 {
 	int rc = SEPOL_ERR;
@@ -2116,19 +2363,77 @@  static int cil_post_db(struct cil_db *db)
 		goto exit;
 	}
 
-	qsort(db->netifcon->array, db->netifcon->count, sizeof(db->netifcon->array), cil_post_netifcon_compare);
-	qsort(db->genfscon->array, db->genfscon->count, sizeof(db->genfscon->array), cil_post_genfscon_compare);
-	qsort(db->ibpkeycon->array, db->ibpkeycon->count, sizeof(db->ibpkeycon->array), cil_post_ibpkeycon_compare);
-	qsort(db->ibendportcon->array, db->ibendportcon->count, sizeof(db->ibendportcon->array), cil_post_ibendportcon_compare);
-	qsort(db->portcon->array, db->portcon->count, sizeof(db->portcon->array), cil_post_portcon_compare);
-	qsort(db->nodecon->array, db->nodecon->count, sizeof(db->nodecon->array), cil_post_nodecon_compare);
-	qsort(db->fsuse->array, db->fsuse->count, sizeof(db->fsuse->array), cil_post_fsuse_compare);
-	qsort(db->filecon->array, db->filecon->count, sizeof(db->filecon->array), cil_post_filecon_compare);
-	qsort(db->pirqcon->array, db->pirqcon->count, sizeof(db->pirqcon->array), cil_post_pirqcon_compare);
-	qsort(db->iomemcon->array, db->iomemcon->count, sizeof(db->iomemcon->array), cil_post_iomemcon_compare);
-	qsort(db->ioportcon->array, db->ioportcon->count, sizeof(db->ioportcon->array), cil_post_ioportcon_compare);
-	qsort(db->pcidevicecon->array, db->pcidevicecon->count, sizeof(db->pcidevicecon->array), cil_post_pcidevicecon_compare);
-	qsort(db->devicetreecon->array, db->devicetreecon->count, sizeof(db->devicetreecon->array), cil_post_devicetreecon_compare);
+	rc = __cil_post_process_context_rules(db->netifcon, cil_post_netifcon_compare, cil_post_netifcon_context_compare, db, CIL_NETIFCON, CIL_KEY_NETIFCON);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Problems processing netifcon rules\n");
+		goto exit;
+	}
+
+	rc = __cil_post_process_context_rules(db->genfscon, cil_post_genfscon_compare, cil_post_genfscon_context_compare, db, CIL_GENFSCON, CIL_KEY_GENFSCON);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Problems processing genfscon rules\n");
+		goto exit;
+	}
+
+	rc = __cil_post_process_context_rules(db->ibpkeycon, cil_post_ibpkeycon_compare, cil_post_ibpkeycon_context_compare, db, CIL_IBPKEYCON, CIL_KEY_IBPKEYCON);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Problems processing ibpkeycon rules\n");
+		goto exit;
+	}
+
+	rc = __cil_post_process_context_rules(db->ibendportcon, cil_post_ibendportcon_compare, cil_post_ibendportcon_context_compare, db, CIL_IBENDPORTCON, CIL_KEY_IBENDPORTCON);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Problems processing ibendportcon rules\n");
+		goto exit;
+	}
+
+	rc = __cil_post_process_context_rules(db->portcon, cil_post_portcon_compare, cil_post_portcon_context_compare, db, CIL_PORTCON, CIL_KEY_PORTCON);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Problems processing portcon rules\n");
+		goto exit;
+	}
+
+	rc = __cil_post_process_context_rules(db->nodecon, cil_post_nodecon_compare, cil_post_nodecon_context_compare, db, CIL_NODECON, CIL_KEY_NODECON);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Problems processing nodecon rules\n");
+		goto exit;
+	}
+
+	rc = __cil_post_process_context_rules(db->fsuse, cil_post_fsuse_compare, cil_post_fsuse_context_compare, db, CIL_FSUSE, CIL_KEY_FSUSE);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Problems processing fsuse rules\n");
+		goto exit;
+	}
+
+	rc = __cil_post_process_context_rules(db->filecon, cil_post_filecon_compare, cil_post_filecon_context_compare, db, CIL_FILECON, CIL_KEY_FILECON);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Problems processing filecon rules\n");
+		goto exit;
+	}
+
+	rc = __cil_post_process_context_rules(db->iomemcon, cil_post_iomemcon_compare, cil_post_iomemcon_context_compare, db, CIL_IOMEMCON, CIL_KEY_IOMEMCON);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Problems processing iomemcon rules\n");
+		goto exit;
+	}
+
+	rc = __cil_post_process_context_rules(db->ioportcon, cil_post_ioportcon_compare, cil_post_ioportcon_context_compare, db, CIL_IOPORTCON, CIL_KEY_IOPORTCON);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Problems processing ioportcon rules\n");
+		goto exit;
+	}
+
+	rc = __cil_post_process_context_rules(db->pcidevicecon, cil_post_pcidevicecon_compare, cil_post_pcidevicecon_context_compare, db, CIL_PCIDEVICECON, CIL_KEY_PCIDEVICECON);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Problems processing pcidevicecon rules\n");
+		goto exit;
+	}
+
+	rc = __cil_post_process_context_rules(db->devicetreecon, cil_post_devicetreecon_compare, cil_post_devicetreecon_context_compare, db, CIL_DEVICETREECON, CIL_KEY_DEVICETREECON);
+	if (rc != SEPOL_OK) {
+		cil_log(CIL_ERR, "Problems processing devicetreecon rules\n");
+		goto exit;
+	}
 
 exit:
 	return rc;