On Sun, Sep 28, 2025 at 05:37:02PM -0600, Abhinav Saxena wrote: > Thanks for the detailed reply Mickaël! > > Mickaël Salaün <[email protected]> writes: > > > Thanks for this patch series Abhinav! The code looks good overall, but > > we should clarify the design. Sorry for the delayed response, it is on > > my radar now.
Please feel free to ping me after two weeks without answer, I might miss some emails. > > > > CCing Jeff and Daniel > > > > On Sat, Jul 19, 2025 at 05:13:10AM -0600, Abhinav Saxena wrote: > >> This patch series introduces LANDLOCK_SCOPE_MEMFD_EXEC, a new Landlock > >> scoping mechanism that restricts execution of anonymous memory file > >> descriptors (memfd) created via memfd_create(2). This addresses security > >> gaps where processes can bypass W^X policies and execute arbitrary code > >> through anonymous memory objects. > >> > >> Fixes: <https://github.com/landlock-lsm/linux/issues/37> > >> > >> SECURITY PROBLEM > >> `==============' > >> > >> Current Landlock filesystem restrictions do not cover memfd objects, > >> allowing processes to: > >> > >> 1. Read-to-execute bypass: Create writable memfd, inject code, > >> then execute via mmap(PROT_EXEC) or direct execve() > >> 2. Anonymous execution: Execute code without touching the filesystem via > >> execve(“/proc/self/fd/N”) where N is a memfd descriptor > > > >> 3. Cross-domain access violations: Pass memfd between processes to > >> bypass domain restrictions > > > > Landlock only restricts access at open time, which is a useful property. > > This enables to create more restricted sandboxes but still get access to > > outside resources via trusted processes. If the process passing the FDs > > is not trusted, the sandboxed process could just ask to execute > > arbitrary code outside the sandbox anyway. > > > > However, the Landlock scopes are designed to block IPC from within a > > sandbox to outside the sandbox. We could have a new scope to forbid a > > sandbox process to receive or inherit file descriptors, but that would > > be a different and generic feature. For compatibility reasons, this > > might not be easy to implement and I think there are more important > > features to implement before that. > > > > Thinking more about it, restricting memfd should not be a “scoped” flag > > because the semantic is not the same, but we should have a new ruleset > > property instead, something like “ruleset.denied” with a related > > LANDLOCK_DENY_EXECUTE_MEMFD flag. This flag will only have an impact on > > newly created memfd from a sandboxed process with this restriction at > > creation time. This could be implemented with hook_file_alloc_security() > > by checking if the file is indeed a memfd and checking inode->i_mode for > > executability bits (which would imply MFD_NOEXEC_SEAL). > > > > Thanks for the clarification! So if I understood correctly we are > proposing adding a `denied` field to the `landlock_ruleset_attr` struct > > struct landlock_ruleset_attr { > __u64 handled_access_fs; > __u64 handled_access_net; > __u64 scoped; > __u64 denied; /* New field */ > }; > > which allows memfd_create() to be allowed by default unless > LANDLOCK_DENY_EXECUTE_MEMFD bit is set. Yes > Also it seems Thiébaud > Weksteen’s patch[1] will land, and maybe we can use > security_inode_init_security_anon instead? What do you think? Definitely, and this patch is now merged in -next. > > Apologies for my ignorance, do we have to wait till his patch has > landed into Linus’s tree? As long as you explain this dependency in the commit message and point to the patch (as a comment, after a "---" line), we're good. > > >> > >> These scenarios can occur in sandboxed environments where filesystem > >> access is restricted but memfd creation remains possible. > >> > >> IMPLEMENTATION > >> `============' > >> > >> The implementation adds hierarchical execution control through domain > >> scoping: > >> > >> Core Components: > >> - is_memfd_file(): Reliable memfd detection via “memfd:” dentry prefix > >> - domain_is_scoped(): Cross-domain hierarchy checking (moved to domain.c) > >> - LSM hooks: mmap_file, file_mprotect, bprm_creds_for_exec > >> - Creation-time restrictions: hook_file_alloc_security > >> > >> Security Matrix: > >> Execution decisions follow domain hierarchy rules preventing both > >> same-domain bypass attempts and cross-domain access violations while > >> preserving legitimate hierarchical access patterns. > >> > >> Domain Hierarchy with LANDLOCK_SCOPE_MEMFD_EXEC: > >> `=============================================' > >> > >> Root (no domain) - No restrictions > >> | > >> +– Domain A [SCOPE_MEMFD_EXEC] Layer 1 > >> | +– memfd_A (tagged with Domain A as creator) > >> | | > >> | +– Domain A1 (child) [NO SCOPE] Layer 2 > >> | | +– Inherits Layer 1 restrictions from parent > >> | | +– memfd_A1 (can create, inherits restrictions) > >> | | +– Domain A1a [SCOPE_MEMFD_EXEC] Layer 3 > >> | | +– memfd_A1a (tagged with Domain A1a) > >> | | > >> | +– Domain A2 (child) [SCOPE_MEMFD_EXEC] Layer 2 > >> | +– memfd_A2 (tagged with Domain A2 as creator) > >> | +– CANNOT access memfd_A1 (different subtree) > >> | > >> +– Domain B [SCOPE_MEMFD_EXEC] Layer 1 > >> +– memfd_B (tagged with Domain B as creator) > >> +– CANNOT access ANY memfd from Domain A subtree > >> > >> Execution Decision Matrix: > >> `======================' > >> Executor-> | A | A1 | A1a | A2 | B | Root > >> Creator | | | | | | > >> ————|—–|—-|—–|—-|—-|—– > >> Domain A | X | X | X | X | X | Y > >> Domain A1 | Y | X | X | X | X | Y > >> Domain A1a | Y | Y | X | X | X | Y > >> Domain A2 | Y | X | X | X | X | Y > >> Domain B | X | X | X | X | X | Y > >> Root | Y | Y | Y | Y | Y | Y > >> > >> Legend: Y = Execution allowed, X = Execution denied > > > > Because checks should not be related to scopes, this will be much > > simpler. > > > >> > >> Scenarios Covered: > >> - Direct mmap(PROT_EXEC) on memfd files > >> - Two-stage mmap(PROT_READ) + mprotect(PROT_EXEC) bypass attempts > >> - execve("/proc/self/fd/N") anonymous execution > >> - execveat() and fexecve() file descriptor execution > >> - Cross-process memfd inheritance and IPC passing > >> > >> TESTING > >> `=====' > >> > >> All patches have been validated with: > >> - scripts/checkpatch.pl –strict (clean) > >> - Selftests covering same-domain restrictions, cross-domain > >> hierarchy enforcement, and regular file isolation > >> - KUnit tests for memfd detection edge cases > > > > Thanks for all these tests! > > > >> > >> DISCLAIMER > >> `========' > >> > >> My understanding of Landlock scoping semantics may be limited, but this > >> implementation reflects my current understanding based on available > >> documentation and code analysis. I welcome feedback and corrections > >> regarding the scoping logic and domain hierarchy enforcement. > >> > >> Signed-off-by: Abhinav Saxena <[email protected]> > >> — > >> Abhinav Saxena (4): > >> landlock: add LANDLOCK_SCOPE_MEMFD_EXEC scope > >> landlock: implement memfd detection > >> landlock: add memfd exec LSM hooks and scoping > >> selftests/landlock: add memfd execution tests > >> > >> include/uapi/linux/landlock.h | 5 + > >> security/landlock/.kunitconfig | 1 + > >> security/landlock/audit.c | 4 + > >> security/landlock/audit.h | 1 + > >> security/landlock/cred.c | 14 - > >> security/landlock/domain.c | 67 ++++ > >> security/landlock/domain.h | 4 + > >> security/landlock/fs.c | 405 > >> ++++++++++++++++++++- > >> security/landlock/limits.h | 2 +- > >> security/landlock/task.c | 67 —- > >> …/selftests/landlock/scoped_memfd_exec_test.c | 325 +++++++++++++++++ > >> 11 files changed, 812 insertions(+), 83 deletions(-) > >> — > >> base-commit: 5b74b2eff1eeefe43584e5b7b348c8cd3b723d38 > >> change-id: 20250716-memfd-exec-ac0d582018c3 > >> > >> Best regards, > >> – > >> Abhinav Saxena <[email protected]> > >> > >> > > Best, > Abhinav > > [1] - <https://lore.kernel.org/all/[email protected]/>

