From: Justin Suess <utilityemal77@gmail.com>
To: gnoack3000@gmail.com, mic@digikod.net
Cc: linux-kernel@vger.kernel.org,
linux-security-module@vger.kernel.org,
Justin Suess <utilityemal77@gmail.com>
Subject: [PATCH v8 00/10] Implement LANDLOCK_ADD_RULE_NO_INHERIT
Date: Thu, 28 May 2026 21:51:59 -0400 [thread overview]
Message-ID: <20260529015210.500291-1-utilityemal77@gmail.com> (raw)
Hi,
This is version 8 of the LANDLOCK_ADD_RULE_NO_INHERIT series, which
implements a new flag to suppress inheritance of access rights and
flags from parent objects.
This version is mostly cleanup: a preparatory patch was replaced to
avoid needing to move find_rule(), the no_inherit bookkeeping was
folded into the existing per-layer mask, syscall flag validation was
centralized, and the selftest coverage was reorganized around
fixtures and variants to cut roughly 290 lines of near-duplicate test
code while keeping equivalent coverage.
Behavior of the flag is identical to the previous version.
This series remains rebased on v9 of Tingmao Wang's "quiet flag"
series.
Previous patch summary:
The new flag enables policies where a parent directory needs broader
access than its children. For example, a sandbox may permit read-write
access to /home/user but still prohibit writes to ~/.bashrc or
~/.ssh, even though they are nested beneath the parent. Today this is
not possible because access rights always propagate from parent to
child inodes.
When a rule is added with LANDLOCK_ADD_RULE_NO_INHERIT:
* access rights on parent inodes are ignored for that inode and its
descendants; and
* operations that reparent, rename, or remove the tagged inode or
its ancestors (via rename, rmdir, link) are denied up to the VFS
root; and
* parent flags do not propagate below a NO_INHERIT rule.
These parent-directory restrictions help mitigate sandbox-restart
attacks: a sandboxed process could otherwise move a protected
directory before exit, causing the next sandbox instance to apply its
policy to the wrong path.
Changes since v7:
1. Replaced the v7 "Move find_rule definition above
landlock_append_fs_rule" preparatory patch with a new
preparatory patch that makes landlock_insert_rule() return the
inserted struct landlock_rule * via ERR_PTR(). The core
implementation patch now tags ancestor rules directly from the
return value, removing the find_rule() round trip after
insertion.
2. Folded the no_inherit / has_no_inherit_descendant bookkeeping
into the existing struct layer_mask as a single per-layer
no_inherit bit. The separate collected_rule_flags fields
(no_inherit_masks, no_inherit_desc_masks) are gone;
landlock_unmask_layers() now skips layers whose mask already has
no_inherit set, and landlock_init_layer_masks() clears the new
bit on initialization.
3. has_no_inherit_descendant is now auto-set on the rule's own
object when LANDLOCK_ADD_RULE_NO_INHERIT is passed, sealing it
against topology changes without requiring a separate blank-rule
insertion.
4. Centralized flag validation in sys_landlock_add_rule(): a single
mask check rejects unknown flags, and NO_INHERIT on any rule
type other than path-beneath is rejected at the syscall entry
point. The redundant per-rule-type NO_INHERIT check in
add_rule_net_port() was removed.
5. collect_domain_accesses() now takes a single struct path *
instead of separate mnt_root/dir parameters, matching
is_access_to_paths_allowed(). The disconnected-directory stop
condition was tightened with an explicit !d_unhashed() check at
the mount root.
6. deny_no_inherit_topology_change() dropped its override_layers
accumulator (it was always 0 in practice) and now just
OR-collects sealed layers.
7. Selftest coverage in fs_test.c was reorganized around fixtures
and variants: the v7 layout1 tests collapse into a
layout1_no_inherit fixture with five variants and three shared
tests; the four v7 layout4 mount tests collapse into a single
variant + test; and a new audit_no_inherit fixture replaces the
ad hoc audit case. Net change: 705 added lines in v7 -> 419
added lines in v8, with equivalent coverage.
8. The single KUnit test was expanded into five focused tests
covering propagation, skip, both-set, multi-layer, and
sequential-walk behavior of the per-layer no_inherit bit.
9. UAPI and userspace-api documentation reworded for clarity. The
new EINVAL case (NO_INHERIT on unsupported rule types) is
documented in the syscall kernel-doc.
10. Various commit messages reworded; switch arms in
is_access_to_paths_allowed() reordered so the fast path comes
first.
Changes since v6:
1. The main implementation of NO_INHERIT was split into smaller more
reviewable patches, separating the landlock_walk_path_up
implementation, usages of landlock_walk_path_up, and the find_rule
move to separate patches
2. A small issue regarding disconnected directory handling, where rules
inserted with NO_INHERIT only had protection up to a disconnected
directory instead of the mountpoint was fixed. In practice, this
isn't a problem at the current time since landlock forbids the mount
syscall needed to move a mountpoint with MS_MOVE. However, for
future-proofing in the case landlock allows some mount operations,
restrictions on parent directories now apply to the real root.
Changes since v5:
1. Retain existing documentation for path traversal in
is_access_to_paths_allowed.
2. Change conditional for path walk in is_access_to_paths_allowed
removing possibility of infinite loop and renamed constant.
3. Remove (now) redundant mnt_root parameter from
collect_domain_accesses.
4. Change path parameter to a dentry for
deny_no_inherit_topology_change because only the dentry was needed.
5. Remove duplicated tree diagram comment from selftests.
6. Minor documentation fixes.
Credit to Tingmao Wang for pointing out 1, 2, 3, 4, and 6.
Changes since v4:
1. Trimmed 120 lines from core implementation in fs.c.
2. Centralized path traversal logic with a helper function
landlock_walk_path_up.
3. Fixed bug in test on applying LANDLOCK_ADD_RULE_NO_INHERIT on
a file, giving it valid access rights.
4. Restructured commits to allow independent builds.
5. Adds userspace API documentation for the flag.
Changes since v3:
1. Trimmed core implementation in fs.c by removing redundant functions.
2. Fixed placement/inclusion of prototypes.
3. Added 4 new selftests for bind mount cases.
4. Protections now apply up to the VFS root instead of the mountpoint
root.
Links:
v1:
https://lore.kernel.org/linux-security-module/20251105180019.1432367-1-utilityemal77@gmail.com/
v2:
https://lore.kernel.org/linux-security-module/20251120222346.1157004-1-utilityemal77@gmail.com/
v3:
https://lore.kernel.org/linux-security-module/20251126122039.3832162-1-utilityemal77@gmail.com/
v4:
https://lore.kernel.org/linux-security-module/20251207015132.800576-1-utilityemal77@gmail.com/
v5:
https://lore.kernel.org/linux-security-module/20251214170548.408142-1-utilityemal77@gmail.com/
v6:
https://lore.kernel.org/linux-security-module/20260118000000.000000-1-utilityemal77@gmail.com/
v7:
https://lore.kernel.org/linux-security-module/20260412193214.87072-1-utilityemal77@gmail.com/
quiet-flag v6:
https://lore.kernel.org/linux-security-module/cover.1765040503.git.m@maowtm.org/
quiet-flag v7:
https://lore.kernel.org/linux-security-module/cover.1766330134.git.m@maowtm.org/
quiet-flag v8:
https://lore.kernel.org/linux-security-module/cover.1775490344.git.m@maowtm.org/
quiet-flag v9:
https://lore.kernel.org/linux-security-module/cover.1779843375.git.m@maowtm.org/
Example usage:
# LL_FS_RO="/a/b/c" LL_FS_RW="/" LL_FS_NO_INHERIT="/a/b/c"
landlock-sandboxer sh
# touch /a/b/c/fi # denied; / RW does not inherit
# rmdir /a/b/c # denied by ancestor protections
# mv /a /bad # denied
# mkdir /a/good; touch /a/good/fi # allowed; unrelated path
All tests added by this series, and all other existing landlock tests,
are passing. This patch was also validated through checkpatch.pl.
Special thanks to Tingmao Wang and Mickaël Salaün for your valuable
feedback.
Thank you for your time and review.
Regards,
Justin Suess
Justin Suess (10):
landlock: Add landlock_walk_path_up() helper
landlock: Use landlock_walk_path_up() in is_access_to_paths_allowed()
landlock: Use landlock_walk_path_up() in collect_domain_accesses()
landlock: Add LANDLOCK_ADD_RULE_NO_INHERIT user API
landlock: Return inserted rule from landlock_insert_rule()
landlock: Implement LANDLOCK_ADD_RULE_NO_INHERIT
landlock: Add documentation for LANDLOCK_ADD_RULE_NO_INHERIT
samples/landlock: Add LANDLOCK_ADD_RULE_NO_INHERIT to
landlock-sandboxer
selftests/landlock: Add selftests for LANDLOCK_ADD_RULE_NO_INHERIT
landlock: Add KUnit tests for LANDLOCK_ADD_RULE_NO_INHERIT
Documentation/userspace-api/landlock.rst | 18 ++
include/uapi/linux/landlock.h | 24 ++
samples/landlock/sandboxer.c | 13 +-
security/landlock/access.h | 4 +
security/landlock/fs.c | 290 ++++++++++++++------
security/landlock/net.c | 8 +-
security/landlock/ruleset.c | 280 ++++++++++++++++---
security/landlock/ruleset.h | 20 +-
security/landlock/syscalls.c | 14 +-
tools/testing/selftests/landlock/fs_test.c | 419 +++++++++++++++++++++++++++++
10 files changed, 966 insertions(+), 124 deletions(-)
--
2.53.0
Justin Suess (10):
landlock: Add landlock_walk_path_up() helper
landlock: Use landlock_walk_path_up() in is_access_to_paths_allowed()
landlock: Use landlock_walk_path_up() in collect_domain_accesses()
landlock: Add LANDLOCK_ADD_RULE_NO_INHERIT user API
landlock: Return inserted rule from landlock_insert_rule()
landlock: Implement LANDLOCK_ADD_RULE_NO_INHERIT
landlock: Add documentation for LANDLOCK_ADD_RULE_NO_INHERIT
samples/landlock: Add LANDLOCK_ADD_RULE_NO_INHERIT to
landlock-sandboxer
selftests/landlock: Add selftests for LANDLOCK_ADD_RULE_NO_INHERIT
landlock: Add KUnit tests for LANDLOCK_ADD_RULE_NO_INHERIT
Documentation/userspace-api/landlock.rst | 18 +
include/uapi/linux/landlock.h | 24 ++
samples/landlock/sandboxer.c | 13 +-
security/landlock/access.h | 4 +
security/landlock/fs.c | 290 ++++++++++----
security/landlock/net.c | 8 +-
security/landlock/ruleset.c | 280 ++++++++++++--
security/landlock/ruleset.h | 20 +-
security/landlock/syscalls.c | 14 +-
tools/testing/selftests/landlock/fs_test.c | 419 +++++++++++++++++++++
10 files changed, 966 insertions(+), 124 deletions(-)
base-commit: fe7832557561ed6312563368854d5f8df1fa55e3
prerequisite-patch-id: e3aaf6d74feae4e831f7ecf033987028f2b9fa89
prerequisite-patch-id: c0fe2c5da8481b5712e4289ed969e5374a8d3d14
prerequisite-patch-id: 7af9880bb7747f3b4e1dc38c405ea84256ffb853
prerequisite-patch-id: 707ec2e5bb927ab78302e2500ca9c4ed0af74c26
prerequisite-patch-id: 4fc670726f25b501ed244ad6177e24ec833642bc
prerequisite-patch-id: 90971f3bce38e63ab6c829c1daf34e0f343003dd
prerequisite-patch-id: cf58f275348749ab5adf03ccba5fd6f11a349fce
prerequisite-patch-id: 34a66721c66f731e7aa45a7ccab6eacb24e0218e
prerequisite-patch-id: 3d5eb906e6e923a85b9b9eeb12ed3bc3b69ee366
--
2.53.0
next reply other threads:[~2026-05-29 1:52 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-29 1:51 Justin Suess [this message]
2026-05-29 1:52 ` [PATCH v8 01/10] landlock: Add landlock_walk_path_up() helper Justin Suess
2026-05-29 1:52 ` [PATCH v8 02/10] landlock: Use landlock_walk_path_up() in is_access_to_paths_allowed() Justin Suess
2026-05-29 1:52 ` [PATCH v8 03/10] landlock: Use landlock_walk_path_up() in collect_domain_accesses() Justin Suess
2026-05-29 1:52 ` [PATCH v8 04/10] landlock: Add LANDLOCK_ADD_RULE_NO_INHERIT user API Justin Suess
2026-05-29 1:52 ` [PATCH v8 05/10] landlock: Return inserted rule from landlock_insert_rule() Justin Suess
2026-05-29 1:52 ` [PATCH v8 06/10] landlock: Implement LANDLOCK_ADD_RULE_NO_INHERIT Justin Suess
2026-05-29 1:52 ` [PATCH v8 07/10] landlock: Add documentation for LANDLOCK_ADD_RULE_NO_INHERIT Justin Suess
2026-05-29 1:52 ` [PATCH v8 08/10] samples/landlock: Add LANDLOCK_ADD_RULE_NO_INHERIT to landlock-sandboxer Justin Suess
2026-05-29 1:52 ` [PATCH v8 09/10] selftests/landlock: Add selftests for LANDLOCK_ADD_RULE_NO_INHERIT Justin Suess
2026-05-29 1:52 ` [PATCH v8 10/10] landlock: Add KUnit tests " 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=20260529015210.500291-1-utilityemal77@gmail.com \
--to=utilityemal77@gmail.com \
--cc=gnoack3000@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox