* [PATCH v4 0/5] Implement LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS
@ 2026-08-09 15:45 Justin Suess
2026-08-09 15:45 ` [PATCH v4 1/5] landlock: Check landlock_restrict_self(2)'s flags before privileges Justin Suess
` (5 more replies)
0 siblings, 6 replies; 7+ messages in thread
From: Justin Suess @ 2026-08-09 15:45 UTC (permalink / raw)
To: gnoack3000, mic; +Cc: linux-kernel, linux-security-module, Justin Suess
Howdy
This series adds a new landlock_restrict_self(2) flag:
LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS.
The flag sets the no_new_privs attribute of the calling thread only
once the enforcement of the ruleset succeeded: no_new_privs is set if
and only if the landlock_restrict_self(2) call succeeds.
Semantics:
A single call replaces the usual prctl(PR_SET_NO_NEW_PRIVS) +
landlock_restrict_self(2) pair. Because no_new_privs is set by the
call itself, the no_new_privs/CAP_SYS_ADMIN precondition is fulfilled
by construction, so the flag is usable by unprivileged processes. This
is safe for the same reason the prctl(2) pair is: the executed programs
can either gain privileges or be restricted, never both.
The two states cannot diverge. A failed call (invalid ruleset FD,
E2BIG, ENOMEM, interrupted TSYNC, ...) leaves no_new_privs unchanged,
and a successful call never returns without no_new_privs set: the
attribute is set past the last point of failure, right before
commit_creds(), which cannot fail.
Combined with LANDLOCK_RESTRICT_SELF_TSYNC, no_new_privs is set on all
threads with the same guarantee: each sibling thread sets it in the
commit phase of the TSYNC protocol, after its all-or-nothing barrier,
so either every thread gets both the domain and no_new_privs, or none
does. This also makes it possible to set no_new_privs process-wide in
one call, which prctl(2) cannot do.
The flag requires a ruleset: calls with a ruleset_fd of -1 are
rejected. Such a call would be nothing more than a Landlock-flavored
prctl(PR_SET_NO_NEW_PRIVS), and rejecting it keeps the option of giving
it a meaning later.
Following Mickaël's feedback on v3 [1], a new preparatory patch first
moves the no_new_privs/CAP_SYS_ADMIN check after the flags check, in
the same order as seccomp(2). Unprivileged callers passing unknown
flag bits now consistently get EINVAL instead of EPERM, whether or not
the new flag is involved; the selftests pin this error ordering.
The Landlock ABI version is bumped to 11.
Test coverage:
base_test checks that a successful call sets no_new_privs without a
prior prctl(2) nor CAP_SYS_ADMIN, that a failed call (invalid ruleset
FD or layer maximum) leaves it unchanged, that the flag requires a
ruleset FD, and the flags-before-privileges error ordering.
tsync_test checks, through variants of a common multi_threaded
fixture, that TSYNC sets no_new_privs on sibling threads along with
the domain, and that a TSYNC call failing on the layer maximum leaves
it unset on every thread.
Changes since v3:
- New preparatory patch: check the landlock_restrict_self(2) flags
before the no_new_privs/CAP_SYS_ADMIN requirement, like seccomp(2),
per Mickaël's feedback. The EINVAL/EPERM visible change now stems
from this patch instead of the new flag.
- Folded the minimal selftest changes (ABI version, last-flag, and
checks-ordering updates) into the main patch to keep the series
bisectable, following the commit tweaked by Mickaël in his next
branch.
- Dropped the set_no_new_privs local variable; the flag is now checked
directly at both use sites.
- Turned the multi_threaded_{success,no_new_privs,
no_new_privs_max_layers} tests into variants of a common
multi_threaded fixture.
- Reworded the documentation: removed the ambiguous "it"s in the
tutorial paragraph on CAP_SYS_ADMIN, and used the suggested
"call (or CAP_SYS_ADMIN use)" wording in both the compatibility
section and the uapi kdoc.
Per-patch changelogs are below each patch.
[1] https://lore.kernel.org/linux-security-module/20260803223109.707353-1-utilityemal77@gmail.com/
Justin Suess (5):
landlock: Check landlock_restrict_self(2)'s flags before privileges
landlock: Add LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS
selftests/landlock: Test LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS
landlock: Document LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS
samples/landlock: Add LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS to sampler
Documentation/userspace-api/landlock.rst | 47 +++++++-
include/uapi/linux/landlock.h | 13 +++
samples/landlock/sandboxer.c | 16 ++-
security/landlock/limits.h | 2 +-
security/landlock/syscalls.c | 35 ++++--
security/landlock/tsync.c | 8 +-
security/landlock/tsync.h | 4 +-
tools/testing/selftests/landlock/base_test.c | 104 +++++++++++++++++-
tools/testing/selftests/landlock/tsync_test.c | 96 ++++++++++++++--
9 files changed, 283 insertions(+), 42 deletions(-)
--
2.55.0
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v4 1/5] landlock: Check landlock_restrict_self(2)'s flags before privileges
2026-08-09 15:45 [PATCH v4 0/5] Implement LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS Justin Suess
@ 2026-08-09 15:45 ` Justin Suess
2026-08-09 15:45 ` [PATCH v4 3/5] selftests/landlock: Test LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS Justin Suess
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Justin Suess @ 2026-08-09 15:45 UTC (permalink / raw)
To: gnoack3000, mic; +Cc: linux-kernel, linux-security-module, Justin Suess
sys_landlock_restrict_self() currently checks the no_new_privs /
CAP_SYS_ADMIN requirement before validating the flags argument. An
unprivileged caller without no_new_privs thus gets EPERM even when the
passed flags are invalid, hiding the EINVAL error.
Move the no_new_privs / CAP_SYS_ADMIN check just after the flags check
so that malformed calls consistently error out with EINVAL whatever the
caller's privileges, the same way seccomp(2) validates its flags before
checking no_new_privs.
Update the restrict_self_checks_ordering test accordingly.
Cc: Mickaël Salaün <mic@digikod.net>
Signed-off-by: Justin Suess <utilityemal77@gmail.com>
---
Notes:
v4:
- New patch, following Mickaël's review of the main patch: check
the flags argument before the no_new_privs / CAP_SYS_ADMIN
requirement, in the same order as seccomp(2).
security/landlock/syscalls.c | 8 ++++----
tools/testing/selftests/landlock/base_test.c | 6 +++++-
2 files changed, 9 insertions(+), 5 deletions(-)
diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c
index 36b02892c62f..e3ef7b980c82 100644
--- a/security/landlock/syscalls.c
+++ b/security/landlock/syscalls.c
@@ -535,6 +535,10 @@ SYSCALL_DEFINE2(landlock_restrict_self, const int, ruleset_fd, const __u32,
if (!is_initialized())
return -EOPNOTSUPP;
+ if ((flags | LANDLOCK_MASK_RESTRICT_SELF) !=
+ LANDLOCK_MASK_RESTRICT_SELF)
+ return -EINVAL;
+
/*
* Similar checks as for seccomp(2), except that an -EPERM may be
* returned.
@@ -543,10 +547,6 @@ SYSCALL_DEFINE2(landlock_restrict_self, const int, ruleset_fd, const __u32,
!ns_capable_noaudit(current_user_ns(), CAP_SYS_ADMIN))
return -EPERM;
- if ((flags | LANDLOCK_MASK_RESTRICT_SELF) !=
- LANDLOCK_MASK_RESTRICT_SELF)
- return -EINVAL;
-
/* Translates "off" flag to boolean. */
log_same_exec = !(flags & LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF);
/* Translates "on" flag to boolean. */
diff --git a/tools/testing/selftests/landlock/base_test.c b/tools/testing/selftests/landlock/base_test.c
index cbd3c1669951..f3c126d5c003 100644
--- a/tools/testing/selftests/landlock/base_test.c
+++ b/tools/testing/selftests/landlock/base_test.c
@@ -255,8 +255,12 @@ TEST(restrict_self_checks_ordering)
/* Checks unprivileged enforcement without no_new_privs. */
drop_caps(_metadata);
+ /*
+ * The flags validity is checked before the no_new_privs /
+ * CAP_SYS_ADMIN requirement.
+ */
ASSERT_EQ(-1, landlock_restrict_self(-1, -1));
- ASSERT_EQ(EPERM, errno);
+ ASSERT_EQ(EINVAL, errno);
ASSERT_EQ(-1, landlock_restrict_self(-1, 0));
ASSERT_EQ(EPERM, errno);
ASSERT_EQ(-1, landlock_restrict_self(ruleset_fd, 0));
--
2.55.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v4 3/5] selftests/landlock: Test LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS
2026-08-09 15:45 [PATCH v4 0/5] Implement LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS Justin Suess
2026-08-09 15:45 ` [PATCH v4 1/5] landlock: Check landlock_restrict_self(2)'s flags before privileges Justin Suess
@ 2026-08-09 15:45 ` Justin Suess
2026-08-09 15:45 ` [PATCH v4 4/5] landlock: Document LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS Justin Suess
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Justin Suess @ 2026-08-09 15:45 UTC (permalink / raw)
To: gnoack3000, mic; +Cc: linux-kernel, linux-security-module, Justin Suess
Check that a successful landlock_restrict_self(2) call with
LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS sets no_new_privs without a prior
prctl(2) call nor CAP_SYS_ADMIN, that a failed call from both an
invalid ruleset and hitting the layer maximum leaves the attribute
unchanged, and that LANDLOCK_RESTRICT_SELF_TSYNC extends it to sibling
threads. Also check that this flag requires a ruleset.
Turn the multi_threaded_success test into a multi_threaded fixture with
success, no_new_privs, and no_new_privs_max_layers variants to factor
out the threading code.
Finally, rename restrict_self_fd_logging_flags to
restrict_self_fd_flags, and restrict_self_logging_flags to
restrict_self_flags to indicate that non-logging flags are now tested.
Signed-off-by: Justin Suess <utilityemal77@gmail.com>
---
Notes:
v3->v4:
- Turn multi_threaded_{success,no_new_privs,no_new_privs_max_layers}
into variants of a multi_threaded fixture, per Mickaël's
feedback.
- Move the minimal ABI/flag checks into the previous patch.
tools/testing/selftests/landlock/base_test.c | 86 ++++++++++++++++-
tools/testing/selftests/landlock/tsync_test.c | 96 ++++++++++++++++---
2 files changed, 168 insertions(+), 14 deletions(-)
diff --git a/tools/testing/selftests/landlock/base_test.c b/tools/testing/selftests/landlock/base_test.c
index 288d6bc19232..d20ab8f0862c 100644
--- a/tools/testing/selftests/landlock/base_test.c
+++ b/tools/testing/selftests/landlock/base_test.c
@@ -289,6 +289,41 @@ TEST(restrict_self_checks_ordering)
ASSERT_EQ(0, close(ruleset_fd));
}
+TEST(restrict_self_max_layers)
+{
+ const struct landlock_ruleset_attr ruleset_attr = {
+ .handled_access_fs = LANDLOCK_ACCESS_FS_EXECUTE,
+ };
+ struct landlock_path_beneath_attr path_beneath_attr = {
+ .allowed_access = LANDLOCK_ACCESS_FS_EXECUTE,
+ .parent_fd = -1,
+ };
+ const int ruleset_fd =
+ landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
+ ASSERT_LE(0, ruleset_fd);
+
+ path_beneath_attr.parent_fd =
+ open("/tmp", O_PATH | O_NOFOLLOW | O_DIRECTORY | O_CLOEXEC);
+ ASSERT_LE(0, path_beneath_attr.parent_fd);
+ ASSERT_EQ(0, landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH,
+ &path_beneath_attr, 0));
+ ASSERT_EQ(0, close(path_beneath_attr.parent_fd));
+
+ /* Enforces the maximum number of allowed layers. */
+ for (int i = 0; i < LANDLOCK_MAX_NUM_LAYERS; i++)
+ ASSERT_EQ(0, landlock_restrict_self(ruleset_fd, 0));
+
+ /* Enforces one too many rulesets. */
+ drop_caps(_metadata);
+ ASSERT_EQ(-1, landlock_restrict_self(
+ ruleset_fd, LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS));
+ ASSERT_EQ(E2BIG, errno);
+
+ /* Checks that the failed call did not set no_new_privs. */
+ ASSERT_EQ(0, prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0));
+ ASSERT_EQ(0, close(ruleset_fd));
+}
+
TEST(restrict_self_fd)
{
int fd;
@@ -300,7 +335,7 @@ TEST(restrict_self_fd)
EXPECT_EQ(EBADFD, errno);
}
-TEST(restrict_self_fd_logging_flags)
+TEST(restrict_self_fd_flags)
{
int fd;
@@ -314,9 +349,14 @@ TEST(restrict_self_fd_logging_flags)
EXPECT_EQ(-1, landlock_restrict_self(
fd, LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF));
EXPECT_EQ(EBADFD, errno);
+
+ /* LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS requires a ruleset FD. */
+ EXPECT_EQ(-1, landlock_restrict_self(
+ fd, LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS));
+ EXPECT_EQ(EBADFD, errno);
}
-TEST(restrict_self_logging_flags)
+TEST(restrict_self_flags)
{
const __u32 last_flag = LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS;
@@ -361,6 +401,17 @@ TEST(restrict_self_logging_flags)
LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON));
EXPECT_EQ(EBADF, errno);
+ /* LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS requires a ruleset FD. */
+
+ EXPECT_EQ(-1, landlock_restrict_self(
+ -1, LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS));
+ EXPECT_EQ(EBADF, errno);
+
+ EXPECT_EQ(-1, landlock_restrict_self(
+ -1, LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF |
+ LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS));
+ EXPECT_EQ(EBADF, errno);
+
/* Tests with an invalid ruleset_fd. */
EXPECT_EQ(-1, landlock_restrict_self(
@@ -371,6 +422,37 @@ TEST(restrict_self_logging_flags)
-1, LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF));
}
+TEST(restrict_self_no_new_privs)
+{
+ const struct landlock_ruleset_attr ruleset_attr = {
+ .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
+ };
+ const int ruleset_fd =
+ landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
+
+ ASSERT_LE(0, ruleset_fd);
+
+ /*
+ * The calling thread does not need CAP_SYS_ADMIN nor an explicit
+ * prctl(2) PR_SET_NO_NEW_PRIVS call.
+ */
+ drop_caps(_metadata);
+ ASSERT_EQ(0, prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0));
+
+ /* Checks that a failed call does not set no_new_privs. */
+ EXPECT_EQ(-1, landlock_restrict_self(
+ -1, LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS));
+ EXPECT_EQ(EBADF, errno);
+ EXPECT_EQ(0, prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0));
+
+ /* Checks that a successful call sets no_new_privs. */
+ ASSERT_EQ(0, landlock_restrict_self(
+ ruleset_fd, LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS));
+ EXPECT_EQ(1, prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0));
+
+ EXPECT_EQ(0, close(ruleset_fd));
+}
+
TEST(ruleset_fd_io)
{
struct landlock_ruleset_attr ruleset_attr = {
diff --git a/tools/testing/selftests/landlock/tsync_test.c b/tools/testing/selftests/landlock/tsync_test.c
index 9cf1491bbaaf..2b53596c986e 100644
--- a/tools/testing/selftests/landlock/tsync_test.c
+++ b/tools/testing/selftests/landlock/tsync_test.c
@@ -62,32 +62,104 @@ static void *idle(void *data)
pthread_cleanup_pop(1);
}
-TEST(multi_threaded_success)
+FIXTURE(multi_threaded)
{
- pthread_t t1, t2;
- bool no_new_privs1, no_new_privs2;
- const int ruleset_fd = create_ruleset(_metadata);
+ int ruleset_fd;
+};
+
+FIXTURE_VARIANT(multi_threaded)
+{
+ const __u32 restrict_flags;
+ /* Sets no_new_privs with prctl(2) before the enforcement. */
+ const bool prior_no_new_privs;
+ /* Enforces the maximum number of allowed layers beforehand. */
+ const bool max_layers;
+ const int expected_errno;
+ /* Expected no_new_privs state of all threads after the call. */
+ const bool expected_no_new_privs;
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(multi_threaded, success) {
+ /* clang-format on */
+ .restrict_flags = LANDLOCK_RESTRICT_SELF_TSYNC,
+ .prior_no_new_privs = true,
+ .expected_no_new_privs = true,
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(multi_threaded, no_new_privs) {
+ /* clang-format on */
+ .restrict_flags = LANDLOCK_RESTRICT_SELF_TSYNC |
+ LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS,
+ .expected_no_new_privs = true,
+};
+
+/* clang-format off */
+FIXTURE_VARIANT_ADD(multi_threaded, no_new_privs_max_layers) {
+ /* clang-format on */
+ .restrict_flags = LANDLOCK_RESTRICT_SELF_TSYNC |
+ LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS,
+ .max_layers = true,
+ .expected_errno = E2BIG,
+ .expected_no_new_privs = false,
+};
+
+FIXTURE_SETUP(multi_threaded)
+{
+ self->ruleset_fd = create_ruleset(_metadata);
+
+ if (variant->max_layers) {
+ /* Enforces the maximum number of allowed layers. */
+ for (int i = 0; i < LANDLOCK_MAX_NUM_LAYERS; i++)
+ ASSERT_EQ(0,
+ landlock_restrict_self(self->ruleset_fd, 0));
+ }
disable_caps(_metadata);
+}
+
+FIXTURE_TEARDOWN(multi_threaded)
+{
+ EXPECT_EQ(0, close(self->ruleset_fd));
+}
+
+TEST_F(multi_threaded, restrict)
+{
+ pthread_t t1, t2;
+ bool no_new_privs1, no_new_privs2;
ASSERT_EQ(0, pthread_create(&t1, NULL, idle, &no_new_privs1));
ASSERT_EQ(0, pthread_create(&t2, NULL, idle, &no_new_privs2));
- ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
+ if (variant->prior_no_new_privs) {
+ ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
+ } else {
+ /* No prior prctl(2) PR_SET_NO_NEW_PRIVS call. */
+ ASSERT_EQ(0, prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0));
+ }
- EXPECT_EQ(0, landlock_restrict_self(ruleset_fd,
- LANDLOCK_RESTRICT_SELF_TSYNC));
+ if (variant->expected_errno) {
+ EXPECT_EQ(-1, landlock_restrict_self(self->ruleset_fd,
+ variant->restrict_flags));
+ EXPECT_EQ(variant->expected_errno, errno);
+ } else {
+ EXPECT_EQ(0, landlock_restrict_self(self->ruleset_fd,
+ variant->restrict_flags));
+ }
+
+ /* Checks the no_new_privs state of the calling thread. */
+ EXPECT_EQ(variant->expected_no_new_privs,
+ prctl(PR_GET_NO_NEW_PRIVS, 0, 0, 0, 0));
ASSERT_EQ(0, pthread_cancel(t1));
ASSERT_EQ(0, pthread_cancel(t2));
ASSERT_EQ(0, pthread_join(t1, NULL));
ASSERT_EQ(0, pthread_join(t2, NULL));
- /* The no_new_privs flag was implicitly enabled on all threads. */
- EXPECT_TRUE(no_new_privs1);
- EXPECT_TRUE(no_new_privs2);
-
- EXPECT_EQ(0, close(ruleset_fd));
+ /* Checks the no_new_privs state of the sibling threads. */
+ EXPECT_EQ(variant->expected_no_new_privs, no_new_privs1);
+ EXPECT_EQ(variant->expected_no_new_privs, no_new_privs2);
}
TEST(multi_threaded_success_despite_diverging_domains)
--
2.55.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v4 4/5] landlock: Document LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS
2026-08-09 15:45 [PATCH v4 0/5] Implement LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS Justin Suess
2026-08-09 15:45 ` [PATCH v4 1/5] landlock: Check landlock_restrict_self(2)'s flags before privileges Justin Suess
2026-08-09 15:45 ` [PATCH v4 3/5] selftests/landlock: Test LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS Justin Suess
@ 2026-08-09 15:45 ` Justin Suess
2026-08-09 15:45 ` [PATCH v4 5/5] samples/landlock: Add LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS to sampler Justin Suess
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Justin Suess @ 2026-08-09 15:45 UTC (permalink / raw)
To: gnoack3000, mic; +Cc: linux-kernel, linux-security-module, Justin Suess
Document setting no_new_privs with ruleset enforcement, following the
same compatibility section style as previous ABI additions.
Include a section explaining the tradeoffs of setting no_new_privs
through any means for privileged users of Landlock.
Signed-off-by: Justin Suess <utilityemal77@gmail.com>
---
Notes:
v3->v4:
- Reword the tutorial paragraph on CAP_SYS_ADMIN and no_new_privs to
remove the ambiguous "it"s, per Mickaël's feedback.
- Use the suggested "call (or ``CAP_SYS_ADMIN`` use)" wording in the
compatibility section.
Documentation/userspace-api/landlock.rst | 47 +++++++++++++++++++++---
1 file changed, 41 insertions(+), 6 deletions(-)
diff --git a/Documentation/userspace-api/landlock.rst b/Documentation/userspace-api/landlock.rst
index 5085822d8930..782e65020b77 100644
--- a/Documentation/userspace-api/landlock.rst
+++ b/Documentation/userspace-api/landlock.rst
@@ -8,7 +8,7 @@ Landlock: unprivileged access control
=====================================
:Author: Mickaël Salaün
-:Date: July 2026
+:Date: August 2026
The goal of Landlock is to enable restriction of ambient rights (e.g. global
filesystem or network access) for a set of processes. Because Landlock
@@ -250,7 +250,8 @@ similar backwards compatibility check is needed for the restrict flags
__u32 restrict_flags =
LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON |
- LANDLOCK_RESTRICT_SELF_TSYNC;
+ LANDLOCK_RESTRICT_SELF_TSYNC |
+ LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS;
switch (abi) {
case 1 ... 6:
/* Removes logging flags for ABI < 7 */
@@ -269,16 +270,37 @@ similar backwards compatibility check is needed for the restrict flags
* children (and not for all threads, including parents and siblings).
*/
restrict_flags &= ~LANDLOCK_RESTRICT_SELF_TSYNC;
+ __attribute__((fallthrough));
+ case 8 ... 10:
+ /* Removes no new privs flag for ABI < 11 */
+ restrict_flags &= ~LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS;
}
The next step is to restrict the current thread from gaining more privileges
-(e.g. through a SUID binary). We now have a ruleset with the first rule
-allowing read and execute access to ``/usr`` while denying all other handled
-accesses for the filesystem, and two more rules allowing DNS queries.
+(e.g. through a SUID binary). For unprivileged processes, setting the
+no_new_privs attribute is required by Landlock.
+
+Processes with ``CAP_SYS_ADMIN`` in their namespace can enforce a ruleset
+without setting no_new_privs, but leaving no_new_privs unset is risky even
+when Landlock does not require this attribute: sandboxed processes could
+still execute set-user-ID, set-group-ID or file-capability binaries, which
+would then run with elevated privileges while being restricted by a Landlock
+domain they may not expect, making them potential confused deputies.
+no_new_privs should only be left unset if such a privilege transition is
+expected.
+
+We now have a ruleset with the first rule allowing read and execute access to
+``/usr`` while denying all other handled accesses for the filesystem, and two
+more rules allowing DNS queries.
.. code-block:: c
- if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
+ /*
+ * If the ABI > 10, we can tie setting no_new_privs with successful ruleset
+ * enforcement and skip the manual prctl(PR_SET_NO_NEW_PRIVS, ...) call.
+ */
+ if (!(restrict_flags & LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS) &&
+ prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
perror("Failed to restrict privileges");
close(ruleset_fd);
return 1;
@@ -792,6 +814,19 @@ when at least one sys_landlock_add_rule() call is made for it with the
``LANDLOCK_ADD_RULE_QUIET`` flag, additional add-rule calls for the same
object without this flag do not clear it.
+no_new_privs flag (ABI < 11)
+----------------------------
+
+Starting with the Landlock ABI version 11, sys_landlock_restrict_self()
+accepts the ``LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS`` flag, which sets the
+no_new_privs attribute of the calling thread only once the enforcement of
+the ruleset succeeded: no_new_privs is set if and only if the call
+succeeds. This removes the need for a prior :manpage:`prctl(2)`
+``PR_SET_NO_NEW_PRIVS`` call (or ``CAP_SYS_ADMIN`` use). When combined
+with ``LANDLOCK_RESTRICT_SELF_TSYNC``, no_new_privs is set on all threads
+of the process. As explained in the tutorial above, leaving no_new_privs
+unset is risky even when Landlock does not require it.
+
.. _kernel_support:
Kernel support
--
2.55.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v4 5/5] samples/landlock: Add LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS to sampler
2026-08-09 15:45 [PATCH v4 0/5] Implement LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS Justin Suess
` (2 preceding siblings ...)
2026-08-09 15:45 ` [PATCH v4 4/5] landlock: Document LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS Justin Suess
@ 2026-08-09 15:45 ` Justin Suess
2026-08-09 15:53 ` [PATCH v4 0/5] Implement LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS Justin Suess
2026-08-09 21:24 ` [PATCH v4 2/5] landlock: Add LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS Justin Suess
5 siblings, 0 replies; 7+ messages in thread
From: Justin Suess @ 2026-08-09 15:45 UTC (permalink / raw)
To: gnoack3000, mic; +Cc: linux-kernel, linux-security-module, Justin Suess
Add LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS to the default flag setting.
Gate the flag on the ABI version, but do not expose any userspace
control over this flag as it has no practical effect on the resulting
sandbox.
Signed-off-by: Justin Suess <utilityemal77@gmail.com>
---
Notes:
v3->v4:
- No change.
samples/landlock/sandboxer.c | 16 ++++++++++++----
1 file changed, 12 insertions(+), 4 deletions(-)
diff --git a/samples/landlock/sandboxer.c b/samples/landlock/sandboxer.c
index ac71019e6212..030583273f3f 100644
--- a/samples/landlock/sandboxer.c
+++ b/samples/landlock/sandboxer.c
@@ -369,7 +369,7 @@ static int add_quiet_access(const char *const env_var,
return 0;
}
-#define LANDLOCK_ABI_LAST 10
+#define LANDLOCK_ABI_LAST 11
#define XSTR(s) #s
#define STR(s) XSTR(s)
@@ -453,8 +453,9 @@ int main(const int argc, char *const argv[], char *const *const envp)
.quiet_scoped = 0,
};
bool quiet_supported = true;
- int supported_restrict_flags = LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON;
- int set_restrict_flags = 0;
+ int supported_restrict_flags = LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON |
+ LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS;
+ int set_restrict_flags = LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS;
if (argc < 2) {
fprintf(stderr, help, argv[0]);
@@ -545,6 +546,12 @@ int main(const int argc, char *const argv[], char *const *const envp)
LANDLOCK_ACCESS_NET_CONNECT_SEND_UDP);
/* Removes quiet flags for ABI < 10 later on. */
quiet_supported = false;
+ __attribute__((fallthrough));
+ case 10:
+ /* Removes LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS for ABI < 11 */
+ supported_restrict_flags &=
+ ~LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS;
+ set_restrict_flags &= ~LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS;
/* Must be printed for any ABI < LANDLOCK_ABI_LAST. */
fprintf(stderr,
@@ -673,7 +680,8 @@ int main(const int argc, char *const argv[], char *const *const envp)
}
}
- if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
+ if (!(set_restrict_flags & LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS) &&
+ prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) {
perror("Failed to restrict privileges");
goto err_close_ruleset;
}
--
2.55.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v4 0/5] Implement LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS
2026-08-09 15:45 [PATCH v4 0/5] Implement LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS Justin Suess
` (3 preceding siblings ...)
2026-08-09 15:45 ` [PATCH v4 5/5] samples/landlock: Add LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS to sampler Justin Suess
@ 2026-08-09 15:53 ` Justin Suess
2026-08-09 21:24 ` [PATCH v4 2/5] landlock: Add LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS Justin Suess
5 siblings, 0 replies; 7+ messages in thread
From: Justin Suess @ 2026-08-09 15:53 UTC (permalink / raw)
To: gnoack3000, mic; +Cc: linux-kernel, linux-security-module
On Sun, Aug 09, 2026 at 11:45:18AM -0400, Justin Suess wrote:
> Howdy
>
> This series adds a new landlock_restrict_self(2) flag:
> LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS.
>
gmail for some reason in their infinite wisdom decided to drop my second
patch 2/5 (the core patch of this series) for seemengly no reason. At
least they sent me a bounce email...
Anyways I'll RESEND the series later and hope I don't get bounced again...
Justin
> The flag sets the no_new_privs attribute of the calling thread only
> once the enforcement of the ruleset succeeded: no_new_privs is set if
> and only if the landlock_restrict_self(2) call succeeds.
>
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v4 2/5] landlock: Add LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS
2026-08-09 15:45 [PATCH v4 0/5] Implement LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS Justin Suess
` (4 preceding siblings ...)
2026-08-09 15:53 ` [PATCH v4 0/5] Implement LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS Justin Suess
@ 2026-08-09 21:24 ` Justin Suess
5 siblings, 0 replies; 7+ messages in thread
From: Justin Suess @ 2026-08-09 21:24 UTC (permalink / raw)
To: gnoack3000, mic; +Cc: linux-kernel, linux-security-module, Justin Suess
Add a landlock_restrict_self(2) flag to set the no_new_privs attribute
of the calling thread only after enforcement of the ruleset:
no_new_privs is set if and only if the call succeeds. This removes the
need for a prior prctl(2) PR_SET_NO_NEW_PRIVS call and guarantees that
a failed enforcement leaves the attribute unchanged.
Because no_new_privs is set by the call itself, the no_new_privs /
CAP_SYS_ADMIN requirement of landlock_restrict_self(2) is fulfilled by
construction, and the related EPERM check is skipped.
Unlike LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF, this flag always
requires a valid ruleset: with a ruleset_fd of -1, such a call would be
nothing more than a Landlock-flavored prctl(2) PR_SET_NO_NEW_PRIVS, and
there is no valid use case for setting no_new_privs (possibly with
LANDLOCK_RESTRICT_SELF_TSYNC) without also enforcing Landlock
restrictions. Rejecting these calls also keeps the option of giving
them a meaning later.
The attribute is only set past the last point of failure, just before
committing the new credentials. When combined with
LANDLOCK_RESTRICT_SELF_TSYNC, no_new_privs is set on the sibling threads
as well, in their commit phase, with the same ordering.
Bump the Landlock ABI version to 11, and include the minimal related
test changes to keep the tests bisectable.
Cc: Mickaël Salaün <mic@digikod.net>
Signed-off-by: Justin Suess <utilityemal77@gmail.com>
---
Notes:
v3->v4:
- Rebase on the new preparatory patch: the flags-before-privileges
ordering (and its EINVAL/EPERM visible change) is now handled
there.
- Drop the set_no_new_privs variable and check the flag directly at
both use sites, per Mickaël's feedback.
- Fold in the minimal selftest changes (ABI version, last-flag, and
checks-ordering updates) to keep the series bisectable, following
the commit tweaked by Mickaël.
- Reword the flag kdoc: "call (or %CAP_SYS_ADMIN use)" instead of
"call, and with it the %CAP_SYS_ADMIN requirement".
include/uapi/linux/landlock.h | 13 ++++++++++
security/landlock/limits.h | 2 +-
security/landlock/syscalls.c | 27 +++++++++++++++-----
security/landlock/tsync.c | 8 ++++--
security/landlock/tsync.h | 4 ++-
tools/testing/selftests/landlock/base_test.c | 12 +++++++--
6 files changed, 53 insertions(+), 13 deletions(-)
diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h
index 27ae3f39cafb..cceda3b3b961 100644
--- a/include/uapi/linux/landlock.h
+++ b/include/uapi/linux/landlock.h
@@ -191,12 +191,25 @@ struct landlock_ruleset_attr {
*
* If the calling thread is running with no_new_privs, this operation
* enables no_new_privs on the sibling threads as well.
+ *
+ * The following flag ties the no_new_privs attribute to the ruleset
+ * enforcement:
+ *
+ * %LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS
+ * Sets the no_new_privs attribute of the calling thread only once the
+ * enforcement of the ruleset succeeded: no_new_privs is set if and only
+ * if sys_landlock_restrict_self() succeeds. This removes the need for a
+ * prior :manpage:`prctl(2)` ``PR_SET_NO_NEW_PRIVS`` call (or
+ * %CAP_SYS_ADMIN use). This flag requires a ruleset. When
+ * combined with %LANDLOCK_RESTRICT_SELF_TSYNC, no_new_privs is set on the
+ * sibling threads as well.
*/
/* clang-format off */
#define LANDLOCK_RESTRICT_SELF_LOG_SAME_EXEC_OFF (1U << 0)
#define LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON (1U << 1)
#define LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF (1U << 2)
#define LANDLOCK_RESTRICT_SELF_TSYNC (1U << 3)
+#define LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS (1U << 4)
/* clang-format on */
/**
diff --git a/security/landlock/limits.h b/security/landlock/limits.h
index 08d5f2f6d321..1a7c5fb8f6fd 100644
--- a/security/landlock/limits.h
+++ b/security/landlock/limits.h
@@ -34,7 +34,7 @@
#define LANDLOCK_NUM_ACCESS_MAX \
MAX(MAX(LANDLOCK_NUM_ACCESS_FS, LANDLOCK_NUM_ACCESS_NET), LANDLOCK_NUM_SCOPE)
-#define LANDLOCK_LAST_RESTRICT_SELF LANDLOCK_RESTRICT_SELF_TSYNC
+#define LANDLOCK_LAST_RESTRICT_SELF LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS
#define LANDLOCK_MASK_RESTRICT_SELF ((LANDLOCK_LAST_RESTRICT_SELF << 1) - 1)
/* clang-format on */
diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c
index e3ef7b980c82..e5f65a1c35ff 100644
--- a/security/landlock/syscalls.c
+++ b/security/landlock/syscalls.c
@@ -169,7 +169,7 @@ static const struct file_operations ruleset_fops = {
* If the change involves a fix that requires userspace awareness, also update
* the errata documentation in Documentation/userspace-api/landlock.rst .
*/
-const int landlock_abi_version = 10;
+const int landlock_abi_version = 11;
/**
* sys_landlock_create_ruleset - Create a new ruleset
@@ -502,21 +502,28 @@ SYSCALL_DEFINE4(landlock_add_rule, const int, ruleset_fd,
* - %LANDLOCK_RESTRICT_SELF_LOG_NEW_EXEC_ON
* - %LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF
* - %LANDLOCK_RESTRICT_SELF_TSYNC
+ * - %LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS
*
* This system call enforces a Landlock ruleset on the current thread.
* Enforcing a ruleset requires that the task has %CAP_SYS_ADMIN in its
* namespace or is running with no_new_privs. This avoids scenarios where
* unprivileged tasks can affect the behavior of privileged children.
*
+ * With %LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS, the no_new_privs attribute of the
+ * calling thread is set only once the enforcement of the ruleset succeeded,
+ * which fulfills the above requirement: no_new_privs is set if and only if the
+ * call succeeds.
+ *
* Return: 0 on success, or -errno on failure. Possible returned errors are:
*
* - %EOPNOTSUPP: Landlock is supported by the kernel but disabled at boot time;
* - %EINVAL: @flags contains an unknown bit.
* - %EBADF: @ruleset_fd is not a file descriptor for the current thread;
* - %EBADFD: @ruleset_fd is not a ruleset file descriptor;
- * - %EPERM: @ruleset_fd has no read access to the underlying ruleset, or the
- * current thread is not running with no_new_privs, or it doesn't have
- * %CAP_SYS_ADMIN in its namespace.
+ * - %EPERM: @ruleset_fd has no read access to the underlying ruleset, or
+ * %LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS is not set while the current thread
+ * is not running with no_new_privs and doesn't have %CAP_SYS_ADMIN in its
+ * namespace.
* - %E2BIG: The maximum number of stacked rulesets is reached for the current
* thread.
*
@@ -541,9 +548,11 @@ SYSCALL_DEFINE2(landlock_restrict_self, const int, ruleset_fd, const __u32,
/*
* Similar checks as for seccomp(2), except that an -EPERM may be
- * returned.
+ * returned. LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS fulfills this
+ * requirement.
*/
- if (!task_no_new_privs(current) &&
+ if (!(flags & LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS) &&
+ !task_no_new_privs(current) &&
!ns_capable_noaudit(current_user_ns(), CAP_SYS_ADMIN))
return -EPERM;
@@ -620,12 +629,16 @@ SYSCALL_DEFINE2(landlock_restrict_self, const int, ruleset_fd, const __u32,
if (flags & LANDLOCK_RESTRICT_SELF_TSYNC) {
const int err = landlock_restrict_sibling_threads(
- current_cred(), new_cred);
+ current_cred(), new_cred, flags);
if (err) {
abort_creds(new_cred);
return err;
}
}
+ /* Sets no_new_privs past the last point of failure. */
+ if (flags & LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS)
+ task_set_no_new_privs(current);
+
return commit_creds(new_cred);
}
diff --git a/security/landlock/tsync.c b/security/landlock/tsync.c
index c5730bbd9ed3..0b71e158c3f5 100644
--- a/security/landlock/tsync.c
+++ b/security/landlock/tsync.c
@@ -17,6 +17,7 @@
#include <linux/sched/task.h>
#include <linux/slab.h>
#include <linux/task_work.h>
+#include <uapi/linux/landlock.h>
#include "cred.h"
#include "tsync.h"
@@ -466,7 +467,8 @@ static void cancel_tsync_works(const struct tsync_works *works,
* restrict_sibling_threads - enables a Landlock policy for all sibling threads
*/
int landlock_restrict_sibling_threads(const struct cred *old_cred,
- const struct cred *new_cred)
+ const struct cred *new_cred,
+ const u32 restrict_flags)
{
int err;
struct tsync_shared_context shared_ctx;
@@ -481,7 +483,9 @@ int landlock_restrict_sibling_threads(const struct cred *old_cred,
init_completion(&shared_ctx.all_finished);
shared_ctx.old_cred = old_cred;
shared_ctx.new_cred = new_cred;
- shared_ctx.set_no_new_privs = task_no_new_privs(current);
+ shared_ctx.set_no_new_privs =
+ (restrict_flags & LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS) ||
+ task_no_new_privs(current);
/*
* Serialize concurrent TSYNC operations to prevent deadlocks when
diff --git a/security/landlock/tsync.h b/security/landlock/tsync.h
index ef86bb61c2f6..2ae4f938ca00 100644
--- a/security/landlock/tsync.h
+++ b/security/landlock/tsync.h
@@ -9,8 +9,10 @@
#define _SECURITY_LANDLOCK_TSYNC_H
#include <linux/cred.h>
+#include <linux/types.h>
int landlock_restrict_sibling_threads(const struct cred *old_cred,
- const struct cred *new_cred);
+ const struct cred *new_cred,
+ u32 restrict_flags);
#endif /* _SECURITY_LANDLOCK_TSYNC_H */
diff --git a/tools/testing/selftests/landlock/base_test.c b/tools/testing/selftests/landlock/base_test.c
index f3c126d5c003..288d6bc19232 100644
--- a/tools/testing/selftests/landlock/base_test.c
+++ b/tools/testing/selftests/landlock/base_test.c
@@ -76,7 +76,7 @@ TEST(abi_version)
const struct landlock_ruleset_attr ruleset_attr = {
.handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE,
};
- ASSERT_EQ(10, landlock_create_ruleset(NULL, 0,
+ ASSERT_EQ(11, landlock_create_ruleset(NULL, 0,
LANDLOCK_CREATE_RULESET_VERSION));
ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0,
@@ -265,6 +265,14 @@ TEST(restrict_self_checks_ordering)
ASSERT_EQ(EPERM, errno);
ASSERT_EQ(-1, landlock_restrict_self(ruleset_fd, 0));
ASSERT_EQ(EPERM, errno);
+ /*
+ * LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS fulfills the no_new_privs /
+ * CAP_SYS_ADMIN requirement but requires a ruleset, so the FD is
+ * checked next.
+ */
+ ASSERT_EQ(-1, landlock_restrict_self(
+ -1, LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS));
+ ASSERT_EQ(EBADF, errno);
ASSERT_EQ(0, prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0));
@@ -310,7 +318,7 @@ TEST(restrict_self_fd_logging_flags)
TEST(restrict_self_logging_flags)
{
- const __u32 last_flag = LANDLOCK_RESTRICT_SELF_TSYNC;
+ const __u32 last_flag = LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS;
/* Tests invalid flag combinations. */
--
2.55.0
^ permalink raw reply related [flat|nested] 7+ messages in thread
end of thread, other threads:[~2026-08-09 21:25 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-09 15:45 [PATCH v4 0/5] Implement LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS Justin Suess
2026-08-09 15:45 ` [PATCH v4 1/5] landlock: Check landlock_restrict_self(2)'s flags before privileges Justin Suess
2026-08-09 15:45 ` [PATCH v4 3/5] selftests/landlock: Test LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS Justin Suess
2026-08-09 15:45 ` [PATCH v4 4/5] landlock: Document LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS Justin Suess
2026-08-09 15:45 ` [PATCH v4 5/5] samples/landlock: Add LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS to sampler Justin Suess
2026-08-09 15:53 ` [PATCH v4 0/5] Implement LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS Justin Suess
2026-08-09 21:24 ` [PATCH v4 2/5] landlock: Add LANDLOCK_RESTRICT_SELF_NO_NEW_PRIVS Justin Suess
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox