Linux Security Modules development
 help / color / mirror / Atom feed
From: "Farid Zakaria" <farid.m.zakaria@gmail.com>
To: "Günther Noack" <gnoack3000@gmail.com>,
	"Farid Zakaria" <farid.m.zakaria@gmail.com>
Cc: "Mickaël Salaün" <mic@digikod.net>,
	"Günther Noack" <gnoack@google.com>,
	"Paul Moore" <paul@paul-moore.com>,
	"James Morris" <jmorris@namei.org>,
	"Serge E. Hallyn" <serge@hallyn.com>,
	"Shuah Khan" <shuah@kernel.org>,
	"Jonathan Corbet" <corbet@lwn.net>,
	"John Ericson" <mail@johnericson.me>,
	linux-security-module@vger.kernel.org,
	linux-kselftest@vger.kernel.org, linux-doc@vger.kernel.org,
	linux-kernel@vger.kernel.org
Subject: Re: [PATCH RFC 0/3] landlock: Add access rights on created files
Date: Sun, 25 Oct 2026 10:52:14 -0700	[thread overview]
Message-ID: <DME3ZOI3Z6VE.1XGI920DJV4LE@gmail.com> (raw)
In-Reply-To: <20261025.8e22954c9c47@gnoack.org>

On Sun Oct 25, 2026 at 7:57 AM PDT, Günther Noack wrote:
> On Sun, Oct 25, 2026 at 12:07:10PM +0100, Günther Noack wrote:
>> Hello Farid!
>> 
>> On Sat, Oct 24, 2026 at 01:39:16PM -0700, Farid Zakaria wrote:
>> > This is a proposal for an idea to add support for landlock to work
>> > better with build systems such as Nix where they want to apply
>> > restrictions but the paths may not yet exist.
>> > 
>> > TL;DR;
>> > ========
>> > 
>> > Landlock rules attach to inodes that exist when a ruleset is built.
>> > That makes a directory shared between trusted and sandboxed tasks hard
>> > to confine: the sandbox may create entries there with
>> > LANDLOCK_ACCESS_FS_MAKE_*, but no rule can name those entries ahead of
>> > time, and granting read access on the directory to cover them exposes
>> > every other entry as well. This series adds a rule flag that grants
>> > access rights on the entries a domain creates in a directory, instead
>> > of on the directory.
>> > 
>> > Motivation
>> > ==========
>> > 
>> > The motivating user is the Nix build sandbox. Every Nix build runs in
>> > its own sandbox, and a build may only read its declared inputs in
>> > /nix/store and must be able to write and read back the outputs it
>> > creates there. Nix enforces this with a private mount namespace: it
>> > creates an empty store directory and bind-mounts each input path into
>> > it, one mount per input. Nix has paid this per-input cost since the
>> > sandbox was introduced [1].
>> > 
>> > The cost is paid per build and grows with the size of the input
>> > closure. Nix is moving towards much finer-grained builds (many small
>> > derivations instead of a few large ones), so the number of sandboxes
>> > grows while each build's own work shrinks, and the sandbox setup is
>> > becoming the bottleneck. A typical build has hundreds of inputs; large
>> > ones have thousands.
>> > 
>> > A microbenchmark sets up and tears down a Nix-like sandbox (user,
>> > mount, PID, IPC, UTS and network namespaces, pivot_root into a chroot,
>> > removing the chroot afterwards). It compares one bind mount per input
>> > with a single bind mount of the whole store plus one Landlock rule per
>> > input. Median latency per sandbox, one sandbox at a time, Linux 7.1,
>> > ext4, 16 cores:
>> > 
>> >   inputs   bind mount per input   one bind mount + Landlock   speedup
>> >       10         3.2 ms                    2.3 ms               1.4x
>> >      100        11.6 ms                    2.8 ms               4.1x
>> >     1000        79.3 ms                    6.4 ms              12.4x
>> >     5000       400.1 ms                   24.4 ms              16.4x
>> > 
>> > With Landlock, an input costs an O_PATH open and a landlock_add_rule()
>> > call: there is a single mount, and no mountpoint directory to create
>> > before the build and remove after it (removing the 1000 empty
>> > mountpoints alone took 17 ms).
>> > 
>> > The single bind mount is only sound if the store listing and the
>> > undeclared store paths stay unreadable while the build can still use
>> > its outputs. Without this series, covering the outputs requires a rule
>> > on /nix/store itself, which makes every store path readable again.
>> > 
>> > [1] https://github.com/NixOS/nix/issues/179
>> 
>> I have not done a thorough code review yet, and will focus on the
>> general approach.
>> 
>> I am generally in favor of this approach where we keep track of the
>> directory inode plus the file name.
>
> Apologies, I think I was jumping to conclusions here when I read this
> too superficially - I realize that you have implemented something
> different;
>
> If I understand correctly, your proposed patch set is granting the
> access rights on every file that you are creating freshly, but not on
> files that were created by other processes in the same directory.  The
> semantics, from what I can see, seem like a Landlock variant to what
> the "sticky bit" does in /tmp -- you have access to what you create
> yourself, but not to the files created by other processes.
>
>
> ## Alternative suggestion
>
> I have been discussing the other approach with Mickaël a while back.
> This would also work in use cases where we want to express a rule on a
> path whose underlying file inode might change, with examples being
> /etc/resolv.conf (recreated by a DHCP client) or Pathname Unix Domain
> Sockets (commonly recreated when services restart).
>
> In that approach, we'd add a rule like
>
> /* pseudocode; name and exact layout TBD */
> struct landlock_path_beneath2_attr {
> 	__u64 allowed_access;
>         __s32 parent_fd;
>         char  *basename;
> }
>
> During the path walk when checking for an access right, it would match
> if the parent_fd matches an inode and the name of the next path
> component is basename.  For example, to access a (potentially
> changing) /etc/resolv.conf:
>
> struct landlock_path_beneath_attr2 attr = {
> 	.allowed_access = READ_ONLY_ACCESSES,
>         .parent_fd      = open("/etc", O_PATH|O_CLOEXEC),
>         .basename       = "resolv.conf",
> }
>
> Or to allow the creation of an output file:
>
> struct landlock_path_beneath_attr2 attr = {
> 	.allowed_access = READ_WRITE_ACCESSES | LANDLOCK_ACCESS_FS_MAKE_REG,
>         .parent_fd      = open("/output/directory", O_PATH|O_CLOEXEC),
>         .basename       = "mymodule.o",
> }
>
> Would that be a model that would work for your Nix use case as well?
> I'm imagining that you are declaring the exact list of output files,
> is that correct?
>
> –Günther

Gunther,

From my reading of your suggestion and the code, I think that would work
for Nix and maybe a little simpler. Nix does know ahead of time the
output directory (/nix/store/<hash>-<name>, one per output), so
a parent_fd and a basename that we walk uptowards would be sufficient
without creating inodes.

This sounds like a good approach to me and my research upon your
suggestion is that it would simplify the proposal as well (drop
a patch). Should I try to implement this and send a new patch series?
(Disclosure: Will use AI to help me write the code, but will review and
test it myself.)

  reply	other threads:[~2026-10-25 17:52 UTC|newest]

Thread overview: 14+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-24 20:39 [PATCH RFC 0/3] landlock: Add access rights on created files Farid Zakaria
2026-10-24 20:39 ` [PATCH RFC 1/3] lsm: Call inode_init_security hooks without xattrs Farid Zakaria
2026-10-24 21:38   ` sashiko-bot
2026-10-24 20:39 ` [PATCH RFC 2/3] landlock: Add access rights on created files Farid Zakaria
2026-10-24 22:06   ` sashiko-bot
2026-10-24 20:39 ` [PATCH RFC 3/3] selftests/landlock: Test LANDLOCK_ADD_RULE_CREATED Farid Zakaria
2026-10-24 21:41   ` sashiko-bot
2026-10-24 21:43 ` [PATCH RFC 0/3] landlock: Add access rights on created files Justin Suess
2026-10-24 22:03   ` Justin Suess
2026-10-24 23:59     ` Farid Zakaria
2026-10-25 11:07 ` Günther Noack
2026-10-25 14:57   ` Günther Noack
2026-10-25 17:52     ` Farid Zakaria [this message]
2026-10-25 17:55   ` Farid Zakaria

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=DME3ZOI3Z6VE.1XGI920DJV4LE@gmail.com \
    --to=farid.m.zakaria@gmail.com \
    --cc=corbet@lwn.net \
    --cc=gnoack3000@gmail.com \
    --cc=gnoack@google.com \
    --cc=jmorris@namei.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-kselftest@vger.kernel.org \
    --cc=linux-security-module@vger.kernel.org \
    --cc=mail@johnericson.me \
    --cc=mic@digikod.net \
    --cc=paul@paul-moore.com \
    --cc=serge@hallyn.com \
    --cc=shuah@kernel.org \
    /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