All of lore.kernel.org
 help / color / mirror / Atom feed
From: Wake Liu via ltp <ltp@lists.linux.it>
To: ltp@lists.linux.it
Cc: Wake Liu <wakel@google.com>
Subject: [LTP] [PATCH v2] swapon04: Report TCONF when SELinux denies loop device I/O
Date: Mon, 19 Oct 2026 13:26:21 +0000	[thread overview]
Message-ID: <20261019132621.3943362-1-wakel@google.com> (raw)
In-Reply-To: <20261014093618.1475191-1-wakel@google.com>

Kernels without commit f2fed441c69b ("loop: stop using
vfs_iter_{read,write} for buffered I/O") access the loop backing file
through vfs_iter_{read,write}(), which run the LSM file permission
checks with the credentials of the loop worker kernel thread.

swapon04 backs the loop device with a file on the freshly formatted
test filesystem. That file has no SELinux label, and strict policies
such as Android's do not allow the kernel domain to access unlabeled
files. Every I/O on the loop device then fails with EIO and the test
breaks on the first mkswap call:

  tst_cmd.c:114: TBROK: 'mkswap' exited with a non-zero code 1

  avc: denied { read } for comm="kworker/u8:0" dev="loop52" ino=12
    scontext=u:r:kernel:s0 tcontext=u:object_r:unlabeled:s0
    tclass=file permissive=0

This is a policy restriction rather than a swap bug, and it does not
depend on how LTP is built: running the system's losetup and mkswap
on such a file fails the same way. The test passes on the same 6.1
kernel once SELinux is switched to permissive mode, and on a 6.18
kernel in enforcing mode.

The commit was merged in v6.15, so v6.15 and newer are not affected.
On older kernels the version alone does not tell whether the test can
run: the commit has been backported to stable kernels such as v6.12.25
and v6.14.4, and kernels without it still pass the test unless the
policy gets in the way.

So on kernels older than v6.15 with SELinux in enforcing mode, read
the first sector of the loop device in setup() and report TCONF if it
fails with EIO. On the 6.1 kernel above, ext2, ext3 and ext4 are now
skipped, while tmpfs, whose files the kernel domain is allowed to
access, still passes.

Signed-off-by: Wake Liu <wakel@google.com>
---
Changes in v2:
- Return early on v6.15 and newer and when SELinux is not enforcing,
  so the loop device is only probed where the denial can happen
  (Cyril).
- Mention v6.15 and the stable backports in the comment and the
  commit message.

v1: https://lore.kernel.org/ltp/20261014093618.1475191-1-wakel@google.com/

 testcases/kernel/syscalls/swapon/swapon04.c | 35 +++++++++++++++++++++
 1 file changed, 35 insertions(+)

diff --git a/testcases/kernel/syscalls/swapon/swapon04.c b/testcases/kernel/syscalls/swapon/swapon04.c
index de95849e3..5f5206d87 100644
--- a/testcases/kernel/syscalls/swapon/swapon04.c
+++ b/testcases/kernel/syscalls/swapon/swapon04.c
@@ -84,6 +84,39 @@ static struct tcase {
 	},
 };
 
+/*
+ * Kernels without commit f2fed441c69b ("loop: stop using
+ * vfs_iter_{read,write} for buffered I/O"), merged in v6.15, access the
+ * backing file through vfs_iter_{read,write}(), which run LSM permission
+ * checks with the credentials of the loop worker kernel thread. Strict
+ * SELinux policies, such as Android's, do not allow the kernel to access
+ * the unlabeled files on the freshly formatted test filesystem, so any I/O
+ * on the loop device fails with EIO.
+ *
+ * The commit has been backported to some stable kernels (e.g. v6.12.25),
+ * so on older kernels the loop device has to be probed.
+ */
+static void check_loop_io(void)
+{
+	char buf[512];
+	int fd;
+
+	if (tst_kvercmp(6, 15, 0) >= 0 || !tst_selinux_enforcing())
+		return;
+
+	fd = SAFE_OPEN(loop_dev, O_RDONLY);
+	TEST(read(fd, buf, sizeof(buf)));
+	SAFE_CLOSE(fd);
+
+	if (TST_RET == (long)sizeof(buf))
+		return;
+
+	if (TST_RET == -1 && TST_ERR == EIO)
+		tst_brk(TCONF | TTERRNO, "I/O on %s is likely denied by SELinux", loop_dev);
+
+	tst_brk(TBROK | TTERRNO, "read(%s) returned %ld", loop_dev, TST_RET);
+}
+
 static void setup(void)
 {
 	char discard_path[PATH_MAX];
@@ -114,6 +147,8 @@ static void setup(void)
 		tst_brk(TBROK, "Failed to attach %s to %s", loop_dev, BACKING_FILE);
 	loop_attached = 1;
 
+	check_loop_io();
+
 	snprintf(discard_path, sizeof(discard_path),
 		 "/sys/block/loop%d/queue/discard_max_bytes", loop_dev_id);
 	if (FILE_SCANF(discard_path, "%lu", &discard_max_bytes) != 0 || discard_max_bytes == 0) {
-- 
2.56.0.176.g3575e65682-goog


-- 
Mailing list info: https://lists.linux.it/listinfo/ltp

  parent reply	other threads:[~2026-10-19 13:26 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-14  9:36 [LTP] [PATCH] swapon04: Report TCONF when SELinux denies loop device I/O Wake Liu via ltp
2026-10-14 11:20 ` [LTP] " linuxtestproject.agent
2026-10-19 11:20 ` [LTP] [PATCH] " Cyril Hrubis
2026-10-19 13:26 ` Wake Liu via ltp [this message]
2026-10-19 19:06   ` [LTP] " linuxtestproject.agent
2026-10-19 20:02   ` [LTP] [PATCH v2] " Avinesh Kumar via ltp

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=20261019132621.3943362-1-wakel@google.com \
    --to=ltp@lists.linux.it \
    --cc=wakel@google.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.