[RFC 0/4] Landlock: ioctl support
Günther Noack
gnoack3000 at gmail.com
Tue May 2 17:17:51 UTC 2023
Hello!
These patches add ioctl support to Landlock.
It's an early version - it potentially needs more tests and
documentation. I'd like to circulate the patches early to discuss
whether this approach is feasible.
Objective
~~~~~~~~~
Make ioctl(2) requests restrictable with Landlock,
in a way that is useful for real-world applications.
Proposed approach
~~~~~~~~~~~~~~~~~
Introduce the LANDLOCK_ACCESS_FS_IOCTL right, which restricts the use
of ioctl(2) on file descriptors.
We attach the LANDLOCK_ACCESS_FS_IOCTL right to opened file
descriptors, as we already do for LANDLOCK_ACCESS_FS_TRUNCATE.
I believe that this approach works for the majority of use cases, and
offers a good trade-off between Landlock API and implementation
complexity and flexibility when the feature is used.
Notable implications of this approach
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
* Existing inherited file descriptors stay unaffected
when a program enables Landlock.
This means in particular that in common scenarios,
the terminal's ioctls (ioctl_tty(2)) continue to work.
* ioctl(2) continues to be available for file descriptors acquired
through means other than open(2). Example: Network sockets.
Examples
~~~~~~~~
Starting a sandboxed shell from $HOME with samples/landlock/sandboxer:
LL_FS_RO=/ LL_FS_RW=. ./sandboxer /bin/bash
The LANDLOCK_ACCESS_FS_IOCTL right is part of the "read-write" rights
here, so we expect that newly opened files outside of $HOME don't work
with ioctl(2).
* "stty" works: It probes terminal properties
* "stty </dev/tty" fails: /dev/tty can be reopened, but the ioctl is
denied.
* "eject" fails: ioctls to use CD-ROM drive are denied.
* "ls /dev" works: It uses ioctl to get the terminal size for
columnar layout
* The text editors "vim" and "mg" work. (GNU Emacs fails because it
attempts to reopen /dev/tty.)
Alternatives considered: Allow-listing specific ioctl requests
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
It would be technically possible to keep an allow-list of ioctl
requests and thereby control in more detail which ioctls should work.
I believe that this is not needed for the majority of use cases and
that it is a reasonable trade-off to make here (but I'm happy to hear
about counterexamples). The reasoning is:
* Many programs do not need ioctl at all,
and denying all ioctl(2) requests OK for these.
* Other programs need ioctl, but only for the terminal FDs.
This is supported because these file descriptors are usually
inherited from the parent process - so the parent process gets to
control the ioctl(2) policy for them.
* Some programs need ioctl on specific files that they are opening
themselves. They can allow-list these file paths for ioctl(2).
This makes the programs work, but it restricts a variety of other
ioctl requests which are otherwise possible through opening other
files.
Because the LANDLOCK_ACCESS_FS_IOCTL right is attached to the file
descriptor, programs have flexible options to control which ioctl
operations should work, without the implementation complexity of
additional ioctl allow-lists in the kernel.
Finally, the proposed approach is simpler in implementation and has
lower API complexity, but it does *not* preclude us from implementing
per-ioctl-request allow lists later, if that turns out to be necessary
at a later point.
Related Work
~~~~~~~~~~~~
OpenBSD's pledge(2) [1] restricts ioctl(2) independent of the file
descriptor which is used. The implementers maintain multiple
allow-lists of predefined ioctl(2) operations required for different
application domains such as "audio", "bpf", "tty" and "inet".
OpenBSD does not guarantee ABI backwards compatibility to the same
extent as Linux does, so it's easier for them to update these lists in
later versions. It might not be a feasible approach for Linux though.
[1] https://man.openbsd.org/OpenBSD-7.3/pledge.2
Feedback I'm looking for
~~~~~~~~~~~~~~~~~~~~~~~~
Some specific points I would like to get your opinion on:
* Is this the right general approach to restricting ioctl(2)?
It will probably be possible to find counter-examples where the
alternative (see below) is better. I'd be interested in these, and
in how common they are, to understand whether we have picked the
right trade-off here.
* Should we introduce a "landlock_fd_rights_limit()" syscall?
We could potentially implement a system call for dropping the
LANDLOCK_ACCESS_FS_IOCTL and LANDLOCK_ACCESS_FS_TRUNCATE rights from
existing file descriptors (independent of the type of file
descriptor, even).
Possible use cases would be to (a) restrict the rights on inherited
file descriptors like std{in,out,err} and to (b) restrict ioctl and
truncate operations on file descriptors that are not acquired
through open(2), such as network sockets.
This would be similar to the cap_rights_limit(2) system call in
FreeBSD's Capsicum.
This idea feels somewhat orthogonal to the ioctl patch, but it would
start to be more useful if the ioctl right exists.
Günther Noack (4):
landlock: Increment Landlock ABI version to 4
landlock: Add LANDLOCK_ACCESS_FS_IOCTL access right
selftests/landlock: Test ioctl support
samples/landlock: Add support for LANDLOCK_ACCESS_FS_IOCTL
include/uapi/linux/landlock.h | 19 ++++--
samples/landlock/sandboxer.c | 12 +++-
security/landlock/fs.c | 20 +++++-
security/landlock/limits.h | 2 +-
security/landlock/syscalls.c | 2 +-
tools/testing/selftests/landlock/base_test.c | 2 +-
tools/testing/selftests/landlock/fs_test.c | 67 +++++++++++++++++++-
7 files changed, 107 insertions(+), 17 deletions(-)
base-commit: 457391b0380335d5e9a5babdec90ac53928b23b4
--
2.40.1
More information about the Linux-security-module-archive
mailing list