mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Christian Brauner <brauner@kernel.org>
To: linux-fsdevel@vger.kernel.org
Cc: "Mickaël Salaün" <mic@digikod.net>,
	"Serge Hallyn" <serge@hallyn.com>,
	linux-kernel@vger.kernel.org, linux-mm@kvack.org,
	"Jann Horn" <jannh@google.com>,
	"Christian Brauner (Amutable)" <brauner@kernel.org>
Subject: [PATCH 2/2] selftests/exec: check that user namespaces keep the exec securebits
Date: Mon, 26 Oct 2026 21:53:30 +0100	[thread overview]
Message-ID: <20261026-work-securebits-userns-v1-2-b35473fa1a34@kernel.org> (raw)
In-Reply-To: <20261026-work-securebits-userns-v1-0-b35473fa1a34@kernel.org>

Check that the exec securebits survive creating a user namespace with
unshare(CLONE_NEWUSER) and joining one with setns():

- both bits with their locks, which can't be changed in there
- both bits without their locks, which can still be cleared in there
- only the locks, which keep the bits from being set in there

The other securebits are reset as before.

Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
 tools/testing/selftests/exec/check-exec.c | 83 +++++++++++++++++++++++++++++++
 1 file changed, 83 insertions(+)

diff --git a/tools/testing/selftests/exec/check-exec.c b/tools/testing/selftests/exec/check-exec.c
index f2397e75aa7c..5753c657808e 100644
--- a/tools/testing/selftests/exec/check-exec.c
+++ b/tools/testing/selftests/exec/check-exec.c
@@ -10,11 +10,13 @@
  * Author: Mickaël Salaün <mic@digikod.net>
  */
 
+#define _GNU_SOURCE
 #include <asm-generic/unistd.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <linux/prctl.h>
 #include <linux/securebits.h>
+#include <sched.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/capability.h>
@@ -24,6 +26,7 @@
 #include <sys/stat.h>
 #include <sys/syscall.h>
 #include <sys/sysmacros.h>
+#include <sys/wait.h>
 #include <unistd.h>
 
 /* Defines AT_EXECVE_CHECK without type conflicts. */
@@ -460,4 +463,84 @@ TEST_F(secbits, restrict_locked_unset)
 	CHILD(EXPECT_EQ(EPERM, test_secbits_set(0)));
 }
 
+static const unsigned int exec_bits = SECBIT_EXEC_RESTRICT_FILE |
+				       SECBIT_EXEC_DENY_INTERACTIVE;
+static const unsigned int exec_locks = SECBIT_EXEC_RESTRICT_FILE_LOCKED |
+					SECBIT_EXEC_DENY_INTERACTIVE_LOCKED;
+
+/*
+ * Checks that the exec securebits in @exec survive creating and joining a user
+ * namespace, and that in there they can be changed exactly when they are not
+ * locked.
+ */
+static void test_userns(struct __test_metadata *const _metadata,
+			const unsigned int exec)
+{
+	const int error = (exec & exec_locks) ? EPERM : 0;
+	int ready[2], done[2], userns_fd, status;
+	char path[64], c = 0;
+	pid_t pid;
+
+	/* A user namespace owned by us to join later. */
+	ASSERT_EQ(0, pipe(ready));
+	ASSERT_EQ(0, pipe(done));
+	pid = fork();
+	ASSERT_LE(0, pid);
+	if (pid == 0) {
+		close(ready[0]);
+		close(done[1]);
+		if (unshare(CLONE_NEWUSER))
+			_exit(1);
+		if (write(ready[1], &c, 1) != 1)
+			_exit(1);
+		if (read(done[0], &c, 1) < 0)
+			_exit(1);
+		_exit(0);
+	}
+	close(ready[1]);
+	close(done[0]);
+	if (read(ready[0], &c, 1) != 1) {
+		waitpid(pid, &status, 0);
+		SKIP(return, "Cannot create a user namespace");
+	}
+
+	snprintf(path, sizeof(path), "/proc/%d/ns/user", pid);
+	userns_fd = open(path, O_RDONLY | O_CLOEXEC);
+	ASSERT_LE(0, userns_fd);
+
+	EXPECT_EQ(0, test_secbits_set(prctl(PR_GET_SECUREBITS) | exec));
+
+	/* Creating a user namespace keeps them... */
+	CHILD(EXPECT_EQ(0, unshare(CLONE_NEWUSER));
+	      EXPECT_EQ(exec, prctl(PR_GET_SECUREBITS));
+	      EXPECT_EQ(error, test_secbits_set(exec ^ exec_bits));
+	      EXPECT_EQ(error, test_secbits_set(0)));
+
+	/* ...and so does joining one. */
+	CHILD(EXPECT_EQ(0, setns(userns_fd, CLONE_NEWUSER));
+	      EXPECT_EQ(exec, prctl(PR_GET_SECUREBITS));
+	      EXPECT_EQ(error, test_secbits_set(exec ^ exec_bits));
+	      EXPECT_EQ(error, test_secbits_set(0)));
+
+	close(userns_fd);
+	close(done[1]);
+	EXPECT_EQ(pid, waitpid(pid, &status, 0));
+	close(ready[0]);
+}
+
+TEST_F(secbits, userns_locked)
+{
+	test_userns(_metadata, exec_bits | exec_locks);
+}
+
+TEST_F(secbits, userns_unlocked)
+{
+	test_userns(_metadata, exec_bits);
+}
+
+TEST_F(secbits, userns_lock_only)
+{
+	test_userns(_metadata, exec_locks);
+}
+
 TEST_HARNESS_MAIN

-- 
2.53.0


      parent reply	other threads:[~2026-10-26 20:54 UTC|newest]

Thread overview: 3+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-26 20:53 [PATCH 0/2] userns: " Christian Brauner
2026-10-26 20:53 ` [PATCH 1/2] userns: don't drop " Christian Brauner
2026-10-26 20:53 ` Christian Brauner [this message]

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=20261026-work-securebits-userns-v1-2-b35473fa1a34@kernel.org \
    --to=brauner@kernel.org \
    --cc=jannh@google.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=mic@digikod.net \
    --cc=serge@hallyn.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

all inboxes | Powered by JetHome®