From patchwork Wed May 31 11:49:07 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juraj Marcin X-Patchwork-Id: 13262081 X-Patchwork-Delegate: plautrba@redhat.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 28478C77B73 for ; Wed, 31 May 2023 11:50:09 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232298AbjEaLuH (ORCPT ); Wed, 31 May 2023 07:50:07 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48696 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S229765AbjEaLuG (ORCPT ); Wed, 31 May 2023 07:50:06 -0400 Received: from sender11-of-o52.zoho.eu (sender11-of-o52.zoho.eu [31.186.226.238]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 4EDECE5 for ; Wed, 31 May 2023 04:50:03 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1685533790; cv=none; d=zohomail.eu; s=zohoarc; b=eOZ69bsr87Led+3yJj88fAAsFfHCATVAvjAABn7DwpdP/xWXL4X7WuRbWHLfTieIkGr3YlBvPn2dthQI6ObFTi2Yh6oXYFDZmGsJvURR+MZl9jqZrQ1KNB4GLWi7IMjVF/vtHLqSdt6CwjFwF0lJ7Httyw1VC9DO5woqX1UaoHE= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.eu; s=zohoarc; t=1685533790; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:To; bh=0gHxMwEe0R5fsSCPK6Ecusnh6EFKYo1ZdUc0Y21qMho=; b=iZYuNAcI6TPwgySdWY5sOAbjjifzvGwSavZpFAqLoCXgY+PQb4AXLXtd3sEfWAp0Ij8yG9R93n8fn3fZOCOShfuoKrnRFWjgv9kP2qlW5AFHpsLatPBAGOGGlOj/KZvdl2WkaSLHtBQq8lFD2d2aArzrgZgA0coxLW1/yeDywP0= ARC-Authentication-Results: i=1; mx.zohomail.eu; dkim=pass header.i=jurajmarcin.com; spf=pass smtp.mailfrom=juraj@jurajmarcin.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1685533790; s=zoho; d=jurajmarcin.com; i=juraj@jurajmarcin.com; h=From:From:To:To:Cc:Cc:Subject:Subject:Date:Date:Message-Id:Message-Id:In-Reply-To:References:MIME-Version:Content-Transfer-Encoding:Reply-To; bh=0gHxMwEe0R5fsSCPK6Ecusnh6EFKYo1ZdUc0Y21qMho=; b=cUq/Ib0s18+WD7kSZZqfeu4BmKlhD1kPZLSPTaD73ks5xRPD7cb97IKKvfztyRJ3 WSxE8VRxrs5bBmcpzfuC02ZNqiwplBEW56PDx3JftFF84QnrLhy6SztDcq9TgZQdh8A cfdXwjww5Fk4fKXvE9PcCLfOw19iYZbXqtAY5wyU= Received: from morty01.jurajmarcin.com (129.159.244.31 [129.159.244.31]) by mx.zoho.eu with SMTPS id 1685533787770466.90415684581524; Wed, 31 May 2023 13:49:47 +0200 (CEST) Received: from jmarcin-t14s-01.redhat.com (unknown [147.251.183.113]) by morty01.jurajmarcin.com (Postfix) with ESMTPSA id 315BE2081F76; Wed, 31 May 2023 11:49:47 +0000 (UTC) From: Juraj Marcin To: selinux@vger.kernel.org Cc: Stephen Smalley , Ondrej Mosnacek Subject: [PATCH 1/8] checkpolicy, libsepol: move transition to separate structure in avtab Date: Wed, 31 May 2023 13:49:07 +0200 Message-Id: <20230531114914.2237609-2-juraj@jurajmarcin.com> In-Reply-To: <20230531114914.2237609-1-juraj@jurajmarcin.com> References: <20230531114914.2237609-1-juraj@jurajmarcin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org To move filename transitions to be part of avtab, we need to create space for it in the avtab_datum structure which holds the rule for a certain combination of stype, ttype and tclass. As only type transitions have a special variant that uses a filename, it would be suboptimal to add a (mostly empty) pointer to some structure to all avtab rules. Therefore, this patch adds a new structure to the avtab_datum and moves the otype of the transition to this structure. In the next patch, this structure will also hold filename transitions for the combination of stype, ttype and tclass. Reviewed-by: Ondrej Mosnacek Signed-off-by: Juraj Marcin --- checkpolicy/test/dispol.c | 2 +- libsepol/cil/src/cil_binary.c | 26 +++++++++++++++----- libsepol/include/sepol/policydb/avtab.h | 7 +++++- libsepol/src/avtab.c | 32 ++++++++++++++++++++++++- libsepol/src/expand.c | 8 +++++-- libsepol/src/kernel_to_cil.c | 3 ++- libsepol/src/kernel_to_conf.c | 3 ++- libsepol/src/optimize.c | 4 ++++ libsepol/src/policydb_validate.c | 4 +++- libsepol/src/services.c | 5 +++- libsepol/src/write.c | 17 ++++++++++--- 11 files changed, 93 insertions(+), 18 deletions(-) diff --git a/checkpolicy/test/dispol.c b/checkpolicy/test/dispol.c index b61f1b4b..dea4f8da 100644 --- a/checkpolicy/test/dispol.c +++ b/checkpolicy/test/dispol.c @@ -132,7 +132,7 @@ static int render_av_rule(avtab_key_t * key, avtab_datum_t * datum, uint32_t wha if (key->specified & AVTAB_TRANSITION) { fprintf(fp, "type_transition "); render_key(key, p, fp); - render_type(datum->data, p, fp); + render_type(datum->trans->otype, p, fp); fprintf(fp, ";\n"); } if (key->specified & AVTAB_MEMBER) { diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c index c4ee2380..3f264594 100644 --- a/libsepol/cil/src/cil_binary.c +++ b/libsepol/cil/src/cil_binary.c @@ -975,28 +975,34 @@ static int __cil_insert_type_rule(policydb_t *pdb, uint32_t kind, uint32_t src, int rc = SEPOL_OK; avtab_key_t avtab_key; avtab_datum_t avtab_datum; + avtab_trans_t trans; avtab_ptr_t existing; avtab_key.source_type = src; avtab_key.target_type = tgt; avtab_key.target_class = obj; + memset(&avtab_datum, 0, sizeof(avtab_datum_t)); + memset(&trans, 0, sizeof(avtab_trans_t)); + switch (kind) { case CIL_TYPE_TRANSITION: avtab_key.specified = AVTAB_TRANSITION; + trans.otype = res; + avtab_datum.trans = &trans; break; case CIL_TYPE_CHANGE: avtab_key.specified = AVTAB_CHANGE; + avtab_datum.data = res; break; case CIL_TYPE_MEMBER: avtab_key.specified = AVTAB_MEMBER; + avtab_datum.data = res; break; default: rc = SEPOL_ERR; goto exit; } - - avtab_datum.data = res; existing = avtab_search_node(&pdb->te_avtab, &avtab_key); if (existing) { @@ -1004,13 +1010,17 @@ static int __cil_insert_type_rule(policydb_t *pdb, uint32_t kind, uint32_t src, * A warning should have been previously given if there is a * non-duplicate rule using the same key. */ - if (existing->datum.data != res) { + uint32_t existing_otype = + existing->key.specified & AVTAB_TRANSITION + ? existing->datum.trans->otype + : existing->datum.data; + if (existing_otype != res) { cil_log(CIL_ERR, "Conflicting type rules (scontext=%s tcontext=%s tclass=%s result=%s), existing=%s\n", pdb->p_type_val_to_name[src - 1], pdb->p_type_val_to_name[tgt - 1], pdb->p_class_val_to_name[obj - 1], pdb->p_type_val_to_name[res - 1], - pdb->p_type_val_to_name[existing->datum.data - 1]); + pdb->p_type_val_to_name[existing_otype - 1]); cil_log(CIL_ERR, "Expanded from type rule (scontext=%s tcontext=%s tclass=%s result=%s)\n", cil_rule->src_str, cil_rule->tgt_str, cil_rule->obj_str, cil_rule->result_str); rc = SEPOL_ERR; @@ -1037,13 +1047,17 @@ static int __cil_insert_type_rule(policydb_t *pdb, uint32_t kind, uint32_t src, search_datum = cil_cond_av_list_search(&avtab_key, other_list); if (search_datum == NULL) { - if (existing->datum.data != res) { + uint32_t existing_otype = + existing->key.specified & AVTAB_TRANSITION + ? existing->datum.trans->otype + : existing->datum.data; + if (existing_otype != res) { cil_log(CIL_ERR, "Conflicting type rules (scontext=%s tcontext=%s tclass=%s result=%s), existing=%s\n", pdb->p_type_val_to_name[src - 1], pdb->p_type_val_to_name[tgt - 1], pdb->p_class_val_to_name[obj - 1], pdb->p_type_val_to_name[res - 1], - pdb->p_type_val_to_name[existing->datum.data - 1]); + pdb->p_type_val_to_name[existing_otype - 1]); cil_log(CIL_ERR, "Expanded from type rule (scontext=%s tcontext=%s tclass=%s result=%s)\n", cil_rule->src_str, cil_rule->tgt_str, cil_rule->obj_str, cil_rule->result_str); rc = SEPOL_ERR; diff --git a/libsepol/include/sepol/policydb/avtab.h b/libsepol/include/sepol/policydb/avtab.h index e4c48576..ca009c16 100644 --- a/libsepol/include/sepol/policydb/avtab.h +++ b/libsepol/include/sepol/policydb/avtab.h @@ -70,6 +70,10 @@ typedef struct avtab_key { uint16_t specified; /* what fields are specified */ } avtab_key_t; +typedef struct avtab_trans { + uint32_t otype; /* resulting type of the new object */ +} avtab_trans_t; + typedef struct avtab_extended_perms { #define AVTAB_XPERMS_IOCTLFUNCTION 0x01 @@ -81,7 +85,8 @@ typedef struct avtab_extended_perms { } avtab_extended_perms_t; typedef struct avtab_datum { - uint32_t data; /* access vector or type */ + uint32_t data; /* access vector, member or change value */ + avtab_trans_t *trans; /* transition value */ avtab_extended_perms_t *xperms; } avtab_datum_t; diff --git a/libsepol/src/avtab.c b/libsepol/src/avtab.c index 82fec783..4c292e8b 100644 --- a/libsepol/src/avtab.c +++ b/libsepol/src/avtab.c @@ -94,6 +94,7 @@ avtab_insert_node(avtab_t * h, int hvalue, avtab_ptr_t prev, avtab_key_t * key, avtab_datum_t * datum) { avtab_ptr_t newnode; + avtab_trans_t *trans; avtab_extended_perms_t *xperms; newnode = (avtab_ptr_t) malloc(sizeof(struct avtab_node)); @@ -117,6 +118,16 @@ avtab_insert_node(avtab_t * h, int hvalue, avtab_ptr_t prev, avtab_key_t * key, * So copy data so it is set in the avtab */ newnode->datum.data = datum->data; + } else if (key->specified & AVTAB_TRANSITION) { + trans = calloc(1, sizeof(*trans)); + if (trans == NULL) { + free(newnode); + return NULL; + } + if (datum->trans) /* else caller populates transition */ + *trans = *(datum->trans); + + newnode->datum.trans = trans; } else { newnode->datum = *datum; } @@ -317,6 +328,8 @@ void avtab_destroy(avtab_t * h) while (cur != NULL) { if (cur->key.specified & AVTAB_XPERMS) { free(cur->datum.xperms); + } else if (cur->key.specified & AVTAB_TRANSITION) { + free(cur->datum.trans); } temp = cur; cur = cur->next; @@ -440,6 +453,7 @@ int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a, uint32_t buf32[8], items, items2, val; avtab_key_t key; avtab_datum_t datum; + avtab_trans_t trans; avtab_extended_perms_t xperms; unsigned set; unsigned int i; @@ -447,6 +461,7 @@ int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a, memset(&key, 0, sizeof(avtab_key_t)); memset(&datum, 0, sizeof(avtab_datum_t)); + memset(&trans, 0, sizeof(avtab_trans_t)); memset(&xperms, 0, sizeof(avtab_extended_perms_t)); if (vers < POLICYDB_VERSION_AVTAB) { @@ -509,7 +524,14 @@ int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a, return -1; } key.specified = spec_order[i] | enabled; - datum.data = le32_to_cpu(buf32[items++]); + if (key.specified & AVTAB_TRANSITION) { + trans.otype = + le32_to_cpu(buf32[items++]); + datum.trans = &trans; + } else { + datum.data = + le32_to_cpu(buf32[items++]); + } rc = insertf(a, &key, &datum, p); if (rc) return rc; @@ -571,6 +593,14 @@ int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a, for (i = 0; i < ARRAY_SIZE(xperms.perms); i++) xperms.perms[i] = le32_to_cpu(buf32[i]); datum.xperms = &xperms; + } else if (key.specified & AVTAB_TRANSITION) { + rc = next_entry(buf32, fp, sizeof(uint32_t)); + if (rc < 0) { + ERR(fp->handle, "truncated entry"); + return -1; + } + trans.otype = le32_to_cpu(*buf32); + datum.trans = &trans; } else { rc = next_entry(buf32, fp, sizeof(uint32_t)); if (rc < 0) { diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c index c08d3a35..065bfbcf 100644 --- a/libsepol/src/expand.c +++ b/libsepol/src/expand.c @@ -1746,7 +1746,7 @@ static int expand_terule_helper(sepol_handle_t * handle, if (conflict) { avdatump = &node->datum; if (specified & AVRULE_TRANSITION) { - oldtype = avdatump->data; + oldtype = avdatump->trans->otype; } else if (specified & AVRULE_MEMBER) { oldtype = avdatump->data; } else if (specified & AVRULE_CHANGE) { @@ -1789,7 +1789,11 @@ static int expand_terule_helper(sepol_handle_t * handle, } avdatump = &node->datum; - avdatump->data = remapped_data; + if (specified & AVRULE_TRANSITION) { + avdatump->trans->otype = remapped_data; + } else { + avdatump->data = remapped_data; + } cur = cur->next; } diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c index e9cd89c2..d80f4cae 100644 --- a/libsepol/src/kernel_to_cil.c +++ b/libsepol/src/kernel_to_cil.c @@ -1703,7 +1703,8 @@ static char *xperms_to_str(avtab_extended_perms_t *xperms) static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_datum_t *datum) { - uint32_t data = datum->data; + uint32_t data = key->specified & AVTAB_TRANSITION + ? datum->trans->otype : datum->data; type_datum_t *type; const char *flavor, *tgt; char *src, *class, *perms, *new; diff --git a/libsepol/src/kernel_to_conf.c b/libsepol/src/kernel_to_conf.c index c48a7114..edee311b 100644 --- a/libsepol/src/kernel_to_conf.c +++ b/libsepol/src/kernel_to_conf.c @@ -1681,7 +1681,8 @@ exit: static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_datum_t *datum) { - uint32_t data = datum->data; + uint32_t data = key->specified & AVTAB_TRANSITION + ? datum->trans->otype : datum->data; type_datum_t *type; const char *flavor, *src, *tgt, *class, *perms, *new; char *rule = NULL; diff --git a/libsepol/src/optimize.c b/libsepol/src/optimize.c index a38025ec..2d4a2d7a 100644 --- a/libsepol/src/optimize.c +++ b/libsepol/src/optimize.c @@ -308,6 +308,8 @@ static void optimize_avtab(policydb_t *p, const struct type_vec *type_map) *cur = tmp->next; if (tmp->key.specified & AVTAB_XPERMS) free(tmp->datum.xperms); + if (tmp->key.specified & AVTAB_TRANSITION) + free(tmp->datum.trans); free(tmp); tab->nel--; @@ -427,6 +429,8 @@ static void optimize_cond_avtab(policydb_t *p, const struct type_vec *type_map) *cur = tmp->next; if (tmp->key.specified & AVTAB_XPERMS) free(tmp->datum.xperms); + if (tmp->key.specified & AVTAB_TRANSITION) + free(tmp->datum.trans); free(tmp); tab->nel--; diff --git a/libsepol/src/policydb_validate.c b/libsepol/src/policydb_validate.c index 301aa200..519ab961 100644 --- a/libsepol/src/policydb_validate.c +++ b/libsepol/src/policydb_validate.c @@ -832,7 +832,9 @@ static int validate_avtab_key_and_datum(avtab_key_t *k, avtab_datum_t *d, void * if (validate_avtab_key(k, 0, margs->policy, margs->flavors)) return -1; - if ((k->specified & AVTAB_TYPE) && validate_simpletype(d->data, margs->policy, margs->flavors)) + uint32_t otype = k->specified & AVTAB_TRANSITION + ? d->trans->otype : d->data; + if ((k->specified & AVTAB_TYPE) && validate_simpletype(otype, margs->policy, margs->flavors)) return -1; if ((k->specified & AVTAB_XPERMS) && validate_xperms(d->xperms)) diff --git a/libsepol/src/services.c b/libsepol/src/services.c index 062510ab..72772dbd 100644 --- a/libsepol/src/services.c +++ b/libsepol/src/services.c @@ -1423,7 +1423,10 @@ static int sepol_compute_sid(sepol_security_id_t ssid, if (avdatum) { /* Use the type from the type transition/member/change rule. */ - newcontext.type = avdatum->data; + if (specified & AVTAB_TRANSITION) + newcontext.type = avdatum->trans->otype; + else + newcontext.type = avdatum->data; } /* Check for class-specific changes. */ diff --git a/libsepol/src/write.c b/libsepol/src/write.c index 024fe628..0d3d5f14 100644 --- a/libsepol/src/write.c +++ b/libsepol/src/write.c @@ -190,14 +190,20 @@ static int avtab_write_item(policydb_t * p, ERR(fp->handle, "missing node"); return POLICYDB_ERROR; } - buf32[items++] = - cpu_to_le32(node->datum.data); + uint32_t data = + node->key.specified & AVTAB_TRANSITION + ? node->datum.trans->otype + : node->datum.data; + buf32[items++] = cpu_to_le32(data); set--; node->merged = 1; } } } else { - buf32[items++] = cpu_to_le32(cur->datum.data); + uint32_t data = cur->key.specified & AVTAB_TRANSITION + ? cur->datum.trans->otype + : cur->datum.data; + buf32[items++] = cpu_to_le32(data); cur->merged = 1; set--; } @@ -256,6 +262,11 @@ static int avtab_write_item(policydb_t * p, items = put_entry(buf32, sizeof(uint32_t),8,fp); if (items != 8) return POLICYDB_ERROR; + } else if (cur->key.specified & AVTAB_TRANSITION) { + buf32[0] = cpu_to_le32(cur->datum.trans->otype); + items = put_entry(buf32, sizeof(uint32_t), 1, fp); + if (items != 1) + return POLICYDB_ERROR; } else { buf32[0] = cpu_to_le32(cur->datum.data); items = put_entry(buf32, sizeof(uint32_t), 1, fp); From patchwork Wed May 31 11:49:08 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juraj Marcin X-Patchwork-Id: 13262085 X-Patchwork-Delegate: plautrba@redhat.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3A80AC77B7C for ; Wed, 31 May 2023 11:50:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235406AbjEaLuW (ORCPT ); Wed, 31 May 2023 07:50:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48764 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235449AbjEaLuQ (ORCPT ); Wed, 31 May 2023 07:50:16 -0400 Received: from sender11-of-o52.zoho.eu (sender11-of-o52.zoho.eu [31.186.226.238]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6376B10F for ; Wed, 31 May 2023 04:50:10 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1685533804; cv=none; d=zohomail.eu; s=zohoarc; b=K+G9VIP3ZL1q8WL+hH5RCsT/2v0Usw1a9oiLhZQpNNKBtnrKoLX+xi0lHdmhQ8F7oJ9TIYhBbrTJkOcBMV8yN7rGdtWLoeLfCLtr6CoMqSJY7lXzlz8xjguzGV8vFJwY3PH34lxxu5x3XEKf9r0dg6/93ynosqHo2A4+RanEwWo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.eu; s=zohoarc; t=1685533804; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:To; bh=D8BHtWLaW7A8ks/sLfMFyBI8GbQRBcdJaoeYy5LGjdU=; b=c8DNoaN+NDzmic4Qx+tPyWbD6/5p34g4WRF97BnnouowkaZ9kH8sDuLRu8Iy9tVqiS4sQtZkdvRrdMQnmmz8JpCd9nTZcfB83b2RSMrYlIqjvr/pqpsF5RB6QOWxt0ojuab2ZIKNMgdY8+DMhZeT0FXVAR41dz7v9HD3vlohyJU= ARC-Authentication-Results: i=1; mx.zohomail.eu; dkim=pass header.i=jurajmarcin.com; spf=pass smtp.mailfrom=juraj@jurajmarcin.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1685533804; s=zoho; d=jurajmarcin.com; i=juraj@jurajmarcin.com; h=From:From:To:To:Cc:Cc:Subject:Subject:Date:Date:Message-Id:Message-Id:In-Reply-To:References:MIME-Version:Content-Transfer-Encoding:Reply-To; bh=D8BHtWLaW7A8ks/sLfMFyBI8GbQRBcdJaoeYy5LGjdU=; b=VyjB5iVSSPAoLe9TZCC3+9/q4T2EPYeTIVlgSm9vQClPAKNGHhWRVWfKWmqp2hig Ai9hEMkAvU3WN84ZMB2HTx1efpW8ntWRxjB8zRErZHuQjKhvOjLDOdOcgRllPhrrNfx CceLL1DaJGIqBWv5GDAyPwX8uSQeFBQv+tBTM464= Received: from morty01.jurajmarcin.com (129.159.244.31 [129.159.244.31]) by mx.zoho.eu with SMTPS id 1685533792862376.46193496474586; Wed, 31 May 2023 13:49:52 +0200 (CEST) Received: from jmarcin-t14s-01.redhat.com (unknown [147.251.183.113]) by morty01.jurajmarcin.com (Postfix) with ESMTPSA id E6AD02081F76; Wed, 31 May 2023 11:49:51 +0000 (UTC) From: Juraj Marcin To: selinux@vger.kernel.org Cc: Stephen Smalley , Ondrej Mosnacek Subject: [PATCH 2/8] checkpolicy, libsepol: move filename transitions to avtab Date: Wed, 31 May 2023 13:49:08 +0200 Message-Id: <20230531114914.2237609-3-juraj@jurajmarcin.com> In-Reply-To: <20230531114914.2237609-1-juraj@jurajmarcin.com> References: <20230531114914.2237609-1-juraj@jurajmarcin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org Currently, filename transitions are stored separately from other type enforcement rules. This leads to possibly sub-optimal performance and makes further improvements cumbersome. This patch adds a symbol table with filename transitions to the transition structure added to avtab in the previous patch. It also implements functions required for reading and writing filename transitions (either binary or source formats) and updates the code for expanding attributes. Last but not least, it updates the conflict check in the conditional avtab to account for empty transitions in the non-conditional avtab. These changes are expected to cause higher memory usage, as now there needs to be a filename transition structure for every stype. This patch effectively undoes most of the commit 42ae834a ("libsepol,checkpolicy: optimize storage of filename transitions"), but this will be mitigated by providing support for matching prefix/suffix of the filename for filename transitions in future patches which will reduce to need to have so many of them. Reviewed-by: Ondrej Mosnacek Signed-off-by: Juraj Marcin --- checkpolicy/checkmodule.c | 9 + checkpolicy/checkpolicy.c | 9 + checkpolicy/policy_define.c | 21 +- checkpolicy/test/dispol.c | 83 ++-- libsepol/cil/src/cil_binary.c | 27 +- libsepol/include/sepol/policydb/avtab.h | 9 + libsepol/include/sepol/policydb/hashtab.h | 6 + libsepol/include/sepol/policydb/policydb.h | 22 - libsepol/src/avtab.c | 197 +++++++++ libsepol/src/conditional.c | 6 +- libsepol/src/expand.c | 27 +- libsepol/src/kernel_to_cil.c | 159 ++----- libsepol/src/kernel_to_common.h | 9 + libsepol/src/kernel_to_conf.c | 155 ++----- libsepol/src/optimize.c | 8 +- libsepol/src/policydb.c | 343 +-------------- libsepol/src/policydb_validate.c | 69 ++- libsepol/src/write.c | 462 +++++++++++++++------ 18 files changed, 799 insertions(+), 822 deletions(-) diff --git a/checkpolicy/checkmodule.c b/checkpolicy/checkmodule.c index 3432608b..d68a56a1 100644 --- a/checkpolicy/checkmodule.c +++ b/checkpolicy/checkmodule.c @@ -275,6 +275,15 @@ int main(int argc, char **argv) modpolicydb.mls = mlspol; modpolicydb.handle_unknown = handle_unknown; + /* + * Init and alloc te_avtab for filename transition duplicate + * checking + */ + if (avtab_init(&modpolicydb.te_avtab)) + exit(1); + if (avtab_alloc(&modpolicydb.te_avtab, 1 << 11)) + exit(1); + if (read_source_policy(&modpolicydb, file, argv[0]) == -1) { exit(1); } diff --git a/checkpolicy/checkpolicy.c b/checkpolicy/checkpolicy.c index 2485142d..6e8ed833 100644 --- a/checkpolicy/checkpolicy.c +++ b/checkpolicy/checkpolicy.c @@ -611,6 +611,15 @@ int main(int argc, char **argv) parse_policy.mls = mlspol; parse_policy.handle_unknown = handle_unknown; + /* + * Init and alloc te_avtab for filename transition duplicate + * checking + */ + if (avtab_init(&parse_policy.te_avtab)) + exit(1); + if (avtab_alloc(&parse_policy.te_avtab, 1 << 11)) + exit(1); + policydbp = &parse_policy; if (read_source_policy(policydbp, file, "checkpolicy") < 0) diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c index d4e376ad..acc78baf 100644 --- a/checkpolicy/policy_define.c +++ b/checkpolicy/policy_define.c @@ -3341,6 +3341,7 @@ int define_filename_trans(void) ebitmap_node_t *snode, *tnode, *cnode; filename_trans_rule_t *ftr; type_datum_t *typdatum; + avtab_key_t avt_key; uint32_t otype; unsigned int c, s, t; int add, self, rc; @@ -3432,9 +3433,13 @@ int define_filename_trans(void) ebitmap_for_each_positive_bit(&e_tclasses, cnode, c) { ebitmap_for_each_positive_bit(&e_stypes, snode, s) { ebitmap_for_each_positive_bit(&e_ttypes, tnode, t) { - rc = policydb_filetrans_insert( - policydbp, s+1, t+1, c+1, name, - NULL, otype, NULL + avt_key.specified = AVTAB_TRANSITION; + avt_key.source_type = s + 1; + avt_key.target_type = t + 1; + avt_key.target_class = c + 1; + rc = avtab_insert_filename_trans( + &policydbp->te_avtab, &avt_key, otype, + name, NULL ); if (rc != SEPOL_OK) { if (rc == SEPOL_EEXIST) { @@ -3450,9 +3455,13 @@ int define_filename_trans(void) } } if (self) { - rc = policydb_filetrans_insert( - policydbp, s+1, s+1, c+1, name, - NULL, otype, NULL + avt_key.specified = AVTAB_TRANSITION; + avt_key.source_type = s + 1; + avt_key.target_type = t + 1; + avt_key.target_class = c + 1; + rc = avtab_insert_filename_trans( + &policydbp->te_avtab, &avt_key, otype, + name, NULL ); if (rc != SEPOL_OK) { if (rc == SEPOL_EEXIST) { diff --git a/checkpolicy/test/dispol.c b/checkpolicy/test/dispol.c index dea4f8da..4455407c 100644 --- a/checkpolicy/test/dispol.c +++ b/checkpolicy/test/dispol.c @@ -78,6 +78,26 @@ static int render_key(avtab_key_t * key, policydb_t * p, FILE * fp) return 0; } +typedef struct { + avtab_key_t *key; + policydb_t *p; + FILE *fp; +} render_name_trans_args_t; + +static int render_name_trans_helper(hashtab_key_t k, hashtab_datum_t d, void *a) +{ + char *name = k; + uint32_t *otype = d; + render_name_trans_args_t *args = a; + + fprintf(args->fp, "type_transition "); + render_key(args->key, args->p, args->fp); + render_type(*otype, args->p, args->fp); + fprintf(args->fp, " \"%s\";\n", name); + + return 0; +} + /* 'what' values for this function */ #define RENDER_UNCONDITIONAL 0x0001 /* render all regardless of enabled state */ #define RENDER_ENABLED 0x0002 @@ -130,10 +150,19 @@ static int render_av_rule(avtab_key_t * key, avtab_datum_t * datum, uint32_t wha } } else if (key->specified & AVTAB_TYPE) { if (key->specified & AVTAB_TRANSITION) { - fprintf(fp, "type_transition "); - render_key(key, p, fp); - render_type(datum->trans->otype, p, fp); - fprintf(fp, ";\n"); + if (datum->trans->otype) { + fprintf(fp, "type_transition "); + render_key(key, p, fp); + render_type(datum->trans->otype, p, fp); + fprintf(fp, ";\n"); + } + render_name_trans_args_t args = { + .key = key, + .p = p, + .fp = fp, + }; + hashtab_map(datum->trans->name_trans.table, + render_name_trans_helper, &args); } if (key->specified & AVTAB_MEMBER) { fprintf(fp, "type_member "); @@ -400,48 +429,6 @@ static void display_role_trans(policydb_t *p, FILE *fp) } } -struct filenametr_display_args { - policydb_t *p; - FILE *fp; -}; - -static int filenametr_display(hashtab_key_t key, - hashtab_datum_t datum, - void *ptr) -{ - struct filename_trans_key *ft = (struct filename_trans_key *)key; - struct filename_trans_datum *ftdatum = datum; - struct filenametr_display_args *args = ptr; - policydb_t *p = args->p; - FILE *fp = args->fp; - ebitmap_node_t *node; - uint32_t bit; - - do { - ebitmap_for_each_positive_bit(&ftdatum->stypes, node, bit) { - display_id(p, fp, SYM_TYPES, bit, ""); - display_id(p, fp, SYM_TYPES, ft->ttype - 1, ""); - display_id(p, fp, SYM_CLASSES, ft->tclass - 1, ":"); - display_id(p, fp, SYM_TYPES, ftdatum->otype - 1, ""); - fprintf(fp, " %s\n", ft->name); - } - ftdatum = ftdatum->next; - } while (ftdatum); - - return 0; -} - - -static void display_filename_trans(policydb_t *p, FILE *fp) -{ - struct filenametr_display_args args; - - fprintf(fp, "filename_trans rules:\n"); - args.p = p; - args.fp = fp; - hashtab_map(p->filename_trans, filenametr_display, &args); -} - static int menu(void) { printf("\nSelect a command:\n"); @@ -462,7 +449,6 @@ static int menu(void) printf("a) display type attributes\n"); printf("p) display the list of permissive types\n"); printf("u) display unknown handling setting\n"); - printf("F) display filename_trans rules\n"); printf("\n"); printf("f) set output file\n"); printf("m) display menu\n"); @@ -634,9 +620,6 @@ int main(int argc, char **argv) if (out_fp != stdout) printf("\nOutput to file: %s\n", OutfileName); break; - case 'F': - display_filename_trans(&policydb, out_fp); - break; case 'q': policydb_destroy(&policydb); exit(0); diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c index 3f264594..7150d405 100644 --- a/libsepol/cil/src/cil_binary.c +++ b/libsepol/cil/src/cil_binary.c @@ -1005,7 +1005,12 @@ static int __cil_insert_type_rule(policydb_t *pdb, uint32_t kind, uint32_t src, } existing = avtab_search_node(&pdb->te_avtab, &avtab_key); - if (existing) { + /* + * There might be empty transition node containing filename transitions + * only. That is okay, we can merge them later. + */ + if (existing && !(existing->key.specified & AVTAB_TRANSITION && + !existing->datum.trans->otype)) { /* Don't add duplicate type rule and warn if they conflict. * A warning should have been previously given if there is a * non-duplicate rule using the same key. @@ -1029,7 +1034,13 @@ static int __cil_insert_type_rule(policydb_t *pdb, uint32_t kind, uint32_t src, } if (!cond_node) { - rc = avtab_insert(&pdb->te_avtab, &avtab_key, &avtab_datum); + /* If we have node from empty filename transition, use it */ + if (existing && existing->key.specified & AVTAB_TRANSITION && + !existing->datum.trans->otype) + existing->datum.trans->otype = avtab_datum.trans->otype; + else + rc = avtab_insert(&pdb->te_avtab, &avtab_key, + &avtab_datum); } else { existing = avtab_search_node(&pdb->te_cond_avtab, &avtab_key); if (existing) { @@ -1189,16 +1200,18 @@ static int __cil_typetransition_to_avtab_helper(policydb_t *pdb, class_datum_t *sepol_obj = NULL; uint32_t otype; struct cil_list_item *c; + avtab_key_t avt_key; cil_list_for_each(c, class_list) { rc = __cil_get_sepol_class_datum(pdb, DATUM(c->data), &sepol_obj); if (rc != SEPOL_OK) return rc; - rc = policydb_filetrans_insert( - pdb, sepol_src->s.value, sepol_tgt->s.value, - sepol_obj->s.value, name, NULL, - sepol_result->s.value, &otype - ); + avt_key.specified = AVTAB_TRANSITION; + avt_key.source_type = sepol_src->s.value; + avt_key.target_type = sepol_tgt->s.value; + avt_key.target_class = sepol_obj->s.value; + rc = avtab_insert_filename_trans(&pdb->te_avtab, &avt_key, + sepol_result->s.value, name, &otype); if (rc != SEPOL_OK) { if (rc == SEPOL_EEXIST) { if (sepol_result->s.value!= otype) { diff --git a/libsepol/include/sepol/policydb/avtab.h b/libsepol/include/sepol/policydb/avtab.h index ca009c16..5dc720cc 100644 --- a/libsepol/include/sepol/policydb/avtab.h +++ b/libsepol/include/sepol/policydb/avtab.h @@ -42,6 +42,7 @@ #include #include +#include #ifdef __cplusplus extern "C" { @@ -72,6 +73,7 @@ typedef struct avtab_key { typedef struct avtab_trans { uint32_t otype; /* resulting type of the new object */ + symtab_t name_trans; /* filename transitions */ } avtab_trans_t; typedef struct avtab_extended_perms { @@ -115,6 +117,8 @@ extern int avtab_insert(avtab_t * h, avtab_key_t * k, avtab_datum_t * d); extern avtab_datum_t *avtab_search(avtab_t * h, avtab_key_t * k); +extern void avtab_trans_destroy(avtab_trans_t *trans); + extern void avtab_destroy(avtab_t * h); extern int avtab_map(const avtab_t * h, @@ -148,6 +152,11 @@ extern avtab_ptr_t avtab_search_node_next(avtab_ptr_t node, int specified); /* avtab_alloc uses one bucket per 2-4 elements, so adjust to get maximum buckets */ #define MAX_AVTAB_SIZE (MAX_AVTAB_HASH_BUCKETS << 1) +extern int avtab_insert_filename_trans(avtab_t *a, avtab_key_t *key, + uint32_t otype, const char *name, + uint32_t *present_otype); +extern int avtab_filename_trans_read(void *fp, uint32_t vers, avtab_t *a); + #ifdef __cplusplus } #endif diff --git a/libsepol/include/sepol/policydb/hashtab.h b/libsepol/include/sepol/policydb/hashtab.h index dca8c983..3a6b953e 100644 --- a/libsepol/include/sepol/policydb/hashtab.h +++ b/libsepol/include/sepol/policydb/hashtab.h @@ -110,6 +110,12 @@ extern int hashtab_map(hashtab_t h, extern void hashtab_hash_eval(hashtab_t h, char *tag); +/* Checks if the hashtab is empty (its size is zero) */ +static inline int hashtab_is_empty(hashtab_t h) +{ + return !h || !h->size; +} + #ifdef __cplusplus } #endif diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h index b014b7a8..8bb11d18 100644 --- a/libsepol/include/sepol/policydb/policydb.h +++ b/libsepol/include/sepol/policydb/policydb.h @@ -161,19 +161,6 @@ typedef struct role_allow { struct role_allow *next; } role_allow_t; -/* filename_trans rules */ -typedef struct filename_trans_key { - uint32_t ttype; - uint32_t tclass; - char *name; -} filename_trans_key_t; - -typedef struct filename_trans_datum { - ebitmap_t stypes; - uint32_t otype; - struct filename_trans_datum *next; -} filename_trans_datum_t; - /* Type attributes */ typedef struct type_datum { symtab_datum_t s; @@ -592,10 +579,6 @@ typedef struct policydb { /* range transitions table (range_trans_key -> mls_range) */ hashtab_t range_tr; - /* file transitions with the last path component */ - hashtab_t filename_trans; - uint32_t filename_trans_count; - ebitmap_t *type_attr_map; ebitmap_t *attr_type_map; /* not saved in the binary policy */ @@ -654,11 +637,6 @@ extern int policydb_load_isids(policydb_t * p, sidtab_t * s); extern int policydb_sort_ocontexts(policydb_t *p); -extern int policydb_filetrans_insert(policydb_t *p, uint32_t stype, - uint32_t ttype, uint32_t tclass, - const char *name, char **name_alloc, - uint32_t otype, uint32_t *present_otype); - /* Deprecated */ extern int policydb_context_isvalid(const policydb_t * p, const context_struct_t * c); diff --git a/libsepol/src/avtab.c b/libsepol/src/avtab.c index 4c292e8b..3d8d6769 100644 --- a/libsepol/src/avtab.c +++ b/libsepol/src/avtab.c @@ -315,6 +315,20 @@ avtab_ptr_t avtab_search_node_next(avtab_ptr_t node, int specified) return NULL; } +static int avtab_trans_destroy_helper(hashtab_key_t k, hashtab_datum_t d, + void *a __attribute__ ((unused))) +{ + free(k); + free(d); + return 0; +} + +void avtab_trans_destroy(avtab_trans_t *trans) +{ + hashtab_map(trans->name_trans.table, avtab_trans_destroy_helper, NULL); + symtab_destroy(&trans->name_trans); +} + void avtab_destroy(avtab_t * h) { unsigned int i; @@ -329,6 +343,7 @@ void avtab_destroy(avtab_t * h) if (cur->key.specified & AVTAB_XPERMS) { free(cur->datum.xperms); } else if (cur->key.specified & AVTAB_TRANSITION) { + avtab_trans_destroy(cur->datum.trans); free(cur->datum.trans); } temp = cur; @@ -660,3 +675,185 @@ int avtab_read(avtab_t * a, struct policy_file *fp, uint32_t vers) avtab_destroy(a); return -1; } + +/* policydb filename transition compatibility */ + +int avtab_insert_filename_trans(avtab_t *a, avtab_key_t *key, + uint32_t otype, const char *name, + uint32_t *present_otype) +{ + int rc = SEPOL_ENOMEM; + avtab_trans_t new_trans = {0}; + avtab_datum_t new_datum = {.trans = &new_trans}; + avtab_datum_t *datum; + avtab_ptr_t node; + char *name_key = NULL; + uint32_t *otype_datum = NULL; + + datum = avtab_search(a, key); + if (!datum) { + /* + * insert is actually unique, but with this function we can get + * the inserted node and therefore the datum + */ + node = avtab_insert_nonunique(a, key, &new_datum); + if (!node) + return SEPOL_ENOMEM; + datum = &node->datum; + } + + if (hashtab_is_empty(datum->trans->name_trans.table)) { + rc = symtab_init(&datum->trans->name_trans, 1 << 8); + if (rc < 0) + return rc; + } + + name_key = strdup(name); + if (!name_key) + goto bad; + + otype_datum = malloc(sizeof(*otype_datum)); + if (!otype_datum) + goto bad; + *otype_datum = otype; + + rc = hashtab_insert(datum->trans->name_trans.table, name_key, + otype_datum); + if (rc < 0) + goto bad; + + return SEPOL_OK; + +bad: + free(name_key); + free(otype_datum); + if (rc == SEPOL_EEXIST && present_otype) { + otype_datum = hashtab_search(datum->trans->name_trans.table, + name); + if (otype_datum) + *present_otype = *otype_datum; + } + return rc; +} + +static int filename_trans_read_one(avtab_t *a, void *fp) +{ + int rc; + uint32_t buf[4], len, otype; + char *name = NULL; + avtab_key_t key; + + /* read length of the name and the name */ + rc = next_entry(buf, fp, sizeof(uint32_t)); + if (rc < 0) + return SEPOL_ERR; + len = le32_to_cpu(*buf); + rc = str_read(&name, fp, len); + if (rc < 0) + return SEPOL_ERR; + + /* read stype, ttype, tclass and otype */ + rc = next_entry(buf, fp, sizeof(uint32_t) * 4); + if (rc < 0) + goto err; + + key.specified = AVTAB_TRANSITION; + key.source_type = le32_to_cpu(buf[0]); + key.target_type = le32_to_cpu(buf[1]); + key.target_class = le32_to_cpu(buf[2]); + otype = le32_to_cpu(buf[3]); + + rc = avtab_insert_filename_trans(a, &key, otype, name, NULL); + if (rc) + goto err; + + free(name); + return SEPOL_OK; +err: + free(name); + return SEPOL_ERR; +} + +static int filename_trans_comp_read_one(avtab_t *a, void *fp) +{ + int rc; + uint32_t buf[3], len, ndatum, i, bit, otype; + char *name = NULL; + avtab_key_t key; + ebitmap_t stypes; + ebitmap_node_t *node; + + /* read length of the name and the name */ + rc = next_entry(buf, fp, sizeof(uint32_t)); + if (rc < 0) + return SEPOL_ERR; + len = le32_to_cpu(*buf); + rc = str_read(&name, fp, len); + if (rc < 0) + return SEPOL_ERR; + + /* read ttype, tclass, ndatum */ + rc = next_entry(buf, fp, sizeof(uint32_t) * 3); + if (rc < 0) + goto err; + + key.specified = AVTAB_TRANSITION; + key.target_type = le32_to_cpu(buf[0]); + key.target_class = le32_to_cpu(buf[1]); + + ndatum = le32_to_cpu(buf[2]); + for (i = 0; i < ndatum; i++) { + rc = ebitmap_read(&stypes, fp); + if (rc < 0) + goto err; + + rc = next_entry(buf, fp, sizeof(uint32_t)); + if (rc < 0) + goto err_ebitmap; + otype = le32_to_cpu(*buf); + + ebitmap_for_each_positive_bit(&stypes, node, bit) { + key.source_type = bit + 1; + + rc = avtab_insert_filename_trans(a, &key, otype, name, + NULL); + if (rc < 0) + goto err_ebitmap; + } + } + + free(name); + return SEPOL_OK; + +err_ebitmap: + ebitmap_destroy(&stypes); +err: + free(name); + return rc; +} + +int avtab_filename_trans_read(void *fp, uint32_t vers, avtab_t *a) +{ + uint32_t buf[1], nel, i; + int rc; + + rc = next_entry(buf, fp, sizeof(uint32_t)); + if (rc < 0) + return rc; + nel = le32_to_cpu(*buf); + + if (vers < POLICYDB_VERSION_COMP_FTRANS) { + for (i = 0; i < nel; i++) { + rc = filename_trans_read_one(a, fp); + if (rc < 0) + return rc; + } + } else { + for (i = 0; i < nel; i++) { + rc = filename_trans_comp_read_one(a, fp); + if (rc < 0) + return rc; + } + } + return SEPOL_OK; +} diff --git a/libsepol/src/conditional.c b/libsepol/src/conditional.c index 24380ea0..7900e928 100644 --- a/libsepol/src/conditional.c +++ b/libsepol/src/conditional.c @@ -624,6 +624,7 @@ static int cond_insertf(avtab_t * a struct policydb *p = data->p; cond_av_list_t *other = data->other, *list, *cur; avtab_ptr_t node_ptr; + avtab_datum_t *existing; uint8_t found; /* @@ -632,7 +633,10 @@ static int cond_insertf(avtab_t * a * cond_te_avtab. */ if (k->specified & AVTAB_TYPE) { - if (avtab_search(&p->te_avtab, k)) { + existing = avtab_search(&p->te_avtab, k); + /* empty transition rule is not a conflict */ + if (existing && !(k->specified & AVTAB_TRANSITION + && !existing->trans->otype)) { WARN(NULL, "security: type rule already exists outside of a conditional."); return -1; } diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c index 065bfbcf..8ffe1c90 100644 --- a/libsepol/src/expand.c +++ b/libsepol/src/expand.c @@ -1413,14 +1413,17 @@ static int expand_filename_trans_helper(expand_state_t *state, { uint32_t mapped_otype, present_otype; int rc; + avtab_key_t avt_key; mapped_otype = state->typemap[rule->otype - 1]; - rc = policydb_filetrans_insert( - state->out, s + 1, t + 1, - rule->tclass, rule->name, - NULL, mapped_otype, &present_otype - ); + avt_key.specified = AVTAB_TRANSITION; + avt_key.source_type = s + 1; + avt_key.target_type = t + 1; + avt_key.target_class = rule->tclass; + + rc = avtab_insert_filename_trans(&state->out->te_avtab, &avt_key, + mapped_otype, rule->name, &present_otype); if (rc == SEPOL_EEXIST) { /* duplicate rule, ignore */ if (present_otype == mapped_otype) @@ -1734,6 +1737,16 @@ static int expand_terule_helper(sepol_handle_t * handle, * either in the global scope or in another * conditional AV tab */ node = avtab_search_node(&p->te_avtab, &avkey); + + /* + * if node does not already contain transition, it is not a + * conflict and transition otype will be set to node found by + * find_avtab_node() + */ + if (specified & AVRULE_TRANSITION && node && + !node->datum.trans->otype) + node = NULL; + if (node) { conflict = 1; } else { @@ -1741,6 +1754,10 @@ static int expand_terule_helper(sepol_handle_t * handle, if (node && node->parse_context != other) { conflict = 2; } + /* + * conditional avtab does not contain filename + * transitions, no need to check for otype == 0 + */ } if (conflict) { diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c index d80f4cae..655581ef 100644 --- a/libsepol/src/kernel_to_cil.c +++ b/libsepol/src/kernel_to_cil.c @@ -1701,14 +1701,24 @@ static char *xperms_to_str(avtab_extended_perms_t *xperms) return xpermsbuf; } -static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_datum_t *datum) +static int name_trans_to_strs_helper(hashtab_key_t k, hashtab_datum_t d, void *a) { - uint32_t data = key->specified & AVTAB_TRANSITION - ? datum->trans->otype : datum->data; + char *name = k; + uint32_t *otype = d; + name_trans_to_strs_args_t *args = a; + return strs_create_and_add(args->strs, "(%s %s %s %s \"%s\" %s)", 6, + args->flavor, args->src, args->tgt, + args->class, name, + args->pdb->p_type_val_to_name[*otype - 1]); +} + +static int avtab_node_to_strs(struct policydb *pdb, avtab_key_t *key, avtab_datum_t *datum, struct strs *strs) +{ + int rc = SEPOL_OK; + uint32_t data = datum->data; type_datum_t *type; const char *flavor, *tgt; char *src, *class, *perms, *new; - char *rule = NULL; switch (0xFFF & key->specified) { case AVTAB_ALLOWED: @@ -1741,7 +1751,7 @@ static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_dat break; default: sepol_log_err("Unknown avtab type: %i", key->specified); - goto exit; + return SEPOL_ERR; } src = pdb->p_type_val_to_name[key->source_type - 1]; @@ -1758,33 +1768,44 @@ static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_dat perms = sepol_av_to_string(pdb, key->target_class, data); if (perms == NULL) { sepol_log_err("Failed to generate permission string"); - goto exit; + return SEPOL_ERR; } - rule = create_str("(%s %s %s (%s (%s)))", 5, - flavor, src, tgt, class, perms+1); + rc = strs_create_and_add(strs, "(%s %s %s (%s (%s)))", 5, + flavor, src, tgt, class, perms + 1); } else if (key->specified & AVTAB_XPERMS) { perms = xperms_to_str(datum->xperms); if (perms == NULL) { sepol_log_err("Failed to generate extended permission string"); - goto exit; + return SEPOL_ERR; } - rule = create_str("(%s %s %s (%s %s (%s)))", 6, - flavor, src, tgt, "ioctl", class, perms); + rc = strs_create_and_add(strs, "(%s %s %s (%s %s (%s)))", 6, + flavor, src, tgt, "ioctl", class, perms); + } else if (key->specified & AVTAB_TRANSITION) { + if (datum->trans->otype) { + rc = strs_create_and_add(strs, "(%s %s %s %s %s)", 5, + flavor, src, tgt, class, + pdb->p_type_val_to_name[datum->trans->otype - 1]); + if (rc < 0) + return rc; + } + name_trans_to_strs_args_t args = { + .pdb = pdb, + .strs = strs, + .flavor = flavor, + .src = src, + .tgt = tgt, + .class = class, + }; + rc = hashtab_map(datum->trans->name_trans.table, + name_trans_to_strs_helper, &args); } else { new = pdb->p_type_val_to_name[data - 1]; - rule = create_str("(%s %s %s %s %s)", 5, flavor, src, tgt, class, new); - } - - if (!rule) { - goto exit; + rc = strs_create_and_add(strs, "(%s %s %s %s %s)", 5, flavor, src, tgt, class, new); } - return rule; - -exit: - return NULL; + return rc; } struct map_avtab_args { @@ -1799,23 +1820,12 @@ static int map_avtab_write_helper(avtab_key_t *key, avtab_datum_t *datum, void * uint32_t flavor = map_args->flavor; struct policydb *pdb = map_args->pdb; struct strs *strs = map_args->strs; - char *rule; int rc = 0; if (key->specified & flavor) { - rule = avtab_node_to_str(pdb, key, datum); - if (!rule) { - rc = -1; - goto exit; - } - rc = strs_add(strs, rule); - if (rc != 0) { - free(rule); - goto exit; - } + rc = avtab_node_to_strs(pdb, key, datum, strs); } -exit: return rc; } @@ -1869,77 +1879,6 @@ exit: return rc; } -struct map_filename_trans_args { - struct policydb *pdb; - struct strs *strs; -}; - -static int map_filename_trans_to_str(hashtab_key_t key, void *data, void *arg) -{ - filename_trans_key_t *ft = (filename_trans_key_t *)key; - filename_trans_datum_t *datum = data; - struct map_filename_trans_args *map_args = arg; - struct policydb *pdb = map_args->pdb; - struct strs *strs = map_args->strs; - char *src, *tgt, *class, *filename, *new; - struct ebitmap_node *node; - uint32_t bit; - int rc; - - tgt = pdb->p_type_val_to_name[ft->ttype - 1]; - class = pdb->p_class_val_to_name[ft->tclass - 1]; - filename = ft->name; - do { - new = pdb->p_type_val_to_name[datum->otype - 1]; - - ebitmap_for_each_positive_bit(&datum->stypes, node, bit) { - src = pdb->p_type_val_to_name[bit]; - rc = strs_create_and_add(strs, - "(typetransition %s %s %s \"%s\" %s)", - 5, src, tgt, class, filename, new); - if (rc) - return rc; - } - - datum = datum->next; - } while (datum); - - return 0; -} - -static int write_filename_trans_rules_to_cil(FILE *out, struct policydb *pdb) -{ - struct map_filename_trans_args args; - struct strs *strs; - int rc = 0; - - rc = strs_init(&strs, 100); - if (rc != 0) { - goto exit; - } - - args.pdb = pdb; - args.strs = strs; - - rc = hashtab_map(pdb->filename_trans, map_filename_trans_to_str, &args); - if (rc != 0) { - goto exit; - } - - strs_sort(strs); - strs_write_each(strs, out); - -exit: - strs_free_all(strs); - strs_destroy(&strs); - - if (rc != 0) { - sepol_log_err("Error writing filename typetransition rules to CIL\n"); - } - - return rc; -} - static char *level_to_str(struct policydb *pdb, struct mls_level *level) { ebitmap_t *cats = &level->cat; @@ -2059,7 +1998,6 @@ static int write_cond_av_list_to_cil(FILE *out, struct policydb *pdb, cond_av_li avtab_key_t *key; avtab_datum_t *datum; struct strs *strs; - char *rule; unsigned i; int rc; @@ -2075,14 +2013,8 @@ static int write_cond_av_list_to_cil(FILE *out, struct policydb *pdb, cond_av_li key = &node->key; datum = &node->datum; if (key->specified & flavor) { - rule = avtab_node_to_str(pdb, key, datum); - if (!rule) { - rc = -1; - goto exit; - } - rc = strs_add(strs, rule); + rc = avtab_node_to_strs(pdb, key, datum, strs); if (rc != 0) { - free(rule); goto exit; } } @@ -3330,11 +3262,6 @@ int sepol_kernel_policydb_to_cil(FILE *out, struct policydb *pdb) goto exit; } - rc = write_filename_trans_rules_to_cil(out, pdb); - if (rc != 0) { - goto exit; - } - if (pdb->mls) { rc = write_range_trans_rules_to_cil(out, pdb); if (rc != 0) { diff --git a/libsepol/src/kernel_to_common.h b/libsepol/src/kernel_to_common.h index 159c4289..eee2e1a0 100644 --- a/libsepol/src/kernel_to_common.h +++ b/libsepol/src/kernel_to_common.h @@ -83,6 +83,15 @@ struct strs { size_t size; }; +typedef struct { + policydb_t *pdb; + struct strs *strs; + const char *flavor; + const char *src; + const char *tgt; + const char *class; +} name_trans_to_strs_args_t; + __attribute__ ((format(printf, 1, 2))) void sepol_log_err(const char *fmt, ...); void sepol_indent(FILE *out, int indent); diff --git a/libsepol/src/kernel_to_conf.c b/libsepol/src/kernel_to_conf.c index edee311b..065f84eb 100644 --- a/libsepol/src/kernel_to_conf.c +++ b/libsepol/src/kernel_to_conf.c @@ -1679,13 +1679,24 @@ exit: return rc; } -static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_datum_t *datum) +static int name_trans_to_strs_helper(hashtab_key_t k, hashtab_datum_t d, void *a) { - uint32_t data = key->specified & AVTAB_TRANSITION - ? datum->trans->otype : datum->data; + char *name = k; + uint32_t *otype = d; + name_trans_to_strs_args_t *args = a; + return strs_create_and_add(args->strs, "%s %s %s:%s %s \"%s\";", 6, + args->flavor, args->src, args->tgt, + args->class, + args->pdb->p_type_val_to_name[*otype - 1], + name); +} + +static int avtab_node_to_strs(struct policydb *pdb, avtab_key_t *key, avtab_datum_t *datum, struct strs *strs) +{ + int rc = SEPOL_OK; + uint32_t data = datum->data; type_datum_t *type; const char *flavor, *src, *tgt, *class, *perms, *new; - char *rule = NULL; switch (0xFFF & key->specified) { case AVTAB_ALLOWED: @@ -1718,7 +1729,7 @@ static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_dat break; default: sepol_log_err("Unknown avtab type: %i", key->specified); - goto exit; + return SEPOL_ERR; } src = pdb->p_type_val_to_name[key->source_type - 1]; @@ -1735,32 +1746,42 @@ static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_dat perms = sepol_av_to_string(pdb, key->target_class, data); if (perms == NULL) { sepol_log_err("Failed to generate permission string"); - goto exit; + return SEPOL_ERR; } - rule = create_str("%s %s %s:%s { %s };", 5, - flavor, src, tgt, class, perms+1); + rc = strs_create_and_add(strs, "%s %s %s:%s { %s };", 5, + flavor, src, tgt, class, perms + 1); } else if (key->specified & AVTAB_XPERMS) { perms = sepol_extended_perms_to_string(datum->xperms); if (perms == NULL) { sepol_log_err("Failed to generate extended permission string"); - goto exit; + return SEPOL_ERR; + } + rc = strs_create_and_add(strs, "%s %s %s:%s %s;", 5, flavor, src, tgt, class, perms); + } else if (key->specified & AVTAB_TRANSITION) { + if (datum->trans->otype) { + rc = strs_create_and_add(strs, "%s %s %s:%s %s;", 5, + flavor, src, tgt, class, + pdb->p_type_val_to_name[datum->trans->otype - 1]); + if (rc < 0) + return rc; } - - rule = create_str("%s %s %s:%s %s;", 5, flavor, src, tgt, class, perms); + name_trans_to_strs_args_t args = { + .pdb = pdb, + .strs = strs, + .flavor = flavor, + .src = src, + .tgt = tgt, + .class = class, + }; + rc = hashtab_map(datum->trans->name_trans.table, + name_trans_to_strs_helper, &args); } else { new = pdb->p_type_val_to_name[data - 1]; - rule = create_str("%s %s %s:%s %s;", 5, flavor, src, tgt, class, new); + rc = strs_create_and_add(strs, "%s %s %s:%s %s;", 5, flavor, src, tgt, class, new); } - if (!rule) { - goto exit; - } - - return rule; - -exit: - return NULL; + return rc; } struct map_avtab_args { @@ -1775,23 +1796,12 @@ static int map_avtab_write_helper(avtab_key_t *key, avtab_datum_t *datum, void * uint32_t flavor = map_args->flavor; struct policydb *pdb = map_args->pdb; struct strs *strs = map_args->strs; - char *rule; int rc = 0; if (key->specified & flavor) { - rule = avtab_node_to_str(pdb, key, datum); - if (!rule) { - rc = -1; - goto exit; - } - rc = strs_add(strs, rule); - if (rc != 0) { - free(rule); - goto exit; - } + rc = avtab_node_to_strs(pdb, key, datum, strs); } -exit: return rc; } @@ -1845,77 +1855,6 @@ exit: return rc; } -struct map_filename_trans_args { - struct policydb *pdb; - struct strs *strs; -}; - -static int map_filename_trans_to_str(hashtab_key_t key, void *data, void *arg) -{ - filename_trans_key_t *ft = (filename_trans_key_t *)key; - filename_trans_datum_t *datum = data; - struct map_filename_trans_args *map_args = arg; - struct policydb *pdb = map_args->pdb; - struct strs *strs = map_args->strs; - char *src, *tgt, *class, *filename, *new; - struct ebitmap_node *node; - uint32_t bit; - int rc; - - tgt = pdb->p_type_val_to_name[ft->ttype - 1]; - class = pdb->p_class_val_to_name[ft->tclass - 1]; - filename = ft->name; - do { - new = pdb->p_type_val_to_name[datum->otype - 1]; - - ebitmap_for_each_positive_bit(&datum->stypes, node, bit) { - src = pdb->p_type_val_to_name[bit]; - rc = strs_create_and_add(strs, - "type_transition %s %s:%s %s \"%s\";", - 5, src, tgt, class, new, filename); - if (rc) - return rc; - } - - datum = datum->next; - } while (datum); - - return 0; -} - -static int write_filename_trans_rules_to_conf(FILE *out, struct policydb *pdb) -{ - struct map_filename_trans_args args; - struct strs *strs; - int rc = 0; - - rc = strs_init(&strs, 100); - if (rc != 0) { - goto exit; - } - - args.pdb = pdb; - args.strs = strs; - - rc = hashtab_map(pdb->filename_trans, map_filename_trans_to_str, &args); - if (rc != 0) { - goto exit; - } - - strs_sort(strs); - strs_write_each(strs, out); - -exit: - strs_free_all(strs); - strs_destroy(&strs); - - if (rc != 0) { - sepol_log_err("Error writing filename typetransition rules to policy.conf\n"); - } - - return rc; -} - static char *level_to_str(struct policydb *pdb, struct mls_level *level) { ebitmap_t *cats = &level->cat; @@ -2035,7 +1974,6 @@ static int write_cond_av_list_to_conf(FILE *out, struct policydb *pdb, cond_av_l avtab_key_t *key; avtab_datum_t *datum; struct strs *strs; - char *rule; unsigned i; int rc; @@ -2051,14 +1989,8 @@ static int write_cond_av_list_to_conf(FILE *out, struct policydb *pdb, cond_av_l key = &node->key; datum = &node->datum; if (key->specified & flavor) { - rule = avtab_node_to_str(pdb, key, datum); - if (!rule) { - rc = -1; - goto exit; - } - rc = strs_add(strs, rule); + rc = avtab_node_to_strs(pdb, key, datum, strs); if (rc != 0) { - free(rule); goto exit; } } @@ -3206,7 +3138,6 @@ int sepol_kernel_policydb_to_conf(FILE *out, struct policydb *pdb) if (rc != 0) { goto exit; } - write_filename_trans_rules_to_conf(out, pdb); if (pdb->mls) { rc = write_range_trans_rules_to_conf(out, pdb); diff --git a/libsepol/src/optimize.c b/libsepol/src/optimize.c index 2d4a2d7a..7948d983 100644 --- a/libsepol/src/optimize.c +++ b/libsepol/src/optimize.c @@ -308,8 +308,10 @@ static void optimize_avtab(policydb_t *p, const struct type_vec *type_map) *cur = tmp->next; if (tmp->key.specified & AVTAB_XPERMS) free(tmp->datum.xperms); - if (tmp->key.specified & AVTAB_TRANSITION) + if (tmp->key.specified & AVTAB_TRANSITION) { + avtab_trans_destroy(tmp->datum.trans); free(tmp->datum.trans); + } free(tmp); tab->nel--; @@ -429,8 +431,10 @@ static void optimize_cond_avtab(policydb_t *p, const struct type_vec *type_map) *cur = tmp->next; if (tmp->key.specified & AVTAB_XPERMS) free(tmp->datum.xperms); - if (tmp->key.specified & AVTAB_TRANSITION) + if (tmp->key.specified & AVTAB_TRANSITION) { + avtab_trans_destroy(tmp->datum.trans); free(tmp->datum.trans); + } free(tmp); tab->nel--; diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c index b79c19b9..91836183 100644 --- a/libsepol/src/policydb.c +++ b/libsepol/src/policydb.c @@ -801,47 +801,6 @@ static int roles_init(policydb_t * p) goto out; } -ignore_unsigned_overflow_ -static inline unsigned long -partial_name_hash(unsigned long c, unsigned long prevhash) -{ - return (prevhash + (c << 4) + (c >> 4)) * 11; -} - -static unsigned int filenametr_hash(hashtab_t h, const_hashtab_key_t k) -{ - const filename_trans_key_t *ft = (const filename_trans_key_t *)k; - unsigned long hash; - unsigned int byte_num; - unsigned char focus; - - hash = ft->ttype ^ ft->tclass; - - byte_num = 0; - while ((focus = ft->name[byte_num++])) - hash = partial_name_hash(focus, hash); - return hash & (h->size - 1); -} - -static int filenametr_cmp(hashtab_t h __attribute__ ((unused)), - const_hashtab_key_t k1, const_hashtab_key_t k2) -{ - const filename_trans_key_t *ft1 = (const filename_trans_key_t *)k1; - const filename_trans_key_t *ft2 = (const filename_trans_key_t *)k2; - int v; - - v = spaceship_cmp(ft1->ttype, ft2->ttype); - if (v) - return v; - - v = spaceship_cmp(ft1->tclass, ft2->tclass); - if (v) - return v; - - return strcmp(ft1->name, ft2->name); - -} - static unsigned int rangetr_hash(hashtab_t h, const_hashtab_key_t k) { const struct range_trans *key = (const struct range_trans *)k; @@ -909,12 +868,6 @@ int policydb_init(policydb_t * p) if (rc) goto err; - p->filename_trans = hashtab_create(filenametr_hash, filenametr_cmp, (1 << 10)); - if (!p->filename_trans) { - rc = -ENOMEM; - goto err; - } - p->range_tr = hashtab_create(rangetr_hash, rangetr_cmp, 256); if (!p->range_tr) { rc = -ENOMEM; @@ -926,7 +879,6 @@ int policydb_init(policydb_t * p) return 0; err: - hashtab_destroy(p->filename_trans); hashtab_destroy(p->range_tr); for (i = 0; i < SYM_NUM; i++) { hashtab_destroy(p->symtab[i].table); @@ -1412,23 +1364,6 @@ static int (*destroy_f[SYM_NUM]) (hashtab_key_t key, hashtab_datum_t datum, common_destroy, class_destroy, role_destroy, type_destroy, user_destroy, cond_destroy_bool, sens_destroy, cat_destroy,}; -static int filenametr_destroy(hashtab_key_t key, hashtab_datum_t datum, - void *p __attribute__ ((unused))) -{ - filename_trans_key_t *ft = (filename_trans_key_t *)key; - filename_trans_datum_t *fd = datum, *next; - - free(ft->name); - free(key); - do { - next = fd->next; - ebitmap_destroy(&fd->stypes); - free(fd); - fd = next; - } while (fd); - return 0; -} - static int range_tr_destroy(hashtab_key_t key, hashtab_datum_t datum, void *p __attribute__ ((unused))) { @@ -1564,9 +1499,6 @@ void policydb_destroy(policydb_t * p) if (lra) free(lra); - hashtab_map(p->filename_trans, filenametr_destroy, NULL); - hashtab_destroy(p->filename_trans); - hashtab_map(p->range_tr, range_tr_destroy, NULL); hashtab_destroy(p->range_tr); @@ -2596,279 +2528,6 @@ static int role_allow_read(role_allow_t ** r, struct policy_file *fp) return 0; } -int policydb_filetrans_insert(policydb_t *p, uint32_t stype, uint32_t ttype, - uint32_t tclass, const char *name, - char **name_alloc, uint32_t otype, - uint32_t *present_otype) -{ - filename_trans_key_t *ft, key; - filename_trans_datum_t *datum, *last; - - key.ttype = ttype; - key.tclass = tclass; - key.name = (char *)name; - - last = NULL; - datum = hashtab_search(p->filename_trans, (hashtab_key_t)&key); - while (datum) { - if (ebitmap_get_bit(&datum->stypes, stype - 1)) { - if (present_otype) - *present_otype = datum->otype; - return SEPOL_EEXIST; - } - if (datum->otype == otype) - break; - last = datum; - datum = datum->next; - } - if (!datum) { - datum = malloc(sizeof(*datum)); - if (!datum) - return SEPOL_ENOMEM; - - ebitmap_init(&datum->stypes); - datum->otype = otype; - datum->next = NULL; - - if (last) { - last->next = datum; - } else { - char *name_dup; - - if (name_alloc) { - name_dup = *name_alloc; - *name_alloc = NULL; - } else { - name_dup = strdup(name); - if (!name_dup) { - free(datum); - return SEPOL_ENOMEM; - } - } - - ft = malloc(sizeof(*ft)); - if (!ft) { - free(name_dup); - free(datum); - return SEPOL_ENOMEM; - } - - ft->ttype = ttype; - ft->tclass = tclass; - ft->name = name_dup; - - if (hashtab_insert(p->filename_trans, (hashtab_key_t)ft, - (hashtab_datum_t)datum)) { - free(name_dup); - free(datum); - free(ft); - return SEPOL_ENOMEM; - } - } - } - - p->filename_trans_count++; - return ebitmap_set_bit(&datum->stypes, stype - 1, 1); -} - -static int filename_trans_read_one_compat(policydb_t *p, struct policy_file *fp) -{ - uint32_t buf[4], len, stype, ttype, tclass, otype; - char *name = NULL; - int rc; - - rc = next_entry(buf, fp, sizeof(uint32_t)); - if (rc < 0) - return -1; - len = le32_to_cpu(buf[0]); - if (zero_or_saturated(len)) - return -1; - - name = calloc(len + 1, sizeof(*name)); - if (!name) - return -1; - - rc = next_entry(name, fp, len); - if (rc < 0) - goto err; - - rc = next_entry(buf, fp, sizeof(uint32_t) * 4); - if (rc < 0) - goto err; - - stype = le32_to_cpu(buf[0]); - if (stype == 0) - goto err; - - ttype = le32_to_cpu(buf[1]); - tclass = le32_to_cpu(buf[2]); - otype = le32_to_cpu(buf[3]); - - rc = policydb_filetrans_insert(p, stype, ttype, tclass, name, &name, - otype, NULL); - if (rc) { - if (rc != SEPOL_EEXIST) - goto err; - /* - * Some old policies were wrongly generated with - * duplicate filename transition rules. For backward - * compatibility, do not reject such policies, just - * ignore the duplicate. - */ - } - free(name); - return 0; -err: - free(name); - return -1; -} - -static int filename_trans_check_datum(filename_trans_datum_t *datum) -{ - ebitmap_t stypes, otypes; - int rc = -1; - - ebitmap_init(&stypes); - ebitmap_init(&otypes); - - while (datum) { - if (ebitmap_get_bit(&otypes, datum->otype)) - goto out; - - if (ebitmap_set_bit(&otypes, datum->otype, 1)) - goto out; - - if (ebitmap_match_any(&stypes, &datum->stypes)) - goto out; - - if (ebitmap_union(&stypes, &datum->stypes)) - goto out; - - datum = datum->next; - } - rc = 0; -out: - ebitmap_destroy(&stypes); - ebitmap_destroy(&otypes); - return rc; -} - -static int filename_trans_read_one(policydb_t *p, struct policy_file *fp) -{ - filename_trans_key_t *ft = NULL; - filename_trans_datum_t **dst, *datum, *first = NULL; - unsigned int i; - uint32_t buf[3], len, ttype, tclass, ndatum; - char *name = NULL; - int rc; - - rc = next_entry(buf, fp, sizeof(uint32_t)); - if (rc < 0) - return -1; - len = le32_to_cpu(buf[0]); - if (zero_or_saturated(len)) - return -1; - - name = calloc(len + 1, sizeof(*name)); - if (!name) - return -1; - - rc = next_entry(name, fp, len); - if (rc < 0) - goto err; - - rc = next_entry(buf, fp, sizeof(uint32_t) * 3); - if (rc < 0) - goto err; - - ttype = le32_to_cpu(buf[0]); - tclass = le32_to_cpu(buf[1]); - ndatum = le32_to_cpu(buf[2]); - if (ndatum == 0) - goto err; - - dst = &first; - for (i = 0; i < ndatum; i++) { - datum = malloc(sizeof(*datum)); - if (!datum) - goto err; - - datum->next = NULL; - *dst = datum; - - /* ebitmap_read() will at least init the bitmap */ - rc = ebitmap_read(&datum->stypes, fp); - if (rc < 0) - goto err; - - rc = next_entry(buf, fp, sizeof(uint32_t)); - if (rc < 0) - goto err; - - datum->otype = le32_to_cpu(buf[0]); - - p->filename_trans_count += ebitmap_cardinality(&datum->stypes); - - dst = &datum->next; - } - - if (ndatum > 1 && filename_trans_check_datum(first)) - goto err; - - ft = malloc(sizeof(*ft)); - if (!ft) - goto err; - - ft->ttype = ttype; - ft->tclass = tclass; - ft->name = name; - - rc = hashtab_insert(p->filename_trans, (hashtab_key_t)ft, - (hashtab_datum_t)first); - if (rc) - goto err; - - return 0; -err: - free(ft); - free(name); - while (first) { - datum = first; - first = first->next; - - ebitmap_destroy(&datum->stypes); - free(datum); - } - return -1; -} - -static int filename_trans_read(policydb_t *p, struct policy_file *fp) -{ - unsigned int i; - uint32_t buf[1], nel; - int rc; - - rc = next_entry(buf, fp, sizeof(uint32_t)); - if (rc < 0) - return -1; - nel = le32_to_cpu(buf[0]); - - if (p->policyvers < POLICYDB_VERSION_COMP_FTRANS) { - for (i = 0; i < nel; i++) { - rc = filename_trans_read_one_compat(p, fp); - if (rc < 0) - return -1; - } - } else { - for (i = 0; i < nel; i++) { - rc = filename_trans_read_one(p, fp); - if (rc < 0) - return -1; - } - } - return 0; -} - static int ocontext_read_xen(const struct policydb_compat_info *info, policydb_t *p, struct policy_file *fp) { @@ -4470,7 +4129,7 @@ int policydb_read(policydb_t * p, struct policy_file *fp, unsigned verbose) if (role_allow_read(&p->role_allow, fp)) goto bad; if (r_policyvers >= POLICYDB_VERSION_FILENAME_TRANS && - filename_trans_read(p, fp)) + avtab_filename_trans_read(fp, r_policyvers, &p->te_avtab)) goto bad; } else { /* first read the AV rule blocks, then the scope tables */ diff --git a/libsepol/src/policydb_validate.c b/libsepol/src/policydb_validate.c index 519ab961..e7af3fb8 100644 --- a/libsepol/src/policydb_validate.c +++ b/libsepol/src/policydb_validate.c @@ -825,6 +825,18 @@ static int validate_xperms(const avtab_extended_perms_t *xperms) bad: return -1; } + +static int validate_name_trans_helper(hashtab_key_t k __attribute__ ((unused)), + hashtab_datum_t d, void *a) +{ + uint32_t *otype = d; + map_arg_t *margs = a; + + if (validate_simpletype(*otype, margs->policy, margs->flavors)) + return -1; + return 0; +} + static int validate_avtab_key_and_datum(avtab_key_t *k, avtab_datum_t *d, void *args) { map_arg_t *margs = args; @@ -832,10 +844,23 @@ static int validate_avtab_key_and_datum(avtab_key_t *k, avtab_datum_t *d, void * if (validate_avtab_key(k, 0, margs->policy, margs->flavors)) return -1; - uint32_t otype = k->specified & AVTAB_TRANSITION - ? d->trans->otype : d->data; - if ((k->specified & AVTAB_TYPE) && validate_simpletype(otype, margs->policy, margs->flavors)) + if (k->specified & AVTAB_TRANSITION) { + /* if otype is set (non-zero), it must by a valid simple type */ + if (d->trans->otype && validate_simpletype(d->trans->otype, margs->policy, margs->flavors)) + return -1; + + /* also each transition must be non empty */ + if (!d->trans->otype && + (!d->trans->name_trans.table || !d->trans->name_trans.table->nel)) + return -1; + + /* and each filename transition must be also valid */ + if (hashtab_map(d->trans->name_trans.table, + validate_name_trans_helper, margs)) + return -1; + } else if ((k->specified & AVTAB_TYPE) && validate_simpletype(d->data, margs->policy, margs->flavors)) { return -1; + } if ((k->specified & AVTAB_XPERMS) && validate_xperms(d->xperms)) return -1; @@ -1086,41 +1111,6 @@ bad: return -1; } -static int validate_filename_trans(hashtab_key_t k, hashtab_datum_t d, void *args) -{ - const filename_trans_key_t *ftk = (filename_trans_key_t *)k; - const filename_trans_datum_t *ftd = d; - validate_t *flavors = (validate_t *)args; - - if (validate_value(ftk->ttype, &flavors[SYM_TYPES])) - goto bad; - if (validate_value(ftk->tclass, &flavors[SYM_CLASSES])) - goto bad; - if (!ftd) - goto bad; - for (; ftd; ftd = ftd->next) { - if (validate_ebitmap(&ftd->stypes, &flavors[SYM_TYPES])) - goto bad; - if (validate_value(ftd->otype, &flavors[SYM_TYPES])) - goto bad; - } - - return 0; - -bad: - return -1; -} - -static int validate_filename_trans_hashtab(sepol_handle_t *handle, hashtab_t filename_trans, validate_t flavors[]) -{ - if (hashtab_map(filename_trans, validate_filename_trans, flavors)) { - ERR(handle, "Invalid filename trans"); - return -1; - } - - return 0; -} - static int validate_context(const context_struct_t *con, validate_t flavors[], int mls) { if (validate_value(con->user, &flavors[SYM_USERS])) @@ -1520,9 +1510,6 @@ int policydb_validate(sepol_handle_t *handle, const policydb_t *p) goto bad; if (validate_role_allows(handle, p->role_allow, flavors)) goto bad; - if (p->policyvers >= POLICYDB_VERSION_FILENAME_TRANS) - if (validate_filename_trans_hashtab(handle, p->filename_trans, flavors)) - goto bad; } else { if (validate_avrule_blocks(handle, p->global, p, flavors)) goto bad; diff --git a/libsepol/src/write.c b/libsepol/src/write.c index 0d3d5f14..7f580685 100644 --- a/libsepol/src/write.c +++ b/libsepol/src/write.c @@ -116,6 +116,14 @@ static int avtab_write_item(policydb_t * p, && p->policyvers < POLICYDB_VERSION_AVTAB); unsigned int i; + /* skip entries which only contain filename transitions */ + if (cur->key.specified & AVTAB_TRANSITION && !cur->datum.trans->otype) { + /* if oldvers, reduce nel, because this node will be skipped */ + if (oldvers && nel) + (*nel)--; + return 0; + } + if (oldvers) { /* Generate the old avtab format. Requires merging similar entries if uncond avtab. */ @@ -313,8 +321,23 @@ static int avtab_write(struct policydb *p, avtab_t * a, struct policy_file *fp) avtab_reset_merged(a); nel = a->nel; } else { - /* New avtab format. nel is good to go. */ - nel = cpu_to_le32(a->nel); + /* + * New avtab format. nel is good to go unless we need to skip + * filename transitions. + */ + nel = a->nel; + /* + * entries containing only filename transitions are skipped and + * written out later + */ + for (i = 0; i < a->nslot; i++) { + for (cur = a->htable[i]; cur; cur = cur->next) { + if (cur->key.specified & AVTAB_TRANSITION && + !cur->datum.trans->otype) + nel--; + } + } + nel = cpu_to_le32(nel); items = put_entry(&nel, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; @@ -358,6 +381,306 @@ static int avtab_write(struct policydb *p, avtab_t * a, struct policy_file *fp) return rc; } +/* policydb filename transition compatibility */ + +typedef struct filenametr_key { + uint32_t ttype; + uint32_t tclass; + char *name; +} filenametr_key_t; + +typedef struct filenametr_datum { + ebitmap_t stypes; + uint32_t otype; + struct filenametr_datum *next; +} filenametr_datum_t; + +ignore_unsigned_overflow_ +static inline unsigned long +partial_name_hash(unsigned long c, unsigned long prevhash) +{ + return (prevhash + (c << 4) + (c >> 4)) * 11; +} + +static unsigned int filenametr_hash(hashtab_t h, const_hashtab_key_t k) +{ + const filenametr_key_t *ft = (const filenametr_key_t *)k; + unsigned long hash; + unsigned int byte_num; + unsigned char focus; + + hash = ft->ttype ^ ft->tclass; + + byte_num = 0; + while ((focus = ft->name[byte_num++])) + hash = partial_name_hash(focus, hash); + return hash & (h->size - 1); +} + +static int filenametr_cmp(hashtab_t h __attribute__ ((unused)), + const_hashtab_key_t k1, const_hashtab_key_t k2) +{ + const filenametr_key_t *ft1 = (const filenametr_key_t *)k1; + const filenametr_key_t *ft2 = (const filenametr_key_t *)k2; + int v; + + v = spaceship_cmp(ft1->ttype, ft2->ttype); + if (v) + return v; + + v = spaceship_cmp(ft1->tclass, ft2->tclass); + if (v) + return v; + + return strcmp(ft1->name, ft2->name); +} + +static int filenametr_destroy(hashtab_key_t key, hashtab_datum_t datum, + void *p __attribute__ ((unused))) +{ + filenametr_datum_t *fd = datum, *next; + + free(key); + do { + next = fd->next; + ebitmap_destroy(&fd->stypes); + free(fd); + fd = next; + } while (fd); + return 0; +} + +typedef struct { + void *fp; + avtab_key_t *key; +} name_trans_write_args_t; + +static int name_trans_write_helper(hashtab_key_t k, hashtab_datum_t d, void *a) +{ + char *name = k; + uint32_t *otype = d; + name_trans_write_args_t *args = a; + size_t items; + uint32_t len, buf[4]; + + len = strlen(name); + buf[0] = cpu_to_le32(len); + items = put_entry(buf, sizeof(uint32_t), 1, args->fp); + if (items != 1) + return -1; + + items = put_entry(name, sizeof(char), len,args-> fp); + if (items != len) + return -1; + + buf[0] = cpu_to_le32(args->key->source_type); + buf[1] = cpu_to_le32(args->key->target_type); + buf[2] = cpu_to_le32(args->key->target_class); + buf[3] = cpu_to_le32(*otype); + + items = put_entry(buf, sizeof(uint32_t), 4, args->fp); + if (items != 4) + return -1; + return 0; +} + +typedef struct { + hashtab_t fnts_tab; + avtab_key_t *av_key; +} name_trans_insert_args_t; + +static int name_trans_insert_helper(hashtab_key_t k, hashtab_datum_t d, void *a) +{ + char *name = k; + uint32_t *otype = d; + name_trans_insert_args_t *args = a; + filenametr_key_t key, *ft = NULL; + filenametr_datum_t *last, *datum = NULL; + int rc; + + key.ttype = args->av_key->target_type; + key.tclass = args->av_key->target_class; + key.name = name; + + last = NULL; + datum = hashtab_search(args->fnts_tab, (hashtab_key_t)&key); + while (datum) { + if (ebitmap_get_bit(&datum->stypes, args->av_key->source_type - 1)) { + datum = NULL; + goto bad; + } + if (datum->otype == *otype) + break; + last = datum; + datum = datum->next; + } + if (!datum) { + datum = malloc(sizeof(filenametr_datum_t)); + if (!datum) + goto bad; + + ebitmap_init(&datum->stypes); + datum->otype = *otype; + datum->next = NULL; + + if (last) { + last->next = datum; + } else { + ft = malloc(sizeof(filenametr_key_t)); + if (!ft) + goto bad; + + ft->ttype = args->av_key->target_type; + ft->tclass = args->av_key->target_class; + ft->name = strdup(name); + if (!ft->name) + goto bad; + + rc = hashtab_insert(args->fnts_tab, (hashtab_key_t)ft, datum); + if (rc) + goto bad; + } + } + + return ebitmap_set_bit(&datum->stypes, args->av_key->source_type - 1, 1); + +bad: + if (ft != NULL) + free(ft->name); + free(ft); + free(datum); + return -1; +} + +static int filenametr_comp_write_one(hashtab_key_t key, void *data, void *ptr) +{ + uint32_t buf[3]; + size_t items, len, ndatum; + filenametr_key_t *ft = (filenametr_key_t *)key; + filenametr_datum_t *datum; + void *fp = ptr; + + len = strlen(ft->name); + buf[0] = cpu_to_le32(len); + items = put_entry(buf, sizeof(uint32_t), 1, fp); + if (items != 1) + return POLICYDB_ERROR; + + items = put_entry(ft->name, sizeof(char), len, fp); + if (items != len) + return POLICYDB_ERROR; + + ndatum = 0; + datum = data; + do { + ndatum++; + datum = datum->next; + } while (datum); + + buf[0] = cpu_to_le32(ft->ttype); + buf[1] = cpu_to_le32(ft->tclass); + buf[2] = cpu_to_le32(ndatum); + items = put_entry(buf, sizeof(uint32_t), 3, fp); + if (items != 3) + return POLICYDB_ERROR; + + datum = data; + do { + if (ebitmap_write(&datum->stypes, fp)) + return POLICYDB_ERROR; + + buf[0] = cpu_to_le32(datum->otype); + items = put_entry(buf, sizeof(uint32_t), 1, fp); + if (items != 1) + return POLICYDB_ERROR; + + datum = datum->next; + } while (datum); + + return 0; +} + +static int avtab_filename_trans_write(policydb_t *pol, avtab_t *a, + policy_file_t *fp) +{ + policydb_t *p = pol; + uint32_t buf[1]; + int rc; + size_t items; + uint32_t i, nel = 0; + struct avtab_node *cur; + hashtab_t fnts_tab; + name_trans_write_args_t write_args = { .fp = fp }; + name_trans_insert_args_t insert_args; + + /* count number of filename transitions */ + for (i = 0; i < a->nslot; i++) { + for (cur = a->htable[i]; cur; cur = cur->next) { + if (cur->key.specified & AVTAB_TRANSITION && + cur->datum.trans->name_trans.table) { + nel += cur->datum.trans->name_trans.table->nel; + } + } + } + + if (p->policyvers < POLICYDB_VERSION_COMP_FTRANS) { + buf[0] = cpu_to_le32(nel); + items = put_entry(buf, sizeof(uint32_t), 1, fp); + if (items != 1) + return -1; + + /* write filename transitions */ + for (i = 0; i < a->nslot; i++) { + for (cur = a->htable[i]; cur; cur = cur->next) { + if (cur->key.specified & AVTAB_TRANSITION) { + write_args.key = &cur->key; + rc = hashtab_map(cur->datum.trans->name_trans.table, + name_trans_write_helper, + &write_args); + if (rc) + return -1; + } + } + } + return 0; + } + + /* init filename transitions */ + fnts_tab = hashtab_create(filenametr_hash, filenametr_cmp, nel); + if (!fnts_tab) + return -1; + insert_args.fnts_tab = fnts_tab; + + for (i = 0; i < a->nslot; i++) { + for (cur = a->htable[i]; cur; cur = cur->next) { + if (cur->key.specified & AVTAB_TRANSITION) { + insert_args.av_key = &cur->key; + rc = hashtab_map(cur->datum.trans->name_trans.table, + name_trans_insert_helper, + &insert_args); + } + } + } + + rc = -1; + /* write compressed filename transitions */ + buf[0] = cpu_to_le32(fnts_tab->nel); + items = put_entry(buf, sizeof(uint32_t), 1, fp); + if (items != 1) + goto out; + + rc = hashtab_map(fnts_tab, filenametr_comp_write_one, fp); + +out: + /* destroy temp filename transitions table */ + hashtab_map(fnts_tab, filenametr_destroy, NULL); + hashtab_destroy(fnts_tab); + + return rc ? -1 : 0; +} + +/* end policydb filename transition compatibility */ + /* * Write a semantic MLS level structure to a policydb binary * representation file. @@ -580,118 +903,6 @@ static int role_allow_write(role_allow_t * r, struct policy_file *fp) return POLICYDB_SUCCESS; } -static int filename_write_one_compat(hashtab_key_t key, void *data, void *ptr) -{ - uint32_t bit, buf[4]; - size_t items, len; - filename_trans_key_t *ft = (filename_trans_key_t *)key; - filename_trans_datum_t *datum = data; - ebitmap_node_t *node; - void *fp = ptr; - - len = strlen(ft->name); - do { - ebitmap_for_each_positive_bit(&datum->stypes, node, bit) { - buf[0] = cpu_to_le32(len); - items = put_entry(buf, sizeof(uint32_t), 1, fp); - if (items != 1) - return POLICYDB_ERROR; - - items = put_entry(ft->name, sizeof(char), len, fp); - if (items != len) - return POLICYDB_ERROR; - - buf[0] = cpu_to_le32(bit + 1); - buf[1] = cpu_to_le32(ft->ttype); - buf[2] = cpu_to_le32(ft->tclass); - buf[3] = cpu_to_le32(datum->otype); - items = put_entry(buf, sizeof(uint32_t), 4, fp); - if (items != 4) - return POLICYDB_ERROR; - } - - datum = datum->next; - } while (datum); - - return 0; -} - -static int filename_write_one(hashtab_key_t key, void *data, void *ptr) -{ - uint32_t buf[3]; - size_t items, len, ndatum; - filename_trans_key_t *ft = (filename_trans_key_t *)key; - filename_trans_datum_t *datum; - void *fp = ptr; - - len = strlen(ft->name); - buf[0] = cpu_to_le32(len); - items = put_entry(buf, sizeof(uint32_t), 1, fp); - if (items != 1) - return POLICYDB_ERROR; - - items = put_entry(ft->name, sizeof(char), len, fp); - if (items != len) - return POLICYDB_ERROR; - - ndatum = 0; - datum = data; - do { - ndatum++; - datum = datum->next; - } while (datum); - - buf[0] = cpu_to_le32(ft->ttype); - buf[1] = cpu_to_le32(ft->tclass); - buf[2] = cpu_to_le32(ndatum); - items = put_entry(buf, sizeof(uint32_t), 3, fp); - if (items != 3) - return POLICYDB_ERROR; - - datum = data; - do { - if (ebitmap_write(&datum->stypes, fp)) - return POLICYDB_ERROR; - - buf[0] = cpu_to_le32(datum->otype); - items = put_entry(buf, sizeof(uint32_t), 1, fp); - if (items != 1) - return POLICYDB_ERROR; - - datum = datum->next; - } while (datum); - - return 0; -} - -static int filename_trans_write(struct policydb *p, void *fp) -{ - size_t items; - uint32_t buf[1]; - int rc; - - if (p->policyvers < POLICYDB_VERSION_FILENAME_TRANS) - return 0; - - if (p->policyvers < POLICYDB_VERSION_COMP_FTRANS) { - buf[0] = cpu_to_le32(p->filename_trans_count); - items = put_entry(buf, sizeof(uint32_t), 1, fp); - if (items != 1) - return POLICYDB_ERROR; - - rc = hashtab_map(p->filename_trans, filename_write_one_compat, - fp); - } else { - buf[0] = cpu_to_le32(p->filename_trans->nel); - items = put_entry(buf, sizeof(uint32_t), 1, fp); - if (items != 1) - return POLICYDB_ERROR; - - rc = hashtab_map(p->filename_trans, filename_write_one, fp); - } - return rc; -} - static int role_set_write(role_set_t * x, struct policy_file *fp) { size_t items; @@ -2202,6 +2413,21 @@ static int role_attr_uncount(hashtab_key_t key __attribute__ ((unused)), return 0; } +static int avtab_has_filename_transitions(avtab_t *a) +{ + uint32_t i; + struct avtab_node *cur; + for (i = 0; i < a->nslot; i++) { + for (cur = a->htable[i]; cur; cur = cur->next) { + if (cur->key.specified & AVTAB_TRANSITION) { + if (hashtab_nel(cur->datum.trans->name_trans.table)) + return 1; + } + } + } + return 0; +} + /* * Write the configuration data in a policy database * structure to a policy database binary representation @@ -2381,11 +2607,11 @@ int policydb_write(policydb_t * p, struct policy_file *fp) if (role_allow_write(p->role_allow, fp)) return POLICYDB_ERROR; if (p->policyvers >= POLICYDB_VERSION_FILENAME_TRANS) { - if (filename_trans_write(p, fp)) + if (avtab_filename_trans_write(p, &p->te_avtab, fp)) return POLICYDB_ERROR; - } else { - if (p->filename_trans) - WARN(fp->handle, "Discarding filename type transition rules"); + } else if (avtab_has_filename_transitions(&p->te_avtab)) { + WARN(fp->handle, + "Discarding filename type transition rules"); } } else { if (avrule_block_write(p->global, num_syms, p, fp) == -1) { From patchwork Wed May 31 11:49:09 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juraj Marcin X-Patchwork-Id: 13262082 X-Patchwork-Delegate: plautrba@redhat.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 20654C7EE2F for ; Wed, 31 May 2023 11:50:16 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235361AbjEaLuP (ORCPT ); Wed, 31 May 2023 07:50:15 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48746 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235406AbjEaLuN (ORCPT ); Wed, 31 May 2023 07:50:13 -0400 Received: from sender11-of-o52.zoho.eu (sender11-of-o52.zoho.eu [31.186.226.238]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id EC6A5E8 for ; Wed, 31 May 2023 04:50:08 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1685533797; cv=none; d=zohomail.eu; s=zohoarc; b=kjFL92dWj1aIUMlK5TV/5sOykQJPQMxjJnLaadaxofhpvps+M3a1YVZMBGDvwpkiw8x6Aa7KWO7ynDA5vxJlthPqN832BzamP8Rtwg1nGyXsfNUprPiqPbelEAtH5sO7Ejh9yC07a6J0NPQL7eXjBTuVf0egqWqxf+SXrSY4fzs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.eu; s=zohoarc; t=1685533797; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:To; bh=W9/+LHmz8edYNAUEMnBBp0mngjBCw1yOfUdRq508Qho=; b=R5vQ4KfQOfVl2NhVi0GCJwTYxKqe0OMwGkQsLUpb/YYTSrWBLXKQIPImJDUB3ClK6YP9C3RhLdaxPxahRM/8D8XS5RoxpU1+EJfAZ5UJU1CHFjgjXVMTcdV/gogiyVbRgbKv0cGwzVnhMOy37ChURjkYUUg/Avn/a6wJ/ULhYN0= ARC-Authentication-Results: i=1; mx.zohomail.eu; dkim=pass header.i=jurajmarcin.com; spf=pass smtp.mailfrom=juraj@jurajmarcin.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1685533797; s=zoho; d=jurajmarcin.com; i=juraj@jurajmarcin.com; h=From:From:To:To:Cc:Cc:Subject:Subject:Date:Date:Message-Id:Message-Id:In-Reply-To:References:MIME-Version:Content-Transfer-Encoding:Reply-To; bh=W9/+LHmz8edYNAUEMnBBp0mngjBCw1yOfUdRq508Qho=; b=PweyrW231qfWEO7nOh+X7ICQsi17qoTxL3qlyTIALzMrrcQ6f/Ye2n36g9SdnGIN 4wHAqNUUaqB+BmKbQwiovSZAO/dceBbE93CoTSdvB84rCBFlQNKmJE3netZCLtla75R lEE9H+XJfhDWTRLR3/HDffYesNDWcxbqDIdG8OcM= Received: from morty01.jurajmarcin.com (129.159.244.31 [129.159.244.31]) by mx.zoho.eu with SMTPS id 168553379619821.44871740747294; Wed, 31 May 2023 13:49:56 +0200 (CEST) Received: from jmarcin-t14s-01.redhat.com (unknown [147.251.183.113]) by morty01.jurajmarcin.com (Postfix) with ESMTPSA id 8F0982081F76; Wed, 31 May 2023 11:49:55 +0000 (UTC) From: Juraj Marcin To: selinux@vger.kernel.org Cc: Stephen Smalley , Ondrej Mosnacek Subject: [PATCH 3/8] checkpolicy, libsepol: move filename transition rules to avrule Date: Wed, 31 May 2023 13:49:09 +0200 Message-Id: <20230531114914.2237609-4-juraj@jurajmarcin.com> In-Reply-To: <20230531114914.2237609-1-juraj@jurajmarcin.com> References: <20230531114914.2237609-1-juraj@jurajmarcin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org Similarly to the previous patch, filename transition rules are stored and parsed separately from other type enforcement rules. Moving them to avrule makes it consistent with the filename transitions in avtab and makes future improvements easier to implement. This patch adds an optional object name attribute to the avrule structure and uses this new attribute to move filename transition rules to avrule. It also updates functions for parsing type enforcement rules to accept rules with a filename as their last argument (filename transition rules), separate functions for parsing filename transitions are therefore no longer needed. Reviewed-by: Ondrej Mosnacek Signed-off-by: Juraj Marcin --- checkpolicy/checkpolicy.c | 9 - checkpolicy/module_compiler.c | 12 -- checkpolicy/module_compiler.h | 1 - checkpolicy/policy_define.c | 215 +++------------------ checkpolicy/policy_define.h | 3 +- checkpolicy/policy_parse.y | 8 +- checkpolicy/test/dismod.c | 25 +-- libsepol/cil/src/cil_binary.c | 2 + libsepol/include/sepol/policydb/policydb.h | 16 +- libsepol/src/avrule_block.c | 1 - libsepol/src/expand.c | 128 +++--------- libsepol/src/link.c | 56 +----- libsepol/src/module_to_cil.c | 71 +------ libsepol/src/policydb.c | 70 ++----- libsepol/src/policydb_validate.c | 27 --- libsepol/src/write.c | 86 +++++---- 16 files changed, 150 insertions(+), 580 deletions(-) diff --git a/checkpolicy/checkpolicy.c b/checkpolicy/checkpolicy.c index 6e8ed833..2485142d 100644 --- a/checkpolicy/checkpolicy.c +++ b/checkpolicy/checkpolicy.c @@ -611,15 +611,6 @@ int main(int argc, char **argv) parse_policy.mls = mlspol; parse_policy.handle_unknown = handle_unknown; - /* - * Init and alloc te_avtab for filename transition duplicate - * checking - */ - if (avtab_init(&parse_policy.te_avtab)) - exit(1); - if (avtab_alloc(&parse_policy.te_avtab, 1 << 11)) - exit(1); - policydbp = &parse_policy; if (read_source_policy(policydbp, file, "checkpolicy") < 0) diff --git a/checkpolicy/module_compiler.c b/checkpolicy/module_compiler.c index 3188af89..5fe1729a 100644 --- a/checkpolicy/module_compiler.c +++ b/checkpolicy/module_compiler.c @@ -1278,18 +1278,6 @@ void append_role_allow(role_allow_rule_t * role_allow_rules) decl->role_allow_rules = role_allow_rules; } -/* this doesn't actually append, but really prepends it */ -void append_filename_trans(filename_trans_rule_t * filename_trans_rules) -{ - avrule_decl_t *decl = stack_top->decl; - - /* filename transitions are not allowed within conditionals */ - assert(stack_top->type == 1); - - filename_trans_rules->next = decl->filename_trans_rules; - decl->filename_trans_rules = filename_trans_rules; -} - /* this doesn't actually append, but really prepends it */ void append_range_trans(range_trans_rule_t * range_tr_rules) { diff --git a/checkpolicy/module_compiler.h b/checkpolicy/module_compiler.h index 29b824b4..6f8bb9b9 100644 --- a/checkpolicy/module_compiler.h +++ b/checkpolicy/module_compiler.h @@ -83,7 +83,6 @@ void append_avrule(avrule_t * avrule); void append_role_trans(role_trans_rule_t * role_tr_rules); void append_role_allow(role_allow_rule_t * role_allow_rules); void append_range_trans(range_trans_rule_t * range_tr_rules); -void append_filename_trans(filename_trans_rule_t * filename_trans_rules); /* Create a new optional block and add it to the global policy. * During the second pass resolve the block's requirements. Return 0 diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c index acc78baf..455255ba 100644 --- a/checkpolicy/policy_define.c +++ b/checkpolicy/policy_define.c @@ -1601,7 +1601,7 @@ static int set_types(type_set_t * set, char *id, int *add, char starallowed) return -1; } -static int define_compute_type_helper(int which, avrule_t ** rule) +static int define_compute_type_helper(int which, avrule_t ** rule, int has_filename) { char *id; type_datum_t *datum; @@ -1669,6 +1669,14 @@ static int define_compute_type_helper(int which, avrule_t ** rule) } free(id); + if (has_filename) { + avrule->object_name = queue_remove(id_queue); + if (!avrule->object_name) { + yyerror("no object_name?"); + goto bad; + } + } + ebitmap_for_each_positive_bit(&tclasses, node, i) { perm = malloc(sizeof(class_perm_node_t)); if (!perm) { @@ -1692,7 +1700,7 @@ static int define_compute_type_helper(int which, avrule_t ** rule) return -1; } -int define_compute_type(int which) +int define_compute_type(int which, int has_filename) { char *id; avrule_t *avrule; @@ -1706,10 +1714,14 @@ int define_compute_type(int which) free(id); id = queue_remove(id_queue); free(id); + if (has_filename) { + id = queue_remove(id_queue); + free(id); + } return 0; } - if (define_compute_type_helper(which, &avrule)) + if (define_compute_type_helper(which, &avrule, has_filename)) return -1; append_avrule(avrule); @@ -1733,7 +1745,7 @@ avrule_t *define_cond_compute_type(int which) return (avrule_t *) 1; } - if (define_compute_type_helper(which, &avrule)) + if (define_compute_type_helper(which, &avrule, 0)) return COND_ERR; return avrule; @@ -2375,6 +2387,13 @@ static int avrule_cpy(avrule_t *dest, const avrule_t *src) yyerror("out of memory"); return -1; } + if (src->object_name) { + dest->object_name = strdup(src->object_name); + if (!dest->object_name) { + yyerror("out of memory"); + return -1; + } + } dest->line = src->line; dest->source_filename = strdup(source_file); if (!dest->source_filename) { @@ -3332,194 +3351,6 @@ avrule_t *define_cond_filename_trans(void) return COND_ERR; } -int define_filename_trans(void) -{ - char *id, *name = NULL; - type_set_t stypes, ttypes; - ebitmap_t e_stypes, e_ttypes; - ebitmap_t e_tclasses; - ebitmap_node_t *snode, *tnode, *cnode; - filename_trans_rule_t *ftr; - type_datum_t *typdatum; - avtab_key_t avt_key; - uint32_t otype; - unsigned int c, s, t; - int add, self, rc; - - if (pass == 1) { - /* stype */ - while ((id = queue_remove(id_queue))) - free(id); - /* ttype */ - while ((id = queue_remove(id_queue))) - free(id); - /* tclass */ - while ((id = queue_remove(id_queue))) - free(id); - /* otype */ - id = queue_remove(id_queue); - free(id); - /* name */ - id = queue_remove(id_queue); - free(id); - return 0; - } - - type_set_init(&stypes); - type_set_init(&ttypes); - ebitmap_init(&e_stypes); - ebitmap_init(&e_ttypes); - ebitmap_init(&e_tclasses); - - add = 1; - while ((id = queue_remove(id_queue))) { - if (set_types(&stypes, id, &add, 0)) - goto bad; - } - - self = 0; - add = 1; - while ((id = queue_remove(id_queue))) { - if (strcmp(id, "self") == 0) { - free(id); - if (add == 0) { - yyerror("-self is not supported"); - goto bad; - } - self = 1; - continue; - } - if (set_types(&ttypes, id, &add, 0)) - goto bad; - } - - if (read_classes(&e_tclasses)) - goto bad; - - id = (char *)queue_remove(id_queue); - if (!id) { - yyerror("no otype in transition definition?"); - goto bad; - } - if (!is_id_in_scope(SYM_TYPES, id)) { - yyerror2("type %s is not within scope", id); - free(id); - goto bad; - } - typdatum = hashtab_search(policydbp->p_types.table, id); - if (!typdatum) { - yyerror2("unknown type %s used in transition definition", id); - free(id); - goto bad; - } - free(id); - otype = typdatum->s.value; - - name = queue_remove(id_queue); - if (!name) { - yyerror("no pathname specified in filename_trans definition?"); - goto bad; - } - - /* We expand the class set into separate rules. We expand the types - * just to make sure there are not duplicates. They will get turned - * into separate rules later */ - if (type_set_expand(&stypes, &e_stypes, policydbp, 1)) - goto bad; - - if (type_set_expand(&ttypes, &e_ttypes, policydbp, 1)) - goto bad; - - ebitmap_for_each_positive_bit(&e_tclasses, cnode, c) { - ebitmap_for_each_positive_bit(&e_stypes, snode, s) { - ebitmap_for_each_positive_bit(&e_ttypes, tnode, t) { - avt_key.specified = AVTAB_TRANSITION; - avt_key.source_type = s + 1; - avt_key.target_type = t + 1; - avt_key.target_class = c + 1; - rc = avtab_insert_filename_trans( - &policydbp->te_avtab, &avt_key, otype, - name, NULL - ); - if (rc != SEPOL_OK) { - if (rc == SEPOL_EEXIST) { - yyerror2("duplicate filename transition for: filename_trans %s %s %s:%s", - name, - policydbp->p_type_val_to_name[s], - policydbp->p_type_val_to_name[t], - policydbp->p_class_val_to_name[c]); - goto bad; - } - yyerror("out of memory"); - goto bad; - } - } - if (self) { - avt_key.specified = AVTAB_TRANSITION; - avt_key.source_type = s + 1; - avt_key.target_type = t + 1; - avt_key.target_class = c + 1; - rc = avtab_insert_filename_trans( - &policydbp->te_avtab, &avt_key, otype, - name, NULL - ); - if (rc != SEPOL_OK) { - if (rc == SEPOL_EEXIST) { - yyerror2("duplicate filename transition for: filename_trans %s %s %s:%s", - name, - policydbp->p_type_val_to_name[s], - policydbp->p_type_val_to_name[s], - policydbp->p_class_val_to_name[c]); - goto bad; - } - yyerror("out of memory"); - goto bad; - } - } - } - - /* Now add the real rule since we didn't find any duplicates */ - ftr = malloc(sizeof(*ftr)); - if (!ftr) { - yyerror("out of memory"); - goto bad; - } - filename_trans_rule_init(ftr); - append_filename_trans(ftr); - - ftr->name = strdup(name); - if (type_set_cpy(&ftr->stypes, &stypes)) { - yyerror("out of memory"); - goto bad; - } - if (type_set_cpy(&ftr->ttypes, &ttypes)) { - yyerror("out of memory"); - goto bad; - } - ftr->tclass = c + 1; - ftr->otype = otype; - ftr->flags = self ? RULE_SELF : 0; - } - - free(name); - ebitmap_destroy(&e_stypes); - ebitmap_destroy(&e_ttypes); - ebitmap_destroy(&e_tclasses); - type_set_destroy(&stypes); - type_set_destroy(&ttypes); - - return 0; - -bad: - free(name); - ebitmap_destroy(&e_stypes); - ebitmap_destroy(&e_ttypes); - ebitmap_destroy(&e_tclasses); - type_set_destroy(&stypes); - type_set_destroy(&ttypes); - return -1; -} - static constraint_expr_t *constraint_expr_clone(const constraint_expr_t * expr) { constraint_expr_t *h = NULL, *l = NULL, *newe; diff --git a/checkpolicy/policy_define.h b/checkpolicy/policy_define.h index 50a7ba78..5d0f70e4 100644 --- a/checkpolicy/policy_define.h +++ b/checkpolicy/policy_define.h @@ -28,7 +28,7 @@ int define_default_role(int which); int define_default_type(int which); int define_default_range(int which); int define_common_perms(void); -int define_compute_type(int which); +int define_compute_type(int which, int has_filename); int define_conditional(cond_expr_t *expr, avrule_t *t_list, avrule_t *f_list ); int define_constraint(constraint_expr_t *expr); int define_dominance(void); @@ -57,7 +57,6 @@ int define_role_trans(int class_specified); int define_role_types(void); int define_role_attr(void); int define_roleattribute(void); -int define_filename_trans(void); int define_sens(void); int define_te_avtab(int which); int define_te_avtab_extended_perms(int which); diff --git a/checkpolicy/policy_parse.y b/checkpolicy/policy_parse.y index 45f973ff..fccbc052 100644 --- a/checkpolicy/policy_parse.y +++ b/checkpolicy/policy_parse.y @@ -452,13 +452,13 @@ cond_dontaudit_def : DONTAUDIT names names ':' names names ';' ; ; transition_def : TYPE_TRANSITION names names ':' names identifier filename ';' - {if (define_filename_trans()) return -1; } + {if (define_compute_type(AVRULE_TRANSITION, 1)) return -1; } | TYPE_TRANSITION names names ':' names identifier ';' - {if (define_compute_type(AVRULE_TRANSITION)) return -1;} + {if (define_compute_type(AVRULE_TRANSITION, 0)) return -1;} | TYPE_MEMBER names names ':' names identifier ';' - {if (define_compute_type(AVRULE_MEMBER)) return -1;} + {if (define_compute_type(AVRULE_MEMBER, 0)) return -1;} | TYPE_CHANGE names names ':' names identifier ';' - {if (define_compute_type(AVRULE_CHANGE)) return -1;} + {if (define_compute_type(AVRULE_CHANGE, 0)) return -1;} ; range_trans_def : RANGE_TRANSITION names names mls_range_def ';' { if (define_range_trans(0)) return -1; } diff --git a/checkpolicy/test/dismod.c b/checkpolicy/test/dismod.c index 929ee308..f26f360c 100644 --- a/checkpolicy/test/dismod.c +++ b/checkpolicy/test/dismod.c @@ -51,7 +51,6 @@ #define DISPLAY_AVBLOCK_ROLE_ALLOW 4 #define DISPLAY_AVBLOCK_REQUIRES 5 #define DISPLAY_AVBLOCK_DECLARES 6 -#define DISPLAY_AVBLOCK_FILENAME_TRANS 7 static policydb_t policydb; extern unsigned int ss_initialized; @@ -292,6 +291,8 @@ static int display_avrule(avrule_t * avrule, policydb_t * policy, policy, fp); } else if (avrule->specified & AVRULE_TYPE) { display_id(policy, fp, SYM_TYPES, avrule->perms->data - 1, ""); + if (avrule->object_name) + fprintf(fp, " \"%s\"", avrule->object_name); } else if (avrule->specified & AVRULE_XPERMS) { avtab_extended_perms_t xperms; int i; @@ -509,18 +510,6 @@ static void display_role_allow(role_allow_rule_t * ra, policydb_t * p, FILE * fp } } -static void display_filename_trans(filename_trans_rule_t * tr, policydb_t * p, FILE * fp) -{ - fprintf(fp, "filename transition"); - for (; tr; tr = tr->next) { - display_type_set(&tr->stypes, 0, p, fp); - display_type_set(&tr->ttypes, 0, p, fp); - display_id(p, fp, SYM_CLASSES, tr->tclass - 1, ":"); - display_id(p, fp, SYM_TYPES, tr->otype - 1, ""); - fprintf(fp, " %s\n", tr->name); - } -} - static int role_display_callback(hashtab_key_t key __attribute__((unused)), hashtab_datum_t datum, void *data) { @@ -685,10 +674,6 @@ static int display_avdecl(avrule_decl_t * decl, int field, } break; } - case DISPLAY_AVBLOCK_FILENAME_TRANS: - display_filename_trans(decl->filename_trans_rules, policy, - out_fp); - break; default:{ assert(0); } @@ -859,7 +844,6 @@ static int menu(void) printf("c) Display policy capabilities\n"); printf("l) Link in a module\n"); printf("u) Display the unknown handling setting\n"); - printf("F) Display filename_trans rules\n"); printf("\n"); printf("f) set output file\n"); printf("m) display menu\n"); @@ -1005,11 +989,6 @@ int main(int argc, char **argv) if (out_fp != stdout) printf("\nOutput to file: %s\n", OutfileName); break; - case 'F': - fprintf(out_fp, "filename_trans rules:\n"); - display_avblock(DISPLAY_AVBLOCK_FILENAME_TRANS, - &policydb, out_fp); - break; case 'l': link_module(&policydb, out_fp); break; diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c index 7150d405..996bad70 100644 --- a/libsepol/cil/src/cil_binary.c +++ b/libsepol/cil/src/cil_binary.c @@ -4650,6 +4650,7 @@ static avrule_t *__cil_init_sepol_avrule(uint32_t kind, struct cil_tree_node *no __cil_init_sepol_type_set(&avrule->stypes); __cil_init_sepol_type_set(&avrule->ttypes); avrule->perms = NULL; + avrule->object_name = NULL; avrule->line = node->line; avrule->source_filename = NULL; @@ -4676,6 +4677,7 @@ static void __cil_destroy_sepol_avrules(avrule_t *curr) ebitmap_destroy(&curr->stypes.negset); ebitmap_destroy(&curr->ttypes.types); ebitmap_destroy(&curr->ttypes.negset); + free(curr->object_name); __cil_destroy_sepol_class_perms(curr->perms); free(curr); curr = next; diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h index 8bb11d18..d30f26af 100644 --- a/libsepol/include/sepol/policydb/policydb.h +++ b/libsepol/include/sepol/policydb/policydb.h @@ -278,6 +278,7 @@ typedef struct avrule { type_set_t stypes; type_set_t ttypes; class_perm_node_t *perms; + char *object_name; /* optional object name */ av_extended_perms_t *xperms; unsigned long line; /* line number from policy.conf where * this rule originated */ @@ -301,16 +302,6 @@ typedef struct role_allow_rule { struct role_allow_rule *next; } role_allow_rule_t; -typedef struct filename_trans_rule { - uint32_t flags; /* may have RULE_SELF set */ - type_set_t stypes; - type_set_t ttypes; - uint32_t tclass; - char *name; - uint32_t otype; /* new type */ - struct filename_trans_rule *next; -} filename_trans_rule_t; - typedef struct range_trans_rule { type_set_t stypes; type_set_t ttypes; @@ -451,9 +442,6 @@ typedef struct avrule_decl { scope_index_t required; /* symbols needed to activate this block */ scope_index_t declared; /* symbols declared within this block */ - /* type transition rules with a 'name' component */ - filename_trans_rule_t *filename_trans_rules; - /* for additive statements (type attribute, roles, and users) */ symtab_t symtab[SYM_NUM]; @@ -656,8 +644,6 @@ extern void avrule_destroy(avrule_t * x); extern void avrule_list_destroy(avrule_t * x); extern void role_trans_rule_init(role_trans_rule_t * x); extern void role_trans_rule_list_destroy(role_trans_rule_t * x); -extern void filename_trans_rule_init(filename_trans_rule_t * x); -extern void filename_trans_rule_list_destroy(filename_trans_rule_t * x); extern void role_datum_init(role_datum_t * x); extern void role_datum_destroy(role_datum_t * x); diff --git a/libsepol/src/avrule_block.c b/libsepol/src/avrule_block.c index dcfce8b8..fce4e772 100644 --- a/libsepol/src/avrule_block.c +++ b/libsepol/src/avrule_block.c @@ -99,7 +99,6 @@ void avrule_decl_destroy(avrule_decl_t * x) cond_list_destroy(x->cond_list); avrule_list_destroy(x->avrules); role_trans_rule_list_destroy(x->role_tr_rules); - filename_trans_rule_list_destroy(x->filename_trans_rules); role_allow_rule_list_destroy(x->role_allow_rules); range_trans_rule_list_destroy(x->range_tr_rules); scope_index_destroy(&x->required); diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c index 8ffe1c90..f3417547 100644 --- a/libsepol/src/expand.c +++ b/libsepol/src/expand.c @@ -1407,94 +1407,6 @@ static int copy_role_trans(expand_state_t * state, role_trans_rule_t * rules) return 0; } -static int expand_filename_trans_helper(expand_state_t *state, - filename_trans_rule_t *rule, - unsigned int s, unsigned int t) -{ - uint32_t mapped_otype, present_otype; - int rc; - avtab_key_t avt_key; - - mapped_otype = state->typemap[rule->otype - 1]; - - avt_key.specified = AVTAB_TRANSITION; - avt_key.source_type = s + 1; - avt_key.target_type = t + 1; - avt_key.target_class = rule->tclass; - - rc = avtab_insert_filename_trans(&state->out->te_avtab, &avt_key, - mapped_otype, rule->name, &present_otype); - if (rc == SEPOL_EEXIST) { - /* duplicate rule, ignore */ - if (present_otype == mapped_otype) - return 0; - - ERR(state->handle, "Conflicting name-based type_transition %s %s:%s \"%s\": %s vs %s", - state->out->p_type_val_to_name[s], - state->out->p_type_val_to_name[t], - state->out->p_class_val_to_name[rule->tclass - 1], - rule->name, - state->out->p_type_val_to_name[present_otype - 1], - state->out->p_type_val_to_name[mapped_otype - 1]); - return -1; - } else if (rc < 0) { - ERR(state->handle, "Out of memory!"); - return -1; - } - return 0; -} - -static int expand_filename_trans(expand_state_t *state, filename_trans_rule_t *rules) -{ - unsigned int i, j; - filename_trans_rule_t *cur_rule; - ebitmap_t stypes, ttypes; - ebitmap_node_t *snode, *tnode; - int rc; - - cur_rule = rules; - while (cur_rule) { - ebitmap_init(&stypes); - ebitmap_init(&ttypes); - - if (expand_convert_type_set(state->out, state->typemap, - &cur_rule->stypes, &stypes, 1)) { - ERR(state->handle, "Out of memory!"); - return -1; - } - - if (expand_convert_type_set(state->out, state->typemap, - &cur_rule->ttypes, &ttypes, 1)) { - ERR(state->handle, "Out of memory!"); - return -1; - } - - - ebitmap_for_each_positive_bit(&stypes, snode, i) { - ebitmap_for_each_positive_bit(&ttypes, tnode, j) { - rc = expand_filename_trans_helper( - state, cur_rule, i, j - ); - if (rc) - return rc; - } - if (cur_rule->flags & RULE_SELF) { - rc = expand_filename_trans_helper( - state, cur_rule, i, i - ); - if (rc) - return rc; - } - } - - ebitmap_destroy(&stypes); - ebitmap_destroy(&ttypes); - - cur_rule = cur_rule->next; - } - return 0; -} - static int exp_rangetr_helper(uint32_t stype, uint32_t ttype, uint32_t tclass, mls_semantic_range_t * trange, expand_state_t * state) @@ -1708,7 +1620,7 @@ static int expand_terule_helper(sepol_handle_t * handle, uint32_t specified, cond_av_list_t ** cond, cond_av_list_t ** other, uint32_t stype, uint32_t ttype, class_perm_node_t * perms, - avtab_t * avtab, int enabled) + char *object_name, avtab_t * avtab, int enabled) { avtab_key_t avkey; avtab_datum_t *avdatump; @@ -1732,6 +1644,30 @@ static int expand_terule_helper(sepol_handle_t * handle, typemap ? typemap[cur->data - 1] : cur->data; avkey.target_class = cur->tclass; + /* + * if expanded node is a filename transition, insert it, insert + * function checks for duplicates + */ + if (specified & AVRULE_TRANSITION && object_name) { + int rc = avtab_insert_filename_trans(avtab, &avkey, + remapped_data, + object_name, + &oldtype); + if (rc == SEPOL_EEXIST) { + ERR(handle, "conflicting filename transition %s %s:%s \"%s\": %s vs %s", + p->p_type_val_to_name[avkey.source_type - 1], + p->p_type_val_to_name[avkey.target_type - 1], + p->p_class_val_to_name[avkey.target_class - 1], + object_name, + p->p_type_val_to_name[oldtype - 1], + p->p_type_val_to_name[remapped_data - 1]); + return EXPAND_RULE_CONFLICT; + } + if (rc < 0) + return EXPAND_RULE_ERROR; + return EXPAND_RULE_SUCCESS; + } + conflict = 0; /* check to see if the expanded TE already exists -- * either in the global scope or in another @@ -1777,12 +1713,9 @@ static int expand_terule_helper(sepol_handle_t * handle, || node->parse_context == cond) return EXPAND_RULE_SUCCESS; ERR(handle, "duplicate TE rule for %s %s:%s %s", - p->p_type_val_to_name[avkey.source_type - - 1], - p->p_type_val_to_name[avkey.target_type - - 1], - p->p_class_val_to_name[avkey.target_class - - 1], + p->p_type_val_to_name[avkey.source_type - 1], + p->p_type_val_to_name[avkey.target_type - 1], + p->p_class_val_to_name[avkey.target_class - 1], p->p_type_val_to_name[oldtype - 1]); return EXPAND_RULE_CONFLICT; } @@ -1947,6 +1880,7 @@ static int expand_rule_helper(sepol_handle_t * handle, retval = expand_terule_helper(handle, p, typemap, source_rule->specified, cond, other, i, i, source_rule->perms, + source_rule->object_name, dest_avtab, enabled); if (retval != EXPAND_RULE_SUCCESS) return retval; @@ -1963,6 +1897,7 @@ static int expand_rule_helper(sepol_handle_t * handle, retval = expand_terule_helper(handle, p, typemap, source_rule->specified, cond, other, i, j, source_rule->perms, + source_rule->object_name, dest_avtab, enabled); if (retval != EXPAND_RULE_SUCCESS) return retval; @@ -2791,9 +2726,6 @@ static int copy_and_expand_avrule_block(expand_state_t * state) goto cleanup; } - if (expand_filename_trans(state, decl->filename_trans_rules)) - goto cleanup; - /* expand the range transition rules */ if (expand_range_trans(state, decl->range_tr_rules)) goto cleanup; diff --git a/libsepol/src/link.c b/libsepol/src/link.c index 3b7742bc..88b23594 100644 --- a/libsepol/src/link.c +++ b/libsepol/src/link.c @@ -1249,6 +1249,12 @@ static int copy_avrule_list(avrule_t * list, avrule_t ** dst, goto cleanup; } + if (cur->object_name) { + new_rule->object_name = strdup(cur->object_name); + if (!new_rule->object_name) + goto cleanup; + } + cur_perm = cur->perms; tail_perm = NULL; while (cur_perm) { @@ -1412,51 +1418,6 @@ static int copy_role_allow_list(role_allow_rule_t * list, return -1; } -static int copy_filename_trans_list(filename_trans_rule_t * list, - filename_trans_rule_t ** dst, - policy_module_t * module, - link_state_t * state) -{ - filename_trans_rule_t *cur, *new_rule, *tail; - - cur = list; - tail = *dst; - while (tail && tail->next) - tail = tail->next; - - while (cur) { - new_rule = malloc(sizeof(*new_rule)); - if (!new_rule) - goto err; - - filename_trans_rule_init(new_rule); - - if (*dst == NULL) - *dst = new_rule; - else - tail->next = new_rule; - tail = new_rule; - - new_rule->name = strdup(cur->name); - if (!new_rule->name) - goto err; - - if (type_set_or_convert(&cur->stypes, &new_rule->stypes, module) || - type_set_or_convert(&cur->ttypes, &new_rule->ttypes, module)) - goto err; - - new_rule->tclass = module->map[SYM_CLASSES][cur->tclass - 1]; - new_rule->otype = module->map[SYM_TYPES][cur->otype - 1]; - new_rule->flags = cur->flags; - - cur = cur->next; - } - return 0; -err: - ERR(state->handle, "Out of memory!"); - return -1; -} - static int copy_range_trans_list(range_trans_rule_t * rules, range_trans_rule_t ** dst, policy_module_t * mod, link_state_t * state) @@ -1679,11 +1640,6 @@ static int copy_avrule_decl(link_state_t * state, policy_module_t * module, return -1; } - if (copy_filename_trans_list(src_decl->filename_trans_rules, - &dest_decl->filename_trans_rules, - module, state)) - return -1; - if (copy_range_trans_list(src_decl->range_tr_rules, &dest_decl->range_tr_rules, module, state)) return -1; diff --git a/libsepol/src/module_to_cil.c b/libsepol/src/module_to_cil.c index e7bc6ee6..653b4b33 100644 --- a/libsepol/src/module_to_cil.c +++ b/libsepol/src/module_to_cil.c @@ -560,7 +560,7 @@ static int semantic_level_to_cil(struct policydb *pdb, int sens_offset, struct m return 0; } -static int avrule_to_cil(int indent, struct policydb *pdb, uint32_t type, const char *src, const char *tgt, const struct class_perm_node *classperms) +static int avrule_to_cil(int indent, struct policydb *pdb, uint32_t type, const char *src, const char *tgt, const char *object_name, const struct class_perm_node *classperms) { int rc = -1; const char *rule; @@ -610,6 +610,12 @@ static int avrule_to_cil(int indent, struct policydb *pdb, uint32_t type, const rule, src, tgt, pdb->p_class_val_to_name[classperm->tclass - 1], perms + 1); + } else if (object_name) { + cil_println(indent, "(%s %s %s %s \"%s\" %s)", + rule, src, tgt, + pdb->p_class_val_to_name[classperm->tclass - 1], + object_name, + pdb->p_type_val_to_name[classperm->data - 1]); } else { cil_println(indent, "(%s %s %s %s %s)", rule, src, tgt, @@ -1212,7 +1218,7 @@ static int avrule_list_to_cil(int indent, struct policydb *pdb, struct avrule *a if (avrule->specified & AVRULE_XPERMS) { rc = avrulex_to_cil(indent, pdb, avrule->specified, snames[s], tnames[t], avrule->perms, avrule->xperms); } else { - rc = avrule_to_cil(indent, pdb, avrule->specified, snames[s], tnames[t], avrule->perms); + rc = avrule_to_cil(indent, pdb, avrule->specified, snames[s], tnames[t], avrule->object_name, avrule->perms); } if (rc != 0) { goto exit; @@ -1223,7 +1229,7 @@ static int avrule_list_to_cil(int indent, struct policydb *pdb, struct avrule *a if (avrule->specified & AVRULE_XPERMS) { rc = avrulex_to_cil(indent, pdb, avrule->specified, snames[s], "self", avrule->perms, avrule->xperms); } else { - rc = avrule_to_cil(indent, pdb, avrule->specified, snames[s], "self", avrule->perms); + rc = avrule_to_cil(indent, pdb, avrule->specified, snames[s], "self", avrule->object_name, avrule->perms); } if (rc != 0) { goto exit; @@ -1589,60 +1595,6 @@ exit: return rc; } -static int filename_trans_to_cil(int indent, struct policydb *pdb, struct filename_trans_rule *rules, struct list *attr_list) -{ - int rc = -1; - char **stypes = NULL; - unsigned int num_stypes = 0; - unsigned int stype; - char **ttypes = NULL; - unsigned int num_ttypes = 0; - unsigned int ttype; - struct type_set *ts; - struct filename_trans_rule *rule; - - for (rule = rules; rule != NULL; rule = rule->next) { - ts = &rule->stypes; - rc = process_typeset(pdb, ts, attr_list, &stypes, &num_stypes); - if (rc != 0) { - goto exit; - } - - ts = &rule->ttypes; - rc = process_typeset(pdb, ts, attr_list, &ttypes, &num_ttypes); - if (rc != 0) { - goto exit; - } - - for (stype = 0; stype < num_stypes; stype++) { - for (ttype = 0; ttype < num_ttypes; ttype++) { - cil_println(indent, "(typetransition %s %s %s \"%s\" %s)", - stypes[stype], ttypes[ttype], - pdb->p_class_val_to_name[rule->tclass - 1], - rule->name, - pdb->p_type_val_to_name[rule->otype - 1]); - } - if (rule->flags & RULE_SELF) { - cil_println(indent, "(typetransition %s self %s \"%s\" %s)", - stypes[stype], - pdb->p_class_val_to_name[rule->tclass - 1], - rule->name, - pdb->p_type_val_to_name[rule->otype - 1]); - } - } - - names_destroy(&stypes, &num_stypes); - names_destroy(&ttypes, &num_ttypes); - } - - rc = 0; -exit: - names_destroy(&stypes, &num_stypes); - names_destroy(&ttypes, &num_ttypes); - - return rc; -} - struct class_perm_datum { char *name; uint32_t val; @@ -3696,11 +3648,6 @@ static int block_to_cil(struct policydb *pdb, struct avrule_block *block, struct goto exit; } - rc = filename_trans_to_cil(indent, pdb, decl->filename_trans_rules, type_attr_list); - if (rc != 0) { - goto exit; - } - rc = cond_list_to_cil(indent, pdb, decl->cond_list, type_attr_list); if (rc != 0) { goto exit; diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c index 91836183..30c70d29 100644 --- a/libsepol/src/policydb.c +++ b/libsepol/src/policydb.c @@ -638,6 +638,7 @@ void avrule_destroy(avrule_t * x) } free(x->xperms); + free(x->object_name); } void role_trans_rule_init(role_trans_rule_t * x) @@ -667,33 +668,6 @@ void role_trans_rule_list_destroy(role_trans_rule_t * x) } } -void filename_trans_rule_init(filename_trans_rule_t * x) -{ - memset(x, 0, sizeof(*x)); - type_set_init(&x->stypes); - type_set_init(&x->ttypes); -} - -static void filename_trans_rule_destroy(filename_trans_rule_t * x) -{ - if (!x) - return; - type_set_destroy(&x->stypes); - type_set_destroy(&x->ttypes); - free(x->name); -} - -void filename_trans_rule_list_destroy(filename_trans_rule_t * x) -{ - filename_trans_rule_t *next; - while (x) { - next = x->next; - filename_trans_rule_destroy(x); - free(x); - x = next; - } -} - void role_allow_rule_init(role_allow_rule_t * x) { memset(x, 0, sizeof(role_allow_rule_t)); @@ -3493,31 +3467,32 @@ static int role_allow_rule_read(role_allow_rule_t ** r, struct policy_file *fp) return 0; } -static int filename_trans_rule_read(policydb_t *p, filename_trans_rule_t **r, +static int filename_trans_rule_read(policydb_t *p, avrule_t **r, struct policy_file *fp) { uint32_t buf[3], nel, i, len; unsigned int entries; - filename_trans_rule_t *ftr, *lftr; + avrule_t *cur; int rc; rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) return -1; nel = le32_to_cpu(buf[0]); - lftr = NULL; for (i = 0; i < nel; i++) { - ftr = malloc(sizeof(*ftr)); - if (!ftr) + cur = malloc(sizeof(avrule_t)); + if (!cur) return -1; + avrule_init(cur); - filename_trans_rule_init(ftr); + cur->next = *r; + *r = cur; - if (lftr) - lftr->next = ftr; - else - *r = ftr; - lftr = ftr; + cur->specified = AVRULE_TRANSITION; + cur->perms = malloc(sizeof(class_perm_node_t)); + if (!cur->perms) + return -1; + class_perm_node_init(cur->perms); rc = next_entry(buf, fp, sizeof(uint32_t)); if (rc < 0) @@ -3527,19 +3502,14 @@ static int filename_trans_rule_read(policydb_t *p, filename_trans_rule_t **r, if (zero_or_saturated(len)) return -1; - ftr->name = malloc(len + 1); - if (!ftr->name) - return -1; - - rc = next_entry(ftr->name, fp, len); + rc = str_read(&cur->object_name, fp, len); if (rc) return -1; - ftr->name[len] = 0; - if (type_set_read(&ftr->stypes, fp)) + if (type_set_read(&cur->stypes, fp)) return -1; - if (type_set_read(&ftr->ttypes, fp)) + if (type_set_read(&cur->ttypes, fp)) return -1; if (p->policyvers >= MOD_POLICYDB_VERSION_SELF_TYPETRANS) @@ -3550,10 +3520,10 @@ static int filename_trans_rule_read(policydb_t *p, filename_trans_rule_t **r, rc = next_entry(buf, fp, sizeof(uint32_t) * entries); if (rc < 0) return -1; - ftr->tclass = le32_to_cpu(buf[0]); - ftr->otype = le32_to_cpu(buf[1]); + cur->perms->tclass = le32_to_cpu(buf[0]); + cur->perms->data = le32_to_cpu(buf[1]); if (p->policyvers >= MOD_POLICYDB_VERSION_SELF_TYPETRANS) - ftr->flags = le32_to_cpu(buf[2]); + cur->flags = le32_to_cpu(buf[2]); } return 0; @@ -3656,7 +3626,7 @@ static int avrule_decl_read(policydb_t * p, avrule_decl_t * decl, } if (p->policyvers >= MOD_POLICYDB_VERSION_FILENAME_TRANS && - filename_trans_rule_read(p, &decl->filename_trans_rules, fp)) + filename_trans_rule_read(p, &decl->avrules, fp)) return -1; if (p->policyvers >= MOD_POLICYDB_VERSION_RANGETRANS && diff --git a/libsepol/src/policydb_validate.c b/libsepol/src/policydb_validate.c index e7af3fb8..66e8cb54 100644 --- a/libsepol/src/policydb_validate.c +++ b/libsepol/src/policydb_validate.c @@ -1277,31 +1277,6 @@ bad: return -1; } - -static int validate_filename_trans_rules(sepol_handle_t *handle, const filename_trans_rule_t *filename_trans, const policydb_t *p, validate_t flavors[]) -{ - for (; filename_trans; filename_trans = filename_trans->next) { - if (validate_type_set(&filename_trans->stypes, &flavors[SYM_TYPES])) - goto bad; - if (validate_type_set(&filename_trans->ttypes, &flavors[SYM_TYPES])) - goto bad; - if (validate_value(filename_trans->tclass,&flavors[SYM_CLASSES] )) - goto bad; - if (validate_simpletype(filename_trans->otype, p, flavors)) - goto bad; - - /* currently only the RULE_SELF flag can be set */ - if ((filename_trans->flags & ~RULE_SELF) != 0) - goto bad; - } - - return 0; - -bad: - ERR(handle, "Invalid filename trans rule list"); - return -1; -} - static int validate_symtabs(sepol_handle_t *handle, const symtab_t symtabs[], validate_t flavors[]) { unsigned int i; @@ -1336,8 +1311,6 @@ static int validate_avrule_blocks(sepol_handle_t *handle, const avrule_block_t * goto bad; if (validate_scope_index(handle, &decl->declared, flavors)) goto bad; - if (validate_filename_trans_rules(handle, decl->filename_trans_rules, p, flavors)) - goto bad; if (validate_symtabs(handle, decl->symtab, flavors)) goto bad; } diff --git a/libsepol/src/write.c b/libsepol/src/write.c index 7f580685..7b0ef705 100644 --- a/libsepol/src/write.c +++ b/libsepol/src/write.c @@ -1969,6 +1969,10 @@ static int avrule_write(policydb_t *p, avrule_t * avrule, uint32_t buf[32], len; class_perm_node_t *cur; + /* skip filename transitions for now */ + if (avrule->specified & AVRULE_TRANSITION && avrule->object_name) + return POLICYDB_SUCCESS; + if (p->policyvers < MOD_POLICYDB_VERSION_SELF_TYPETRANS && (avrule->specified & AVRULE_TYPE) && (avrule->flags & RULE_SELF)) { @@ -2062,7 +2066,9 @@ static int avrule_write_list(policydb_t *p, avrule_t * avrules, avrule = avrules; len = 0; while (avrule) { - len++; + if (!(avrule->specified & AVRULE_TRANSITION && + avrule->object_name)) + len++; avrule = avrule->next; } @@ -2161,55 +2167,67 @@ static int role_allow_rule_write(role_allow_rule_t * r, struct policy_file *fp) return POLICYDB_SUCCESS; } -static int filename_trans_rule_write(policydb_t *p, filename_trans_rule_t *t, +static int filename_trans_rule_write(policydb_t *p, avrule_t *rules, struct policy_file *fp) { int nel = 0; size_t items, entries; uint32_t buf[3], len; - filename_trans_rule_t *ftr; + avrule_t *rule; + class_perm_node_t *perm; - for (ftr = t; ftr; ftr = ftr->next) - nel++; + for (rule = rules; rule; rule = rule->next) { + if (rule->specified & AVRULE_TRANSITION && rule->object_name) { + for (perm = rule->perms; perm; perm = perm->next) { + nel++; + } + } + } buf[0] = cpu_to_le32(nel); items = put_entry(buf, sizeof(uint32_t), 1, fp); if (items != 1) return POLICYDB_ERROR; - for (ftr = t; ftr; ftr = ftr->next) { - len = strlen(ftr->name); - buf[0] = cpu_to_le32(len); - items = put_entry(buf, sizeof(uint32_t), 1, fp); - if (items != 1) - return POLICYDB_ERROR; + for (rule = rules; rule; rule = rule->next) { + if (!(rule->specified & AVRULE_TRANSITION && rule->object_name)) + continue; + len = strlen(rule->object_name); + for (perm = rule->perms; perm; perm = perm->next) { + buf[0] = cpu_to_le32(len); + items = put_entry(buf, sizeof(uint32_t), 1, fp); + if (items != 1) + return POLICYDB_ERROR; - items = put_entry(ftr->name, sizeof(char), len, fp); - if (items != len) - return POLICYDB_ERROR; + items = put_entry(rule->object_name, sizeof(char), len, + fp); + if (items != len) + return POLICYDB_ERROR; - if (type_set_write(&ftr->stypes, fp)) - return POLICYDB_ERROR; - if (type_set_write(&ftr->ttypes, fp)) - return POLICYDB_ERROR; + if (type_set_write(&rule->stypes, fp)) + return POLICYDB_ERROR; + if (type_set_write(&rule->ttypes, fp)) + return POLICYDB_ERROR; - buf[0] = cpu_to_le32(ftr->tclass); - buf[1] = cpu_to_le32(ftr->otype); - buf[2] = cpu_to_le32(ftr->flags); + buf[0] = cpu_to_le32(perm->tclass); + buf[1] = cpu_to_le32(perm->data); + buf[2] = cpu_to_le32(rule->flags); + + if (p->policyvers >= + MOD_POLICYDB_VERSION_SELF_TYPETRANS) { + entries = 3; + } else if (!(rule->flags & RULE_SELF)) { + entries = 2; + } else { + ERR(fp->handle, + "Module contains a self rule not supported by the target module policy version"); + return POLICYDB_ERROR; + } - if (p->policyvers >= MOD_POLICYDB_VERSION_SELF_TYPETRANS) { - entries = 3; - } else if (!(ftr->flags & RULE_SELF)) { - entries = 2; - } else { - ERR(fp->handle, - "Module contains a self rule not supported by the target module policy version"); - return POLICYDB_ERROR; + items = put_entry(buf, sizeof(uint32_t), entries, fp); + if (items != entries) + return POLICYDB_ERROR; } - - items = put_entry(buf, sizeof(uint32_t), entries, fp); - if (items != entries) - return POLICYDB_ERROR; } return POLICYDB_SUCCESS; } @@ -2283,7 +2301,7 @@ static int avrule_decl_write(avrule_decl_t * decl, int num_scope_syms, } if (p->policyvers >= MOD_POLICYDB_VERSION_FILENAME_TRANS && - filename_trans_rule_write(p, decl->filename_trans_rules, fp)) + filename_trans_rule_write(p, decl->avrules, fp)) return POLICYDB_ERROR; if (p->policyvers >= MOD_POLICYDB_VERSION_RANGETRANS && From patchwork Wed May 31 11:49:10 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juraj Marcin X-Patchwork-Id: 13262083 X-Patchwork-Delegate: plautrba@redhat.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A0C22C77B7A for ; Wed, 31 May 2023 11:50:22 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235417AbjEaLuW (ORCPT ); Wed, 31 May 2023 07:50:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48802 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235494AbjEaLuU (ORCPT ); Wed, 31 May 2023 07:50:20 -0400 Received: from sender11-of-o52.zoho.eu (sender11-of-o52.zoho.eu [31.186.226.238]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C7F55E8 for ; Wed, 31 May 2023 04:50:15 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1685533810; cv=none; d=zohomail.eu; s=zohoarc; b=Mobmp2AK0IMtEP6wYGXWrcmeWfvEEVFjego1hTVtVBlYNP/MNl+9/uHQ4dp3BnNGbtsGCFyzuUacCXEEuN07rtiIj2rgNVcbIxBL8kOkRTwRhJ8LihoKAF24QRomnWf1GQvdoIYsxOFb6wPpd4ADFkdRhD8Nz+U9q9dVbiFCd/I= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.eu; s=zohoarc; t=1685533810; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:To; bh=uiMF4P6loWxDt/pNUCfctiClDniKSQxuJvG7UG1U1f4=; b=F92CxUkMljSRJBRbyYCGKN1TQkbeDYrC/Tbl3zjyVtENgj5/RaxNvOGskVDGEWD/tgip3wPcsLYfxFs766pt5HNEx6FBpU1YDMGIozBDaPPrRNTf9X0xeCsJxa1HbdkUCqnYR/5rZn+rJGNqLZv2DFO/Xtkryv044Ou3OOulvSk= ARC-Authentication-Results: i=1; mx.zohomail.eu; dkim=pass header.i=jurajmarcin.com; spf=pass smtp.mailfrom=juraj@jurajmarcin.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1685533810; s=zoho; d=jurajmarcin.com; i=juraj@jurajmarcin.com; h=From:From:To:To:Cc:Cc:Subject:Subject:Date:Date:Message-Id:Message-Id:In-Reply-To:References:MIME-Version:Content-Transfer-Encoding:Reply-To; bh=uiMF4P6loWxDt/pNUCfctiClDniKSQxuJvG7UG1U1f4=; b=NJ+SSLKIlxdZd4zp6PeONiCuo5UoJXF2NBTmm0NIL95XCJV5H253fg0jwIqVP7Vf pvZuoSMvrMH9kF97nlFtt6Xs8Gi7rVAJWav8+qQtWDjJqvnO+D8pU96EnIdHn1c1I+I WpEka0JgX76Jdf+72zq9Las+KcKAtexOgXMtsdJ4= Received: from morty01.jurajmarcin.com (129.159.244.31 [129.159.244.31]) by mx.zoho.eu with SMTPS id 1685533800901683.0349773556868; Wed, 31 May 2023 13:50:00 +0200 (CEST) Received: from jmarcin-t14s-01.redhat.com (unknown [147.251.183.113]) by morty01.jurajmarcin.com (Postfix) with ESMTPSA id 3165D2081F76; Wed, 31 May 2023 11:50:00 +0000 (UTC) From: Juraj Marcin To: selinux@vger.kernel.org Cc: Stephen Smalley , Ondrej Mosnacek Subject: [PATCH 4/8] libsepol: implement new kernel binary format for avtab Date: Wed, 31 May 2023 13:49:10 +0200 Message-Id: <20230531114914.2237609-5-juraj@jurajmarcin.com> In-Reply-To: <20230531114914.2237609-1-juraj@jurajmarcin.com> References: <20230531114914.2237609-1-juraj@jurajmarcin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org Implement a new binary policy format that closely matches the new internal representation introduced in the previous patch. This patch bumps the maximum kernel policy version and implements reading/writing functions such that kernel binary policy structure matches internal representation. These changes can cause the binary policy to grow in size due to effectively undoing the benefits of the commit 8206b8cb ("libsepol: implement POLICYDB_VERSION_COMP_FTRANS "), but this will be mitigated by adding the prefix/suffix support as described in the previous patch. Reviewed-by: Ondrej Mosnacek Signed-off-by: Juraj Marcin --- libsepol/include/sepol/policydb/hashtab.h | 8 ++ libsepol/include/sepol/policydb/policydb.h | 3 +- libsepol/src/avtab.c | 88 ++++++++++++++++++++-- libsepol/src/policydb.c | 8 ++ libsepol/src/write.c | 86 +++++++++++++++++---- 5 files changed, 172 insertions(+), 21 deletions(-) diff --git a/libsepol/include/sepol/policydb/hashtab.h b/libsepol/include/sepol/policydb/hashtab.h index 3a6b953e..92fedf69 100644 --- a/libsepol/include/sepol/policydb/hashtab.h +++ b/libsepol/include/sepol/policydb/hashtab.h @@ -116,6 +116,14 @@ static inline int hashtab_is_empty(hashtab_t h) return !h || !h->size; } +/* Returns number of elements in the hashtab h or 0 is h is NULL */ +static inline uint32_t hashtab_nel(hashtab_t h) +{ + if (!h) + return 0; + return h->nel; +} + #ifdef __cplusplus } #endif diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h index d30f26af..528c1cad 100644 --- a/libsepol/include/sepol/policydb/policydb.h +++ b/libsepol/include/sepol/policydb/policydb.h @@ -722,10 +722,11 @@ extern int policydb_set_target_platform(policydb_t *p, int platform); #define POLICYDB_VERSION_INFINIBAND 31 /* Linux-specific */ #define POLICYDB_VERSION_GLBLUB 32 #define POLICYDB_VERSION_COMP_FTRANS 33 /* compressed filename transitions */ +#define POLICYDB_VERSION_AVTAB_FTRANS 34 /* filename transitions moved to avtab */ /* Range of policy versions we understand*/ #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE -#define POLICYDB_VERSION_MAX POLICYDB_VERSION_COMP_FTRANS +#define POLICYDB_VERSION_MAX POLICYDB_VERSION_AVTAB_FTRANS /* Module versions and specific changes*/ #define MOD_POLICYDB_VERSION_BASE 4 diff --git a/libsepol/src/avtab.c b/libsepol/src/avtab.c index 3d8d6769..33441a34 100644 --- a/libsepol/src/avtab.c +++ b/libsepol/src/avtab.c @@ -446,6 +446,87 @@ void avtab_hash_eval(avtab_t * h, char *tag) tag, h->nel, slots_used, h->nslot, max_chain_len); } +static int avtab_read_name_trans(policy_file_t *fp, symtab_t *target) +{ + int rc; + uint32_t buf32[2], nel, i, len, *otype = NULL; + char *name = NULL; + + /* read number of name transitions */ + rc = next_entry(buf32, fp, sizeof(uint32_t) * 1); + if (rc < 0) + return rc; + nel = le32_to_cpu(buf32[0]); + + rc = symtab_init(target, nel); + if (rc < 0) + return rc; + + /* read name transitions */ + for (i = 0; i < nel; i++) { + rc = SEPOL_ENOMEM; + otype = malloc(sizeof(uint32_t)); + if (!otype) + goto exit; + + /* read name transition otype and name length */ + rc = next_entry(buf32, fp, sizeof(uint32_t) * 2); + if (rc < 0) + goto exit; + *otype = le32_to_cpu(buf32[0]); + len = le32_to_cpu(buf32[1]); + + /* read the name */ + rc = str_read(&name, fp, len); + if (rc < 0) + goto exit; + + rc = hashtab_insert(target->table, name, otype); + if (rc < 0) + goto exit; + otype = NULL; + name = NULL; + } + +exit: + free(otype); + free(name); + return rc; +} + +static int avtab_trans_read(policy_file_t *fp, uint32_t vers, + avtab_trans_t *trans) +{ + int rc; + uint32_t buf32[1]; + + if (vers < POLICYDB_VERSION_AVTAB_FTRANS) { + rc = next_entry(buf32, fp, sizeof(uint32_t)); + if (rc < 0) { + ERR(fp->handle, "truncated entry"); + return SEPOL_ERR; + } + trans->otype = le32_to_cpu(*buf32); + return SEPOL_OK; + } + + /* read otype */ + rc = next_entry(buf32, fp, sizeof(uint32_t) * 1); + if (rc < 0) + return rc; + trans->otype = le32_to_cpu(buf32[0]); + + rc = avtab_read_name_trans(fp, &trans->name_trans); + if (rc < 0) + goto bad; + + return SEPOL_OK; + +bad: + avtab_trans_destroy(trans); + return rc; +} + /* Ordering of datums in the original avtab format in the policy file. */ static const uint16_t spec_order[] = { AVTAB_ALLOWED, @@ -609,12 +690,9 @@ int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a, xperms.perms[i] = le32_to_cpu(buf32[i]); datum.xperms = &xperms; } else if (key.specified & AVTAB_TRANSITION) { - rc = next_entry(buf32, fp, sizeof(uint32_t)); - if (rc < 0) { - ERR(fp->handle, "truncated entry"); + rc = avtab_trans_read(fp, vers, &trans); + if (rc < 0) return -1; - } - trans.otype = le32_to_cpu(*buf32); datum.trans = &trans; } else { rc = next_entry(buf32, fp, sizeof(uint32_t)); diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c index 30c70d29..f2271524 100644 --- a/libsepol/src/policydb.c +++ b/libsepol/src/policydb.c @@ -208,6 +208,13 @@ static const struct policydb_compat_info policydb_compat[] = { .ocon_num = OCON_IBENDPORT + 1, .target_platform = SEPOL_TARGET_SELINUX, }, + { + .type = POLICY_KERN, + .version = POLICYDB_VERSION_AVTAB_FTRANS, + .sym_num = SYM_NUM, + .ocon_num = OCON_IBENDPORT + 1, + .target_platform = SEPOL_TARGET_SELINUX, + }, { .type = POLICY_BASE, .version = MOD_POLICYDB_VERSION_BASE, @@ -4099,6 +4106,7 @@ int policydb_read(policydb_t * p, struct policy_file *fp, unsigned verbose) if (role_allow_read(&p->role_allow, fp)) goto bad; if (r_policyvers >= POLICYDB_VERSION_FILENAME_TRANS && + r_policyvers < POLICYDB_VERSION_AVTAB_FTRANS && avtab_filename_trans_read(fp, r_policyvers, &p->te_avtab)) goto bad; } else { diff --git a/libsepol/src/write.c b/libsepol/src/write.c index 7b0ef705..12f14670 100644 --- a/libsepol/src/write.c +++ b/libsepol/src/write.c @@ -102,6 +102,56 @@ static uint16_t spec_order[] = { AVTAB_MEMBER }; +static int avtab_trans_write_helper(hashtab_key_t hkey, hashtab_datum_t hdatum, + void *fp) +{ + char *name = hkey; + uint32_t *otype = hdatum; + uint32_t buf32[2], len; + size_t items; + + /* write filename transition otype and name length */ + len = strlen(name); + buf32[0] = cpu_to_le32(*otype); + buf32[1] = cpu_to_le32(len); + items = put_entry(buf32, sizeof(uint32_t), 2, fp); + if (items != 2) + return -1; + + /* write filename transition name */ + items = put_entry(name, sizeof(char), len, fp); + if (items != len) + return -1; + + return 0; +} + +static int avtab_trans_write(policydb_t *p, const avtab_trans_t *cur, + policy_file_t *fp) +{ + size_t items; + uint32_t buf32[2]; + + if (p->policyvers >= POLICYDB_VERSION_AVTAB_FTRANS) { + /* write otype and number of filename transitions */ + buf32[0] = cpu_to_le32(cur->otype); + buf32[1] = cpu_to_le32(hashtab_nel(cur->name_trans.table)); + items = put_entry(buf32, sizeof(uint32_t), 2, fp); + if (items != 2) + return -1; + + /* write filename transitions */ + return hashtab_map(cur->name_trans.table, + avtab_trans_write_helper, fp); + } else if (cur->otype) { + buf32[0] = cpu_to_le32(cur->otype); + items = put_entry(buf32, sizeof(uint32_t), 1, fp); + if (items != 1) + return -1; + } + return 0; +} + static int avtab_write_item(policydb_t * p, avtab_ptr_t cur, struct policy_file *fp, unsigned merge, unsigned commit, uint32_t * nel) @@ -116,8 +166,12 @@ static int avtab_write_item(policydb_t * p, && p->policyvers < POLICYDB_VERSION_AVTAB); unsigned int i; - /* skip entries which only contain filename transitions */ - if (cur->key.specified & AVTAB_TRANSITION && !cur->datum.trans->otype) { + /* + * skip entries which only contain filename transitions in versions + * before filename transitions were moved to avtab + */ + if (p->policyvers < POLICYDB_VERSION_AVTAB_FTRANS && + cur->key.specified & AVTAB_TRANSITION && !cur->datum.trans->otype) { /* if oldvers, reduce nel, because this node will be skipped */ if (oldvers && nel) (*nel)--; @@ -271,9 +325,7 @@ static int avtab_write_item(policydb_t * p, if (items != 8) return POLICYDB_ERROR; } else if (cur->key.specified & AVTAB_TRANSITION) { - buf32[0] = cpu_to_le32(cur->datum.trans->otype); - items = put_entry(buf32, sizeof(uint32_t), 1, fp); - if (items != 1) + if (avtab_trans_write(p, cur->datum.trans, fp) < 0) return POLICYDB_ERROR; } else { buf32[0] = cpu_to_le32(cur->datum.data); @@ -326,15 +378,18 @@ static int avtab_write(struct policydb *p, avtab_t * a, struct policy_file *fp) * filename transitions. */ nel = a->nel; - /* - * entries containing only filename transitions are skipped and - * written out later - */ - for (i = 0; i < a->nslot; i++) { - for (cur = a->htable[i]; cur; cur = cur->next) { - if (cur->key.specified & AVTAB_TRANSITION && - !cur->datum.trans->otype) - nel--; + if (p->policyvers < POLICYDB_VERSION_AVTAB_FTRANS) { + /* + * entries containing only filename transitions are + * skipped and written out later + */ + for (i = 0; i < a->nslot; i++) { + for (cur = a->htable[i]; cur; cur = cur->next) { + if ((cur->key.specified + & AVTAB_TRANSITION) && + !cur->datum.trans->otype) + nel--; + } } } nel = cpu_to_le32(nel); @@ -2625,7 +2680,8 @@ int policydb_write(policydb_t * p, struct policy_file *fp) if (role_allow_write(p->role_allow, fp)) return POLICYDB_ERROR; if (p->policyvers >= POLICYDB_VERSION_FILENAME_TRANS) { - if (avtab_filename_trans_write(p, &p->te_avtab, fp)) + if (p->policyvers < POLICYDB_VERSION_AVTAB_FTRANS && + avtab_filename_trans_write(p, &p->te_avtab, fp)) return POLICYDB_ERROR; } else if (avtab_has_filename_transitions(&p->te_avtab)) { WARN(fp->handle, From patchwork Wed May 31 11:49:11 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juraj Marcin X-Patchwork-Id: 13262084 X-Patchwork-Delegate: plautrba@redhat.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id CEB5EC77B73 for ; Wed, 31 May 2023 11:50:23 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235449AbjEaLuW (ORCPT ); Wed, 31 May 2023 07:50:22 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48784 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235459AbjEaLuR (ORCPT ); Wed, 31 May 2023 07:50:17 -0400 Received: from sender11-of-o52.zoho.eu (sender11-of-o52.zoho.eu [31.186.226.238]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D438110B for ; Wed, 31 May 2023 04:50:15 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1685533810; cv=none; d=zohomail.eu; s=zohoarc; b=Z6cm4X3Y/fgqXmSDxp8zVSLB3nuBbmEfbxpLYBBnmOwnWVMDpuRzYrN/zTZBuL8L4F0hMhOXrivqvSu4+o0ydrrcehPYerF0YRm/kJAC0/BpQErEFq1dATchxZz0EJ/7vfw6S3fezPGGxfHSxXJ3PBRUlXUHHUxxuPNLOQk9xoM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.eu; s=zohoarc; t=1685533810; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:To; bh=LhRaBJpMxDiEU8lVXlQ+rpeXiqiRJEdT9bHsLySyTYo=; b=VD6LUV+/65K9eLHsjwEXz/KPNvuM9koMaGnDLUVamYIpYWGdyWAvwe8YfjdhpjNr6m2Zu1NN3KIVgZpMqf19ucgNJdU7JzMkslL9r2YZ7e/duFhBHSRf5EsLuzAiHeCcHV8DNdLENYyylQw9Zd1/X9/k0EJxaErwN8Z4JEiS9uw= ARC-Authentication-Results: i=1; mx.zohomail.eu; dkim=pass header.i=jurajmarcin.com; spf=pass smtp.mailfrom=juraj@jurajmarcin.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1685533810; s=zoho; d=jurajmarcin.com; i=juraj@jurajmarcin.com; h=From:From:To:To:Cc:Cc:Subject:Subject:Date:Date:Message-Id:Message-Id:In-Reply-To:References:MIME-Version:Content-Transfer-Encoding:Reply-To; bh=LhRaBJpMxDiEU8lVXlQ+rpeXiqiRJEdT9bHsLySyTYo=; b=JJ937ccw+5O6YcONZ4FGETW+zU1ImeF7RG03sA9A+TfwySGjoBcH8XvKSODPdq3t 40xLIKQLONZFmhPeKmoPJq+wxzoupdCNgMDVIutfaOXHBUse/UqeYUf1mep81owbF6P Rrz5t5f+jecwCTG5VwFP9Z3KvKrPh5JubNNjYkKw= Received: from morty01.jurajmarcin.com (129.159.244.31 [129.159.244.31]) by mx.zoho.eu with SMTPS id 1685533803669770.9887823019116; Wed, 31 May 2023 13:50:03 +0200 (CEST) Received: from jmarcin-t14s-01.redhat.com (unknown [147.251.183.113]) by morty01.jurajmarcin.com (Postfix) with ESMTPSA id 1E4292081F76; Wed, 31 May 2023 11:50:03 +0000 (UTC) From: Juraj Marcin To: selinux@vger.kernel.org Cc: Stephen Smalley , Ondrej Mosnacek Subject: [PATCH 5/8] libsepol: implement new module binary format of avrule Date: Wed, 31 May 2023 13:49:11 +0200 Message-Id: <20230531114914.2237609-6-juraj@jurajmarcin.com> In-Reply-To: <20230531114914.2237609-1-juraj@jurajmarcin.com> References: <20230531114914.2237609-1-juraj@jurajmarcin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org Implement a new module policy format that closely matches the new internal representation of avrule introduced in the previous patch. This patch bumps the maximum module policy version and implements reading/writing functions such that the module binary policy structure matches its internal representation, namely, the object name attribute used for the filename transition rules. These changes have no significant effect on the size of the module policy file (tested with Fedora policy). Reviewed-by: Ondrej Mosnacek Signed-off-by: Juraj Marcin --- libsepol/include/sepol/policydb/policydb.h | 3 ++- libsepol/src/policydb.c | 28 ++++++++++++++++++++++ libsepol/src/write.c | 24 ++++++++++++++++--- 3 files changed, 51 insertions(+), 4 deletions(-) diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h index 528c1cad..5efd0a47 100644 --- a/libsepol/include/sepol/policydb/policydb.h +++ b/libsepol/include/sepol/policydb/policydb.h @@ -749,9 +749,10 @@ extern int policydb_set_target_platform(policydb_t *p, int platform); #define MOD_POLICYDB_VERSION_INFINIBAND 19 #define MOD_POLICYDB_VERSION_GLBLUB 20 #define MOD_POLICYDB_VERSION_SELF_TYPETRANS 21 +#define MOD_POLICYDB_VERSION_AVRULE_FTRANS 22 #define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE -#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_SELF_TYPETRANS +#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_AVRULE_FTRANS #define POLICYDB_CONFIG_MLS 1 diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c index f2271524..3776292a 100644 --- a/libsepol/src/policydb.c +++ b/libsepol/src/policydb.c @@ -341,6 +341,13 @@ static const struct policydb_compat_info policydb_compat[] = { .ocon_num = OCON_IBENDPORT + 1, .target_platform = SEPOL_TARGET_SELINUX, }, + { + .type = POLICY_BASE, + .version = MOD_POLICYDB_VERSION_AVRULE_FTRANS, + .sym_num = SYM_NUM, + .ocon_num = OCON_IBENDPORT + 1, + .target_platform = SEPOL_TARGET_SELINUX, + }, { .type = POLICY_MOD, .version = MOD_POLICYDB_VERSION_BASE, @@ -467,6 +474,13 @@ static const struct policydb_compat_info policydb_compat[] = { .ocon_num = 0, .target_platform = SEPOL_TARGET_SELINUX, }, + { + .type = POLICY_MOD, + .version = MOD_POLICYDB_VERSION_AVRULE_FTRANS, + .sym_num = SYM_NUM, + .ocon_num = 0, + .target_platform = SEPOL_TARGET_SELINUX, + }, }; #if 0 @@ -3202,6 +3216,19 @@ static avrule_t *avrule_read(policydb_t * p, struct policy_file *fp) tail = cur; } + if (p->policyvers >= MOD_POLICYDB_VERSION_AVRULE_FTRANS && + avrule->specified & AVRULE_TRANSITION) { + rc = next_entry(buf, fp, sizeof(uint32_t)); + if (rc < 0) + goto bad; + len = le32_to_cpu(*buf); + if (len) { + rc = str_read(&avrule->object_name, fp, len); + if (rc < 0) + goto bad; + } + } + if (avrule->specified & AVRULE_XPERMS) { uint8_t buf8; size_t nel = ARRAY_SIZE(avrule->xperms->perms); @@ -3633,6 +3660,7 @@ static int avrule_decl_read(policydb_t * p, avrule_decl_t * decl, } if (p->policyvers >= MOD_POLICYDB_VERSION_FILENAME_TRANS && + p->policyvers < MOD_POLICYDB_VERSION_AVRULE_FTRANS && filename_trans_rule_read(p, &decl->avrules, fp)) return -1; diff --git a/libsepol/src/write.c b/libsepol/src/write.c index 12f14670..5ba3f2b0 100644 --- a/libsepol/src/write.c +++ b/libsepol/src/write.c @@ -2024,8 +2024,9 @@ static int avrule_write(policydb_t *p, avrule_t * avrule, uint32_t buf[32], len; class_perm_node_t *cur; - /* skip filename transitions for now */ - if (avrule->specified & AVRULE_TRANSITION && avrule->object_name) + /* skip filename transitions if writing older version without name */ + if (p->policyvers < MOD_POLICYDB_VERSION_AVRULE_FTRANS && + avrule->specified & AVRULE_TRANSITION && avrule->object_name) return POLICYDB_SUCCESS; if (p->policyvers < MOD_POLICYDB_VERSION_SELF_TYPETRANS && @@ -2072,6 +2073,21 @@ static int avrule_write(policydb_t *p, avrule_t * avrule, cur = cur->next; } + if (p->policyvers >= MOD_POLICYDB_VERSION_AVRULE_FTRANS && + avrule->specified & AVRULE_TRANSITION) { + len = avrule->object_name ? strlen(avrule->object_name) : 0; + *buf = cpu_to_le32(len); + items = put_entry(buf, sizeof(uint32_t), 1, fp); + if (items != 1) + return POLICYDB_ERROR; + if (avrule->object_name) { + items = put_entry(avrule->object_name, sizeof(char), + len, fp); + if (items != len) + return POLICYDB_ERROR; + } + } + if (avrule->specified & AVRULE_XPERMS) { size_t nel = ARRAY_SIZE(avrule->xperms->perms); uint32_t buf32[nel]; @@ -2121,7 +2137,8 @@ static int avrule_write_list(policydb_t *p, avrule_t * avrules, avrule = avrules; len = 0; while (avrule) { - if (!(avrule->specified & AVRULE_TRANSITION && + if (p->policyvers >= MOD_POLICYDB_VERSION_AVRULE_FTRANS || + !(avrule->specified & AVRULE_TRANSITION && avrule->object_name)) len++; avrule = avrule->next; @@ -2356,6 +2373,7 @@ static int avrule_decl_write(avrule_decl_t * decl, int num_scope_syms, } if (p->policyvers >= MOD_POLICYDB_VERSION_FILENAME_TRANS && + p->policyvers < MOD_POLICYDB_VERSION_AVRULE_FTRANS && filename_trans_rule_write(p, decl->avrules, fp)) return POLICYDB_ERROR; From patchwork Wed May 31 11:49:12 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juraj Marcin X-Patchwork-Id: 13262086 X-Patchwork-Delegate: plautrba@redhat.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 67525C7EE2F for ; Wed, 31 May 2023 11:50:24 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235459AbjEaLuX (ORCPT ); Wed, 31 May 2023 07:50:23 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48804 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235519AbjEaLuU (ORCPT ); Wed, 31 May 2023 07:50:20 -0400 Received: from sender11-of-o52.zoho.eu (sender11-of-o52.zoho.eu [31.186.226.238]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 88A17123 for ; Wed, 31 May 2023 04:50:16 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1685533810; cv=none; d=zohomail.eu; s=zohoarc; b=Jgs5+FPLyFODA4iBCmZDPXXyCc4NoRb/NIOrSy+WvzxGu21wbpSD6axcJOvEwLGV2W3/c2aSAVkIlaRoHUPBVhDO/xWkDKD0VCWuL/CkR0933X4LNUB4GsKuetDRkqQhhO3mO6vSRFbMqqgJ0IMfFZ6GXhXUDqG/1qg4rcRTGEI= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.eu; s=zohoarc; t=1685533810; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:To; bh=WQrQZbDHPe6M8BVXvXlQLQPMzAA43u63+5hh2oEHMyw=; b=cGCLwZIIye4XglitiPaiPpWnFdTdVO6r8GKAoiHpjaw4gq/nWvzFsY+mGnHJ3cXUCCLMkl5wH2pynnJurLDmXD32CDAaYkoAs1nhQvfL2WMzX/SX8onkPmWFDGQQK/CFBnSaUdzWoIYhIoN2yfqVNuV5YiMYb3ggbV65R8uBm0U= ARC-Authentication-Results: i=1; mx.zohomail.eu; dkim=pass header.i=jurajmarcin.com; spf=pass smtp.mailfrom=juraj@jurajmarcin.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1685533810; s=zoho; d=jurajmarcin.com; i=juraj@jurajmarcin.com; h=From:From:To:To:Cc:Cc:Subject:Subject:Date:Date:Message-Id:Message-Id:In-Reply-To:References:MIME-Version:Content-Transfer-Encoding:Reply-To; bh=WQrQZbDHPe6M8BVXvXlQLQPMzAA43u63+5hh2oEHMyw=; b=Xokcaftb3z80UvrYLHW06qICDEUqD4nY/Srbd4/+xwBgvbemlHLfaVMMFlZ5MuBt 31ejPph4UUlZQ9SScr0iH8w0GPRhbOk3Lp+wLiXz6izrapqS4sSTD7rXuqOfx3WqZ2o TRBP0dTdrnBICNMn1r3bRvI0Ln+oI2maphoB6QUQ= Received: from morty01.jurajmarcin.com (129.159.244.31 [129.159.244.31]) by mx.zoho.eu with SMTPS id 1685533806790703.6871953671595; Wed, 31 May 2023 13:50:06 +0200 (CEST) Received: from jmarcin-t14s-01.redhat.com (unknown [147.251.183.113]) by morty01.jurajmarcin.com (Postfix) with ESMTPSA id 3750C2081F76; Wed, 31 May 2023 11:50:06 +0000 (UTC) From: Juraj Marcin To: selinux@vger.kernel.org Cc: Stephen Smalley , Ondrej Mosnacek Subject: [PATCH 6/8] checkpolicy, libsepol: add prefix/suffix support to kernel policy Date: Wed, 31 May 2023 13:49:12 +0200 Message-Id: <20230531114914.2237609-7-juraj@jurajmarcin.com> In-Reply-To: <20230531114914.2237609-1-juraj@jurajmarcin.com> References: <20230531114914.2237609-1-juraj@jurajmarcin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org Currently, filename type transitions support only exact name matching. However, in practice, the names contain variable parts. This leads to many duplicated rules in the policy that differ only in the part of the name, or it is even impossible to cover all possible combinations. This patch extends the filename type transitions structures to include new types of filename transitions - prefix and suffix filename transitions. It also implements the reading and writing of those rules in the kernel binary policy format together with increasing its version. Reviewed-by: Ondrej Mosnacek Signed-off-by: Juraj Marcin --- checkpolicy/test/dispol.c | 25 +++++++++- libsepol/include/sepol/policydb/avtab.h | 2 + libsepol/include/sepol/policydb/policydb.h | 9 +++- libsepol/src/avtab.c | 13 +++++ libsepol/src/kernel_to_cil.c | 30 +++++++++++- libsepol/src/kernel_to_common.h | 1 + libsepol/src/kernel_to_conf.c | 30 +++++++++++- libsepol/src/policydb.c | 7 +++ libsepol/src/policydb_validate.c | 10 +++- libsepol/src/write.c | 55 ++++++++++++++++++++-- 10 files changed, 170 insertions(+), 12 deletions(-) diff --git a/checkpolicy/test/dispol.c b/checkpolicy/test/dispol.c index 4455407c..064cbd4e 100644 --- a/checkpolicy/test/dispol.c +++ b/checkpolicy/test/dispol.c @@ -82,6 +82,7 @@ typedef struct { avtab_key_t *key; policydb_t *p; FILE *fp; + name_trans_match_t match; } render_name_trans_args_t; static int render_name_trans_helper(hashtab_key_t k, hashtab_datum_t d, void *a) @@ -93,7 +94,22 @@ static int render_name_trans_helper(hashtab_key_t k, hashtab_datum_t d, void *a) fprintf(args->fp, "type_transition "); render_key(args->key, args->p, args->fp); render_type(*otype, args->p, args->fp); - fprintf(args->fp, " \"%s\";\n", name); + const char *match_str = ""; + switch (args->match) { + case NAME_TRANS_MATCH_EXACT: + match_str = ""; + break; + case NAME_TRANS_MATCH_PREFIX: + match_str = " MATCH_PREFIX"; + break; + case NAME_TRANS_MATCH_SUFFIX: + match_str = " MATCH_SUFFIX"; + break; + default: + fprintf(args->fp, " ERROR: no valid name match type specified\n"); + return -1; + } + fprintf(args->fp, " \"%s\"%s;\n", name, match_str); return 0; } @@ -160,9 +176,16 @@ static int render_av_rule(avtab_key_t * key, avtab_datum_t * datum, uint32_t wha .key = key, .p = p, .fp = fp, + .match = NAME_TRANS_MATCH_EXACT, }; hashtab_map(datum->trans->name_trans.table, render_name_trans_helper, &args); + args.match = NAME_TRANS_MATCH_PREFIX; + hashtab_map(datum->trans->prefix_trans.table, + render_name_trans_helper, &args); + args.match = NAME_TRANS_MATCH_SUFFIX; + hashtab_map(datum->trans->suffix_trans.table, + render_name_trans_helper, &args); } if (key->specified & AVTAB_MEMBER) { fprintf(fp, "type_member "); diff --git a/libsepol/include/sepol/policydb/avtab.h b/libsepol/include/sepol/policydb/avtab.h index 5dc720cc..870fb08a 100644 --- a/libsepol/include/sepol/policydb/avtab.h +++ b/libsepol/include/sepol/policydb/avtab.h @@ -74,6 +74,8 @@ typedef struct avtab_key { typedef struct avtab_trans { uint32_t otype; /* resulting type of the new object */ symtab_t name_trans; /* filename transitions */ + symtab_t prefix_trans; /* prefix filename transitions */ + symtab_t suffix_trans; /* prefix filename transitions */ } avtab_trans_t; typedef struct avtab_extended_perms { diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h index 5efd0a47..a2df4a62 100644 --- a/libsepol/include/sepol/policydb/policydb.h +++ b/libsepol/include/sepol/policydb/policydb.h @@ -252,6 +252,12 @@ typedef struct av_extended_perms { uint32_t perms[EXTENDED_PERMS_LEN]; } av_extended_perms_t; +typedef enum name_trans_match { + NAME_TRANS_MATCH_EXACT, + NAME_TRANS_MATCH_PREFIX, + NAME_TRANS_MATCH_SUFFIX, +} name_trans_match_t; + typedef struct avrule { /* these typedefs are almost exactly the same as those in avtab.h - they are * here because of the need to include neverallow and dontaudit messages */ @@ -723,10 +729,11 @@ extern int policydb_set_target_platform(policydb_t *p, int platform); #define POLICYDB_VERSION_GLBLUB 32 #define POLICYDB_VERSION_COMP_FTRANS 33 /* compressed filename transitions */ #define POLICYDB_VERSION_AVTAB_FTRANS 34 /* filename transitions moved to avtab */ +#define POLICYDB_VERSION_PREFIX_SUFFIX 35 /* prefix/suffix support for filename transitions */ /* Range of policy versions we understand*/ #define POLICYDB_VERSION_MIN POLICYDB_VERSION_BASE -#define POLICYDB_VERSION_MAX POLICYDB_VERSION_AVTAB_FTRANS +#define POLICYDB_VERSION_MAX POLICYDB_VERSION_PREFIX_SUFFIX /* Module versions and specific changes*/ #define MOD_POLICYDB_VERSION_BASE 4 diff --git a/libsepol/src/avtab.c b/libsepol/src/avtab.c index 33441a34..45cbb3a1 100644 --- a/libsepol/src/avtab.c +++ b/libsepol/src/avtab.c @@ -327,6 +327,10 @@ void avtab_trans_destroy(avtab_trans_t *trans) { hashtab_map(trans->name_trans.table, avtab_trans_destroy_helper, NULL); symtab_destroy(&trans->name_trans); + hashtab_map(trans->prefix_trans.table, avtab_trans_destroy_helper, NULL); + symtab_destroy(&trans->prefix_trans); + hashtab_map(trans->suffix_trans.table, avtab_trans_destroy_helper, NULL); + symtab_destroy(&trans->suffix_trans); } void avtab_destroy(avtab_t * h) @@ -520,6 +524,15 @@ static int avtab_trans_read(policy_file_t *fp, uint32_t vers, if (rc < 0) goto bad; + if (vers >= POLICYDB_VERSION_PREFIX_SUFFIX) { + rc = avtab_read_name_trans(fp, &trans->prefix_trans); + if (rc < 0) + goto bad; + rc = avtab_read_name_trans(fp, &trans->suffix_trans); + if (rc < 0) + goto bad; + } + return SEPOL_OK; bad: diff --git a/libsepol/src/kernel_to_cil.c b/libsepol/src/kernel_to_cil.c index 655581ef..fd036fa9 100644 --- a/libsepol/src/kernel_to_cil.c +++ b/libsepol/src/kernel_to_cil.c @@ -1706,9 +1706,24 @@ static int name_trans_to_strs_helper(hashtab_key_t k, hashtab_datum_t d, void *a char *name = k; uint32_t *otype = d; name_trans_to_strs_args_t *args = a; - return strs_create_and_add(args->strs, "(%s %s %s %s \"%s\" %s)", 6, + const char *match_str = ""; + switch (args->match) { + case NAME_TRANS_MATCH_EXACT: + match_str = ""; + break; + case NAME_TRANS_MATCH_PREFIX: + match_str = " MATCH_PREFIX"; + break; + case NAME_TRANS_MATCH_SUFFIX: + match_str = " MATCH_SUFFIX"; + break; + default: + sepol_log_err("Unknown name match type: %" PRIu8, args->match); + return SEPOL_ERR; + } + return strs_create_and_add(args->strs, "(%s %s %s %s \"%s\"%s %s)", 6, args->flavor, args->src, args->tgt, - args->class, name, + args->class, name, match_str, args->pdb->p_type_val_to_name[*otype - 1]); } @@ -1796,9 +1811,20 @@ static int avtab_node_to_strs(struct policydb *pdb, avtab_key_t *key, avtab_datu .src = src, .tgt = tgt, .class = class, + .match = NAME_TRANS_MATCH_EXACT, }; rc = hashtab_map(datum->trans->name_trans.table, name_trans_to_strs_helper, &args); + if (rc < 0) + return rc; + args.match = NAME_TRANS_MATCH_PREFIX; + rc = hashtab_map(datum->trans->prefix_trans.table, + name_trans_to_strs_helper, &args); + if (rc < 0) + return rc; + args.match = NAME_TRANS_MATCH_SUFFIX; + rc = hashtab_map(datum->trans->suffix_trans.table, + name_trans_to_strs_helper, &args); } else { new = pdb->p_type_val_to_name[data - 1]; diff --git a/libsepol/src/kernel_to_common.h b/libsepol/src/kernel_to_common.h index eee2e1a0..2a1cae85 100644 --- a/libsepol/src/kernel_to_common.h +++ b/libsepol/src/kernel_to_common.h @@ -90,6 +90,7 @@ typedef struct { const char *src; const char *tgt; const char *class; + name_trans_match_t match; } name_trans_to_strs_args_t; __attribute__ ((format(printf, 1, 2))) diff --git a/libsepol/src/kernel_to_conf.c b/libsepol/src/kernel_to_conf.c index 065f84eb..50fad1fb 100644 --- a/libsepol/src/kernel_to_conf.c +++ b/libsepol/src/kernel_to_conf.c @@ -1684,11 +1684,26 @@ static int name_trans_to_strs_helper(hashtab_key_t k, hashtab_datum_t d, void *a char *name = k; uint32_t *otype = d; name_trans_to_strs_args_t *args = a; - return strs_create_and_add(args->strs, "%s %s %s:%s %s \"%s\";", 6, + const char *match_str = ""; + switch (args->match) { + case NAME_TRANS_MATCH_EXACT: + match_str = ""; + break; + case NAME_TRANS_MATCH_PREFIX: + match_str = " MATCH_PREFIX"; + break; + case NAME_TRANS_MATCH_SUFFIX: + match_str = " MATCH_SUFFIX"; + break; + default: + sepol_log_err("Unknown name match type: %" PRIu8, args->match); + return SEPOL_ERR; + } + return strs_create_and_add(args->strs, "%s %s %s:%s %s \"%s\"%s;", 6, args->flavor, args->src, args->tgt, args->class, args->pdb->p_type_val_to_name[*otype - 1], - name); + name, match_str); } static int avtab_node_to_strs(struct policydb *pdb, avtab_key_t *key, avtab_datum_t *datum, struct strs *strs) @@ -1772,9 +1787,20 @@ static int avtab_node_to_strs(struct policydb *pdb, avtab_key_t *key, avtab_datu .src = src, .tgt = tgt, .class = class, + .match = NAME_TRANS_MATCH_EXACT, }; rc = hashtab_map(datum->trans->name_trans.table, name_trans_to_strs_helper, &args); + if (rc < 0) + return rc; + args.match = NAME_TRANS_MATCH_PREFIX; + rc = hashtab_map(datum->trans->prefix_trans.table, + name_trans_to_strs_helper, &args); + if (rc < 0) + return rc; + args.match = NAME_TRANS_MATCH_SUFFIX; + rc = hashtab_map(datum->trans->suffix_trans.table, + name_trans_to_strs_helper, &args); } else { new = pdb->p_type_val_to_name[data - 1]; diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c index 3776292a..bd1a151d 100644 --- a/libsepol/src/policydb.c +++ b/libsepol/src/policydb.c @@ -215,6 +215,13 @@ static const struct policydb_compat_info policydb_compat[] = { .ocon_num = OCON_IBENDPORT + 1, .target_platform = SEPOL_TARGET_SELINUX, }, + { + .type = POLICY_KERN, + .version = POLICYDB_VERSION_PREFIX_SUFFIX, + .sym_num = SYM_NUM, + .ocon_num = OCON_IBENDPORT + 1, + .target_platform = SEPOL_TARGET_SELINUX, + }, { .type = POLICY_BASE, .version = MOD_POLICYDB_VERSION_BASE, diff --git a/libsepol/src/policydb_validate.c b/libsepol/src/policydb_validate.c index 66e8cb54..74f56842 100644 --- a/libsepol/src/policydb_validate.c +++ b/libsepol/src/policydb_validate.c @@ -851,11 +851,17 @@ static int validate_avtab_key_and_datum(avtab_key_t *k, avtab_datum_t *d, void * /* also each transition must be non empty */ if (!d->trans->otype && - (!d->trans->name_trans.table || !d->trans->name_trans.table->nel)) + hashtab_is_empty(d->trans->name_trans.table) && + hashtab_is_empty(d->trans->prefix_trans.table) && + hashtab_is_empty(d->trans->suffix_trans.table)) return -1; - /* and each filename transition must be also valid */ + /* and each name transition must be also valid */ if (hashtab_map(d->trans->name_trans.table, + validate_name_trans_helper, margs) || + hashtab_map(d->trans->prefix_trans.table, + validate_name_trans_helper, margs) || + hashtab_map(d->trans->suffix_trans.table, validate_name_trans_helper, margs)) return -1; } else if ((k->specified & AVTAB_TYPE) && validate_simpletype(d->data, margs->policy, margs->flavors)) { diff --git a/libsepol/src/write.c b/libsepol/src/write.c index 5ba3f2b0..92a7b6cf 100644 --- a/libsepol/src/write.c +++ b/libsepol/src/write.c @@ -133,16 +133,43 @@ static int avtab_trans_write(policydb_t *p, const avtab_trans_t *cur, uint32_t buf32[2]; if (p->policyvers >= POLICYDB_VERSION_AVTAB_FTRANS) { - /* write otype and number of filename transitions */ + /* write otype and number of name transitions */ buf32[0] = cpu_to_le32(cur->otype); buf32[1] = cpu_to_le32(hashtab_nel(cur->name_trans.table)); items = put_entry(buf32, sizeof(uint32_t), 2, fp); if (items != 2) return -1; - /* write filename transitions */ - return hashtab_map(cur->name_trans.table, - avtab_trans_write_helper, fp); + /* write name transitions */ + if (hashtab_map(cur->name_trans.table, + avtab_trans_write_helper, fp)) + return -1; + + if (p->policyvers >= POLICYDB_VERSION_PREFIX_SUFFIX) { + /* write number of prefix transitions */ + buf32[0] = cpu_to_le32(hashtab_nel( + cur->prefix_trans.table)); + items = put_entry(buf32, sizeof(uint32_t), 1, fp); + if (items != 1) + return -1; + + /* write prefix transitions */ + if (hashtab_map(cur->prefix_trans.table, + avtab_trans_write_helper, fp)) + return -1; + + /* write number of suffix transitions */ + buf32[0] = cpu_to_le32(hashtab_nel( + cur->suffix_trans.table)); + items = put_entry(buf32, sizeof(uint32_t), 1, fp); + if (items != 1) + return -1; + + /* write suffix transitions */ + if (hashtab_map(cur->suffix_trans.table, + avtab_trans_write_helper, fp)) + return -1; + } } else if (cur->otype) { buf32[0] = cpu_to_le32(cur->otype); items = put_entry(buf32, sizeof(uint32_t), 1, fp); @@ -2519,6 +2546,22 @@ static int avtab_has_filename_transitions(avtab_t *a) return 0; } +static int avtab_has_prefix_suffix_filename_transitions(avtab_t *a) +{ + uint32_t i; + struct avtab_node *cur; + for (i = 0; i < a->nslot; i++) { + for (cur = a->htable[i]; cur; cur = cur->next) { + if (cur->key.specified & AVTAB_TRANSITION) { + if (hashtab_nel(cur->datum.trans->prefix_trans.table) + || hashtab_nel(cur->datum.trans->suffix_trans.table)) + return 1; + } + } + } + return 0; +} + /* * Write the configuration data in a policy database * structure to a policy database binary representation @@ -2685,6 +2728,10 @@ int policydb_write(policydb_t * p, struct policy_file *fp) if (p->policy_type == POLICY_KERN) { if (avtab_write(p, &p->te_avtab, fp)) return POLICYDB_ERROR; + if (avtab_has_prefix_suffix_filename_transitions(&p->te_avtab)) { + WARN(fp->handle, + "Discarding filename prefix/suffix type transition rules"); + } if (p->policyvers < POLICYDB_VERSION_BOOL) { if (p->p_bools.nprim) WARN(fp->handle, "Discarding " From patchwork Wed May 31 11:49:13 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juraj Marcin X-Patchwork-Id: 13262087 X-Patchwork-Delegate: plautrba@redhat.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 062A2C7EE32 for ; Wed, 31 May 2023 11:50:25 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S235456AbjEaLuY (ORCPT ); Wed, 31 May 2023 07:50:24 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48814 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S235521AbjEaLuU (ORCPT ); Wed, 31 May 2023 07:50:20 -0400 Received: from sender11-of-o52.zoho.eu (sender11-of-o52.zoho.eu [31.186.226.238]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9DB2512E for ; Wed, 31 May 2023 04:50:17 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1685533812; cv=none; d=zohomail.eu; s=zohoarc; b=BAUodeSLJnhMJ2ibiCnbo2NyU9QP/zUfd+yVJxLH7gF2sNlJPX+6UhYqRxQ2zDjUOjcMIXgPofaty0mBOBAiXXMa1BGmUoVSvxRALUrpCAhoANECyarSobNk0ZziRlRJTmNSFSL4xkPQt1U/U7jDGK2DDWjI5omd6zr2IaB6RXc= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.eu; s=zohoarc; t=1685533812; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:To; bh=zTjSuG6H/3UGlixBbeS4SsN3meu6icBei8evXcezSM4=; b=Gob/4OJYSsRyOX4pVaUvsAVJRlm1xlhrfdQ/QLp5M9K9Bj8dpXfJj1cAeKlJI5iRxKWd07IvTBOsa2FXxqt+6cBxzwTRudteUtLPH8lb8Ot0YsIlbx+0SnrveRCNgiuISq3wOQT0wt/woVQUH1SG1FQsQQzS44C9HUSHqX1MAK4= ARC-Authentication-Results: i=1; mx.zohomail.eu; dkim=pass header.i=jurajmarcin.com; spf=pass smtp.mailfrom=juraj@jurajmarcin.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1685533812; s=zoho; d=jurajmarcin.com; i=juraj@jurajmarcin.com; h=From:From:To:To:Cc:Cc:Subject:Subject:Date:Date:Message-Id:Message-Id:In-Reply-To:References:MIME-Version:Content-Transfer-Encoding:Reply-To; bh=zTjSuG6H/3UGlixBbeS4SsN3meu6icBei8evXcezSM4=; b=QzcZtZhWzLKDNDTphiJ7S6Zej7blD6Yqe+8BHt20EsrPPY2Y+awaDma4FhStGe4o lcWfmfJoze9na8teTyAuZg7wj5z2dh1p3m6KWkmJShID4zzS8bQO0X3dz6CN1Z/Y3eq MQYrjmt6CDGzUzYq9YKieczVPJsQvh9D4Sw9LdKY= Received: from morty01.jurajmarcin.com (129.159.244.31 [129.159.244.31]) by mx.zoho.eu with SMTPS id 1685533810833663.9243711343653; Wed, 31 May 2023 13:50:10 +0200 (CEST) Received: from jmarcin-t14s-01.redhat.com (unknown [147.251.183.113]) by morty01.jurajmarcin.com (Postfix) with ESMTPSA id 440D42081F76; Wed, 31 May 2023 11:50:10 +0000 (UTC) From: Juraj Marcin To: selinux@vger.kernel.org Cc: Stephen Smalley , Ondrej Mosnacek Subject: [PATCH 7/8] checkpolicy, libsepol: add prefix/suffix support to module policy Date: Wed, 31 May 2023 13:49:13 +0200 Message-Id: <20230531114914.2237609-8-juraj@jurajmarcin.com> In-Reply-To: <20230531114914.2237609-1-juraj@jurajmarcin.com> References: <20230531114914.2237609-1-juraj@jurajmarcin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org This patch extends the structures for module and base policy (avrule_t) to support prefix/suffix transitions. In addition to this, it implements the necessary changes to functions for reading and writing the binary policy as well as parsing the policy conf. Reviewed-by: Ondrej Mosnacek Signed-off-by: Juraj Marcin --- checkpolicy/policy_define.c | 13 ++++--- checkpolicy/policy_define.h | 2 +- checkpolicy/policy_parse.y | 15 +++++--- checkpolicy/policy_scan.l | 6 ++++ checkpolicy/test/dismod.c | 14 ++++++++ checkpolicy/test/dispol.c | 2 +- libsepol/cil/src/cil_binary.c | 4 ++- libsepol/include/sepol/policydb/avtab.h | 1 + libsepol/include/sepol/policydb/policydb.h | 13 ++++--- libsepol/src/avtab.c | 30 ++++++++++++---- libsepol/src/expand.c | 6 +++- libsepol/src/kernel_to_common.h | 2 +- libsepol/src/link.c | 1 + libsepol/src/module_to_cil.c | 25 +++++++++++--- libsepol/src/policydb.c | 23 ++++++++++++- libsepol/src/write.c | 40 ++++++++++++++++------ 16 files changed, 154 insertions(+), 43 deletions(-) diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c index 455255ba..c3c6af72 100644 --- a/checkpolicy/policy_define.c +++ b/checkpolicy/policy_define.c @@ -1601,7 +1601,8 @@ static int set_types(type_set_t * set, char *id, int *add, char starallowed) return -1; } -static int define_compute_type_helper(int which, avrule_t ** rule, int has_filename) +static int define_compute_type_helper(int which, avrule_t ** rule, + int has_filename, uint8_t name_match) { char *id; type_datum_t *datum; @@ -1676,6 +1677,7 @@ static int define_compute_type_helper(int which, avrule_t ** rule, int has_filen goto bad; } } + avrule->name_match = name_match; ebitmap_for_each_positive_bit(&tclasses, node, i) { perm = malloc(sizeof(class_perm_node_t)); @@ -1700,7 +1702,7 @@ static int define_compute_type_helper(int which, avrule_t ** rule, int has_filen return -1; } -int define_compute_type(int which, int has_filename) +int define_compute_type(int which, int has_filename, uint8_t name_match) { char *id; avrule_t *avrule; @@ -1721,7 +1723,8 @@ int define_compute_type(int which, int has_filename) return 0; } - if (define_compute_type_helper(which, &avrule, has_filename)) + if (define_compute_type_helper(which, &avrule, has_filename, + name_match)) return -1; append_avrule(avrule); @@ -1745,7 +1748,8 @@ avrule_t *define_cond_compute_type(int which) return (avrule_t *) 1; } - if (define_compute_type_helper(which, &avrule, 0)) + if (define_compute_type_helper(which, &avrule, 0, + NAME_TRANS_MATCH_EXACT)) return COND_ERR; return avrule; @@ -2394,6 +2398,7 @@ static int avrule_cpy(avrule_t *dest, const avrule_t *src) return -1; } } + dest->name_match = src->name_match; dest->line = src->line; dest->source_filename = strdup(source_file); if (!dest->source_filename) { diff --git a/checkpolicy/policy_define.h b/checkpolicy/policy_define.h index 5d0f70e4..c1314871 100644 --- a/checkpolicy/policy_define.h +++ b/checkpolicy/policy_define.h @@ -28,7 +28,7 @@ int define_default_role(int which); int define_default_type(int which); int define_default_range(int which); int define_common_perms(void); -int define_compute_type(int which, int has_filename); +int define_compute_type(int which, int has_filename, uint8_t name_match); int define_conditional(cond_expr_t *expr, avrule_t *t_list, avrule_t *f_list ); int define_constraint(constraint_expr_t *expr); int define_dominance(void); diff --git a/checkpolicy/policy_parse.y b/checkpolicy/policy_parse.y index fccbc052..12dff7af 100644 --- a/checkpolicy/policy_parse.y +++ b/checkpolicy/policy_parse.y @@ -109,6 +109,7 @@ typedef int (* require_func_t)(int pass); %token IF %token ELSE %token TYPE_TRANSITION +%token MATCH_EXACT MATCH_PREFIX MATCH_SUFFIX %token TYPE_MEMBER %token TYPE_CHANGE %token ROLE_TRANSITION @@ -452,13 +453,19 @@ cond_dontaudit_def : DONTAUDIT names names ':' names names ';' ; ; transition_def : TYPE_TRANSITION names names ':' names identifier filename ';' - {if (define_compute_type(AVRULE_TRANSITION, 1)) return -1; } + {if (define_compute_type(AVRULE_TRANSITION, 1, NAME_TRANS_MATCH_EXACT)) return -1;} + | TYPE_TRANSITION names names ':' names identifier filename MATCH_EXACT ';' + {if (define_compute_type(AVRULE_TRANSITION, 1, NAME_TRANS_MATCH_EXACT)) return -1;} + | TYPE_TRANSITION names names ':' names identifier filename MATCH_PREFIX ';' + {if (define_compute_type(AVRULE_TRANSITION, 1, NAME_TRANS_MATCH_PREFIX)) return -1;} + | TYPE_TRANSITION names names ':' names identifier filename MATCH_SUFFIX ';' + {if (define_compute_type(AVRULE_TRANSITION, 1, NAME_TRANS_MATCH_SUFFIX)) return -1;} | TYPE_TRANSITION names names ':' names identifier ';' - {if (define_compute_type(AVRULE_TRANSITION, 0)) return -1;} + {if (define_compute_type(AVRULE_TRANSITION, 0, NAME_TRANS_MATCH_EXACT)) return -1;} | TYPE_MEMBER names names ':' names identifier ';' - {if (define_compute_type(AVRULE_MEMBER, 0)) return -1;} + {if (define_compute_type(AVRULE_MEMBER, 0, NAME_TRANS_MATCH_EXACT)) return -1;} | TYPE_CHANGE names names ':' names identifier ';' - {if (define_compute_type(AVRULE_CHANGE, 0)) return -1;} + {if (define_compute_type(AVRULE_CHANGE, 0, NAME_TRANS_MATCH_EXACT)) return -1;} ; range_trans_def : RANGE_TRANSITION names names mls_range_def ';' { if (define_range_trans(0)) return -1; } diff --git a/checkpolicy/policy_scan.l b/checkpolicy/policy_scan.l index 9fefea7b..3f568701 100644 --- a/checkpolicy/policy_scan.l +++ b/checkpolicy/policy_scan.l @@ -125,6 +125,12 @@ EXPANDATTRIBUTE | expandattribute { return(EXPANDATTRIBUTE); } TYPE_TRANSITION | type_transition { return(TYPE_TRANSITION); } +MATCH_EXACT | +match_exact { return(MATCH_EXACT); } +MATCH_PREFIX | +match_prefix { return(MATCH_PREFIX); } +MATCH_SUFFIX | +match_suffix { return(MATCH_SUFFIX); } TYPE_MEMBER | type_member { return(TYPE_MEMBER); } TYPE_CHANGE | diff --git a/checkpolicy/test/dismod.c b/checkpolicy/test/dismod.c index f26f360c..53edecee 100644 --- a/checkpolicy/test/dismod.c +++ b/checkpolicy/test/dismod.c @@ -293,6 +293,20 @@ static int display_avrule(avrule_t * avrule, policydb_t * policy, display_id(policy, fp, SYM_TYPES, avrule->perms->data - 1, ""); if (avrule->object_name) fprintf(fp, " \"%s\"", avrule->object_name); + switch (avrule->name_match) { + case NAME_TRANS_MATCH_EXACT: + /* do nothing */ + break; + case NAME_TRANS_MATCH_PREFIX: + fprintf(fp, " MATCH_PREFIX"); + break; + case NAME_TRANS_MATCH_SUFFIX: + fprintf(fp, " MATCH_SUFFIX"); + break; + default: + fprintf(fp, " ERROR: no valid name match type specified\n"); + return -1; + } } else if (avrule->specified & AVRULE_XPERMS) { avtab_extended_perms_t xperms; int i; diff --git a/checkpolicy/test/dispol.c b/checkpolicy/test/dispol.c index 064cbd4e..87cd6a32 100644 --- a/checkpolicy/test/dispol.c +++ b/checkpolicy/test/dispol.c @@ -82,7 +82,7 @@ typedef struct { avtab_key_t *key; policydb_t *p; FILE *fp; - name_trans_match_t match; + uint8_t match; } render_name_trans_args_t; static int render_name_trans_helper(hashtab_key_t k, hashtab_datum_t d, void *a) diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c index 996bad70..ffa44be7 100644 --- a/libsepol/cil/src/cil_binary.c +++ b/libsepol/cil/src/cil_binary.c @@ -1211,7 +1211,8 @@ static int __cil_typetransition_to_avtab_helper(policydb_t *pdb, avt_key.target_type = sepol_tgt->s.value; avt_key.target_class = sepol_obj->s.value; rc = avtab_insert_filename_trans(&pdb->te_avtab, &avt_key, - sepol_result->s.value, name, &otype); + sepol_result->s.value, name, NAME_TRANS_MATCH_EXACT, + &otype); if (rc != SEPOL_OK) { if (rc == SEPOL_EEXIST) { if (sepol_result->s.value!= otype) { @@ -4651,6 +4652,7 @@ static avrule_t *__cil_init_sepol_avrule(uint32_t kind, struct cil_tree_node *no __cil_init_sepol_type_set(&avrule->ttypes); avrule->perms = NULL; avrule->object_name = NULL; + avrule->name_match = NAME_TRANS_MATCH_EXACT; avrule->line = node->line; avrule->source_filename = NULL; diff --git a/libsepol/include/sepol/policydb/avtab.h b/libsepol/include/sepol/policydb/avtab.h index 870fb08a..7d892879 100644 --- a/libsepol/include/sepol/policydb/avtab.h +++ b/libsepol/include/sepol/policydb/avtab.h @@ -156,6 +156,7 @@ extern avtab_ptr_t avtab_search_node_next(avtab_ptr_t node, int specified); extern int avtab_insert_filename_trans(avtab_t *a, avtab_key_t *key, uint32_t otype, const char *name, + uint8_t name_match, uint32_t *present_otype); extern int avtab_filename_trans_read(void *fp, uint32_t vers, avtab_t *a); diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h index a2df4a62..48b7b8bb 100644 --- a/libsepol/include/sepol/policydb/policydb.h +++ b/libsepol/include/sepol/policydb/policydb.h @@ -252,12 +252,6 @@ typedef struct av_extended_perms { uint32_t perms[EXTENDED_PERMS_LEN]; } av_extended_perms_t; -typedef enum name_trans_match { - NAME_TRANS_MATCH_EXACT, - NAME_TRANS_MATCH_PREFIX, - NAME_TRANS_MATCH_SUFFIX, -} name_trans_match_t; - typedef struct avrule { /* these typedefs are almost exactly the same as those in avtab.h - they are * here because of the need to include neverallow and dontaudit messages */ @@ -285,6 +279,10 @@ typedef struct avrule { type_set_t ttypes; class_perm_node_t *perms; char *object_name; /* optional object name */ +#define NAME_TRANS_MATCH_EXACT 0 +#define NAME_TRANS_MATCH_PREFIX 1 +#define NAME_TRANS_MATCH_SUFFIX 2 + uint8_t name_match; av_extended_perms_t *xperms; unsigned long line; /* line number from policy.conf where * this rule originated */ @@ -757,9 +755,10 @@ extern int policydb_set_target_platform(policydb_t *p, int platform); #define MOD_POLICYDB_VERSION_GLBLUB 20 #define MOD_POLICYDB_VERSION_SELF_TYPETRANS 21 #define MOD_POLICYDB_VERSION_AVRULE_FTRANS 22 +#define MOD_POLICYDB_VERSION_PREFIX_SUFFIX 23 /* preffix/suffix support for filename transitions */ #define MOD_POLICYDB_VERSION_MIN MOD_POLICYDB_VERSION_BASE -#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_AVRULE_FTRANS +#define MOD_POLICYDB_VERSION_MAX MOD_POLICYDB_VERSION_PREFIX_SUFFIX #define POLICYDB_CONFIG_MLS 1 diff --git a/libsepol/src/avtab.c b/libsepol/src/avtab.c index 45cbb3a1..5dc7cc59 100644 --- a/libsepol/src/avtab.c +++ b/libsepol/src/avtab.c @@ -771,7 +771,7 @@ int avtab_read(avtab_t * a, struct policy_file *fp, uint32_t vers) int avtab_insert_filename_trans(avtab_t *a, avtab_key_t *key, uint32_t otype, const char *name, - uint32_t *present_otype) + uint8_t name_match, uint32_t *present_otype) { int rc = SEPOL_ENOMEM; avtab_trans_t new_trans = {0}; @@ -780,6 +780,7 @@ int avtab_insert_filename_trans(avtab_t *a, avtab_key_t *key, avtab_ptr_t node; char *name_key = NULL; uint32_t *otype_datum = NULL; + symtab_t *target_symtab; datum = avtab_search(a, key); if (!datum) { @@ -793,8 +794,22 @@ int avtab_insert_filename_trans(avtab_t *a, avtab_key_t *key, datum = &node->datum; } - if (hashtab_is_empty(datum->trans->name_trans.table)) { - rc = symtab_init(&datum->trans->name_trans, 1 << 8); + switch (name_match) { + case NAME_TRANS_MATCH_EXACT: + target_symtab = &datum->trans->name_trans; + break; + case NAME_TRANS_MATCH_PREFIX: + target_symtab = &datum->trans->prefix_trans; + break; + case NAME_TRANS_MATCH_SUFFIX: + target_symtab = &datum->trans->suffix_trans; + break; + default: + return SEPOL_ERR; + } + + if (hashtab_is_empty(target_symtab->table)) { + rc = symtab_init(target_symtab, 1 << 8); if (rc < 0) return rc; } @@ -808,8 +823,7 @@ int avtab_insert_filename_trans(avtab_t *a, avtab_key_t *key, goto bad; *otype_datum = otype; - rc = hashtab_insert(datum->trans->name_trans.table, name_key, - otype_datum); + rc = hashtab_insert(target_symtab->table, name_key, otype_datum); if (rc < 0) goto bad; @@ -854,7 +868,8 @@ static int filename_trans_read_one(avtab_t *a, void *fp) key.target_class = le32_to_cpu(buf[2]); otype = le32_to_cpu(buf[3]); - rc = avtab_insert_filename_trans(a, &key, otype, name, NULL); + rc = avtab_insert_filename_trans(a, &key, otype, name, + NAME_TRANS_MATCH_EXACT, NULL); if (rc) goto err; @@ -907,7 +922,8 @@ static int filename_trans_comp_read_one(avtab_t *a, void *fp) key.source_type = bit + 1; rc = avtab_insert_filename_trans(a, &key, otype, name, - NULL); + NAME_TRANS_MATCH_EXACT, + NULL); if (rc < 0) goto err_ebitmap; } diff --git a/libsepol/src/expand.c b/libsepol/src/expand.c index f3417547..43f8ab3f 100644 --- a/libsepol/src/expand.c +++ b/libsepol/src/expand.c @@ -1620,7 +1620,8 @@ static int expand_terule_helper(sepol_handle_t * handle, uint32_t specified, cond_av_list_t ** cond, cond_av_list_t ** other, uint32_t stype, uint32_t ttype, class_perm_node_t * perms, - char *object_name, avtab_t * avtab, int enabled) + char *object_name, uint8_t name_match, + avtab_t * avtab, int enabled) { avtab_key_t avkey; avtab_datum_t *avdatump; @@ -1652,6 +1653,7 @@ static int expand_terule_helper(sepol_handle_t * handle, int rc = avtab_insert_filename_trans(avtab, &avkey, remapped_data, object_name, + name_match, &oldtype); if (rc == SEPOL_EEXIST) { ERR(handle, "conflicting filename transition %s %s:%s \"%s\": %s vs %s", @@ -1881,6 +1883,7 @@ static int expand_rule_helper(sepol_handle_t * handle, source_rule->specified, cond, other, i, i, source_rule->perms, source_rule->object_name, + source_rule->name_match, dest_avtab, enabled); if (retval != EXPAND_RULE_SUCCESS) return retval; @@ -1898,6 +1901,7 @@ static int expand_rule_helper(sepol_handle_t * handle, source_rule->specified, cond, other, i, j, source_rule->perms, source_rule->object_name, + source_rule->name_match, dest_avtab, enabled); if (retval != EXPAND_RULE_SUCCESS) return retval; diff --git a/libsepol/src/kernel_to_common.h b/libsepol/src/kernel_to_common.h index 2a1cae85..c0a72107 100644 --- a/libsepol/src/kernel_to_common.h +++ b/libsepol/src/kernel_to_common.h @@ -90,7 +90,7 @@ typedef struct { const char *src; const char *tgt; const char *class; - name_trans_match_t match; + uint8_t match; } name_trans_to_strs_args_t; __attribute__ ((format(printf, 1, 2))) diff --git a/libsepol/src/link.c b/libsepol/src/link.c index 88b23594..332d62b2 100644 --- a/libsepol/src/link.c +++ b/libsepol/src/link.c @@ -1254,6 +1254,7 @@ static int copy_avrule_list(avrule_t * list, avrule_t ** dst, if (!new_rule->object_name) goto cleanup; } + new_rule->name_match = cur->name_match; cur_perm = cur->perms; tail_perm = NULL; diff --git a/libsepol/src/module_to_cil.c b/libsepol/src/module_to_cil.c index 653b4b33..4b15bca1 100644 --- a/libsepol/src/module_to_cil.c +++ b/libsepol/src/module_to_cil.c @@ -560,12 +560,13 @@ static int semantic_level_to_cil(struct policydb *pdb, int sens_offset, struct m return 0; } -static int avrule_to_cil(int indent, struct policydb *pdb, uint32_t type, const char *src, const char *tgt, const char *object_name, const struct class_perm_node *classperms) +static int avrule_to_cil(int indent, struct policydb *pdb, uint32_t type, const char *src, const char *tgt, const char *object_name, uint8_t name_match, const struct class_perm_node *classperms) { int rc = -1; const char *rule; const struct class_perm_node *classperm; char *perms; + const char *match_str = ""; switch (type) { case AVRULE_ALLOWED: @@ -611,10 +612,24 @@ static int avrule_to_cil(int indent, struct policydb *pdb, uint32_t type, const pdb->p_class_val_to_name[classperm->tclass - 1], perms + 1); } else if (object_name) { - cil_println(indent, "(%s %s %s %s \"%s\" %s)", + switch (name_match) { + case NAME_TRANS_MATCH_EXACT: + match_str = ""; + break; + case NAME_TRANS_MATCH_PREFIX: + match_str = " match_prefix"; + break; + case NAME_TRANS_MATCH_SUFFIX: + match_str = " match_suffix"; + break; + default: + log_err("Unknown name match type: %" PRIu8, + name_match); + } + cil_println(indent, "(%s %s %s %s \"%s\"%s %s)", rule, src, tgt, pdb->p_class_val_to_name[classperm->tclass - 1], - object_name, + object_name, match_str, pdb->p_type_val_to_name[classperm->data - 1]); } else { cil_println(indent, "(%s %s %s %s %s)", @@ -1218,7 +1233,7 @@ static int avrule_list_to_cil(int indent, struct policydb *pdb, struct avrule *a if (avrule->specified & AVRULE_XPERMS) { rc = avrulex_to_cil(indent, pdb, avrule->specified, snames[s], tnames[t], avrule->perms, avrule->xperms); } else { - rc = avrule_to_cil(indent, pdb, avrule->specified, snames[s], tnames[t], avrule->object_name, avrule->perms); + rc = avrule_to_cil(indent, pdb, avrule->specified, snames[s], tnames[t], avrule->object_name, avrule->name_match, avrule->perms); } if (rc != 0) { goto exit; @@ -1229,7 +1244,7 @@ static int avrule_list_to_cil(int indent, struct policydb *pdb, struct avrule *a if (avrule->specified & AVRULE_XPERMS) { rc = avrulex_to_cil(indent, pdb, avrule->specified, snames[s], "self", avrule->perms, avrule->xperms); } else { - rc = avrule_to_cil(indent, pdb, avrule->specified, snames[s], "self", avrule->object_name, avrule->perms); + rc = avrule_to_cil(indent, pdb, avrule->specified, snames[s], "self", avrule->object_name, avrule->name_match, avrule->perms); } if (rc != 0) { goto exit; diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c index bd1a151d..594b875e 100644 --- a/libsepol/src/policydb.c +++ b/libsepol/src/policydb.c @@ -355,6 +355,13 @@ static const struct policydb_compat_info policydb_compat[] = { .ocon_num = OCON_IBENDPORT + 1, .target_platform = SEPOL_TARGET_SELINUX, }, + { + .type = POLICY_BASE, + .version = MOD_POLICYDB_VERSION_PREFIX_SUFFIX, + .sym_num = SYM_NUM, + .ocon_num = OCON_IBENDPORT + 1, + .target_platform = SEPOL_TARGET_SELINUX, + }, { .type = POLICY_MOD, .version = MOD_POLICYDB_VERSION_BASE, @@ -488,6 +495,13 @@ static const struct policydb_compat_info policydb_compat[] = { .ocon_num = 0, .target_platform = SEPOL_TARGET_SELINUX, }, + { + .type = POLICY_MOD, + .version = MOD_POLICYDB_VERSION_PREFIX_SUFFIX, + .sym_num = SYM_NUM, + .ocon_num = 0, + .target_platform = SEPOL_TARGET_SELINUX, + }, }; #if 0 @@ -3171,6 +3185,7 @@ common_read, class_read, role_read, type_read, user_read, static avrule_t *avrule_read(policydb_t * p, struct policy_file *fp) { unsigned int i; + uint8_t buf8; uint32_t buf[2], len; class_perm_node_t *cur, *tail = NULL; avrule_t *avrule; @@ -3234,10 +3249,15 @@ static avrule_t *avrule_read(policydb_t * p, struct policy_file *fp) if (rc < 0) goto bad; } + if (p->policyvers >= MOD_POLICYDB_VERSION_PREFIX_SUFFIX) { + rc = next_entry(&buf8, fp, sizeof(uint8_t)); + if (rc < 0) + goto bad; + avrule->name_match = buf8; + } } if (avrule->specified & AVRULE_XPERMS) { - uint8_t buf8; size_t nel = ARRAY_SIZE(avrule->xperms->perms); uint32_t buf32[nel]; @@ -3546,6 +3566,7 @@ static int filename_trans_rule_read(policydb_t *p, avrule_t **r, rc = str_read(&cur->object_name, fp, len); if (rc) return -1; + cur->name_match = NAME_TRANS_MATCH_EXACT; if (type_set_read(&cur->stypes, fp)) return -1; diff --git a/libsepol/src/write.c b/libsepol/src/write.c index 92a7b6cf..da83257d 100644 --- a/libsepol/src/write.c +++ b/libsepol/src/write.c @@ -2048,6 +2048,7 @@ static int avrule_write(policydb_t *p, avrule_t * avrule, struct policy_file *fp) { size_t items, items2; + uint8_t buf8; uint32_t buf[32], len; class_perm_node_t *cur; @@ -2055,6 +2056,11 @@ static int avrule_write(policydb_t *p, avrule_t * avrule, if (p->policyvers < MOD_POLICYDB_VERSION_AVRULE_FTRANS && avrule->specified & AVRULE_TRANSITION && avrule->object_name) return POLICYDB_SUCCESS; + /* skip prefix/suffix name transition if writing older version */ + if (p->policyvers < MOD_POLICYDB_VERSION_PREFIX_SUFFIX && + avrule->specified & AVRULE_TRANSITION && + avrule->object_name && avrule->name_match != NAME_TRANS_MATCH_EXACT) + return POLICYDB_SUCCESS; if (p->policyvers < MOD_POLICYDB_VERSION_SELF_TYPETRANS && (avrule->specified & AVRULE_TYPE) && @@ -2113,12 +2119,17 @@ static int avrule_write(policydb_t *p, avrule_t * avrule, if (items != len) return POLICYDB_ERROR; } + if (p->policyvers >= MOD_POLICYDB_VERSION_PREFIX_SUFFIX) { + buf8 = avrule->name_match; + items = put_entry(&buf8, sizeof(uint8_t), 1, fp); + if (items != 1) + return POLICYDB_ERROR; + } } if (avrule->specified & AVRULE_XPERMS) { size_t nel = ARRAY_SIZE(avrule->xperms->perms); uint32_t buf32[nel]; - uint8_t buf8; unsigned int i; if (p->policyvers < MOD_POLICYDB_VERSION_XPERMS_IOCTL) { @@ -2163,12 +2174,17 @@ static int avrule_write_list(policydb_t *p, avrule_t * avrules, avrule = avrules; len = 0; - while (avrule) { - if (p->policyvers >= MOD_POLICYDB_VERSION_AVRULE_FTRANS || - !(avrule->specified & AVRULE_TRANSITION && - avrule->object_name)) - len++; - avrule = avrule->next; + for (avrule = avrules; avrule; avrule = avrule->next) { + if (p->policyvers < MOD_POLICYDB_VERSION_AVRULE_FTRANS && + (avrule->specified & AVTAB_TRANSITION) && + avrule->object_name) + continue; + if (p->policyvers < MOD_POLICYDB_VERSION_PREFIX_SUFFIX && + (avrule->specified & AVTAB_TRANSITION) && + avrule->object_name && + avrule->name_match != NAME_TRANS_MATCH_EXACT) + continue; + len++; } buf[0] = cpu_to_le32(len); @@ -2276,7 +2292,8 @@ static int filename_trans_rule_write(policydb_t *p, avrule_t *rules, class_perm_node_t *perm; for (rule = rules; rule; rule = rule->next) { - if (rule->specified & AVRULE_TRANSITION && rule->object_name) { + if (rule->specified & AVRULE_TRANSITION && rule->object_name && + rule->name_match == NAME_TRANS_MATCH_EXACT) { for (perm = rule->perms; perm; perm = perm->next) { nel++; } @@ -2289,7 +2306,9 @@ static int filename_trans_rule_write(policydb_t *p, avrule_t *rules, return POLICYDB_ERROR; for (rule = rules; rule; rule = rule->next) { - if (!(rule->specified & AVRULE_TRANSITION && rule->object_name)) + if (!(rule->specified & AVRULE_TRANSITION && + rule->object_name && + rule->name_match == NAME_TRANS_MATCH_EXACT)) continue; len = strlen(rule->object_name); for (perm = rule->perms; perm; perm = perm->next) { @@ -2728,7 +2747,8 @@ int policydb_write(policydb_t * p, struct policy_file *fp) if (p->policy_type == POLICY_KERN) { if (avtab_write(p, &p->te_avtab, fp)) return POLICYDB_ERROR; - if (avtab_has_prefix_suffix_filename_transitions(&p->te_avtab)) { + if (p->policyvers < POLICYDB_VERSION_PREFIX_SUFFIX && + avtab_has_prefix_suffix_filename_transitions(&p->te_avtab)) { WARN(fp->handle, "Discarding filename prefix/suffix type transition rules"); } From patchwork Wed May 31 11:49:14 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juraj Marcin X-Patchwork-Id: 13262088 X-Patchwork-Delegate: plautrba@redhat.com Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id E3AB3C7EE31 for ; Wed, 31 May 2023 11:50:26 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232620AbjEaLu0 (ORCPT ); Wed, 31 May 2023 07:50:26 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:48836 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232018AbjEaLuZ (ORCPT ); Wed, 31 May 2023 07:50:25 -0400 Received: from sender11-of-o52.zoho.eu (sender11-of-o52.zoho.eu [31.186.226.238]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 80777E5 for ; Wed, 31 May 2023 04:50:23 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1685533815; cv=none; d=zohomail.eu; s=zohoarc; b=lO+iBJk5fC4/MHkSTKwH4lE3ncpo+3eTM7MmQqv3CwYoYGInjdTC1inTIa1PWTY9fxNn9qqQbuowxmCcWumVQy9VoztAO5Fmykr9zaJ5W5tcnCdfiq9JAP13qAoxj0/cQv0lQdlbXwFynBn6oun5Ue6WXYLzKDaYYP4VMtUOTwU= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.eu; s=zohoarc; t=1685533815; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:To; bh=yBU36yOK9+tCU5olXnzQYkHqKvuEnqLKUIGP9xo/zps=; b=iensHXrCwiMCyygT++Ml4Nq7jNaYznkx2tWjyoiqlgMyZqnAcLRdU7oPTkqJrdlZrAL1Wk2kVZZDhfj7VozSnOdvPTj4wlw6YCPUJliCJF5Fs0JEUEYP1GbTJVmmDqBEUz4jAnLSCNt2jHu8n2zEdIAkZN0l0TLEBx1HEhMqPBk= ARC-Authentication-Results: i=1; mx.zohomail.eu; dkim=pass header.i=jurajmarcin.com; spf=pass smtp.mailfrom=juraj@jurajmarcin.com; dmarc=pass header.from= DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; t=1685533815; s=zoho; d=jurajmarcin.com; i=juraj@jurajmarcin.com; h=From:From:To:To:Cc:Cc:Subject:Subject:Date:Date:Message-Id:Message-Id:In-Reply-To:References:MIME-Version:Content-Transfer-Encoding:Reply-To; bh=yBU36yOK9+tCU5olXnzQYkHqKvuEnqLKUIGP9xo/zps=; b=HPa89lUpSQJMeqFN0R0sljrfuPo4YAEUXWvBWuti0+pM4jrK8sn1HA6wzgqwZCMu vh0LIwk4zK81CUcZGCn2EYQl738Fq9KzV8UBEr36Pukh8x9i9gEGMT+E7DfxyKOMy3T 3rlWJaEbE55KjAmYljITyAAYpGngXARNWFj8JUyc= Received: from morty01.jurajmarcin.com (129.159.244.31 [129.159.244.31]) by mx.zoho.eu with SMTPS id 1685533814166302.004426577255; Wed, 31 May 2023 13:50:14 +0200 (CEST) Received: from jmarcin-t14s-01.redhat.com (unknown [147.251.183.113]) by morty01.jurajmarcin.com (Postfix) with ESMTPSA id 99C712081F76; Wed, 31 May 2023 11:50:13 +0000 (UTC) From: Juraj Marcin To: selinux@vger.kernel.org Cc: Stephen Smalley , Ondrej Mosnacek Subject: [PATCH 8/8] libsepol/cil: add support for prefix/suffix filename transtions to CIL Date: Wed, 31 May 2023 13:49:14 +0200 Message-Id: <20230531114914.2237609-9-juraj@jurajmarcin.com> In-Reply-To: <20230531114914.2237609-1-juraj@jurajmarcin.com> References: <20230531114914.2237609-1-juraj@jurajmarcin.com> MIME-Version: 1.0 Precedence: bulk List-ID: X-Mailing-List: selinux@vger.kernel.org This patch implements the support for prefix/suffix filename transitions in CIL structures as well as to CIL policy parser. Reviewed-by: Ondrej Mosnacek Signed-off-by: Juraj Marcin --- libsepol/cil/src/cil.c | 8 ++++++++ libsepol/cil/src/cil_binary.c | 8 ++++---- libsepol/cil/src/cil_build_ast.c | 25 +++++++++++++++++++------ libsepol/cil/src/cil_copy_ast.c | 1 + libsepol/cil/src/cil_internal.h | 5 +++++ libsepol/cil/src/cil_policy.c | 17 ++++++++++++++++- libsepol/cil/src/cil_resolve_ast.c | 10 ++++++++++ libsepol/cil/src/cil_write_ast.c | 2 ++ 8 files changed, 65 insertions(+), 11 deletions(-) diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c index 38edcf8e..3b086de9 100644 --- a/libsepol/cil/src/cil.c +++ b/libsepol/cil/src/cil.c @@ -95,6 +95,9 @@ char *CIL_KEY_TUNABLEIF; char *CIL_KEY_ALLOW; char *CIL_KEY_DONTAUDIT; char *CIL_KEY_TYPETRANSITION; +char *CIL_KEY_MATCH_EXACT; +char *CIL_KEY_MATCH_PREFIX; +char *CIL_KEY_MATCH_SUFFIX; char *CIL_KEY_TYPECHANGE; char *CIL_KEY_CALL; char *CIL_KEY_TUNABLE; @@ -264,6 +267,9 @@ static void cil_init_keys(void) CIL_KEY_ALLOW = cil_strpool_add("allow"); CIL_KEY_DONTAUDIT = cil_strpool_add("dontaudit"); CIL_KEY_TYPETRANSITION = cil_strpool_add("typetransition"); + CIL_KEY_MATCH_EXACT = cil_strpool_add("match_exact"); + CIL_KEY_MATCH_PREFIX = cil_strpool_add("match_prefix"); + CIL_KEY_MATCH_SUFFIX = cil_strpool_add("match_suffix"); CIL_KEY_TYPECHANGE = cil_strpool_add("typechange"); CIL_KEY_CALL = cil_strpool_add("call"); CIL_KEY_TUNABLE = cil_strpool_add("tunable"); @@ -2387,6 +2393,8 @@ void cil_nametypetransition_init(struct cil_nametypetransition **nametypetrans) (*nametypetrans)->obj = NULL; (*nametypetrans)->name_str = NULL; (*nametypetrans)->name = NULL; + (*nametypetrans)->name_match_str = NULL; + (*nametypetrans)->name_match = NAME_TRANS_MATCH_EXACT; (*nametypetrans)->result_str = NULL; (*nametypetrans)->result = NULL; } diff --git a/libsepol/cil/src/cil_binary.c b/libsepol/cil/src/cil_binary.c index ffa44be7..ea0cef32 100644 --- a/libsepol/cil/src/cil_binary.c +++ b/libsepol/cil/src/cil_binary.c @@ -1193,7 +1193,7 @@ static int __cil_typetransition_to_avtab_helper(policydb_t *pdb, type_datum_t *sepol_src, type_datum_t *sepol_tgt, struct cil_list *class_list, - char *name, + char *name, uint8_t name_match, type_datum_t *sepol_result) { int rc; @@ -1211,7 +1211,7 @@ static int __cil_typetransition_to_avtab_helper(policydb_t *pdb, avt_key.target_type = sepol_tgt->s.value; avt_key.target_class = sepol_obj->s.value; rc = avtab_insert_filename_trans(&pdb->te_avtab, &avt_key, - sepol_result->s.value, name, NAME_TRANS_MATCH_EXACT, + sepol_result->s.value, name, name_match, &otype); if (rc != SEPOL_OK) { if (rc == SEPOL_EEXIST) { @@ -1280,7 +1280,7 @@ static int __cil_typetransition_to_avtab(policydb_t *pdb, const struct cil_db *d rc = __cil_typetransition_to_avtab_helper( pdb, sepol_src, sepol_src, class_list, - name, sepol_result + name, typetrans->name_match, sepol_result ); if (rc != SEPOL_OK) goto exit; } @@ -1298,7 +1298,7 @@ static int __cil_typetransition_to_avtab(policydb_t *pdb, const struct cil_db *d rc = __cil_typetransition_to_avtab_helper( pdb, sepol_src, sepol_tgt, class_list, - name, sepol_result + name, typetrans->name_match, sepol_result ); if (rc != SEPOL_OK) goto exit; } diff --git a/libsepol/cil/src/cil_build_ast.c b/libsepol/cil/src/cil_build_ast.c index 4177c9f6..47513f92 100644 --- a/libsepol/cil/src/cil_build_ast.c +++ b/libsepol/cil/src/cil_build_ast.c @@ -3334,10 +3334,11 @@ int cil_gen_typetransition(struct cil_db *db, struct cil_tree_node *parse_curren CIL_SYN_STRING, CIL_SYN_STRING, CIL_SYN_STRING | CIL_SYN_END, - CIL_SYN_END + CIL_SYN_STRING | CIL_SYN_END, + CIL_SYN_END, }; size_t syntax_len = sizeof(syntax)/sizeof(*syntax); - char *s1, *s2, *s3, *s4, *s5; + char *s1, *s2, *s3, *s4, *s5, *s6; if (db == NULL || parse_current == NULL || ast_node == NULL ) { goto exit; @@ -3353,16 +3354,27 @@ int cil_gen_typetransition(struct cil_db *db, struct cil_tree_node *parse_curren s3 = parse_current->next->next->next->data; s4 = parse_current->next->next->next->next->data; s5 = NULL; + s6 = NULL; if (parse_current->next->next->next->next->next) { if (s4 == CIL_KEY_STAR) { - s4 = parse_current->next->next->next->next->next->data; + if (parse_current->next->next->next->next->next->next) { + s4 = parse_current->next->next->next->next->next->next->data; + } else { + s4 = parse_current->next->next->next->next->next->data; + } } else { - s5 = parse_current->next->next->next->next->next->data; + if (parse_current->next->next->next->next->next->next) { + s5 = parse_current->next->next->next->next->next->data; + s6 = parse_current->next->next->next->next->next->next->data; + } else { + s5 = CIL_KEY_MATCH_EXACT; + s6 = parse_current->next->next->next->next->next->data; + } } } - if (s5) { + if (s6) { struct cil_nametypetransition *nametypetrans = NULL; cil_nametypetransition_init(&nametypetrans); @@ -3370,8 +3382,9 @@ int cil_gen_typetransition(struct cil_db *db, struct cil_tree_node *parse_curren nametypetrans->src_str = s1; nametypetrans->tgt_str = s2; nametypetrans->obj_str = s3; - nametypetrans->result_str = s5; + nametypetrans->result_str = s6; nametypetrans->name_str = s4; + nametypetrans->name_match_str = s5; ast_node->data = nametypetrans; ast_node->flavor = CIL_NAMETYPETRANSITION; diff --git a/libsepol/cil/src/cil_copy_ast.c b/libsepol/cil/src/cil_copy_ast.c index 17f05021..a2d2fe40 100644 --- a/libsepol/cil/src/cil_copy_ast.c +++ b/libsepol/cil/src/cil_copy_ast.c @@ -726,6 +726,7 @@ int cil_copy_nametypetransition(__attribute__((unused)) struct cil_db *db, void new->tgt_str = orig->tgt_str; new->obj_str = orig->obj_str; new->name_str = orig->name_str; + new->name_match_str = orig->name_match_str; new->result_str = orig->result_str; diff --git a/libsepol/cil/src/cil_internal.h b/libsepol/cil/src/cil_internal.h index a7604762..f7a8d0f7 100644 --- a/libsepol/cil/src/cil_internal.h +++ b/libsepol/cil/src/cil_internal.h @@ -112,6 +112,9 @@ extern char *CIL_KEY_TUNABLEIF; extern char *CIL_KEY_ALLOW; extern char *CIL_KEY_DONTAUDIT; extern char *CIL_KEY_TYPETRANSITION; +extern char *CIL_KEY_MATCH_EXACT; +extern char *CIL_KEY_MATCH_PREFIX; +extern char *CIL_KEY_MATCH_SUFFIX; extern char *CIL_KEY_TYPECHANGE; extern char *CIL_KEY_CALL; extern char *CIL_KEY_TUNABLE; @@ -575,6 +578,8 @@ struct cil_nametypetransition { struct cil_class *obj; char *name_str; struct cil_name *name; + char *name_match_str; + uint8_t name_match; char *result_str; void *result; /* type or alias */ diff --git a/libsepol/cil/src/cil_policy.c b/libsepol/cil/src/cil_policy.c index feb97868..c8253818 100644 --- a/libsepol/cil/src/cil_policy.c +++ b/libsepol/cil/src/cil_policy.c @@ -1260,6 +1260,7 @@ static void cil_nametypetransition_to_policy(FILE *out, struct cil_nametypetrans struct cil_name *name; struct cil_list *class_list; struct cil_list_item *i1; + const char *name_match_str = ""; src = trans->src; tgt = trans->tgt; @@ -1268,7 +1269,21 @@ static void cil_nametypetransition_to_policy(FILE *out, struct cil_nametypetrans class_list = cil_expand_class(trans->obj); cil_list_for_each(i1, class_list) { - fprintf(out, "type_transition %s %s : %s %s \"%s\";\n", src->fqn, tgt->fqn, DATUM(i1->data)->fqn, res->fqn, name->datum.fqn); + switch (trans->name_match) { + case NAME_TRANS_MATCH_EXACT: + name_match_str = ""; + break; + case NAME_TRANS_MATCH_PREFIX: + name_match_str = " MATCH_PREFIX"; + break; + case NAME_TRANS_MATCH_SUFFIX: + name_match_str = " MATCH_SUFFIX"; + break; + default: + name_match_str = "???"; + break; + } + fprintf(out, "type_transition %s %s : %s %s \"%s\"%s;\n", src->fqn, tgt->fqn, DATUM(i1->data)->fqn, res->fqn, name->datum.fqn, name_match_str); } cil_list_destroy(&class_list, CIL_FALSE); } diff --git a/libsepol/cil/src/cil_resolve_ast.c b/libsepol/cil/src/cil_resolve_ast.c index d2bfdc81..fbb0fdcc 100644 --- a/libsepol/cil/src/cil_resolve_ast.c +++ b/libsepol/cil/src/cil_resolve_ast.c @@ -668,6 +668,16 @@ int cil_resolve_nametypetransition(struct cil_tree_node *current, void *extra_ar nametypetrans->name = (struct cil_name *)name_datum; } + if (nametypetrans->name_match_str == CIL_KEY_MATCH_EXACT) { + nametypetrans->name_match = NAME_TRANS_MATCH_EXACT; + } else if (nametypetrans->name_match_str == CIL_KEY_MATCH_PREFIX) { + nametypetrans->name_match = NAME_TRANS_MATCH_PREFIX; + } else if (nametypetrans->name_match_str == CIL_KEY_MATCH_SUFFIX) { + nametypetrans->name_match = NAME_TRANS_MATCH_SUFFIX; + } else { + cil_tree_log(current, CIL_ERR, "Invalid name match type \"%s\"", nametypetrans->name_match_str); + } + rc = cil_resolve_name(current, nametypetrans->result_str, CIL_SYM_TYPES, extra_args, &result_datum); if (rc != SEPOL_OK) { goto exit; diff --git a/libsepol/cil/src/cil_write_ast.c b/libsepol/cil/src/cil_write_ast.c index b75784ef..d96f6c39 100644 --- a/libsepol/cil/src/cil_write_ast.c +++ b/libsepol/cil/src/cil_write_ast.c @@ -1168,6 +1168,8 @@ void cil_write_ast_node(FILE *out, struct cil_tree_node *node) fprintf(out, "%s ", datum_or_str(DATUM(rule->tgt), rule->tgt_str)); fprintf(out, "%s ", datum_or_str(DATUM(rule->obj), rule->obj_str)); fprintf(out, "\"%s\" ", datum_or_str(DATUM(rule->name), rule->name_str)); + if (rule->name_match != NAME_TRANS_MATCH_EXACT) + fprintf(out, "%s ", rule->name_match_str); fprintf(out, "%s", datum_or_str(DATUM(rule->result), rule->result_str)); fprintf(out, ")\n"); break;