All of lore.kernel.org
 help / color / mirror / Atom feed
From: Juraj Marcin <juraj@jurajmarcin.com>
To: selinux@vger.kernel.org
Cc: Stephen Smalley <stephen.smalley.work@gmail.com>,
	Ondrej Mosnacek <omosnace@redhat.com>
Subject: [PATCH 4/8] libsepol: implement new kernel binary format for avtab
Date: Wed, 31 May 2023 13:49:10 +0200	[thread overview]
Message-ID: <20230531114914.2237609-5-juraj@jurajmarcin.com> (raw)
In-Reply-To: <20230531114914.2237609-1-juraj@jurajmarcin.com>

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 <omosnace@redhat.com>
Signed-off-by: Juraj Marcin <juraj@jurajmarcin.com>
---
 libsepol/include/sepol/policydb/hashtab.h  |  8 ++
 libsepol/include/sepol/policydb/policydb.h |  3 +-
 libsepol/src/avtab.c                       | 88 ++++++++++++++++++++--
 libsepol/src/policydb.c                    |  8 ++
 libsepol/src/write.c                       | 86 +++++++++++++++++----
 5 files changed, 172 insertions(+), 21 deletions(-)

diff --git a/libsepol/include/sepol/policydb/hashtab.h b/libsepol/include/sepol/policydb/hashtab.h
index 3a6b953e..92fedf69 100644
--- a/libsepol/include/sepol/policydb/hashtab.h
+++ b/libsepol/include/sepol/policydb/hashtab.h
@@ -116,6 +116,14 @@ static inline int hashtab_is_empty(hashtab_t h)
 	return !h || !h->size;
 }
 
+/* Returns number of elements in the hashtab h or 0 is h is NULL */
+static inline uint32_t hashtab_nel(hashtab_t h)
+{
+	if (!h)
+		return 0;
+	return h->nel;
+}
+
 #ifdef __cplusplus
 }
 #endif
diff --git a/libsepol/include/sepol/policydb/policydb.h b/libsepol/include/sepol/policydb/policydb.h
index d30f26af..528c1cad 100644
--- a/libsepol/include/sepol/policydb/policydb.h
+++ b/libsepol/include/sepol/policydb/policydb.h
@@ -722,10 +722,11 @@ extern int policydb_set_target_platform(policydb_t *p, int platform);
 #define POLICYDB_VERSION_INFINIBAND		31 /* Linux-specific */
 #define POLICYDB_VERSION_GLBLUB		32
 #define POLICYDB_VERSION_COMP_FTRANS	33 /* compressed filename transitions */
+#define POLICYDB_VERSION_AVTAB_FTRANS	34 /* filename transitions moved to avtab */
 
 /* Range of policy versions we understand*/
 #define POLICYDB_VERSION_MIN	POLICYDB_VERSION_BASE
-#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_COMP_FTRANS
+#define POLICYDB_VERSION_MAX	POLICYDB_VERSION_AVTAB_FTRANS
 
 /* Module versions and specific changes*/
 #define MOD_POLICYDB_VERSION_BASE		4
diff --git a/libsepol/src/avtab.c b/libsepol/src/avtab.c
index 3d8d6769..33441a34 100644
--- a/libsepol/src/avtab.c
+++ b/libsepol/src/avtab.c
@@ -446,6 +446,87 @@ void avtab_hash_eval(avtab_t * h, char *tag)
 	     tag, h->nel, slots_used, h->nslot, max_chain_len);
 }
 
+static int avtab_read_name_trans(policy_file_t *fp, symtab_t *target)
+{
+	int rc;
+	uint32_t buf32[2], nel, i, len, *otype = NULL;
+	char *name = NULL;
+
+	/* read number of name transitions */
+	rc = next_entry(buf32, fp, sizeof(uint32_t) * 1);
+	if (rc < 0)
+		return rc;
+	nel = le32_to_cpu(buf32[0]);
+
+	rc = symtab_init(target, nel);
+	if (rc < 0)
+		return rc;
+
+	/* read name transitions */
+	for (i = 0; i < nel; i++) {
+		rc = SEPOL_ENOMEM;
+		otype = malloc(sizeof(uint32_t));
+		if (!otype)
+			goto exit;
+
+		/* read name transition otype and name length */
+		rc = next_entry(buf32, fp, sizeof(uint32_t) * 2);
+		if (rc < 0)
+			goto exit;
+		*otype = le32_to_cpu(buf32[0]);
+		len = le32_to_cpu(buf32[1]);
+
+		/* read the name */
+		rc = str_read(&name, fp, len);
+		if (rc < 0)
+			goto exit;
+
+		rc = hashtab_insert(target->table, name, otype);
+		if (rc < 0)
+			goto exit;
+		otype = NULL;
+		name = NULL;
+	}
+
+exit:
+	free(otype);
+	free(name);
+	return rc;
+}
+
+static int avtab_trans_read(policy_file_t *fp, uint32_t vers,
+			    avtab_trans_t *trans)
+{
+	int rc;
+	uint32_t buf32[1];
+
+	if (vers < POLICYDB_VERSION_AVTAB_FTRANS) {
+		rc = next_entry(buf32, fp, sizeof(uint32_t));
+		if (rc < 0) {
+			ERR(fp->handle, "truncated entry");
+			return SEPOL_ERR;
+		}
+		trans->otype = le32_to_cpu(*buf32);
+		return SEPOL_OK;
+	}
+
+	/* read otype */
+	rc = next_entry(buf32, fp, sizeof(uint32_t) * 1);
+	if (rc < 0)
+		return rc;
+	trans->otype = le32_to_cpu(buf32[0]);
+
+	rc = avtab_read_name_trans(fp, &trans->name_trans);
+	if (rc < 0)
+		goto bad;
+
+	return SEPOL_OK;
+
+bad:
+	avtab_trans_destroy(trans);
+	return rc;
+}
+
 /* Ordering of datums in the original avtab format in the policy file. */
 static const uint16_t spec_order[] = {
 	AVTAB_ALLOWED,
@@ -609,12 +690,9 @@ int avtab_read_item(struct policy_file *fp, uint32_t vers, avtab_t * a,
 			xperms.perms[i] = le32_to_cpu(buf32[i]);
 		datum.xperms = &xperms;
 	} else if (key.specified & AVTAB_TRANSITION) {
-		rc = next_entry(buf32, fp, sizeof(uint32_t));
-		if (rc < 0) {
-			ERR(fp->handle, "truncated entry");
+		rc = avtab_trans_read(fp, vers, &trans);
+		if (rc < 0)
 			return -1;
-		}
-		trans.otype = le32_to_cpu(*buf32);
 		datum.trans = &trans;
 	} else {
 		rc = next_entry(buf32, fp, sizeof(uint32_t));
diff --git a/libsepol/src/policydb.c b/libsepol/src/policydb.c
index 30c70d29..f2271524 100644
--- a/libsepol/src/policydb.c
+++ b/libsepol/src/policydb.c
@@ -208,6 +208,13 @@ static const struct policydb_compat_info policydb_compat[] = {
 	 .ocon_num = OCON_IBENDPORT + 1,
 	 .target_platform = SEPOL_TARGET_SELINUX,
 	},
+	{
+	 .type = POLICY_KERN,
+	 .version = POLICYDB_VERSION_AVTAB_FTRANS,
+	 .sym_num = SYM_NUM,
+	 .ocon_num = OCON_IBENDPORT + 1,
+	 .target_platform = SEPOL_TARGET_SELINUX,
+	},
 	{
 	 .type = POLICY_BASE,
 	 .version = MOD_POLICYDB_VERSION_BASE,
@@ -4099,6 +4106,7 @@ int policydb_read(policydb_t * p, struct policy_file *fp, unsigned verbose)
 		if (role_allow_read(&p->role_allow, fp))
 			goto bad;
 		if (r_policyvers >= POLICYDB_VERSION_FILENAME_TRANS &&
+		    r_policyvers < POLICYDB_VERSION_AVTAB_FTRANS &&
 		    avtab_filename_trans_read(fp, r_policyvers, &p->te_avtab))
 			goto bad;
 	} else {
diff --git a/libsepol/src/write.c b/libsepol/src/write.c
index 7b0ef705..12f14670 100644
--- a/libsepol/src/write.c
+++ b/libsepol/src/write.c
@@ -102,6 +102,56 @@ static uint16_t spec_order[] = {
 	AVTAB_MEMBER
 };
 
+static int avtab_trans_write_helper(hashtab_key_t hkey, hashtab_datum_t hdatum,
+				    void *fp)
+{
+	char *name = hkey;
+	uint32_t *otype = hdatum;
+	uint32_t buf32[2], len;
+	size_t items;
+
+	/* write filename transition otype and name length */
+	len = strlen(name);
+	buf32[0] = cpu_to_le32(*otype);
+	buf32[1] = cpu_to_le32(len);
+	items = put_entry(buf32, sizeof(uint32_t), 2, fp);
+	if (items != 2)
+		return -1;
+
+	/* write filename transition name */
+	items = put_entry(name, sizeof(char), len, fp);
+	if (items != len)
+		return -1;
+
+	return 0;
+}
+
+static int avtab_trans_write(policydb_t *p, const avtab_trans_t *cur,
+			     policy_file_t *fp)
+{
+	size_t items;
+	uint32_t buf32[2];
+
+	if (p->policyvers >= POLICYDB_VERSION_AVTAB_FTRANS) {
+		/* write otype and number of filename transitions */
+		buf32[0] = cpu_to_le32(cur->otype);
+		buf32[1] = cpu_to_le32(hashtab_nel(cur->name_trans.table));
+		items = put_entry(buf32, sizeof(uint32_t), 2, fp);
+		if (items != 2)
+			return -1;
+
+		/* write filename transitions */
+		return hashtab_map(cur->name_trans.table,
+				   avtab_trans_write_helper, fp);
+	} else if (cur->otype) {
+		buf32[0] = cpu_to_le32(cur->otype);
+		items = put_entry(buf32, sizeof(uint32_t), 1, fp);
+		if (items != 1)
+			return -1;
+	}
+	return 0;
+}
+
 static int avtab_write_item(policydb_t * p,
 			    avtab_ptr_t cur, struct policy_file *fp,
 			    unsigned merge, unsigned commit, uint32_t * nel)
@@ -116,8 +166,12 @@ static int avtab_write_item(policydb_t * p,
 				&& p->policyvers < POLICYDB_VERSION_AVTAB);
 	unsigned int i;
 
-	/* skip entries which only contain filename transitions */
-	if (cur->key.specified & AVTAB_TRANSITION && !cur->datum.trans->otype) {
+	/*
+	 * skip entries which only contain filename transitions in versions
+	 * before filename transitions were moved to avtab
+	 */
+	if (p->policyvers < POLICYDB_VERSION_AVTAB_FTRANS &&
+	    cur->key.specified & AVTAB_TRANSITION && !cur->datum.trans->otype) {
 		/* if oldvers, reduce nel, because this node will be skipped */
 		if (oldvers && nel)
 			(*nel)--;
@@ -271,9 +325,7 @@ static int avtab_write_item(policydb_t * p,
 		if (items != 8)
 			return POLICYDB_ERROR;
 	} else if (cur->key.specified & AVTAB_TRANSITION) {
-		buf32[0] = cpu_to_le32(cur->datum.trans->otype);
-		items = put_entry(buf32, sizeof(uint32_t), 1, fp);
-		if (items != 1)
+		if (avtab_trans_write(p, cur->datum.trans, fp) < 0)
 			return POLICYDB_ERROR;
 	} else {
 		buf32[0] = cpu_to_le32(cur->datum.data);
@@ -326,15 +378,18 @@ static int avtab_write(struct policydb *p, avtab_t * a, struct policy_file *fp)
 		 * filename transitions.
 		 */
 		nel = a->nel;
-		/*
-		 * entries containing only filename transitions are skipped and
-		 * written out later
-		 */
-		for (i = 0; i < a->nslot; i++) {
-			for (cur = a->htable[i]; cur; cur = cur->next) {
-				if (cur->key.specified & AVTAB_TRANSITION &&
-				    !cur->datum.trans->otype)
-					nel--;
+		if (p->policyvers < POLICYDB_VERSION_AVTAB_FTRANS) {
+			/*
+			 * entries containing only filename transitions are
+			 * skipped and written out later
+			 */
+			for (i = 0; i < a->nslot; i++) {
+				for (cur = a->htable[i]; cur; cur = cur->next) {
+					if ((cur->key.specified
+					     & AVTAB_TRANSITION) &&
+					    !cur->datum.trans->otype)
+						nel--;
+				}
 			}
 		}
 		nel = cpu_to_le32(nel);
@@ -2625,7 +2680,8 @@ int policydb_write(policydb_t * p, struct policy_file *fp)
 		if (role_allow_write(p->role_allow, fp))
 			return POLICYDB_ERROR;
 		if (p->policyvers >= POLICYDB_VERSION_FILENAME_TRANS) {
-			if (avtab_filename_trans_write(p, &p->te_avtab, fp))
+			if (p->policyvers < POLICYDB_VERSION_AVTAB_FTRANS &&
+			    avtab_filename_trans_write(p, &p->te_avtab, fp))
 				return POLICYDB_ERROR;
 		} else if (avtab_has_filename_transitions(&p->te_avtab)) {
 			WARN(fp->handle,
-- 
2.40.0


  parent reply	other threads:[~2023-05-31 11:50 UTC|newest]

Thread overview: 15+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-05-31 11:49 [PATCH 0/8] checkpolicy, libsepol: add prefix/suffix matching to filename type transitions Juraj Marcin
2023-05-31 11:49 ` [PATCH 1/8] checkpolicy, libsepol: move transition to separate structure in avtab Juraj Marcin
2023-05-31 11:49 ` [PATCH 2/8] checkpolicy, libsepol: move filename transitions to avtab Juraj Marcin
2023-05-31 11:49 ` [PATCH 3/8] checkpolicy, libsepol: move filename transition rules to avrule Juraj Marcin
2023-05-31 11:49 ` Juraj Marcin [this message]
2023-05-31 11:49 ` [PATCH 5/8] libsepol: implement new module binary format of avrule Juraj Marcin
2023-05-31 11:49 ` [PATCH 6/8] checkpolicy, libsepol: add prefix/suffix support to kernel policy Juraj Marcin
2023-05-31 11:49 ` [PATCH 7/8] checkpolicy, libsepol: add prefix/suffix support to module policy Juraj Marcin
2023-06-01 20:59   ` James Carter
2023-06-07  8:31     ` Ondrej Mosnacek
2023-06-07 13:32       ` James Carter
2023-05-31 11:49 ` [PATCH 8/8] libsepol/cil: add support for prefix/suffix filename transtions to CIL Juraj Marcin
2023-06-01 21:00   ` James Carter
2023-06-01 21:03 ` [PATCH 0/8] checkpolicy, libsepol: add prefix/suffix matching to filename type transitions James Carter
2023-06-01 23:59   ` Juraj Marcin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20230531114914.2237609-5-juraj@jurajmarcin.com \
    --to=juraj@jurajmarcin.com \
    --cc=omosnace@redhat.com \
    --cc=selinux@vger.kernel.org \
    --cc=stephen.smalley.work@gmail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.