From patchwork Tue Jun 20 09:01:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juraj Marcin X-Patchwork-Id: 13285372 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 7C788EB64D7 for ; Tue, 20 Jun 2023 09:02:34 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232072AbjFTJCd (ORCPT ); Tue, 20 Jun 2023 05:02:33 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:58618 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232098AbjFTJC3 (ORCPT ); Tue, 20 Jun 2023 05:02:29 -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 B5A9A10F2 for ; Tue, 20 Jun 2023 02:02:25 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1687251740; cv=none; d=zohomail.eu; s=zohoarc; b=I1yxCkFEfO4SABy1TUNmWWHDiMYW6knnqfvltsX75wknjp44KLGfyPvlI1/MLXG3GNXd50Iec8HpdHXpk5h186nWOck9LFGpBM8GKFQeaF47wbYXZ9DeFaUrJ0ySbN0UOQH9An3IfhLc9svwbG0FHYeVLjF0tVT0fZwjH20XOvg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.eu; s=zohoarc; t=1687251740; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:To; bh=8/KV45xD8CR4d3TUd4CBuc69SzeA46V8JHWShVtbAdY=; b=VE37zHpcNIXSpKeAxqiOexClP5Z3d+L96bHzOEBHoj3n3CjlaAkI9vAxteRIe378CMPAsfGggcs43RWRkOuIj4X2vZWI7h+BHN0zGLp0JZsREGeeSncVRyymjwCwDKeLL9XHTeq3gQsT3UJthcPd7PDVvpoFjPWObD7/QfWuGHI= 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=1687251740; 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=8/KV45xD8CR4d3TUd4CBuc69SzeA46V8JHWShVtbAdY=; b=bBdI3NuswyUlq0CnLdDLV9pEHVBUmgblh/Kzj+9ilLazCPrrCQ8Ac27fQFeK9pxT oO0t9PUjui+to0d82iRNjSEkZDIbFT4ewh35hXjUmKnKVPtqAebfeMLWJfwZXYK3j7/ o1PeNyr/wqMDYOX18P9v6MHuv1/toz1f4qgJ4qHU= Received: from morty01.jurajmarcin.com (129.159.244.31 [129.159.244.31]) by mx.zoho.eu with SMTPS id 1687251738298997.8601760372592; Tue, 20 Jun 2023 11:02:18 +0200 (CEST) Received: from jmarcin-t14s-01.redhat.com (unknown [213.175.37.12]) by morty01.jurajmarcin.com (Postfix) with ESMTPSA id 81ADD2081F76; Tue, 20 Jun 2023 09:02:17 +0000 (UTC) From: Juraj Marcin To: selinux@vger.kernel.org Cc: Ondrej Mosnacek Subject: [PATCH v2 1/8] checkpolicy,libsepol: move transition to separate structure in avtab Date: Tue, 20 Jun 2023 11:01:16 +0200 Message-Id: In-Reply-To: References: 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 Acked-by: James Carter --- 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 bee1a660..de1a5d11 100644 --- a/checkpolicy/test/dispol.c +++ b/checkpolicy/test/dispol.c @@ -180,7 +180,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 8795229a..6793a27d 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 f2b0d902..b1fd1bf7 100644 --- a/libsepol/src/kernel_to_cil.c +++ b/libsepol/src/kernel_to_cil.c @@ -1704,7 +1704,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 15161caa..7e1e1b49 100644 --- a/libsepol/src/kernel_to_conf.c +++ b/libsepol/src/kernel_to_conf.c @@ -1682,7 +1682,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 3540f34a..f402b506 100644 --- a/libsepol/src/policydb_validate.c +++ b/libsepol/src/policydb_validate.c @@ -836,7 +836,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 Tue Jun 20 09:01:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juraj Marcin X-Patchwork-Id: 13285374 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 92F23EB64D8 for ; Tue, 20 Jun 2023 09:02:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232070AbjFTJCg (ORCPT ); Tue, 20 Jun 2023 05:02:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59064 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232058AbjFTJCd (ORCPT ); Tue, 20 Jun 2023 05:02:33 -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 B7B0A10FE for ; Tue, 20 Jun 2023 02:02:26 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1687251742; cv=none; d=zohomail.eu; s=zohoarc; b=DmorbhxIa1DAbtSybZsSTh8c5e3Iu2r9ft8KdPu1d0wq9VOes+lSVrb+v30MfLEPJRbd8JIbaHPLewso9zv9FHVRXrxTSqF7lsWuxwGdYEtiySUOfGi0i6X6vpEm9IcKpg/EHuf8SnpG+sCDG0aJQBF1r4YHrWu+y4vMu18HK/8= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.eu; s=zohoarc; t=1687251742; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:To; bh=fubBD2SkN9sov+9T9bkTkDYwpWymMWf4A5oY56B3esA=; b=L/6GrhGnwRvNjozkHxyiBdY0tHnA0cEGcllISar8sEE8oxhU9sJOzJjgiJXkhyGXyIuO8Wi2yDpb8ZGT55UCuc+9kg838Y14FcXbOAp34fllMbqX4CESEZfO93ubSzlZzPMC0YiuXBG+B+kCUMQHhYNwG3BFvlqIg/NQDcyUbTo= 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=1687251742; 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=fubBD2SkN9sov+9T9bkTkDYwpWymMWf4A5oY56B3esA=; b=HaHDjzU5LKkBOho8MD+ZcBOkuS/47T2cp730sfAdVAXwR7PYFWaY9qmlD08yCzoc vMivs4h/xGmzWnK1obQZ+qDhmwku/2PE/XK1RuETbdGRacjsOyo8pVg1EGFX9gmS/Ob MJGSUMF5vtVmArun1oN6cChTmn2kBpQmUDEfLUdg= Received: from morty01.jurajmarcin.com (129.159.244.31 [129.159.244.31]) by mx.zoho.eu with SMTPS id 1687251740596656.9946366253265; Tue, 20 Jun 2023 11:02:20 +0200 (CEST) Received: from jmarcin-t14s-01.redhat.com (unknown [213.175.37.12]) by morty01.jurajmarcin.com (Postfix) with ESMTPSA id 0173D2081F76; Tue, 20 Jun 2023 09:02:19 +0000 (UTC) From: Juraj Marcin To: selinux@vger.kernel.org Cc: Ondrej Mosnacek Subject: [PATCH v2 2/8] checkpolicy,libsepol: move filename transitions to avtab Date: Tue, 20 Jun 2023 11:01:17 +0200 Message-Id: <1e743e36c7f059dbe713f4d3944b1de8ebe149fb.1687251081.git.juraj@jurajmarcin.com> In-Reply-To: References: 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 | 8 + libsepol/include/sepol/policydb/policydb.h | 22 - libsepol/src/avtab.c | 199 +++++++++ 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 | 463 +++++++++++++++------ 18 files changed, 804 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 cef8f3c4..dc2ee8f3 100644 --- a/checkpolicy/policy_define.c +++ b/checkpolicy/policy_define.c @@ -3352,6 +3352,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; @@ -3443,9 +3444,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) { @@ -3461,9 +3466,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 de1a5d11..e86ad2ed 100644 --- a/checkpolicy/test/dispol.c +++ b/checkpolicy/test/dispol.c @@ -63,7 +63,6 @@ static struct command { {CMD, 'a', "display type attributes"}, {CMD, 'p', "display the list of permissive types"}, {CMD, 'u', "display unknown handling setting"}, - {CMD, 'F', "display filename_trans rules"}, {HEADER, 0, ""}, {CMD|NOOPT, 'f', "set output file"}, {CMD|NOOPT, 'm', "display menu"}, @@ -126,6 +125,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 @@ -178,10 +197,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 "); @@ -448,48 +476,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) { unsigned int i; @@ -690,9 +676,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..354ebb43 100644 --- a/libsepol/include/sepol/policydb/hashtab.h +++ b/libsepol/include/sepol/policydb/hashtab.h @@ -110,6 +110,14 @@ extern int hashtab_map(hashtab_t h, extern void hashtab_hash_eval(hashtab_t h, char *tag); +/* 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 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..eef259cf 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,187 @@ 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 (!datum->trans->name_trans.table) { + rc = symtab_init(&datum->trans->name_trans, 1 << 8); + if (rc < 0) + return rc; + } + + rc = SEPOL_ENOMEM; + name_key = strdup(name); + if (!name_key) + goto bad; + + rc = SEPOL_ENOMEM; + 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 6793a27d..878b0f21 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 b1fd1bf7..e829e235 100644 --- a/libsepol/src/kernel_to_cil.c +++ b/libsepol/src/kernel_to_cil.c @@ -1702,14 +1702,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: @@ -1742,7 +1752,7 @@ static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_dat break; default: ERR(NULL, "Unknown avtab type: %i", key->specified); - goto exit; + return SEPOL_ERR; } src = pdb->p_type_val_to_name[key->source_type - 1]; @@ -1759,33 +1769,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) { ERR(NULL, "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) { ERR(NULL, "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 { @@ -1800,23 +1821,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; } @@ -1870,77 +1880,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) { - ERR(NULL, "Error writing filename typetransition rules to CIL"); - } - - return rc; -} - static char *level_to_str(struct policydb *pdb, struct mls_level *level) { ebitmap_t *cats = &level->cat; @@ -2060,7 +1999,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; @@ -2076,14 +2014,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; } } @@ -3331,11 +3263,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 7a3960b0..524a4b0f 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; + void sepol_indent(FILE *out, int indent); __attribute__ ((format(printf, 2, 3))) void sepol_printf(FILE *out, const char *fmt, ...); diff --git a/libsepol/src/kernel_to_conf.c b/libsepol/src/kernel_to_conf.c index 7e1e1b49..a637c207 100644 --- a/libsepol/src/kernel_to_conf.c +++ b/libsepol/src/kernel_to_conf.c @@ -1680,13 +1680,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: @@ -1719,7 +1730,7 @@ static char *avtab_node_to_str(struct policydb *pdb, avtab_key_t *key, avtab_dat break; default: ERR(NULL, "Unknown avtab type: %i", key->specified); - goto exit; + return SEPOL_ERR; } src = pdb->p_type_val_to_name[key->source_type - 1]; @@ -1736,32 +1747,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) { ERR(NULL, "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) { ERR(NULL, "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 { @@ -1776,23 +1797,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; } @@ -1846,77 +1856,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) { - ERR(NULL, "Error writing filename typetransition rules to policy.conf"); - } - - return rc; -} - static char *level_to_str(struct policydb *pdb, struct mls_level *level) { ebitmap_t *cats = &level->cat; @@ -2036,7 +1975,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; @@ -2052,14 +1990,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; } } @@ -3205,7 +3137,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 605d290a..c1ce9c34 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 f402b506..89306185 100644 --- a/libsepol/src/policydb_validate.c +++ b/libsepol/src/policydb_validate.c @@ -829,6 +829,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; @@ -836,10 +848,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 && + !hashtab_nel(d->trans->name_trans.table)) + 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; @@ -1092,41 +1117,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])) @@ -1556,9 +1546,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..c4d593ab 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,307 @@ 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_key_t *ft = (filenametr_key_t *)key; + filenametr_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; +} + +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) { + nel += hashtab_nel(cur->datum.trans->name_trans.table); + } + } + } + + 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 +904,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 +2414,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 +2608,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 Tue Jun 20 09:01:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juraj Marcin X-Patchwork-Id: 13285373 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 1D123EB64DB for ; Tue, 20 Jun 2023 09:02:37 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232099AbjFTJCg (ORCPT ); Tue, 20 Jun 2023 05:02:36 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59066 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231765AbjFTJCd (ORCPT ); Tue, 20 Jun 2023 05:02:33 -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 ABEDE1706 for ; Tue, 20 Jun 2023 02:02:28 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1687251743; cv=none; d=zohomail.eu; s=zohoarc; b=bXSrxpEHdZhQ6cEQB9WHCyt6MiOslmMyKHhh7/m5tQaXPmxmgm1Pz1Qjv4p+BQa/abWn1u7eYrqbDNpVY0e7j7Qed9t0VWcr2o+r+VKcgJqkjaiAN+R6YEsEIneNYscHdtsULtGNziMvsEjHFUbnyRuPdwCj+OegF+Cz+mj9P4U= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.eu; s=zohoarc; t=1687251743; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:To; bh=41DagNBY51Sv6DxbtPcGnCsly9E3PsHLL7ATv5HFqXI=; b=fPaL+ZGQXnz2WBNBgNyFWFL+pTTnx1j+SfeHe5wAKB7fQOkpoja4bWdNwMfc2F2sTJaB1+S7StlbYLT73KdIEwXf0oAThJs1PO210fZqSIiSLo92+QwUEp88oB6HZsf5XuTGFA7XtSuqpFDzaICI798cyHc464+aBibKsucY77M= 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=1687251743; 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=41DagNBY51Sv6DxbtPcGnCsly9E3PsHLL7ATv5HFqXI=; b=V0n7BkVabACIrdtWf0Hpk6vNVBmDqN/cztArtGiUi2/N4LOQEvqYDH975y7h+3vN aLwpdzBBuAmacsbw0TSLmVpqmUQCRSDXDkRiJwqrL225gHpowsl8j99wWSeTxT6eg6a 6xU0Gn5Sl1AsaFgVtkmg71v8pZouhkh1wzBrEc+s= Received: from morty01.jurajmarcin.com (129.159.244.31 [129.159.244.31]) by mx.zoho.eu with SMTPS id 1687251742559691.6562824648195; Tue, 20 Jun 2023 11:02:22 +0200 (CEST) Received: from jmarcin-t14s-01.redhat.com (unknown [213.175.37.12]) by morty01.jurajmarcin.com (Postfix) with ESMTPSA id 03F982081F76; Tue, 20 Jun 2023 09:02:22 +0000 (UTC) From: Juraj Marcin To: selinux@vger.kernel.org Cc: Ondrej Mosnacek Subject: [PATCH v2 3/8] checkpolicy,libsepol: move filename transition rules to avrule Date: Tue, 20 Jun 2023 11:01:18 +0200 Message-Id: In-Reply-To: References: 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 | 132 ++++--------- 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, 154 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 dc2ee8f3..25dbf25d 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) { @@ -3343,194 +3362,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 da32a776..2a14fc1e 100644 --- a/checkpolicy/policy_parse.y +++ b/checkpolicy/policy_parse.y @@ -451,13 +451,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 515fc9a5..cde80f95 100644 --- a/checkpolicy/test/dismod.c +++ b/checkpolicy/test/dismod.c @@ -50,7 +50,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; @@ -90,7 +89,6 @@ static struct command { {CMD, 'c', "Display policy capabilities"}, {CMD|NOOPT, 'l', "Link in a module"}, {CMD, 'u', "Display the unknown handling setting"}, - {CMD, 'F', "Display filename_trans rules"}, {HEADER, 0, ""}, {CMD|NOOPT, 'f', "set output file"}, {CMD|NOOPT, 'm', "display menu"}, @@ -339,6 +337,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; @@ -556,18 +556,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) { @@ -732,10 +720,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); } @@ -1061,11 +1045,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 878b0f21..a4c92f4f 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,34 @@ 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; + /* + * filename transtion inserted, continue with next node + */ + cur = cur->next; + continue; + } + conflict = 0; /* check to see if the expanded TE already exists -- * either in the global scope or in another @@ -1777,12 +1717,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 +1884,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 +1901,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 +2730,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 1a490089..1e002c4e 100644 --- a/libsepol/src/module_to_cil.c +++ b/libsepol/src/module_to_cil.c @@ -547,7 +547,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; @@ -597,6 +597,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, @@ -1199,7 +1205,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; @@ -1210,7 +1216,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; @@ -1576,60 +1582,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; @@ -3683,11 +3635,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 c1ce9c34..4913ee21 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 89306185..0b8e8eee 100644 --- a/libsepol/src/policydb_validate.c +++ b/libsepol/src/policydb_validate.c @@ -1313,31 +1313,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; @@ -1372,8 +1347,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 c4d593ab..2035b350 100644 --- a/libsepol/src/write.c +++ b/libsepol/src/write.c @@ -1970,6 +1970,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)) { @@ -2063,7 +2067,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; } @@ -2162,55 +2168,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; } @@ -2284,7 +2302,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 Tue Jun 20 09:01:19 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juraj Marcin X-Patchwork-Id: 13285375 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 9157BEB64D7 for ; Tue, 20 Jun 2023 09:02:38 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232065AbjFTJCi (ORCPT ); Tue, 20 Jun 2023 05:02:38 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59128 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232095AbjFTJCg (ORCPT ); Tue, 20 Jun 2023 05:02:36 -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 C5BB510DC for ; Tue, 20 Jun 2023 02:02:30 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1687251746; cv=none; d=zohomail.eu; s=zohoarc; b=iHJB4HzMPmHnjtV+U45WJtUUTyRRaxExLaAlyt0bX/puvH0sjElUGmrp2Hk6dNiIBcNZXcoSsO+/otLFIVBvOxCo3qZaxlux6RAqq/oU0KVGNR7KjlutzyFRwp9S88w23IVb1t8vwcraBBZwjCaa5MifqN9+st+PCShCday5VG4= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.eu; s=zohoarc; t=1687251746; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:To; bh=y9ZhCNVBAloE7l4glUSm2MlpKfa0I0SO+Us6kfzd+EQ=; b=Ofw3dQT5PXZzAh3YQ3pOpy2B+TlJKhFwgbvZdr6d9Yo/thZG6aYYPa57BvHFBkTjZqNmUyBAU0nqrMxWctXeeUFhFPanCYXk0LgLNTw2GIH9Y9xwJ/BvD2JGCiIBKkcE4C4mhHLZJ5HbTGdIJCciOGOfTdoTbJpJydzpccDutLE= 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=1687251746; 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=y9ZhCNVBAloE7l4glUSm2MlpKfa0I0SO+Us6kfzd+EQ=; b=G9s06DySu/bucTb2u6R0ZDs50l6GslDf9o3iDZXyG5R/auUie+ybXg5fWbAa6L2K RDaPLyY8JJ2KnYYxztZe+U0O9nVV3Uri9MpcThuNjwqzPWCGGxBYJNZfUSEXd3ff3/a RXqtit7+DxJmppDXq8AkuQZwY6cQpF78qNCdljI0= Received: from morty01.jurajmarcin.com (129.159.244.31 [129.159.244.31]) by mx.zoho.eu with SMTPS id 1687251745083555.4385759342427; Tue, 20 Jun 2023 11:02:25 +0200 (CEST) Received: from jmarcin-t14s-01.redhat.com (unknown [213.175.37.12]) by morty01.jurajmarcin.com (Postfix) with ESMTPSA id 7BC2F2081F76; Tue, 20 Jun 2023 09:02:24 +0000 (UTC) From: Juraj Marcin To: selinux@vger.kernel.org Cc: Ondrej Mosnacek Subject: [PATCH v2 4/8] libsepol: implement new kernel binary format for avtab Date: Tue, 20 Jun 2023 11:01:19 +0200 Message-Id: In-Reply-To: References: 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/policydb.h | 3 +- libsepol/src/avtab.c | 88 ++++++++++++++++++++-- libsepol/src/policydb.c | 8 ++ libsepol/src/write.c | 86 +++++++++++++++++---- 4 files changed, 164 insertions(+), 21 deletions(-) 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 eef259cf..2a9564ba 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 4913ee21..b15d4163 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 2035b350..68495198 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); @@ -2626,7 +2681,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 Tue Jun 20 09:01:20 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juraj Marcin X-Patchwork-Id: 13285376 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 DB9C7EB64D7 for ; Tue, 20 Jun 2023 09:02:46 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232082AbjFTJCq (ORCPT ); Tue, 20 Jun 2023 05:02:46 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59108 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232108AbjFTJCn (ORCPT ); Tue, 20 Jun 2023 05:02:43 -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 2DD9A1727 for ; Tue, 20 Jun 2023 02:02:34 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1687251749; cv=none; d=zohomail.eu; s=zohoarc; b=dGhfzH86yMcjLgA0W+cAu3kK1/b+/UcymBuYrTOinqMN/KDJexO+b/lamTmaINJuCzfxafbTMny5xmGZnmy4mBVqshUaUvE92vMpKgSjGm1zrqhKnh+ZfRn25EhwJwbaxrvtonPxNf5/sMtocLc+dFWw81Q1LoY6J75ajT/ARMQ= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.eu; s=zohoarc; t=1687251749; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:To; bh=kDLfbC2iXNX6QJ0fMhIsW5RhIaV4N2CGeC0JQd7Dkf8=; b=MIuC5VWcTLVJywXsA+5+nndRWH6IXlqrq+eTdYkxtplfMChCjyDaxE+3R4Kcp5vvx7KOf7JoIdhMhRVhcdy+zvHv182RTzHnmziCCOnpw5PfeWazj3W71WzW9zTX60ULLjmL637Cpy858kkAheAZBbAW9cfeJ1CTq5fL56lbGKc= 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=1687251749; 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=kDLfbC2iXNX6QJ0fMhIsW5RhIaV4N2CGeC0JQd7Dkf8=; b=eKy3VBkxfZi/J87/GB3244vw44uObbjVjhEVXrHTb4poyhaFoABA9/T5Y/0QE0vd noSi6n4PHmouw/P1fe4zCq1RTxwHiUnI0/nb1T9E40xPj2xqpxQkDG1wRXqKI5yITO1 1utnXstNoy1zZHZew8nfvr6TbJbzIMya/gyZeJyE= Received: from morty01.jurajmarcin.com (129.159.244.31 [129.159.244.31]) by mx.zoho.eu with SMTPS id 1687251748292225.7484242147002; Tue, 20 Jun 2023 11:02:28 +0200 (CEST) Received: from jmarcin-t14s-01.redhat.com (unknown [213.175.37.12]) by morty01.jurajmarcin.com (Postfix) with ESMTPSA id C688C2081F76; Tue, 20 Jun 2023 09:02:27 +0000 (UTC) From: Juraj Marcin To: selinux@vger.kernel.org Cc: Ondrej Mosnacek Subject: [PATCH v2 5/8] libsepol: implement new module binary format of avrule Date: Tue, 20 Jun 2023 11:01:20 +0200 Message-Id: <84f1ed9810a7b0df59238c2f97c6b3d05b29e6d6.1687251081.git.juraj@jurajmarcin.com> In-Reply-To: References: 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 b15d4163..37bb97a1 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 68495198..d7f47c8d 100644 --- a/libsepol/src/write.c +++ b/libsepol/src/write.c @@ -2025,8 +2025,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 && @@ -2073,6 +2074,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]; @@ -2122,7 +2138,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; @@ -2357,6 +2374,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 Tue Jun 20 09:01:21 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juraj Marcin X-Patchwork-Id: 13285377 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 9FD53EB64D8 for ; Tue, 20 Jun 2023 09:02:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S232091AbjFTJCt (ORCPT ); Tue, 20 Jun 2023 05:02:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59304 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232096AbjFTJCr (ORCPT ); Tue, 20 Jun 2023 05:02:47 -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 6B37110F0 for ; Tue, 20 Jun 2023 02:02:37 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1687251752; cv=none; d=zohomail.eu; s=zohoarc; b=g8GUk0FFiC13kZasYAXv0Tk/cXcDSn0rYWMwq4wtapfDaqSz1S/+JnMiMaXtFUrHPQ5xnhX8cdSbJBxcKsOu+MvREYRoHSqn8o9NLPJrI5cxAdJ/be3iDeTqe/sdokQe9YAp8Do8mrMwgYhElxrgZwUnDKGumPnUo1rywMRPT18= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.eu; s=zohoarc; t=1687251752; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:To; bh=YxH3MTJb4A3uIDbmYOcLLyySFTNEN4Q/zBhPHDhqIoE=; b=b6uY0EM+WFBSVoYsZMWrEiulUR1fXKhjMkUoJcZyyY5ItKwdQ3StI7HaJKNAOKsfMlftIzgK1j3OZe9/zfAD0d+WYW31NxtQPWEmb9gl++XcEQ4yrWWL9mDxNM7Qu5TI0kbivTcskJJH+Mb4CmLGXhPDI58Rx8jRPfMCYUIUJ4g= 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=1687251752; 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=YxH3MTJb4A3uIDbmYOcLLyySFTNEN4Q/zBhPHDhqIoE=; b=OyoGrZ0NctwbVKv2NXwfJSN4l5LfrQvAv7Kr94oLQzaXtnPCtwuwOuD9Zj9inviN BN4HEgPI11kZ4arSgLdY4/jeUuReuFdybNwjHwSlHrV32Y+duxE9ffv8F7CgOBXh5QH JxoSWOFiJ1IdPJ8G379yTxRm8f/58o1v4XQx+GtU= Received: from morty01.jurajmarcin.com (129.159.244.31 [129.159.244.31]) by mx.zoho.eu with SMTPS id 1687251750774130.89658454671098; Tue, 20 Jun 2023 11:02:30 +0200 (CEST) Received: from jmarcin-t14s-01.redhat.com (unknown [213.175.37.12]) by morty01.jurajmarcin.com (Postfix) with ESMTPSA id 174622081F76; Tue, 20 Jun 2023 09:02:30 +0000 (UTC) From: Juraj Marcin To: selinux@vger.kernel.org Cc: Ondrej Mosnacek Subject: [PATCH v2 6/8] checkpolicy,libsepol: add prefix/suffix support to kernel policy Date: Tue, 20 Jun 2023 11:01:21 +0200 Message-Id: In-Reply-To: References: 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 | 11 +- libsepol/src/write.c | 113 +++++++++++++++++---- 10 files changed, 211 insertions(+), 30 deletions(-) diff --git a/checkpolicy/test/dispol.c b/checkpolicy/test/dispol.c index e86ad2ed..efdd102b 100644 --- a/checkpolicy/test/dispol.c +++ b/checkpolicy/test/dispol.c @@ -129,6 +129,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) @@ -140,7 +141,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 = " PREFIX"; + break; + case NAME_TRANS_MATCH_SUFFIX: + match_str = " 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; } @@ -207,9 +223,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 2a9564ba..90cfb90b 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 e829e235..8824fe01 100644 --- a/libsepol/src/kernel_to_cil.c +++ b/libsepol/src/kernel_to_cil.c @@ -1707,9 +1707,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 = " prefix"; + break; + case NAME_TRANS_MATCH_SUFFIX: + match_str = " suffix"; + break; + default: + ERR(NULL, "Unknown name match type: %" PRIu8, args->match); + return SEPOL_ERR; + } + return strs_create_and_add(args->strs, "(%s %s %s %s \"%s\"%s %s)", 7, args->flavor, args->src, args->tgt, - args->class, name, + args->class, name, match_str, args->pdb->p_type_val_to_name[*otype - 1]); } @@ -1797,9 +1812,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 524a4b0f..96169228 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; void sepol_indent(FILE *out, int indent); diff --git a/libsepol/src/kernel_to_conf.c b/libsepol/src/kernel_to_conf.c index a637c207..5f232f47 100644 --- a/libsepol/src/kernel_to_conf.c +++ b/libsepol/src/kernel_to_conf.c @@ -1685,11 +1685,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 = " PREFIX"; + break; + case NAME_TRANS_MATCH_SUFFIX: + match_str = " SUFFIX"; + break; + default: + ERR(NULL, "Unknown name match type: %" PRIu8, args->match); + return SEPOL_ERR; + } + return strs_create_and_add(args->strs, "%s %s %s:%s %s \"%s\"%s;", 7, 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) @@ -1773,9 +1788,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 37bb97a1..f1f6cec6 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 0b8e8eee..08b4a477 100644 --- a/libsepol/src/policydb_validate.c +++ b/libsepol/src/policydb_validate.c @@ -855,11 +855,18 @@ 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 && - !hashtab_nel(d->trans->name_trans.table)) + !hashtab_nel(d->trans->name_trans.table) && + !hashtab_nel(d->trans->name_trans.table) && + !hashtab_nel(d->trans->prefix_trans.table) && + !hashtab_nel(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 d7f47c8d..df47197c 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); @@ -168,14 +195,26 @@ static int avtab_write_item(policydb_t * p, /* * skip entries which only contain filename transitions in versions - * before filename transitions were moved to avtab + * before filename transitions were moved to avtab, + * skip entries which only contain prefix/suffix transitions in versions + * before prefix/suffix filename transitions */ - 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)--; - return 0; + if (cur->key.specified & AVTAB_TRANSITION) { + 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)--; + return 0; + } + if (p->policyvers < POLICYDB_VERSION_PREFIX_SUFFIX && + !cur->datum.trans->otype && + !hashtab_nel(cur->datum.trans->name_trans.table)) + return 0; } if (oldvers) { @@ -378,17 +417,27 @@ static int avtab_write(struct policydb *p, avtab_t * a, struct policy_file *fp) * filename transitions. */ nel = a->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--; + for (i = 0; i < a->nslot; i++) { + for (cur = a->htable[i]; cur; cur = cur->next) { + if (!(cur->key.specified & AVTAB_TRANSITION)) + continue; + if (p->policyvers < POLICYDB_VERSION_AVTAB_FTRANS && + !cur->datum.trans->otype) { + /* + * entries containing only filename + * transitions are skipped and written + * out later + */ + nel--; + } else if (p->policyvers < POLICYDB_VERSION_PREFIX_SUFFIX && + !cur->datum.trans->otype && + !hashtab_nel(cur->datum.trans->name_trans.table)) { + /* + * entries containing only prefix/suffix + * transitions are not supported in + * previous versions + */ + nel--; } } } @@ -2520,6 +2569,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 @@ -2686,6 +2751,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 Tue Jun 20 09:01:22 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juraj Marcin X-Patchwork-Id: 13285378 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 6AE60EB64DB for ; Tue, 20 Jun 2023 09:02:53 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231765AbjFTJCw (ORCPT ); Tue, 20 Jun 2023 05:02:52 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59350 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S232096AbjFTJCu (ORCPT ); Tue, 20 Jun 2023 05:02:50 -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 37CFC10FB for ; Tue, 20 Jun 2023 02:02:38 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1687251753; cv=none; d=zohomail.eu; s=zohoarc; b=KUpUEtUI4s9dSTc69Qgfgh0VF3WIZWEzFzTQl5H9y+vFWwcpJ6R+mtgpX0Jg4yhFwZFm+kS1VgDVhBPBzcvokIKTTKadp4YtSeupe+CEKOzzbGPiG6wAYES3uL6LVVDpdhrg96+vMhGU1kEuuKcHVhgJenwJOofqy872KNlfI6o= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.eu; s=zohoarc; t=1687251753; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:To; bh=59yinTypS12WtggpBA46FAvu8GE1TVj6p8OQ6dtwv2o=; b=larr9A6/DV2pkYbYh3Npxy9K3XBj5qeNK+cMShdaYxD/J2XTw4LQLX14OLAM0ZMVXcLry69KcQbZhZZ2hLOgo15QvtvXY1GbSkVVoN+YExXPY97ys/C3S7kTrKPP+giztwENSaUVHVpbjNIWSuCmscaDVoy9o4yjNCG9Hnn5zk0= 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=1687251753; 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=59yinTypS12WtggpBA46FAvu8GE1TVj6p8OQ6dtwv2o=; b=GPWTas88YrEZJd3LZSaw2DqUWGOLCpgFVjDyITbPKQMTtiKnD+1ibYT7NW73psUR mQF4AvnGXejBEVZI8aNEfsbvVMeYKs1F7zWUqNZD7PbJFZwf273i4L/OO0wM3exWJGz dKymk4Ku0r7EwQcyHr2BJXIzWdNsK2Ez0qoS6N38= Received: from morty01.jurajmarcin.com (129.159.244.31 [129.159.244.31]) by mx.zoho.eu with SMTPS id 1687251752960321.03290794525094; Tue, 20 Jun 2023 11:02:32 +0200 (CEST) Received: from jmarcin-t14s-01.redhat.com (unknown [213.175.37.12]) by morty01.jurajmarcin.com (Postfix) with ESMTPSA id 6B3292081F76; Tue, 20 Jun 2023 09:02:32 +0000 (UTC) From: Juraj Marcin To: selinux@vger.kernel.org Cc: Ondrej Mosnacek Subject: [PATCH v2 7/8] checkpolicy,libsepol: add prefix/suffix support to module policy Date: Tue, 20 Jun 2023 11:01:22 +0200 Message-Id: In-Reply-To: References: 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. Syntax of the new prefix/suffix filename transition rule: type_transition source_type target_type : class default_type object_name match_type; where match_type is either keyword "prefix" or "suffix" Examples: type_transition ta tb:CLASS01 tc "file01" prefix; type_transition td te:CLASS01 tf "file02" suffix; Reviewed-by: Ondrej Mosnacek Signed-off-by: Juraj Marcin --- checkpolicy/policy_define.c | 13 ++++--- checkpolicy/policy_define.h | 2 +- checkpolicy/policy_parse.y | 13 ++++--- checkpolicy/policy_scan.l | 4 +++ 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, 150 insertions(+), 43 deletions(-) diff --git a/checkpolicy/policy_define.c b/checkpolicy/policy_define.c index 25dbf25d..8421b253 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 2a14fc1e..6b6890a3 100644 --- a/checkpolicy/policy_parse.y +++ b/checkpolicy/policy_parse.y @@ -108,6 +108,7 @@ typedef int (* require_func_t)(int pass); %token IF %token ELSE %token TYPE_TRANSITION +%token PREFIX SUFFIX %token TYPE_MEMBER %token TYPE_CHANGE %token ROLE_TRANSITION @@ -451,13 +452,17 @@ 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 PREFIX ';' + {if (define_compute_type(AVRULE_TRANSITION, 1, NAME_TRANS_MATCH_PREFIX)) return -1;} + | TYPE_TRANSITION names names ':' names identifier filename 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 2c025b61..9ffac353 100644 --- a/checkpolicy/policy_scan.l +++ b/checkpolicy/policy_scan.l @@ -123,6 +123,10 @@ EXPANDATTRIBUTE | expandattribute { return(EXPANDATTRIBUTE); } TYPE_TRANSITION | type_transition { return(TYPE_TRANSITION); } +PREFIX | +prefix { return(PREFIX); } +SUFFIX | +suffix { return(SUFFIX); } TYPE_MEMBER | type_member { return(TYPE_MEMBER); } TYPE_CHANGE | diff --git a/checkpolicy/test/dismod.c b/checkpolicy/test/dismod.c index cde80f95..671aea2e 100644 --- a/checkpolicy/test/dismod.c +++ b/checkpolicy/test/dismod.c @@ -339,6 +339,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, " PREFIX"); + break; + case NAME_TRANS_MATCH_SUFFIX: + fprintf(fp, " 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 efdd102b..2d2b3ee1 100644 --- a/checkpolicy/test/dispol.c +++ b/checkpolicy/test/dispol.c @@ -129,7 +129,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 90cfb90b..99fdaa87 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 (!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 (!target_symtab->table) { + rc = symtab_init(target_symtab, 1 << 8); if (rc < 0) return rc; } @@ -810,8 +825,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; @@ -856,7 +870,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; @@ -909,7 +924,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 a4c92f4f..7a011508 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", @@ -1885,6 +1887,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; @@ -1902,6 +1905,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 96169228..6e4f36f1 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; void sepol_indent(FILE *out, int indent); 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 1e002c4e..37c34bbe 100644 --- a/libsepol/src/module_to_cil.c +++ b/libsepol/src/module_to_cil.c @@ -547,12 +547,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: @@ -598,10 +599,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 = " prefix"; + break; + case NAME_TRANS_MATCH_SUFFIX: + match_str = " suffix"; + break; + default: + ERR(NULL, "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)", @@ -1205,7 +1220,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; @@ -1216,7 +1231,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 f1f6cec6..552eb77a 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 df47197c..f0ed9e33 100644 --- a/libsepol/src/write.c +++ b/libsepol/src/write.c @@ -2071,6 +2071,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; @@ -2078,6 +2079,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) && @@ -2136,12 +2142,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) { @@ -2186,12 +2197,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); @@ -2299,7 +2315,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++; } @@ -2312,7 +2329,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) { @@ -2751,7 +2770,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 Tue Jun 20 09:01:23 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Juraj Marcin X-Patchwork-Id: 13285379 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 4686DEB64D8 for ; Tue, 20 Jun 2023 09:02:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S231773AbjFTJCz (ORCPT ); Tue, 20 Jun 2023 05:02:55 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:59428 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S231489AbjFTJCy (ORCPT ); Tue, 20 Jun 2023 05:02:54 -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 804631982 for ; Tue, 20 Jun 2023 02:02:43 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1687251757; cv=none; d=zohomail.eu; s=zohoarc; b=M7YHtVDJKBu8I+65+grqA9pSoMeYyTHarLx/1b1gNYWgOgW+7Q0mqY4BRtXgtFU3xYxQYpC5ZD9SpA86lJxXhuknrex46D0wHSGDUqXzQDdjCfDxksvHav3Gz+ddxN4klZG/Y2/Z28vqimfDvA/YcKam2ebH1VSSxnmtYdsYeAg= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.eu; s=zohoarc; t=1687251757; h=Content-Transfer-Encoding:Cc:Date:From:In-Reply-To:MIME-Version:Message-ID:References:Subject:To; bh=M+rOQtUva7ce3aRPNqzkCwCiI7RcxupWLajIV610Twc=; b=ZAw7wG/pfFwbFqx/grVZmdD6XdiqN6QneXx4XoSpIWLosaVa9T3Wgk8J9Rxq6zdRgJmlN7CzdhHXEWG8Xo05YmOG1flCFC7EWd4zq6bjmTYGmn93UhnIQupPecZe3NkeTHDKjzPSFOXIN9wS5bplg1UIBRrStZCKTtyNv0BBp9M= 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=1687251757; 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=M+rOQtUva7ce3aRPNqzkCwCiI7RcxupWLajIV610Twc=; b=GycyJgw9FXJCCxOsRxfDWcEIIcbT3JnjszNeIhD3Fy/FOMTwEspE6MTFHKokESIY tcDgqgTet2bzfdxa2USG99ymnz4R88voVp/5gHokbyBrZren4N9X2B5ZIcVGno/VVrk CRTmwzN2pv9TmsG8zODMeQdjfkSPlbs6to1VEA8I= Received: from morty01.jurajmarcin.com (129.159.244.31 [129.159.244.31]) by mx.zoho.eu with SMTPS id 1687251755802595.8723386728121; Tue, 20 Jun 2023 11:02:35 +0200 (CEST) Received: from jmarcin-t14s-01.redhat.com (unknown [213.175.37.12]) by morty01.jurajmarcin.com (Postfix) with ESMTPSA id 44BF72081F76; Tue, 20 Jun 2023 09:02:35 +0000 (UTC) From: Juraj Marcin To: selinux@vger.kernel.org Cc: Ondrej Mosnacek Subject: [PATCH v2 8/8] libsepol/cil: add support for prefix/suffix filename transtions to CIL Date: Tue, 20 Jun 2023 11:01:23 +0200 Message-Id: In-Reply-To: References: 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 the CIL structures as well as in the CIL policy parser. Syntax of the new prefix/suffix filename transition rule: (typetransition source_type_id target_type_id class_id object_name match_type default_type_id) where match_type is either the keyword "prefix" or "suffix". Examples: (typetransition ta tb CLASS01 "file01" prefix td) (typetransition td te CLASS01 "file02" suffix tf) Reviewed-by: Ondrej Mosnacek Signed-off-by: Juraj Marcin --- libsepol/cil/src/cil.c | 6 ++++++ libsepol/cil/src/cil_binary.c | 8 ++++---- libsepol/cil/src/cil_build_ast.c | 26 +++++++++++++++++++++----- libsepol/cil/src/cil_copy_ast.c | 1 + libsepol/cil/src/cil_internal.h | 4 ++++ 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, 64 insertions(+), 10 deletions(-) diff --git a/libsepol/cil/src/cil.c b/libsepol/cil/src/cil.c index 38edcf8e..fa693020 100644 --- a/libsepol/cil/src/cil.c +++ b/libsepol/cil/src/cil.c @@ -95,6 +95,8 @@ char *CIL_KEY_TUNABLEIF; char *CIL_KEY_ALLOW; char *CIL_KEY_DONTAUDIT; char *CIL_KEY_TYPETRANSITION; +char *CIL_KEY_PREFIX; +char *CIL_KEY_SUFFIX; char *CIL_KEY_TYPECHANGE; char *CIL_KEY_CALL; char *CIL_KEY_TUNABLE; @@ -264,6 +266,8 @@ 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_PREFIX = cil_strpool_add("prefix"); + CIL_KEY_SUFFIX = cil_strpool_add("suffix"); CIL_KEY_TYPECHANGE = cil_strpool_add("typechange"); CIL_KEY_CALL = cil_strpool_add("call"); CIL_KEY_TUNABLE = cil_strpool_add("tunable"); @@ -2387,6 +2391,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..67bbdcab 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,12 +3354,22 @@ 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 = parse_current->next->next->next->next->next->data; + } } } @@ -3370,8 +3381,13 @@ 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->name_str = s4; + if (s6) { + nametypetrans->name_match_str = s5; + nametypetrans->result_str = s6; + } else { + nametypetrans->result_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..a5ff808b 100644 --- a/libsepol/cil/src/cil_internal.h +++ b/libsepol/cil/src/cil_internal.h @@ -112,6 +112,8 @@ extern char *CIL_KEY_TUNABLEIF; extern char *CIL_KEY_ALLOW; extern char *CIL_KEY_DONTAUDIT; extern char *CIL_KEY_TYPETRANSITION; +extern char *CIL_KEY_PREFIX; +extern char *CIL_KEY_SUFFIX; extern char *CIL_KEY_TYPECHANGE; extern char *CIL_KEY_CALL; extern char *CIL_KEY_TUNABLE; @@ -575,6 +577,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..9ee40ba7 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 = " PREFIX"; + break; + case NAME_TRANS_MATCH_SUFFIX: + name_match_str = " 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..1ef0986c 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 == NULL) { + nametypetrans->name_match = NAME_TRANS_MATCH_EXACT; + } else if (nametypetrans->name_match_str == CIL_KEY_PREFIX) { + nametypetrans->name_match = NAME_TRANS_MATCH_PREFIX; + } else if (nametypetrans->name_match_str == CIL_KEY_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;