Skip to content

Commit

Permalink
Merge branch 'next' of git://git.kernel.org/pub/scm/linux/kernel/git/…
Browse files Browse the repository at this point in the history
…mic/linux.git
  • Loading branch information
Mark Brown committed Sep 27, 2022
2 parents 6aa1989 + 3d6723e commit 6c999ed
Show file tree
Hide file tree
Showing 9 changed files with 401 additions and 73 deletions.
8 changes: 4 additions & 4 deletions Documentation/security/landlock.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ Landlock LSM: kernel documentation
==================================

:Author: Mickaël Salaün
:Date: May 2022
:Date: September 2022

Landlock's goal is to create scoped access-control (i.e. sandboxing). To
harden a whole system, this feature should be available to any process,
Expand Down Expand Up @@ -49,13 +49,13 @@ Filesystem access rights
------------------------

All access rights are tied to an inode and what can be accessed through it.
Reading the content of a directory doesn't imply to be allowed to read the
Reading the content of a directory does not imply to be allowed to read the
content of a listed inode. Indeed, a file name is local to its parent
directory, and an inode can be referenced by multiple file names thanks to
(hard) links. Being able to unlink a file only has a direct impact on the
directory, not the unlinked inode. This is the reason why
`LANDLOCK_ACCESS_FS_REMOVE_FILE` or `LANDLOCK_ACCESS_FS_REFER` are not allowed
to be tied to files but only to directories.
``LANDLOCK_ACCESS_FS_REMOVE_FILE`` or ``LANDLOCK_ACCESS_FS_REFER`` are not
allowed to be tied to files but only to directories.

Tests
=====
Expand Down
81 changes: 60 additions & 21 deletions Documentation/userspace-api/landlock.rst
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ Landlock: unprivileged access control
=====================================

:Author: Mickaël Salaün
:Date: May 2022
:Date: September 2022

The goal of Landlock is to enable to restrict ambient rights (e.g. global
filesystem access) for a set of processes. Because Landlock is a stackable
Expand Down Expand Up @@ -60,7 +60,8 @@ the need to be explicit about the denied-by-default access rights.
LANDLOCK_ACCESS_FS_MAKE_FIFO |
LANDLOCK_ACCESS_FS_MAKE_BLOCK |
LANDLOCK_ACCESS_FS_MAKE_SYM |
LANDLOCK_ACCESS_FS_REFER,
LANDLOCK_ACCESS_FS_REFER |
LANDLOCK_ACCESS_FS_TRUNCATE,
};
Because we may not know on which kernel version an application will be
Expand All @@ -69,16 +70,26 @@ should try to protect users as much as possible whatever the kernel they are
using. To avoid binary enforcement (i.e. either all security features or
none), we can leverage a dedicated Landlock command to get the current version
of the Landlock ABI and adapt the handled accesses. Let's check if we should
remove the `LANDLOCK_ACCESS_FS_REFER` access right which is only supported
starting with the second version of the ABI.
remove the ``LANDLOCK_ACCESS_FS_REFER`` or ``LANDLOCK_ACCESS_FS_TRUNCATE``
access rights, which are only supported starting with the second and third
version of the ABI.

.. code-block:: c
int abi;
abi = landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION);
if (abi < 2) {
ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER;
switch (abi) {
case -1:
perror("The running kernel does not enable to use Landlock");
return 1;
case 1:
/* Removes LANDLOCK_ACCESS_FS_REFER for ABI < 2 */
ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER;
__attribute__((fallthrough));
case 2:
/* Removes LANDLOCK_ACCESS_FS_TRUNCATE for ABI < 3 */
ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_TRUNCATE;
}
This enables to create an inclusive ruleset that will contain our rules.
Expand Down Expand Up @@ -127,8 +138,8 @@ descriptor.
It may also be required to create rules following the same logic as explained
for the ruleset creation, by filtering access rights according to the Landlock
ABI version. In this example, this is not required because
`LANDLOCK_ACCESS_FS_REFER` is not allowed by any rule.
ABI version. In this example, this is not required because all of the requested
``allowed_access`` rights are already available in ABI 1.

We now have a ruleset with one rule allowing read access to ``/usr`` while
denying all other handled accesses for the filesystem. The next step is to
Expand All @@ -154,8 +165,8 @@ The current thread is now ready to sandbox itself with the ruleset.
}
close(ruleset_fd);
If the `landlock_restrict_self` system call succeeds, the current thread is now
restricted and this policy will be enforced on all its subsequently created
If the ``landlock_restrict_self`` system call succeeds, the current thread is
now restricted and this policy will be enforced on all its subsequently created
children as well. Once a thread is landlocked, there is no way to remove its
security policy; only adding more restrictions is allowed. These threads are
now in a new Landlock domain, merge of their parent one (if any) with the new
Expand All @@ -170,12 +181,13 @@ It is recommended setting access rights to file hierarchy leaves as much as
possible. For instance, it is better to be able to have ``~/doc/`` as a
read-only hierarchy and ``~/tmp/`` as a read-write hierarchy, compared to
``~/`` as a read-only hierarchy and ``~/tmp/`` as a read-write hierarchy.
Following this good practice leads to self-sufficient hierarchies that don't
Following this good practice leads to self-sufficient hierarchies that do not
depend on their location (i.e. parent directories). This is particularly
relevant when we want to allow linking or renaming. Indeed, having consistent
access rights per directory enables to change the location of such directory
without relying on the destination directory access rights (except those that
are required for this operation, see `LANDLOCK_ACCESS_FS_REFER` documentation).
are required for this operation, see ``LANDLOCK_ACCESS_FS_REFER``
documentation).
Having self-sufficient hierarchies also helps to tighten the required access
rights to the minimal set of data. This also helps avoid sinkhole directories,
i.e. directories where data can be linked to but not linked from. However,
Expand Down Expand Up @@ -251,6 +263,24 @@ To be allowed to use :manpage:`ptrace(2)` and related syscalls on a target
process, a sandboxed process should have a subset of the target process rules,
which means the tracee must be in a sub-domain of the tracer.

Truncating files
----------------

The operations covered by ``LANDLOCK_ACCESS_FS_WRITE_FILE`` and
``LANDLOCK_ACCESS_FS_TRUNCATE`` both change the contents of a file and
sometimes overlap in non-intuitive ways. It is recommended to always specify
both of these together.

A particularly surprising example is :manpage:`creat(2)`. The name suggests
that this system call requires the rights to create and write files. However,
it also requires the truncate right if an existing file under the same name is
already present.

It should also be noted that truncating files does not require the
``LANDLOCK_ACCESS_FS_WRITE_FILE`` right. Apart from the :manpage:`truncate(2)`
system call, this can also be done through :manpage:`open(2)` with the flags
``O_RDONLY | O_TRUNC``.

Compatibility
=============

Expand All @@ -259,7 +289,7 @@ Backward and forward compatibility

Landlock is designed to be compatible with past and future versions of the
kernel. This is achieved thanks to the system call attributes and the
associated bitflags, particularly the ruleset's `handled_access_fs`. Making
associated bitflags, particularly the ruleset's ``handled_access_fs``. Making
handled access right explicit enables the kernel and user space to have a clear
contract with each other. This is required to make sure sandboxing will not
get stricter with a system update, which could break applications.
Expand Down Expand Up @@ -380,8 +410,8 @@ by the Documentation/admin-guide/cgroup-v1/memory.rst.
Previous limitations
====================

File renaming and linking (ABI 1)
---------------------------------
File renaming and linking (ABI < 2)
-----------------------------------

Because Landlock targets unprivileged access controls, it needs to properly
handle composition of rules. Such property also implies rules nesting.
Expand All @@ -394,23 +424,32 @@ according to the potentially lost constraints. To protect against privilege
escalations through renaming or linking, and for the sake of simplicity,
Landlock previously limited linking and renaming to the same directory.
Starting with the Landlock ABI version 2, it is now possible to securely
control renaming and linking thanks to the new `LANDLOCK_ACCESS_FS_REFER`
control renaming and linking thanks to the new ``LANDLOCK_ACCESS_FS_REFER``
access right.

File truncation (ABI < 3)
-------------------------

File truncation could not be denied before the third Landlock ABI, so it is
always allowed when using a kernel that only supports the first or second ABI.

Starting with the Landlock ABI version 3, it is now possible to securely control
truncation thanks to the new ``LANDLOCK_ACCESS_FS_TRUNCATE`` access right.

.. _kernel_support:

Kernel support
==============

Landlock was first introduced in Linux 5.13 but it must be configured at build
time with `CONFIG_SECURITY_LANDLOCK=y`. Landlock must also be enabled at boot
time with ``CONFIG_SECURITY_LANDLOCK=y``. Landlock must also be enabled at boot
time as the other security modules. The list of security modules enabled by
default is set with `CONFIG_LSM`. The kernel configuration should then
contains `CONFIG_LSM=landlock,[...]` with `[...]` as the list of other
default is set with ``CONFIG_LSM``. The kernel configuration should then
contains ``CONFIG_LSM=landlock,[...]`` with ``[...]`` as the list of other
potentially useful security modules for the running system (see the
`CONFIG_LSM` help).
``CONFIG_LSM`` help).

If the running kernel doesn't have `landlock` in `CONFIG_LSM`, then we can
If the running kernel does not have ``landlock`` in ``CONFIG_LSM``, then we can
still enable it by adding ``lsm=landlock,[...]`` to
Documentation/admin-guide/kernel-parameters.rst thanks to the bootloader
configuration.
Expand Down
27 changes: 17 additions & 10 deletions include/uapi/linux/landlock.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ struct landlock_ruleset_attr {
* Landlock filesystem access rights that are not part of
* handled_access_fs are allowed. This is needed for backward
* compatibility reasons. One exception is the
* LANDLOCK_ACCESS_FS_REFER access right, which is always implicitly
* %LANDLOCK_ACCESS_FS_REFER access right, which is always implicitly
* handled, but must still be explicitly handled to add new rules with
* this access right.
*/
Expand Down Expand Up @@ -95,8 +95,15 @@ struct landlock_path_beneath_attr {
* A file can only receive these access rights:
*
* - %LANDLOCK_ACCESS_FS_EXECUTE: Execute a file.
* - %LANDLOCK_ACCESS_FS_WRITE_FILE: Open a file with write access.
* - %LANDLOCK_ACCESS_FS_WRITE_FILE: Open a file with write access. Note that
* you might additionally need the `LANDLOCK_ACCESS_FS_TRUNCATE` right in
* order to overwrite files with :manpage:`open(2)` using `O_TRUNC` or
* :manpage:`creat(2)`.
* - %LANDLOCK_ACCESS_FS_READ_FILE: Open a file with read access.
* - %LANDLOCK_ACCESS_FS_TRUNCATE: Truncate a file with :manpage:`truncate(2)`,
* :manpage:`ftruncate(2)`, :manpage:`creat(2)`, or :manpage:`open(2)` with
* `O_TRUNC`. This access right is available since the third version of the
* Landlock ABI.
*
* A directory can receive access rights related to files or directories. The
* following access right is applied to the directory itself, and the
Expand Down Expand Up @@ -128,21 +135,20 @@ struct landlock_path_beneath_attr {
* hierarchy must also always have the same or a superset of restrictions of
* the source hierarchy. If it is not the case, or if the domain doesn't
* handle this access right, such actions are denied by default with errno
* set to EXDEV. Linking also requires a LANDLOCK_ACCESS_FS_MAKE_* access
* right on the destination directory, and renaming also requires a
* LANDLOCK_ACCESS_FS_REMOVE_* access right on the source's (file or
* set to ``EXDEV``. Linking also requires a ``LANDLOCK_ACCESS_FS_MAKE_*``
* access right on the destination directory, and renaming also requires a
* ``LANDLOCK_ACCESS_FS_REMOVE_*`` access right on the source's (file or
* directory) parent. Otherwise, such actions are denied with errno set to
* EACCES. The EACCES errno prevails over EXDEV to let user space
* ``EACCES``. The ``EACCES`` errno prevails over ``EXDEV`` to let user space
* efficiently deal with an unrecoverable error.
*
* .. warning::
*
* It is currently not possible to restrict some file-related actions
* accessible through these syscall families: :manpage:`chdir(2)`,
* :manpage:`truncate(2)`, :manpage:`stat(2)`, :manpage:`flock(2)`,
* :manpage:`chmod(2)`, :manpage:`chown(2)`, :manpage:`setxattr(2)`,
* :manpage:`utime(2)`, :manpage:`ioctl(2)`, :manpage:`fcntl(2)`,
* :manpage:`access(2)`.
* :manpage:`stat(2)`, :manpage:`flock(2)`, :manpage:`chmod(2)`,
* :manpage:`chown(2)`, :manpage:`setxattr(2)`, :manpage:`utime(2)`,
* :manpage:`ioctl(2)`, :manpage:`fcntl(2)`, :manpage:`access(2)`.
* Future Landlock evolutions will enable to restrict them.
*/
/* clang-format off */
Expand All @@ -160,6 +166,7 @@ struct landlock_path_beneath_attr {
#define LANDLOCK_ACCESS_FS_MAKE_BLOCK (1ULL << 11)
#define LANDLOCK_ACCESS_FS_MAKE_SYM (1ULL << 12)
#define LANDLOCK_ACCESS_FS_REFER (1ULL << 13)
#define LANDLOCK_ACCESS_FS_TRUNCATE (1ULL << 14)
/* clang-format on */

#endif /* _UAPI_LINUX_LANDLOCK_H */
47 changes: 37 additions & 10 deletions samples/landlock/sandboxer.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ static int parse_path(char *env_path, const char ***const path_list)
#define ACCESS_FILE ( \
LANDLOCK_ACCESS_FS_EXECUTE | \
LANDLOCK_ACCESS_FS_WRITE_FILE | \
LANDLOCK_ACCESS_FS_READ_FILE)
LANDLOCK_ACCESS_FS_READ_FILE | \
LANDLOCK_ACCESS_FS_TRUNCATE)

/* clang-format on */

Expand Down Expand Up @@ -160,13 +161,13 @@ static int populate_ruleset(const char *const env_var, const int ruleset_fd,
LANDLOCK_ACCESS_FS_MAKE_FIFO | \
LANDLOCK_ACCESS_FS_MAKE_BLOCK | \
LANDLOCK_ACCESS_FS_MAKE_SYM | \
LANDLOCK_ACCESS_FS_REFER)

#define ACCESS_ABI_2 ( \
LANDLOCK_ACCESS_FS_REFER)
LANDLOCK_ACCESS_FS_REFER | \
LANDLOCK_ACCESS_FS_TRUNCATE)

/* clang-format on */

#define LANDLOCK_ABI_LAST 3

int main(const int argc, char *const argv[], char *const *const envp)
{
const char *cmd_path;
Expand Down Expand Up @@ -196,8 +197,12 @@ int main(const int argc, char *const argv[], char *const *const envp)
"\nexample:\n"
"%s=\"/bin:/lib:/usr:/proc:/etc:/dev/urandom\" "
"%s=\"/dev/null:/dev/full:/dev/zero:/dev/pts:/tmp\" "
"%s bash -i\n",
"%s bash -i\n\n",
ENV_FS_RO_NAME, ENV_FS_RW_NAME, argv[0]);
fprintf(stderr,
"This sandboxer can use Landlock features "
"up to ABI version %d.\n",
LANDLOCK_ABI_LAST);
return 1;
}

Expand Down Expand Up @@ -225,12 +230,34 @@ int main(const int argc, char *const argv[], char *const *const envp)
}
return 1;
}

/* Best-effort security. */
if (abi < 2) {
ruleset_attr.handled_access_fs &= ~ACCESS_ABI_2;
access_fs_ro &= ~ACCESS_ABI_2;
access_fs_rw &= ~ACCESS_ABI_2;
switch (abi) {
case 1:
/* Removes LANDLOCK_ACCESS_FS_REFER for ABI < 2 */
ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_REFER;
__attribute__((fallthrough));
case 2:
/* Removes LANDLOCK_ACCESS_FS_TRUNCATE for ABI < 3 */
ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_TRUNCATE;

fprintf(stderr,
"Hint: You should update the running kernel "
"to leverage Landlock features "
"provided by ABI version %d (instead of %d).\n",
LANDLOCK_ABI_LAST, abi);
__attribute__((fallthrough));
case LANDLOCK_ABI_LAST:
break;
default:
fprintf(stderr,
"Hint: You should update this sandboxer "
"to leverage Landlock features "
"provided by ABI version %d (instead of %d).\n",
abi, LANDLOCK_ABI_LAST);
}
access_fs_ro &= ruleset_attr.handled_access_fs;
access_fs_rw &= ruleset_attr.handled_access_fs;

ruleset_fd =
landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0);
Expand Down
11 changes: 9 additions & 2 deletions security/landlock/fs.c
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,8 @@ static struct landlock_object *get_inode_object(struct inode *const inode)
#define ACCESS_FILE ( \
LANDLOCK_ACCESS_FS_EXECUTE | \
LANDLOCK_ACCESS_FS_WRITE_FILE | \
LANDLOCK_ACCESS_FS_READ_FILE)
LANDLOCK_ACCESS_FS_READ_FILE | \
LANDLOCK_ACCESS_FS_TRUNCATE)
/* clang-format on */

/*
Expand Down Expand Up @@ -712,7 +713,7 @@ static inline access_mask_t maybe_remove(const struct dentry *const dentry)
* allowed accesses in @layer_masks_dom.
*
* This is similar to check_access_path_dual() but much simpler because it only
* handles walking on the same mount point and only check one set of accesses.
* handles walking on the same mount point and only checks one set of accesses.
*
* Returns:
* - true if all the domain access rights are allowed for @dir;
Expand Down Expand Up @@ -1142,6 +1143,11 @@ static int hook_path_rmdir(const struct path *const dir,
return current_check_access_path(dir, LANDLOCK_ACCESS_FS_REMOVE_DIR);
}

static int hook_path_truncate(const struct path *const path)
{
return current_check_access_path(path, LANDLOCK_ACCESS_FS_TRUNCATE);
}

/* File hooks */

static inline access_mask_t get_file_access(const struct file *const file)
Expand Down Expand Up @@ -1194,6 +1200,7 @@ static struct security_hook_list landlock_hooks[] __lsm_ro_after_init = {
LSM_HOOK_INIT(path_symlink, hook_path_symlink),
LSM_HOOK_INIT(path_unlink, hook_path_unlink),
LSM_HOOK_INIT(path_rmdir, hook_path_rmdir),
LSM_HOOK_INIT(path_truncate, hook_path_truncate),

LSM_HOOK_INIT(file_open, hook_file_open),
};
Expand Down
2 changes: 1 addition & 1 deletion security/landlock/limits.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
#define LANDLOCK_MAX_NUM_LAYERS 16
#define LANDLOCK_MAX_NUM_RULES U32_MAX

#define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_REFER
#define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_TRUNCATE
#define LANDLOCK_MASK_ACCESS_FS ((LANDLOCK_LAST_ACCESS_FS << 1) - 1)
#define LANDLOCK_NUM_ACCESS_FS __const_hweight64(LANDLOCK_MASK_ACCESS_FS)

Expand Down
Loading

0 comments on commit 6c999ed

Please sign in to comment.