All of lore.kernel.org
 help / color / mirror / Atom feed
From: Justin Suess <utilityemal77@gmail.com>
To: mic@digikod.net, linux-security-module@vger.kernel.org
Cc: gnoack@google.com, Justin Suess <utilityemal77@gmail.com>
Subject: [PATCH 0/3] Implement LANDLOCK_RESTRICT_SELF_NNP_ON_EXEC
Date: Wed,  8 Jul 2026 09:39:24 -0400	[thread overview]
Message-ID: <20260708133928.852999-1-utilityemal77@gmail.com> (raw)

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


             reply	other threads:[~2026-07-08 13:39 UTC|newest]

Thread overview: 8+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-07-08 13:39 Justin Suess [this message]
2026-07-08 13:39 ` [PATCH 1/3] landlock: Add LANDLOCK_RESTRICT_SELF_NNP_ON_EXEC Justin Suess
2026-07-08 13:39 ` [PATCH 2/3] selftests/landlock: Test LANDLOCK_RESTRICT_SELF_NNP_ON_EXEC Justin Suess
2026-07-08 13:39 ` [PATCH 3/3] landlock: Document LANDLOCK_RESTRICT_SELF_NNP_ON_EXEC Justin Suess
2026-07-09 10:09 ` [PATCH 0/3] Implement LANDLOCK_RESTRICT_SELF_NNP_ON_EXEC Mickaël Salaün
2026-07-09 11:22   ` Simon McVittie
2026-07-11 17:00     ` Justin Suess
2026-07-10 13:56   ` Justin Suess

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=20260708133928.852999-1-utilityemal77@gmail.com \
    --to=utilityemal77@gmail.com \
    --cc=gnoack@google.com \
    --cc=linux-security-module@vger.kernel.org \
    --cc=mic@digikod.net \
    /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.