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 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.