From: "Thiébaud Weksteen" <tweek@google.com>
To: selinux@vger.kernel.org,
Stephen Smalley <stephen.smalley.work@gmail.com>
Cc: "James Carter" <jwcart2@gmail.com>,
"Christian Göttsche" <cgzones@googlemail.com>,
"Ondrej Mosnacek" <omosnace@redhat.com>,
"Thiébaud Weksteen" <tweek@google.com>
Subject: [PATCH testsuite v2 2/2] tests/file_contexts: add tests for multiple SELABEL_OPT_PATH
Date: Thu, 23 Jul 2026 13:13:16 +1000 [thread overview]
Message-ID: <20260723031316.2720083-2-tweek@google.com> (raw)
In-Reply-To: <20260723031316.2720083-1-tweek@google.com>
Add unit tests in test_multiple.c to exercise opening the file contexts
backend with multiple SELABEL_OPT_PATH options under various validation
and path configuration scenarios.
The following test functions were added:
- Verifies opening multiple file contexts without validation.
- Verifies validation failure when contexts contain undefined types.
- Verifies extra files (.subs, .local, .homedirs) are processed only for
the primary path.
- Verifies multiple files with the same definition, no error is raised.
- Verifies context lookups when providing three distinct
SELABEL_OPT_PATH options.
Signed-off-by: Thiébaud Weksteen <tweek@google.com>
---
tests/file_contexts/Makefile | 2 +-
tests/file_contexts/test | 5 +-
tests/file_contexts/test_multiple.c | 233 ++++++++++++++++++++++++++++
3 files changed, 238 insertions(+), 2 deletions(-)
create mode 100644 tests/file_contexts/test_multiple.c
diff --git a/tests/file_contexts/Makefile b/tests/file_contexts/Makefile
index 592a65f..083ef25 100644
--- a/tests/file_contexts/Makefile
+++ b/tests/file_contexts/Makefile
@@ -1,4 +1,4 @@
-TARGETS=test_open test_lookup test_open_base test_validate
+TARGETS=test_open test_lookup test_open_base test_validate test_multiple
CFLAGS += -O2 -Werror -Wall
LDLIBS += -lselinux
diff --git a/tests/file_contexts/test b/tests/file_contexts/test
index 1534925..cd7849b 100755
--- a/tests/file_contexts/test
+++ b/tests/file_contexts/test
@@ -5,7 +5,7 @@
use Test;
-BEGIN { plan tests => 4; }
+BEGIN { plan tests => 5; }
$basedir = $0;
$basedir =~ s|(.*)/[^/]*|$1|;
@@ -22,4 +22,7 @@ ok( $result, 0 );
$result = system "$basedir/test_validate $basedir 2>&1";
ok( $result, 0 );
+$result = system "$basedir/test_multiple $basedir 2>&1";
+ok( $result, 0 );
+
exit;
diff --git a/tests/file_contexts/test_multiple.c b/tests/file_contexts/test_multiple.c
new file mode 100644
index 0000000..65fb726
--- /dev/null
+++ b/tests/file_contexts/test_multiple.c
@@ -0,0 +1,233 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <selinux/label.h>
+#include <selinux/selinux.h>
+
+#include "internal.h"
+
+void test_multiple_no_validation(const char *basedir)
+{
+ struct selabel_handle *hnd;
+
+ /* f1.fc and f2.fc file */
+ char *f1_path, *f2_path;
+ asprintf(&f1_path, "%s/f1.fc", basedir);
+ asprintf(&f2_path, "%s/f2.fc", basedir);
+ struct selinux_opt opts[] = {
+ { .type = SELABEL_OPT_PATH, .value = f1_path },
+ { .type = SELABEL_OPT_PATH, .value = f2_path }
+ };
+
+ hnd = selabel_open(SELABEL_CTX_FILE, opts, ARRAY_SIZE(opts));
+ free(f1_path);
+ free(f2_path);
+
+ if (!hnd) {
+ log_errno("Unable to open file backend");
+ exit(2);
+ }
+
+ struct test_t tests[] = {
+ { .path = "/", .context = "system_u:object_r:rootfs:s0" },
+ {
+ .path = "/base",
+ .context = "system_u:object_r:test_base_t:s0"
+ },
+ };
+ assertContextsMatch(hnd, __func__, tests, ARRAY_SIZE(tests));
+
+ selabel_close(hnd);
+}
+
+void test_multiple_with_validation(const char *basedir)
+{
+ struct selabel_handle *hnd;
+
+ /* f1.fc and f2.fc file - f1 has undefined type rootfs in test policy */
+ char *f1_path, *f2_path;
+ asprintf(&f1_path, "%s/f1.fc", basedir);
+ asprintf(&f2_path, "%s/f2.fc", basedir);
+ struct selinux_opt opts[] = {
+ { .type = SELABEL_OPT_PATH, .value = f1_path },
+ { .type = SELABEL_OPT_PATH, .value = f2_path },
+ { .type = SELABEL_OPT_VALIDATE, .value = "1" }
+ };
+
+ hnd = selabel_open(SELABEL_CTX_FILE, opts, ARRAY_SIZE(opts));
+ free(f1_path);
+ free(f2_path);
+
+ if (hnd) {
+ log_err("Validation of f1 and f2 should have failed");
+ selabel_close(hnd);
+ exit(2);
+ }
+}
+
+void test_multiple_with_extras(const char *basedir)
+{
+ struct selabel_handle *hnd;
+ char *f2_path, *f3_path;
+ asprintf(&f2_path, "%s/f2.fc", basedir);
+ asprintf(&f3_path, "%s/f3.fc", basedir);
+
+ /* 1. f3.fc is the first path: extras (.subs, .local, .homedirs) of f3 ARE processed */
+ struct selinux_opt opts_f3_first[] = {
+ { .type = SELABEL_OPT_PATH, .value = f3_path },
+ { .type = SELABEL_OPT_PATH, .value = f2_path }
+ };
+ hnd = selabel_open(SELABEL_CTX_FILE, opts_f3_first,
+ ARRAY_SIZE(opts_f3_first));
+ if (!hnd) {
+ log_errno("Unable to open file backend");
+ exit(2);
+ }
+
+ struct test_t tests_f3_first[] = {
+ { .path = "/", .context = "system_u:object_r:rootfs:s0" },
+ {
+ .path = "/sub",
+ .context = "system_u:object_r:test_subbed:s0"
+ },
+ {
+ .path = "/local",
+ .context = "system_u:object_r:test_local:s0"
+ },
+ {
+ .path = "/homedirs",
+ .context = "system_u:object_r:test_homedirs:s0"
+ },
+ {
+ .path = "/base",
+ .context = "system_u:object_r:test_base_t:s0"
+ },
+ };
+ assertContextsMatch(hnd, __func__, tests_f3_first,
+ ARRAY_SIZE(tests_f3_first));
+ selabel_close(hnd);
+
+ /* 2. f2.fc is the first path, f3.fc is second: extras from f3 are NOT processed */
+ struct selinux_opt opts_f2_first[] = {
+ { .type = SELABEL_OPT_PATH, .value = f2_path },
+ { .type = SELABEL_OPT_PATH, .value = f3_path }
+ };
+ hnd = selabel_open(SELABEL_CTX_FILE, opts_f2_first,
+ ARRAY_SIZE(opts_f2_first));
+ if (!hnd) {
+ log_errno("Unable to open file backend");
+ exit(2);
+ }
+
+ struct test_t tests_f2_first[] = {
+ {
+ .path = "/base",
+ .context = "system_u:object_r:test_base_t:s0"
+ },
+ { .path = "/", .context = "system_u:object_r:rootfs:s0" },
+ {
+ .path = "/subbed",
+ .context = "system_u:object_r:test_subbed:s0"
+ },
+ /* /sub, /local, /homedirs should NOT match the f3 extra contexts */
+ { .path = "/sub", .context = NULL },
+ { .path = "/local", .context = NULL },
+ { .path = "/homedirs", .context = NULL },
+ };
+ assertContextsMatch(hnd, __func__, tests_f2_first,
+ ARRAY_SIZE(tests_f2_first));
+ selabel_close(hnd);
+
+ free(f2_path);
+ free(f3_path);
+}
+
+void test_multiple_three_paths(const char *basedir)
+{
+ struct selabel_handle *hnd;
+ char *f1_path, *f2_path, *f3_path;
+ asprintf(&f1_path, "%s/f1.fc", basedir);
+ asprintf(&f2_path, "%s/f2.fc", basedir);
+ asprintf(&f3_path, "%s/f3.fc", basedir);
+
+ struct selinux_opt opts[] = {
+ { .type = SELABEL_OPT_PATH, .value = f1_path },
+ { .type = SELABEL_OPT_PATH, .value = f2_path },
+ { .type = SELABEL_OPT_PATH, .value = f3_path }
+ };
+
+ hnd = selabel_open(SELABEL_CTX_FILE, opts, ARRAY_SIZE(opts));
+ free(f1_path);
+ free(f2_path);
+ free(f3_path);
+
+ if (!hnd) {
+ log_errno("Unable to open file backend");
+ exit(2);
+ }
+
+ struct test_t tests[] = {
+ { .path = "/", .context = "system_u:object_r:rootfs:s0" },
+ {
+ .path = "/base",
+ .context = "system_u:object_r:test_base_t:s0"
+ },
+ {
+ .path = "/subbed",
+ .context = "system_u:object_r:test_subbed:s0"
+ },
+ };
+ assertContextsMatch(hnd, __func__, tests, ARRAY_SIZE(tests));
+ selabel_close(hnd);
+}
+
+void test_multiple_duplicate_validation(const char *basedir)
+{
+ struct selabel_handle *hnd;
+
+ /* Two copies of f2.fc to provide duplicate specifications */
+ char *f2_path;
+ asprintf(&f2_path, "%s/f2.fc", basedir);
+ struct selinux_opt opts[] = {
+ { .type = SELABEL_OPT_PATH, .value = f2_path },
+ { .type = SELABEL_OPT_PATH, .value = f2_path },
+ { .type = SELABEL_OPT_VALIDATE, .value = "1" }
+ };
+
+ hnd = selabel_open(SELABEL_CTX_FILE, opts, ARRAY_SIZE(opts));
+ free(f2_path);
+
+ if (!hnd) {
+ log_errno("Unable to open file backend");
+ exit(2);
+ }
+
+ struct test_t tests[] = {
+ {
+ .path = "/base",
+ .context = "system_u:object_r:test_base_t:s0"
+ },
+ };
+ assertContextsMatch(hnd, __func__, tests, ARRAY_SIZE(tests));
+
+ selabel_close(hnd);
+}
+
+int main(int argc, char **argv)
+{
+ if (argc != 2) {
+ log_err("basedir not provided");
+ exit(1);
+ }
+
+ test_multiple_no_validation(argv[1]);
+ test_multiple_with_validation(argv[1]);
+ test_multiple_duplicate_validation(argv[1]);
+ test_multiple_with_extras(argv[1]);
+ test_multiple_three_paths(argv[1]);
+
+ return 0;
+}
--
2.55.0.229.g6434b31f56-goog
next prev parent reply other threads:[~2026-07-23 3:13 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-07-23 3:13 [PATCH testsuite v2 1/2] tests/file_contexts: refactor existing tests Thiébaud Weksteen
2026-07-23 3:13 ` Thiébaud Weksteen [this message]
2026-07-23 16:24 ` [PATCH testsuite v2 2/2] tests/file_contexts: add tests for multiple SELABEL_OPT_PATH Stephen Smalley
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=20260723031316.2720083-2-tweek@google.com \
--to=tweek@google.com \
--cc=cgzones@googlemail.com \
--cc=jwcart2@gmail.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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox