All of lore.kernel.org
 help / color / mirror / Atom feed
From: Juraj Marcin <juraj@jurajmarcin.com>
To: Paul Moore <paul@paul-moore.com>
Cc: Stephen Smalley <stephen.smalley.work@gmail.com>,
	selinux@vger.kernel.org, Ondrej Mosnacek <omosnace@redhat.com>
Subject: [PATCH 4/5] selinux: filename transitions move tests
Date: Wed, 31 May 2023 13:29:27 +0200	[thread overview]
Message-ID: <20230531112927.1957093-5-juraj@jurajmarcin.com> (raw)
In-Reply-To: <20230531112927.1957093-1-juraj@jurajmarcin.com>

This patch adds a set of simple tests that test if the functions for
reading and writing filename transitions in avtab work properly.

Reviewed-by: Ondrej Mosnacek <omosnace@redhat.com>
Signed-off-by: Juraj Marcin <juraj@jurajmarcin.com>
---
 security/selinux/Kconfig         |  17 +
 security/selinux/Makefile        |   2 +
 security/selinux/ss/avtab.c      |  20 +
 security/selinux/ss/avtab_test.c | 729 +++++++++++++++++++++++++++++++
 security/selinux/ss/symtab.c     |   3 +
 5 files changed, 771 insertions(+)
 create mode 100644 security/selinux/ss/avtab_test.c

diff --git a/security/selinux/Kconfig b/security/selinux/Kconfig
index 95a186ec0fcb..78cdc8d4232d 100644
--- a/security/selinux/Kconfig
+++ b/security/selinux/Kconfig
@@ -68,3 +68,20 @@ config SECURITY_SELINUX_SID2STR_CACHE_SIZE
 	  conversion.  Setting this option to 0 disables the cache completely.
 
 	  If unsure, keep the default value.
+
+config SECURITY_SELINUX_KUNIT_TEST
+	tristate "Tests for SELinux" if !KUNIT_ALL_TESTS
+	depends on KUNIT && SECURITY_SELINUX
+	default KUNIT_ALL_TESTS
+	help
+	  This builds the SELinux KUnit tests.
+
+	  KUnit tests run during boot and output the results to the debug log
+	  in TAP format (https://testanything.org/). Only useful for kernel devs
+	  running KUnit test harness and are not for inclusion into a
+	  production build.
+
+	  For more information on KUnit and unit tests in general please refer
+	  to the KUnit documentation in Documentation/dev-tools/kunit/.
+
+	  If unsure, say N.
diff --git a/security/selinux/Makefile b/security/selinux/Makefile
index ab8c3093d5fd..d3d63b28edcf 100644
--- a/security/selinux/Makefile
+++ b/security/selinux/Makefile
@@ -27,3 +27,5 @@ quiet_cmd_genhdrs = GEN     $(addprefix $(obj)/,$(genhdrs))
 targets += $(genhdrs)
 $(addprefix $(obj)/,$(genhdrs)) &: scripts/selinux/genheaders/genheaders FORCE
 	$(call if_changed,genhdrs)
+
+obj-$(CONFIG_SECURITY_SELINUX_KUNIT_TEST) += ss/avtab_test.o
diff --git a/security/selinux/ss/avtab.c b/security/selinux/ss/avtab.c
index 2cd9eabf796c..db7123670ef8 100644
--- a/security/selinux/ss/avtab.c
+++ b/security/selinux/ss/avtab.c
@@ -223,6 +223,9 @@ struct avtab_datum *avtab_search(struct avtab *h, const struct avtab_key *key)
 	return NULL;
 }
 
+/* Export for avtab KUnit tests */
+EXPORT_SYMBOL_GPL(avtab_search);
+
 /* This search function returns a node pointer, and can be used in
  * conjunction with avtab_search_next_node()
  */
@@ -331,6 +334,9 @@ void avtab_destroy(struct avtab *h)
 	h->mask = 0;
 }
 
+/* Export for avtab KUnit tests */
+EXPORT_SYMBOL_GPL(avtab_destroy);
+
 void avtab_init(struct avtab *h)
 {
 	h->htable = NULL;
@@ -378,6 +384,9 @@ int avtab_alloc(struct avtab *h, u32 nrules)
 	return 0;
 }
 
+/* Export for avtab KUnit tests */
+EXPORT_SYMBOL_GPL(avtab_alloc);
+
 int avtab_alloc_dup(struct avtab *new, const struct avtab *orig)
 {
 	return avtab_alloc_common(new, orig->nslot);
@@ -766,6 +775,9 @@ int avtab_read(struct avtab *a, void *fp, struct policydb *pol)
 	goto out;
 }
 
+/* Export for avtab KUnit tests */
+EXPORT_SYMBOL_GPL(avtab_read);
+
 static int avtab_trans_write_helper(void *k, void *d, void *fp)
 {
 	char *name = k;
@@ -900,6 +912,9 @@ int avtab_write(struct policydb *p, struct avtab *a, void *fp)
 	return rc;
 }
 
+/* Export for avtab KUnit tests */
+EXPORT_SYMBOL_GPL(avtab_write);
+
 void __init avtab_cache_init(void)
 {
 	avtab_node_cachep = kmem_cache_create("avtab_node",
@@ -1105,6 +1120,8 @@ int avtab_filename_trans_read(struct avtab *a, void *fp, struct policydb *p)
 	return 0;
 }
 
+/* Export for avtab KUnit tests */
+EXPORT_SYMBOL_GPL(avtab_filename_trans_read);
 
 struct filenametr_write_args {
 	void *fp;
@@ -1406,3 +1423,6 @@ int avtab_filename_trans_write(struct policydb *p, struct avtab *a, void *fp)
 
 	return rc;
 }
+
+/* Export for avtab KUnit tests */
+EXPORT_SYMBOL_GPL(avtab_filename_trans_write);
diff --git a/security/selinux/ss/avtab_test.c b/security/selinux/ss/avtab_test.c
new file mode 100644
index 000000000000..daa8e4cfaeb2
--- /dev/null
+++ b/security/selinux/ss/avtab_test.c
@@ -0,0 +1,729 @@
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * KUnit tests for access vector table type Implementation
+ *
+ * Author: Juraj Marcin <juraj@jurajmarcin.com>
+ */
+
+#include <kunit/test.h>
+#include "policydb.h"
+#include "security.h"
+#include "avtab.h"
+
+static void filename_trans_read__pre_filename_trans(struct kunit *test)
+{
+	struct policydb p = {
+		.te_avtab = {0},
+		.policyvers = POLICYDB_VERSION_FILENAME_TRANS - 1,
+	};
+	struct policy_file fp = {
+		.data = NULL,
+		.len = 0,
+	};
+
+	p.p_types.nprim = 54;
+	p.p_classes.nprim = 49;
+
+	KUNIT_EXPECT_EQ(test, 0,
+			avtab_filename_trans_read(&p.te_avtab, &fp, &p));
+	KUNIT_EXPECT_EQ(test, 0, p.te_avtab.nel);
+	KUNIT_EXPECT_EQ(test, 0, fp.len);
+}
+
+static void filename_trans_read__empty(struct kunit *test)
+{
+	char data[] = {0, 0, 0, 0};
+	struct policydb p = {
+		.te_avtab = {0},
+		.policyvers = POLICYDB_VERSION_FILENAME_TRANS,
+	};
+	struct policy_file fp = {
+		.data = data,
+		.len = sizeof(data),
+	};
+
+	p.p_types.nprim = 54;
+	p.p_classes.nprim = 49;
+
+	KUNIT_EXPECT_EQ(test, 0,
+			avtab_filename_trans_read(&p.te_avtab, &fp, &p));
+	KUNIT_EXPECT_EQ(test, 0, p.te_avtab.nel);
+	KUNIT_EXPECT_EQ(test, 0, fp.len);
+}
+
+static void filename_trans_read__comp_empty(struct kunit *test)
+{
+	char data[] = {0, 0, 0, 0};
+	struct policydb p = {
+		.te_avtab = {0},
+		.policyvers = POLICYDB_VERSION_COMP_FTRANS,
+	};
+	struct policy_file fp = {
+		.data = data,
+		.len = sizeof(data),
+	};
+
+	p.p_types.nprim = 54;
+	p.p_classes.nprim = 49;
+
+	KUNIT_EXPECT_EQ(test, 0,
+			avtab_filename_trans_read(&p.te_avtab, &fp, &p));
+	KUNIT_EXPECT_EQ(test, 0, p.te_avtab.nel);
+	KUNIT_EXPECT_EQ(test, 0, fp.len);
+}
+
+static void filename_trans_read__simple(struct kunit *test)
+{
+	char data[] = {
+		3, 0, 0, 0,	/* count */
+
+		5, 0, 0, 0,			/* entry 1 name len */
+		'f', 'i', 'l', 'e', '1',	/* entry 1 name */
+		42, 0, 0, 0,			/* entry 1 stype */
+		43, 0, 0, 0,			/* entry 1 ttype */
+		44, 0, 0, 0,			/* entry 1 tclass */
+		45, 0, 0, 0,			/* entry 1 otype */
+
+		5, 0, 0, 0,			/* entry 2 name len */
+		'f', 'i', 'l', 'e', '2',	/* entry 2 name */
+		46, 0, 0, 0,			/* entry 2 stype */
+		47, 0, 0, 0,			/* entry 2 ttype */
+		48, 0, 0, 0,			/* entry 2 tclass */
+		49, 0, 0, 0,			/* entry 2 otype */
+
+		5, 0, 0, 0,			/* entry 3 name len */
+		'f', 'i', 'l', 'e', '3',	/* entry 3 name */
+		46, 0, 0, 0,			/* entry 3 stype */
+		47, 0, 0, 0,			/* entry 3 ttype */
+		48, 0, 0, 0,			/* entry 3 tclass */
+		53, 0, 0, 0,			/* entry 3 otype */
+	};
+	struct policydb p = {
+		.te_avtab = {0},
+		.policyvers = POLICYDB_VERSION_FILENAME_TRANS,
+	};
+	struct policy_file fp = {
+		.data = data,
+		.len = sizeof(data),
+	};
+	struct avtab_key key;
+	struct avtab_datum *node;
+	u32 *otype;
+
+	p.p_types.nprim = 54;
+	p.p_classes.nprim = 49;
+	KUNIT_ASSERT_EQ(test, 0, avtab_alloc(&p.te_avtab, 3));
+
+	KUNIT_ASSERT_EQ(test, 0,
+			avtab_filename_trans_read(&p.te_avtab, &fp, &p));
+	KUNIT_EXPECT_EQ(test, 2, p.te_avtab.nel);
+	KUNIT_EXPECT_EQ(test, 0, fp.len);
+
+	key = (struct avtab_key){42, 43, 44, AVTAB_TRANSITION};
+	node = avtab_search(&p.te_avtab, &key);
+	KUNIT_ASSERT_NOT_NULL(test, node);
+	KUNIT_EXPECT_EQ(test, 0, node->u.trans->otype);
+	KUNIT_EXPECT_EQ(test, 1, node->u.trans->name_trans.table.nel);
+
+	otype = symtab_search(&node->u.trans->name_trans, "file1");
+	KUNIT_ASSERT_NOT_NULL(test, otype);
+	KUNIT_EXPECT_EQ(test, 45, *otype);
+
+	key = (struct avtab_key){46, 47, 48, AVTAB_TRANSITION};
+	node = avtab_search(&p.te_avtab, &key);
+	KUNIT_ASSERT_NOT_NULL(test, node);
+	KUNIT_EXPECT_EQ(test, 0, node->u.trans->otype);
+	KUNIT_EXPECT_EQ(test, 2, node->u.trans->name_trans.table.nel);
+
+	otype = symtab_search(&node->u.trans->name_trans, "file2");
+	KUNIT_ASSERT_NOT_NULL(test, otype);
+	KUNIT_EXPECT_EQ(test, 49, *otype);
+
+	otype = symtab_search(&node->u.trans->name_trans, "file3");
+	KUNIT_ASSERT_NOT_NULL(test, otype);
+	KUNIT_EXPECT_EQ(test, 53, *otype);
+
+	avtab_destroy(&p.te_avtab);
+}
+
+static void filename_trans_read__comp_simple(struct kunit *test)
+{
+	char data[] = {
+		3, 0, 0, 0,	/* count */
+
+		5, 0, 0, 0,			/* entry 1 name len */
+		'f', 'i', 'l', 'e', '1',	/* entry 1 name */
+		43, 0, 0, 0,			/* entry 1 ttype */
+		44, 0, 0, 0,			/* entry 1 tclass */
+		1, 0, 0, 0,			/* entry 1 ndatum */
+		64, 0, 0, 0,			/* entry 1 datum 1 stypes */
+		64, 0, 0, 0,
+		1, 0, 0, 0,
+		0, 0, 0, 0,
+		0, 0, 0, 0, 0, 2, 0, 0,
+		45, 0, 0, 0,			/* entry 1 otype */
+
+		5, 0, 0, 0,			/* entry 2 name len */
+		'f', 'i', 'l', 'e', '2',	/* entry 2 name */
+		47, 0, 0, 0,			/* entry 2 ttype */
+		48, 0, 0, 0,			/* entry 2 tclass */
+		1, 0, 0, 0,			/* entry 2 ndatum */
+		64, 0, 0, 0,			/* entry 2 datum 1 stypes */
+		64, 0, 0, 0,
+		1, 0, 0, 0,
+		0, 0, 0, 0,
+		0, 0, 0, 0, 0, 32, 0, 0,
+		49, 0, 0, 0,			/* entry 2 otype */
+
+		5, 0, 0, 0,			/* entry 3 name len */
+		'f', 'i', 'l', 'e', '3',	/* entry 3 name */
+		47, 0, 0, 0,			/* entry 3 ttype */
+		48, 0, 0, 0,			/* entry 3 tclass */
+		1, 0, 0, 0,			/* entry 2 ndatum */
+		64, 0, 0, 0,			/* entry 2 datum 1 stypes */
+		64, 0, 0, 0,
+		1, 0, 0, 0,
+		0, 0, 0, 0,
+		0, 0, 0, 0, 0, 32, 0, 0,
+		53, 0, 0, 0,			/* entry 3 otype */
+	};
+	struct policydb p = {
+		.te_avtab = {0},
+		.policyvers = POLICYDB_VERSION_COMP_FTRANS,
+	};
+	struct policy_file fp = {
+		.data = data,
+		.len = sizeof(data),
+	};
+	struct avtab_key key;
+	struct avtab_datum *node;
+	u32 *otype;
+
+	p.p_types.nprim = 54;
+	p.p_classes.nprim = 49;
+	KUNIT_ASSERT_EQ(test, 0, avtab_alloc(&p.te_avtab, 3));
+
+	KUNIT_ASSERT_EQ(test, 0,
+			avtab_filename_trans_read(&p.te_avtab, &fp, &p));
+	KUNIT_EXPECT_EQ(test, 2, p.te_avtab.nel);
+	KUNIT_EXPECT_EQ(test, 0, fp.len);
+
+	key = (struct avtab_key){42, 43, 44, AVTAB_TRANSITION};
+	node = avtab_search(&p.te_avtab, &key);
+	KUNIT_ASSERT_NOT_NULL(test, node);
+	KUNIT_EXPECT_EQ(test, 0, node->u.trans->otype);
+	KUNIT_EXPECT_EQ(test, 1, node->u.trans->name_trans.table.nel);
+
+	otype = symtab_search(&node->u.trans->name_trans, "file1");
+	KUNIT_ASSERT_NOT_NULL(test, otype);
+	KUNIT_EXPECT_EQ(test, 45, *otype);
+
+	key = (struct avtab_key){46, 47, 48, AVTAB_TRANSITION};
+	node = avtab_search(&p.te_avtab, &key);
+	KUNIT_ASSERT_NOT_NULL(test, node);
+	KUNIT_EXPECT_EQ(test, 0, node->u.trans->otype);
+	KUNIT_EXPECT_EQ(test, 2, node->u.trans->name_trans.table.nel);
+
+	otype = symtab_search(&node->u.trans->name_trans, "file2");
+	KUNIT_ASSERT_NOT_NULL(test, otype);
+	KUNIT_EXPECT_EQ(test, 49, *otype);
+
+	otype = symtab_search(&node->u.trans->name_trans, "file3");
+	KUNIT_ASSERT_NOT_NULL(test, otype);
+	KUNIT_EXPECT_EQ(test, 53, *otype);
+
+	avtab_destroy(&p.te_avtab);
+}
+
+static void filename_trans_write__pre_filename_trans(struct kunit *test)
+{
+	struct policydb p = {
+		.te_avtab = {0},
+		.policyvers = POLICYDB_VERSION_FILENAME_TRANS - 1,
+	};
+	struct policy_file fp = {
+		.data = NULL,
+		.len = 0,
+	};
+
+	p.p_types.nprim = 54;
+	p.p_classes.nprim = 49;
+
+	KUNIT_EXPECT_EQ(test, 0,
+			avtab_filename_trans_write(&p, &p.te_avtab, &fp));
+	KUNIT_EXPECT_EQ(test, 0, fp.len);
+}
+
+static void filename_trans_write__empty(struct kunit *test)
+{
+	char expected_data[] = {0, 0, 0, 0};
+	char data[sizeof(expected_data)] = {0};
+	struct policydb p = {
+		.te_avtab = {0},
+		.policyvers = POLICYDB_VERSION_FILENAME_TRANS,
+	};
+	struct policy_file fp = {
+		.data = data,
+		.len = sizeof(data),
+	};
+
+	p.p_types.nprim = 54;
+	p.p_classes.nprim = 49;
+
+	KUNIT_ASSERT_EQ(test, 0,
+			avtab_filename_trans_write(&p, &p.te_avtab, &fp));
+
+	KUNIT_EXPECT_EQ(test, 0, fp.len);
+	KUNIT_EXPECT_TRUE(test,
+			  !memcmp(expected_data, data, sizeof(expected_data)));
+}
+
+static void filename_trans_write__comp_empty(struct kunit *test)
+{
+	char expected_data[] = {0, 0, 0, 0};
+	char data[sizeof(expected_data)] = {0};
+	struct policydb p = {
+		.te_avtab = {0},
+		.policyvers = POLICYDB_VERSION_COMP_FTRANS,
+	};
+	struct policy_file fp = {
+		.data = data,
+		.len = sizeof(data),
+	};
+
+	p.p_types.nprim = 54;
+	p.p_classes.nprim = 49;
+
+	KUNIT_ASSERT_EQ(test, 0,
+			avtab_filename_trans_write(&p, &p.te_avtab, &fp));
+
+	KUNIT_EXPECT_EQ(test, 0, fp.len);
+	KUNIT_EXPECT_TRUE(test,
+			  !memcmp(expected_data, data, sizeof(expected_data)));
+}
+
+static void filename_trans_write__simple(struct kunit *test)
+{
+	char expected_data[] = {
+		3, 0, 0, 0,	/* count */
+
+		5, 0, 0, 0,			/* entry 1 name len */
+		'f', 'i', 'l', 'e', '1',	/* entry 1 name */
+		42, 0, 0, 0,			/* entry 1 stype */
+		43, 0, 0, 0,			/* entry 1 ttype */
+		44, 0, 0, 0,			/* entry 1 tclass */
+		45, 0, 0, 0,			/* entry 1 otype */
+
+		5, 0, 0, 0,			/* entry 2 name len */
+		'f', 'i', 'l', 'e', '2',	/* entry 2 name */
+		46, 0, 0, 0,			/* entry 2 stype */
+		47, 0, 0, 0,			/* entry 2 ttype */
+		48, 0, 0, 0,			/* entry 2 tclass */
+		49, 0, 0, 0,			/* entry 2 otype */
+
+		5, 0, 0, 0,			/* entry 3 name len */
+		'f', 'i', 'l', 'e', '3',	/* entry 3 name */
+		46, 0, 0, 0,			/* entry 3 stype */
+		47, 0, 0, 0,			/* entry 3 ttype */
+		48, 0, 0, 0,			/* entry 3 tclass */
+		53, 0, 0, 0,			/* entry 3 otype */
+	};
+	char data[sizeof(expected_data)] = {0};
+	struct policydb p = {
+		.te_avtab = {0},
+		.policyvers = POLICYDB_VERSION_FILENAME_TRANS,
+	};
+	struct policy_file fp = {
+		.data = data,
+		.len = sizeof(data),
+	};
+	u32 otypes[] = {45, 49, 53};
+	struct hashtab_node nhnodes[] = {
+		{"file1", &otypes[0], NULL},
+		{"file2", &otypes[1], &nhnodes[2]},
+		{"file3", &otypes[2], NULL},
+	};
+	struct hashtab_node *nhtable[] = {&nhnodes[0], &nhnodes[1]};
+	struct avtab_trans transs[] = {
+		{0, {{&nhtable[0], 1, 1}, 0}},
+		{0, {{&nhtable[1], 1, 2}, 0}},
+	};
+	struct avtab_node nodes[] = {
+		{{42, 43, 44, AVTAB_TRANSITION},
+			{.u.trans = &transs[0]}, NULL},
+		{{46, 47, 48, AVTAB_TRANSITION},
+			{.u.trans = &transs[1]}, NULL},
+	};
+	struct avtab_node *htable[] = {&nodes[0], &nodes[1]};
+
+	p.p_types.nprim = 54;
+	p.p_classes.nprim = 49;
+	p.te_avtab.htable = htable;
+	p.te_avtab.nslot = 2;
+	p.te_avtab.nel = 2;
+
+	KUNIT_ASSERT_EQ(test, 0,
+			avtab_filename_trans_write(&p, &p.te_avtab, &fp));
+
+	KUNIT_ASSERT_EQ(test, 0, fp.len);
+	KUNIT_EXPECT_TRUE(test,
+			  !memcmp(expected_data, data, sizeof(expected_data)));
+}
+
+static void filename_trans_write__comp_simple(struct kunit *test)
+{
+	char expected_data[] = {
+		3, 0, 0, 0,	/* count */
+
+		5, 0, 0, 0,			/* entry 1 name len */
+		'f', 'i', 'l', 'e', '1',	/* entry 1 name */
+		43, 0, 0, 0,			/* entry 1 ttype */
+		44, 0, 0, 0,			/* entry 1 tclass */
+		1, 0, 0, 0,			/* entry 1 ndatum */
+		64, 0, 0, 0,			/* entry 1 datum 1 stypes */
+		64, 0, 0, 0,
+		1, 0, 0, 0,
+		0, 0, 0, 0,
+		0, 0, 0, 0, 0, 2, 0, 0,
+		45, 0, 0, 0,			/* entry 1 otype */
+
+		5, 0, 0, 0,			/* entry 2 name len */
+		'f', 'i', 'l', 'e', '2',	/* entry 2 name */
+		47, 0, 0, 0,			/* entry 2 ttype */
+		48, 0, 0, 0,			/* entry 2 tclass */
+		1, 0, 0, 0,			/* entry 2 ndatum */
+		64, 0, 0, 0,			/* entry 2 datum 1 stypes */
+		64, 0, 0, 0,
+		1, 0, 0, 0,
+		0, 0, 0, 0,
+		0, 0, 0, 0, 0, 32, 0, 0,
+		49, 0, 0, 0,			/* entry 2 otype */
+
+		5, 0, 0, 0,			/* entry 3 name len */
+		'f', 'i', 'l', 'e', '3',	/* entry 3 name */
+		47, 0, 0, 0,			/* entry 3 ttype */
+		48, 0, 0, 0,			/* entry 3 tclass */
+		1, 0, 0, 0,			/* entry 2 ndatum */
+		64, 0, 0, 0,			/* entry 2 datum 1 stypes */
+		64, 0, 0, 0,
+		1, 0, 0, 0,
+		0, 0, 0, 0,
+		0, 0, 0, 0, 0, 32, 0, 0,
+		53, 0, 0, 0,			/* entry 3 otype */
+	};
+	char data[sizeof(expected_data)] = {0};
+	struct policydb p = {
+		.te_avtab = {0},
+		.policyvers = POLICYDB_VERSION_COMP_FTRANS,
+	};
+	struct policy_file fp = {
+		.data = data,
+		.len = sizeof(data),
+	};
+	u32 otypes[] = {45, 49, 53};
+	struct hashtab_node nhnodes[] = {
+		{"file1", &otypes[0], NULL},
+		{"file2", &otypes[1], &nhnodes[2]},
+		{"file3", &otypes[2], NULL},
+	};
+	struct hashtab_node *nhtable[] = {&nhnodes[0], &nhnodes[1]};
+	struct avtab_trans transs[] = {
+		{0, {{&nhtable[0], 1, 1}, 0}},
+		{0, {{&nhtable[1], 1, 2}, 0}},
+	};
+	struct avtab_node nodes[] = {
+		{{42, 43, 44, AVTAB_TRANSITION},
+			{.u.trans = &transs[0]}, NULL},
+		{{46, 47, 48, AVTAB_TRANSITION},
+			{.u.trans = &transs[1]}, NULL},
+	};
+	struct avtab_node *htable[] = {&nodes[0], &nodes[1]};
+
+	p.p_types.nprim = 54;
+	p.p_classes.nprim = 49;
+	p.te_avtab.htable = htable;
+	p.te_avtab.nslot = 2;
+	p.te_avtab.nel = 2;
+
+	KUNIT_ASSERT_EQ(test, 0,
+			avtab_filename_trans_write(&p, &p.te_avtab, &fp));
+
+	KUNIT_ASSERT_EQ(test, 0, fp.len);
+	KUNIT_EXPECT_TRUE(test,
+			  !memcmp(expected_data, data, sizeof(expected_data)));
+}
+
+static void read__pre_avtab_ftrans(struct kunit *test)
+{
+	char data[] = {
+		2, 0, 0, 0,	/* nel */
+
+		42, 0,			/* entry 1 source type */
+		43, 0,			/* entry 1 target type */
+		44, 0,			/* entry 1 target class */
+		AVTAB_TRANSITION, 0,	/* entry 1 specified */
+		45, 0, 0, 0,		/* entry 1 otype */
+
+		46, 0,			/* entry 2 source type */
+		47, 0,			/* entry 2 target type */
+		48, 0,			/* entry 2 target class */
+		AVTAB_TRANSITION, 0,	/* entry 2 specified */
+		49, 0, 0, 0,		/* entry 2 otype */
+	};
+	struct policydb p = {
+		.te_avtab = {0},
+		.policyvers = POLICYDB_VERSION_COMP_FTRANS,
+	};
+	struct policy_file fp = {
+		.data = data,
+		.len = sizeof(data),
+	};
+	struct avtab_key key;
+	struct avtab_datum *node;
+
+	p.p_types.nprim = 54;
+	p.p_classes.nprim = 49;
+	KUNIT_ASSERT_EQ(test, 0,
+			avtab_read(&p.te_avtab, &fp, &p));
+	KUNIT_EXPECT_EQ(test, 2, p.te_avtab.nel);
+	KUNIT_EXPECT_EQ(test, 0, fp.len);
+
+	key = (struct avtab_key){42, 43, 44, AVTAB_TRANSITION};
+	node = avtab_search(&p.te_avtab, &key);
+	KUNIT_ASSERT_NOT_NULL(test, node);
+	KUNIT_EXPECT_EQ(test, 45, node->u.trans->otype);
+	KUNIT_EXPECT_EQ(test, 0, node->u.trans->name_trans.table.nel);
+
+	key = (struct avtab_key){46, 47, 48, AVTAB_TRANSITION};
+	node = avtab_search(&p.te_avtab, &key);
+	KUNIT_ASSERT_NOT_NULL(test, node);
+	KUNIT_EXPECT_EQ(test, 49, node->u.trans->otype);
+	KUNIT_EXPECT_EQ(test, 0, node->u.trans->name_trans.table.nel);
+
+	avtab_destroy(&p.te_avtab);
+}
+
+static void read__simple(struct kunit *test)
+{
+	char data[] = {
+		2, 0, 0, 0,	/* nel */
+
+		42, 0,			/* entry 1 source type */
+		43, 0,			/* entry 1 target type */
+		44, 0,			/* entry 1 target class */
+		AVTAB_TRANSITION, 0,	/* entry 1 specified */
+		41, 0, 0, 0,		/* entry 1 otype */
+		1, 0, 0, 0,		/* entry 1 nfnts */
+		45, 0, 0, 0,			/* entry 1 fnt 1 otype */
+		5, 0, 0, 0,			/* entry 1 fnt 1 name len */
+		'f', 'i', 'l', 'e', '1',	/* entry 1 fnt 1 name */
+
+		46, 0,			/* entry 2 source type */
+		47, 0,			/* entry 2 target type */
+		48, 0,			/* entry 2 target class */
+		AVTAB_TRANSITION, 0,	/* entry 2 specified */
+		40, 0, 0, 0,		/* entry 2 otype */
+		2, 0, 0, 0,		/* entry 2 nfnts */
+		49, 0, 0, 0,			/* entry 2 fnt 1 otype */
+		5, 0, 0, 0,			/* entry 2 fnt 1 name len */
+		'f', 'i', 'l', 'e', '2',	/* entry 2 fnt 1 name */
+		50, 0, 0, 0,			/* entry 2 fnt 2 otype */
+		5, 0, 0, 0,			/* entry 2 fnt 2 name len */
+		'f', 'i', 'l', 'e', '3',	/* entry 2 fnt 2 name */
+	};
+	struct policydb p = {
+		.te_avtab = {0},
+		.policyvers = POLICYDB_VERSION_AVTAB_FTRANS,
+	};
+	struct policy_file fp = {
+		.data = data,
+		.len = sizeof(data),
+	};
+	struct avtab_key key;
+	struct avtab_datum *node;
+	u32 *otype;
+
+	p.p_types.nprim = 54;
+	p.p_classes.nprim = 49;
+	KUNIT_ASSERT_EQ(test, 0,
+			avtab_read(&p.te_avtab, &fp, &p));
+	KUNIT_EXPECT_EQ(test, 2, p.te_avtab.nel);
+	KUNIT_EXPECT_EQ(test, 0, fp.len);
+
+	key = (struct avtab_key){42, 43, 44, AVTAB_TRANSITION};
+	node = avtab_search(&p.te_avtab, &key);
+	KUNIT_ASSERT_NOT_NULL(test, node);
+	KUNIT_EXPECT_EQ(test, 41, node->u.trans->otype);
+	KUNIT_EXPECT_EQ(test, 1, node->u.trans->name_trans.table.nel);
+
+	otype = symtab_search(&node->u.trans->name_trans, "file1");
+	KUNIT_ASSERT_NOT_NULL(test, otype);
+	KUNIT_EXPECT_EQ(test, 45, *otype);
+
+	key = (struct avtab_key){46, 47, 48, AVTAB_TRANSITION};
+	node = avtab_search(&p.te_avtab, &key);
+	KUNIT_ASSERT_NOT_NULL(test, node);
+	KUNIT_EXPECT_EQ(test, 40, node->u.trans->otype);
+	KUNIT_EXPECT_EQ(test, 2, node->u.trans->name_trans.table.nel);
+
+	otype = symtab_search(&node->u.trans->name_trans, "file2");
+	KUNIT_ASSERT_NOT_NULL(test, otype);
+	KUNIT_EXPECT_EQ(test, 49, *otype);
+
+	otype = symtab_search(&node->u.trans->name_trans, "file3");
+	KUNIT_ASSERT_NOT_NULL(test, otype);
+	KUNIT_EXPECT_EQ(test, 50, *otype);
+
+	avtab_destroy(&p.te_avtab);
+}
+
+static void write__pre_avtab_ftrans(struct kunit *test)
+{
+	char expected_data[] = {
+		1, 0, 0, 0,	/* nel */
+
+		46, 0,			/* entry 2 source type */
+		47, 0,			/* entry 2 target type */
+		48, 0,			/* entry 2 target class */
+		AVTAB_TRANSITION, 0,	/* entry 2 specified */
+		40, 0, 0, 0,		/* entry 2 otype */
+	};
+	char data[sizeof(expected_data)] = {0};
+	struct policydb p = {
+		.te_avtab = {0},
+		.policyvers = POLICYDB_VERSION_COMP_FTRANS,
+	};
+	struct policy_file fp = {
+		.data = data,
+		.len = sizeof(data),
+	};
+	u32 otypes[] = {45, 49, 53};
+	struct hashtab_node nhnodes[] = {
+		{"file1", &otypes[0], NULL},
+		{"file2", &otypes[1], &nhnodes[2]},
+		{"file3", &otypes[2], NULL},
+	};
+	struct hashtab_node *nhtable[] = {&nhnodes[0], &nhnodes[1]};
+	struct avtab_trans transs[] = {
+		{0, {{&nhtable[0], 1, 1}, 0}},
+		{40, {{&nhtable[1], 1, 2}, 0}},
+	};
+	struct avtab_node nodes[] = {
+		{{42, 43, 44, AVTAB_TRANSITION},
+			{.u.trans = &transs[0]}, NULL},
+		{{46, 47, 48, AVTAB_TRANSITION},
+			{.u.trans = &transs[1]}, NULL},
+	};
+	struct avtab_node *htable[] = {&nodes[0], &nodes[1]};
+
+	p.p_types.nprim = 54;
+	p.p_classes.nprim = 49;
+	p.te_avtab.htable = htable;
+	p.te_avtab.nslot = 2;
+	p.te_avtab.nel = 2;
+
+	KUNIT_ASSERT_EQ(test, 0, avtab_write(&p, &p.te_avtab, &fp));
+
+	KUNIT_ASSERT_EQ(test, 0, fp.len);
+	KUNIT_EXPECT_TRUE(test,
+			  !memcmp(expected_data, data, sizeof(expected_data)));
+}
+
+static void write__simple(struct kunit *test)
+{
+	char expected_data[] = {
+		2, 0, 0, 0,	/* nel */
+
+		42, 0,			/* entry 1 source type */
+		43, 0,			/* entry 1 target type */
+		44, 0,			/* entry 1 target class */
+		AVTAB_TRANSITION, 0,	/* entry 1 specified */
+		41, 0, 0, 0,		/* entry 1 otype */
+		1, 0, 0, 0,		/* entry 1 nfnts */
+		45, 0, 0, 0,			/* entry 1 fnt 1 otype */
+		5, 0, 0, 0,			/* entry 1 fnt 1 name len */
+		'f', 'i', 'l', 'e', '1',	/* entry 1 fnt 1 name */
+
+		46, 0,			/* entry 2 source type */
+		47, 0,			/* entry 2 target type */
+		48, 0,			/* entry 2 target class */
+		AVTAB_TRANSITION, 0,	/* entry 2 specified */
+		40, 0, 0, 0,		/* entry 2 otype */
+		2, 0, 0, 0,		/* entry 2 nfnts */
+		49, 0, 0, 0,			/* entry 1 fnt 1 otype */
+		5, 0, 0, 0,			/* entry 1 fnt 1 name len */
+		'f', 'i', 'l', 'e', '2',	/* entry 1 fnt 1 name */
+		50, 0, 0, 0,			/* entry 1 fnt 1 otype */
+		5, 0, 0, 0,			/* entry 1 fnt 1 name len */
+		'f', 'i', 'l', 'e', '3',	/* entry 1 fnt 1 name */
+	};
+	char data[sizeof(expected_data)] = {0};
+	struct policydb p = {
+		.te_avtab = {0},
+		.policyvers = POLICYDB_VERSION_AVTAB_FTRANS,
+	};
+	struct policy_file fp = {
+		.data = data,
+		.len = sizeof(data),
+	};
+	u32 otypes[] = {45, 49, 50};
+	struct hashtab_node nhnodes[] = {
+		{"file1", &otypes[0], NULL},
+		{"file2", &otypes[1], &nhnodes[2]},
+		{"file3", &otypes[2], NULL},
+	};
+	struct hashtab_node *nhtable[] = {&nhnodes[0], &nhnodes[1]};
+	struct avtab_trans transs[] = {
+		{41, {{&nhtable[0], 1, 1}, 0}},
+		{40, {{&nhtable[1], 1, 2}, 0}},
+	};
+	struct avtab_node nodes[] = {
+		{{42, 43, 44, AVTAB_TRANSITION},
+			{.u.trans = &transs[0]}, NULL},
+		{{46, 47, 48, AVTAB_TRANSITION},
+			{.u.trans = &transs[1]}, NULL},
+	};
+	struct avtab_node *htable[] = {&nodes[0], &nodes[1]};
+
+	p.p_types.nprim = 54;
+	p.p_classes.nprim = 49;
+	p.te_avtab.htable = htable;
+	p.te_avtab.nslot = 2;
+	p.te_avtab.nel = 2;
+
+	KUNIT_ASSERT_EQ(test, 0, avtab_write(&p, &p.te_avtab, &fp));
+
+	KUNIT_ASSERT_EQ(test, 0, fp.len);
+	KUNIT_EXPECT_TRUE(test,
+			  !memcmp(expected_data, data, sizeof(expected_data)));
+}
+
+static struct kunit_case avtab_test_cases[] = {
+	KUNIT_CASE(filename_trans_read__pre_filename_trans),
+	KUNIT_CASE(filename_trans_read__empty),
+	KUNIT_CASE(filename_trans_read__comp_empty),
+	KUNIT_CASE(filename_trans_read__simple),
+	KUNIT_CASE(filename_trans_read__comp_simple),
+
+	KUNIT_CASE(filename_trans_write__pre_filename_trans),
+	KUNIT_CASE(filename_trans_write__empty),
+	KUNIT_CASE(filename_trans_write__comp_empty),
+	KUNIT_CASE(filename_trans_write__simple),
+	KUNIT_CASE(filename_trans_write__comp_simple),
+
+	KUNIT_CASE(read__pre_avtab_ftrans),
+	KUNIT_CASE(read__simple),
+
+	KUNIT_CASE(write__pre_avtab_ftrans),
+	KUNIT_CASE(write__simple),
+	{0},
+};
+
+static struct kunit_suite avtab_test_suite = {
+	.name = "security-selinux-avtab",
+	.test_cases = avtab_test_cases,
+};
+
+kunit_test_suite(avtab_test_suite);
+
+MODULE_LICENSE("GPL");
diff --git a/security/selinux/ss/symtab.c b/security/selinux/ss/symtab.c
index c42a6648a07d..c53863d5ed40 100644
--- a/security/selinux/ss/symtab.c
+++ b/security/selinux/ss/symtab.c
@@ -52,3 +52,6 @@ void *symtab_search(struct symtab *s, const char *name)
 {
 	return hashtab_search(&s->table, name, symtab_key_params);
 }
+
+/* Export for avtab KUnit tests */
+EXPORT_SYMBOL_GPL(symtab_search);
-- 
2.40.0


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

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2023-05-31 11:29 [PATCH 0/5] selinux: add prefix/suffix matching to filename type transitions Juraj Marcin
2023-05-31 11:29 ` [PATCH 1/5] selinux: move transition to separate structure in avtab_datum Juraj Marcin
2023-05-31 11:29 ` [PATCH 2/5] selinux: move filename transitions to avtab Juraj Marcin
2023-06-01 14:29   ` Christian Göttsche
2023-06-02 13:13   ` Christian Göttsche
2023-06-07  8:04     ` Ondrej Mosnacek
2023-06-08 15:59     ` Juraj Marcin
2023-05-31 11:29 ` [PATCH 3/5] selinux: implement new binary format for filename transitions in avtab Juraj Marcin
2023-05-31 11:29 ` Juraj Marcin [this message]
2023-05-31 11:29 ` [PATCH 5/5] selinux: add prefix/suffix matching support to filename type transitions Juraj Marcin
2023-07-17 18:33   ` Stephen Smalley
2023-07-17 18:51     ` Stephen Smalley
2023-05-31 22:24 ` [PATCH 0/5] selinux: add prefix/suffix matching " Paul Moore
2023-06-01 17:03   ` Juraj Marcin
2023-06-16  2:04     ` Paul Moore
2023-06-18  9:40       ` Juraj Marcin
2023-06-19 21:53         ` Paul Moore
2023-06-20  7:51           ` Juraj Marcin
2023-07-17 18:44             ` Stephen Smalley
2023-07-27 16:42               ` Juraj Marcin
2023-07-28 12:48                 ` Stephen Smalley
2023-07-28 17:52                   ` James Carter
2023-08-01  8:49                     ` 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=20230531112927.1957093-5-juraj@jurajmarcin.com \
    --to=juraj@jurajmarcin.com \
    --cc=omosnace@redhat.com \
    --cc=paul@paul-moore.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.