[PATCH 0/3] Implement LANDLOCK_RESTRICT_SELF_NNP_ON_EXEC
Justin Suess
utilityemal77 at gmail.com
Wed Jul 8 13:39:24 UTC 2026
Good morning,
This series adds a new landlock_restrict_self(2) flag:
LANDLOCK_RESTRICT_SELF_NNP_ON_EXEC.
This flag stages a bit in the Landlock credentials indicating that the
next successful execution will set the no_new_privs attribute while
committing its new credentials.
Differences from prctl(PR_SET_NO_NEW_PRIVS):
PR_SET_NO_NEW_PRIVS takes effect immediately: it prevents gaining
privileges through set-user-ID, set-group-ID and file capabilities
starting with the very next execve(2).
LANDLOCK_RESTRICT_SELF_NNP_ON_EXEC instead only sets the task's
no_new_privs attribute once the next execve(2) is guaranteed to succeed
(past its point of no return, in bprm_committing_creds), after any
privilege gain through set-user-ID, set-group-ID or file capabilities
has already taken place. The executed program then runs with
no_new_privs, so subsequent executions cannot gain privileges. A
failed execve(2) leaves no_new_privs untouched.
Use cases:
Enforcing a Landlock ruleset requires that the calling process either
already has no_new_privs set or possesses CAP_SYS_ADMIN. This series
does not grant any exception to this rule; for a caller that already
has no_new_privs set, the flag is effectively a no-op. It is therefore
mostly useful for CAP_SYS_ADMIN callers that need to execute programs
that legitimately escalate privileges (e.g. transition to another
user), while ensuring that further executions cannot gain privileges.
Consider a sandbox launcher that depends on a set-user-ID helper, such
as launching applications through bubblewrap on distributions where
unprivileged user namespaces are disabled and bwrap is installed
set-user-ID root. The launcher cannot set PR_SET_NO_NEW_PRIVS before
the execution, as that would neuter the very helper it depends on:
sandbox launcher (CAP_SYS_ADMIN)
|
| landlock_restrict_self(-1, LANDLOCK_RESTRICT_SELF_NNP_ON_EXEC)
V
/usr/bin/bwrap (set-user-ID root: honored for this execution;
| no_new_privs set once the execution is past its
| point of no return)
V
sandboxed application (runs with no_new_privs; cannot gain
privileges through any further execution, and
may enforce its own Landlock ruleset without
CAP_SYS_ADMIN)
This flag also closes a gap for CAP_SYS_ADMIN callers of
landlock_restrict_self(2) itself. The no_new_privs/CAP_SYS_ADMIN
requirement exists to keep set-user-ID programs from running confused
inside a sandbox they do not expect. However, a privileged process
that enforces a domain without setting no_new_privs leaves that hole
open for all of its descendants: anything running in the domain may
still execute a set-user-ID binary, which then runs privileged under a
restricted view of the system. A privileged process that needs one
legitimate set-user-ID/set-group-ID transition currently has to choose
between breaking that transition (setting no_new_privs first) or
leaving the hole open for the lifetime of the domain.
LANDLOCK_RESTRICT_SELF_NNP_ON_EXEC allows the one intended transition
and then closes the hole.
Design:
This flag is implemented simply: a bit is stored in the Landlock
credential blob (struct landlock_cred_security) indicating whether the
next execution should set no_new_privs when it commits its new
credentials.
The bit is not coupled to any ruleset and, like
LANDLOCK_RESTRICT_SELF_LOG_SUBDOMAINS_OFF, may be passed with no
ruleset (i.e. ruleset_fd = -1). It may also be combined with
LANDLOCK_RESTRICT_SELF_TSYNC to propagate the staged state to sibling
threads, each thread then setting no_new_privs at its own next
execve(2).
The staged bit is inherited across fork(2) and persists in the
credentials until the next successful execution. To consume it,
Landlock handles the bprm_committing_creds hook, which runs while the
credentials of the new program are being committed: if the bit is set,
task_set_no_new_privs(current) is called and the bit is cleared.
Again, this flag does not bypass the requirement to either have
CAP_SYS_ADMIN or no_new_privs already set to call
landlock_restrict_self(2).
The Landlock ABI version is bumped to 11.
Test coverage:
The new nnp_on_exec fixture generates a shell script that reads the
NoNewPrivs value from /proc/self/status and exits with it. The
variants select the conditions under which the flag is tested (with
and without a ruleset, with and without CAP_SYS_ADMIN/no_new_privs
already set, with and without TSYNC, etc.), then compare no_new_privs
before the execution and in the executed script. The ruleset variants
also check that a ruleset passed along the flag is enforced
immediately, unlike the staged no_new_privs.
Justin Suess (3):
landlock: Add LANDLOCK_RESTRICT_SELF_NNP_ON_EXEC
selftests/landlock: Test LANDLOCK_RESTRICT_SELF_NNP_ON_EXEC
landlock: Document LANDLOCK_RESTRICT_SELF_NNP_ON_EXEC
Documentation/userspace-api/landlock.rst | 21 +-
include/uapi/linux/landlock.h | 36 ++-
security/landlock/cred.c | 22 ++
security/landlock/cred.h | 8 +
security/landlock/limits.h | 2 +-
security/landlock/syscalls.c | 54 +++-
tools/testing/selftests/landlock/base_test.c | 259 ++++++++++++++++++-
7 files changed, 382 insertions(+), 20 deletions(-)
--
2.54.0
More information about the Linux-security-module-archive
mailing list