Re: Question about using Landlock

Jeffrey Walton <[email protected]> Fri, 21 Nov 2025 10:14:23 -0500
Newsgroups dev.linux.lists.landlock
Message-ID <CAH8yC8k=2ZJ5-Y+L8mxH65D8nLtuDvLRfWvy0OjWVsPM7Wx=_w@mail.gmail.com>
On Fri, Nov 21, 2025 at 9:44=E2=80=AFAM Micka=C3=ABl Sala=C3=BCn <mic@digik=
od.net> wrote:
>
> On Thu, Nov 20, 2025 at 08:37:45PM +0000, Marek K=C3=BCthe wrote:
> > On Thu, 20 Nov 2025 18:36:50 +0100
> > Micka=C3=ABl Sala=C3=BCn <[email protected]> wrote:
> >
> > > On Wed, Nov 19, 2025 at 09:19:37PM +0000, Marek K=C3=BCthe wrote:
> >
> > Thanks for your answers! That answered many of my questions.
> >
> > > > When accessing the file system, I'm supposed to specify the fd of t=
he
> > > > file, but then I already have that file open. And that's exactly wh=
at
> > > > Lockland is supposed to control.
> > >
> > > The goal of a file descriptor is to identify a file or another kernel
> > > resource, without race condition, and in an absolute way.  It doesn't
> > > mean it gives access to the underlying resource (but that's the case
> > > most of the time).  With Landlock, it is encouraged to open files wit=
h
> > > O_PATH (see the sandboxer.c example) to avoid leaking opened
> > > files/access.
> > >
> > > Using file paths for kernel interfaces should be avoided.
> >
> > Could you give an example? I think you mean fd's that don't refer to
> > anything in the file system?
>
> I mean that dealing with file paths is racy, it's much better to open a
> file once and then perform operations on the related file descriptor
> instead of on the same path.  For instance, you can do a lot of things
> with syscalls ending with "at" (e.g. openat2 + AT_EMPTY_PATH, ioctl,
> read).

For the OP.... A second benefit of the various *at() functions is a
per-thread working directory in a multithreaded app.  Also see the
Notes section in the openat(2) man page;
<https://linux.die.net/man/2/openat>.

> > > Creating files before sandboxing itself can make sense wrt to the thr=
eat
> > > model (i.e. if the potential attacker cannot interact with the proces=
s
> > > at this time).  However, you should try to open the tap device before
> > > the sandboxing and keep the related file descriptor open.  This way y=
ou
> > > don't need to bother with the file path of the tap device and you avo=
id
> > > other potential issues.
> >
> > Thanks for the clarification. I'm new to developing "secure programs"
> > and still need to learn how to create (useful) threat models.
> >
> > > > 3. Lockland introduces scoped access control starting with ABI 6. T=
o
> > > > avoid getting warnings from the compiler (and linter), I need to kn=
ow
> > > > whether the struct landlock_ruleset_attr has scoped access control =
or
> > > > not when programming. Since I only want to support the case where t=
his
> > > > is true, I would like to check the ABI version at compile time and
> > > > generate a more meaningful error. How can I check the ABI version a=
t
> > > > compile time? Is there a macro for this?
> > >
> > > Checking the ABI version at build time is not recommended because it
> > > doesn't give any guarantee about the ABI version at run time.  That's
> > > why the ABI should be a dynamic check.
> >
> > But I would like to have a build-time guarantee that certain data
> > structures are available in a certain form or that certain macros
> > exist. Hence my question about build-time checking.
>
> You can check the size of a struct at build time, and then infer which
> fields are part of it.  We should probably add some helpers to make this
> simpler.
>
> It's OK to just copy the header file though.  You'll need to update the
> code to leverage new features anyway.
>
> >
> > > > Currently, I am using a check to see if the compiler can compile th=
e
> > > > struct with `scoped`. [5] However, I don't think this is very elega=
nt.
> > >
> > > If the scoped field is defined, then you should use it and update it =
at
> > > runtime according to the current Landlock ABI.  See the sandboxer.c
> > > example for such case.
> >
> > But that assumes that the field exists at build time, and that's
> > exactly what I want to check.
>
> sizeof() should help.
>
> >
> > If I try to initialize a non-existent field, there should be an error
> > from the compiler (so I want to catch that beforehand). And if I don't
> > initialize an existing field, clang-tidy complains.
>
> You should always initialize the Landlock structs to zero, otherwise
> you'll get undefined behavior (depending on the content of the stack).
> We can initialize a whole struct with empty curly braces e.g.:
>
>   struct landlock_ruleset_attr ruleset_attr =3D {};
>
> >
> > As far as I can tell, sandboxer.c always assumes at build time that it
> > has been compiled with a new version. Or am I overlooking something?
>
> That's correct, and it's the case because the landlock.h file is always
> provided with this example, part of the Linux repository.