Pull Landlock LSM from James Morris: "Add Landlock, a new LSM from Mickaël Salaün. Briefly, Landlock provides for unprivileged application sandboxing. From Mickaël's cover letter: "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 LSM [1], it makes possible to create safe security sandboxes as new security layers in addition to the existing system-wide access-controls. This kind of sandbox is expected to help mitigate the security impact of bugs or unexpected/malicious behaviors in user-space applications. Landlock empowers any process, including unprivileged ones, to securely restrict themselves. Landlock is inspired by seccomp-bpf but instead of filtering syscalls and their raw arguments, a Landlock rule can restrict the use of kernel objects like file hierarchies, according to the kernel semantic. Landlock also takes inspiration from other OS sandbox mechanisms: XNU Sandbox, FreeBSD Capsicum or OpenBSD Pledge/Unveil. In this current form, Landlock misses some access-control features. This enables to minimize this patch series and ease review. This series still addresses multiple use cases, especially with the combined use of seccomp-bpf: applications with built-in sandboxing, init systems, security sandbox tools and security-oriented APIs [2]" The cover letter and v34 posting is here: https://lore.kernel.org/linux-security-module/20210422154123.13086-1-mic@digikod.net/ See also: https://landlock.io/ This code has had extensive design discussion and review over several years" Link: https://lore.kernel.org/lkml/50db058a-7dde-441b-a7f9-f6837fe8b69f@schaufler-ca.com/ [1] Link: https://lore.kernel.org/lkml/f646e1c7-33cf-333f-070c-0a40ad0468cd@digikod.net/ [2] * tag 'landlock_v34' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris/linux-security: landlock: Enable user space to infer supported features landlock: Add user and kernel documentation samples/landlock: Add a sandbox manager example selftests/landlock: Add user space tests landlock: Add syscall implementations arch: Wire up Landlock syscalls fs,security: Add sb_delete hook landlock: Support filesystem access-control LSM: Infrastructure management of the superblock landlock: Add ptrace restrictions landlock: Set up the security framework and manage credentials landlock: Add ruleset and domain management landlock: Add object management
Showing the changes to Documentation/userspace-api (2 of 72 files). Show all
Unified · Split
| @@ -18,6 +18,7 @@ place where this information is gathered. · 17 unmodified lines | |||
| 18 | 18 | ||
| 19 | no_new_privs | 19 | no_new_privs |
| 20 | seccomp_filter | 20 | seccomp_filter |
| 21 | landlock | ||
| 21 | unshare | 22 | unshare |
| 22 | spec_ctrl | 23 | spec_ctrl |
| 23 | accelerators/ocxl | 24 | accelerators/ocxl |
| @@ -0,0 +1,311 @@ | |||
| 1 | .. SPDX-License-Identifier: GPL-2.0 | ||
| 2 | .. Copyright © 2017-2020 Mickaël Salaün <mic@digikod.net> | ||
| 3 | .. Copyright © 2019-2020 ANSSI | ||
| 4 | .. Copyright © 2021 Microsoft Corporation | ||
| 5 | |||
| 6 | ===================================== | ||
| 7 | Landlock: unprivileged access control | ||
| 8 | ===================================== | ||
| 9 | |||
| 10 | :Author: Mickaël Salaün | ||
| 11 | :Date: March 2021 | ||
| 12 | |||
| 13 | The goal of Landlock is to enable to restrict ambient rights (e.g. global | ||
| 14 | filesystem access) for a set of processes. Because Landlock is a stackable | ||
| 15 | LSM, it makes possible to create safe security sandboxes as new security layers | ||
| 16 | in addition to the existing system-wide access-controls. This kind of sandbox | ||
| 17 | is expected to help mitigate the security impact of bugs or | ||
| 18 | unexpected/malicious behaviors in user space applications. Landlock empowers | ||
| 19 | any process, including unprivileged ones, to securely restrict themselves. | ||
| 20 | |||
| 21 | Landlock rules | ||
| 22 | ============== | ||
| 23 | |||
| 24 | A Landlock rule describes an action on an object. An object is currently a | ||
| 25 | file hierarchy, and the related filesystem actions are defined with `access | ||
| 26 | rights`_. A set of rules is aggregated in a ruleset, which can then restrict | ||
| 27 | the thread enforcing it, and its future children. | ||
| 28 | |||
| 29 | Defining and enforcing a security policy | ||
| 30 | ---------------------------------------- | ||
| 31 | |||
| 32 | We first need to create the ruleset that will contain our rules. For this | ||
| 33 | example, the ruleset will contain rules that only allow read actions, but write | ||
| 34 | actions will be denied. The ruleset then needs to handle both of these kind of | ||
| 35 | actions. | ||
| 36 | |||
| 37 | .. code-block:: c | ||
| 38 | |||
| 39 | int ruleset_fd; | ||
| 40 | struct landlock_ruleset_attr ruleset_attr = { | ||
| 41 | .handled_access_fs = | ||
| 42 | LANDLOCK_ACCESS_FS_EXECUTE | | ||
| 43 | LANDLOCK_ACCESS_FS_WRITE_FILE | | ||
| 44 | LANDLOCK_ACCESS_FS_READ_FILE | | ||
| 45 | LANDLOCK_ACCESS_FS_READ_DIR | | ||
| 46 | LANDLOCK_ACCESS_FS_REMOVE_DIR | | ||
| 47 | LANDLOCK_ACCESS_FS_REMOVE_FILE | | ||
| 48 | LANDLOCK_ACCESS_FS_MAKE_CHAR | | ||
| 49 | LANDLOCK_ACCESS_FS_MAKE_DIR | | ||
| 50 | LANDLOCK_ACCESS_FS_MAKE_REG | | ||
| 51 | LANDLOCK_ACCESS_FS_MAKE_SOCK | | ||
| 52 | LANDLOCK_ACCESS_FS_MAKE_FIFO | | ||
| 53 | LANDLOCK_ACCESS_FS_MAKE_BLOCK | | ||
| 54 | LANDLOCK_ACCESS_FS_MAKE_SYM, | ||
| 55 | }; | ||
| 56 | |||
| 57 | ruleset_fd = landlock_create_ruleset(&ruleset_attr, sizeof(ruleset_attr), 0); | ||
| 58 | if (ruleset_fd < 0) { | ||
| 59 | perror("Failed to create a ruleset"); | ||
| 60 | return 1; | ||
| 61 | } | ||
| 62 | |||
| 63 | We can now add a new rule to this ruleset thanks to the returned file | ||
| 64 | descriptor referring to this ruleset. The rule will only allow reading the | ||
| 65 | file hierarchy ``/usr``. Without another rule, write actions would then be | ||
| 66 | denied by the ruleset. To add ``/usr`` to the ruleset, we open it with the | ||
| 67 | ``O_PATH`` flag and fill the &struct landlock_path_beneath_attr with this file | ||
| 68 | descriptor. | ||
| 69 | |||
| 70 | .. code-block:: c | ||
| 71 | |||
| 72 | int err; | ||
| 73 | struct landlock_path_beneath_attr path_beneath = { | ||
| 74 | .allowed_access = | ||
| 75 | LANDLOCK_ACCESS_FS_EXECUTE | | ||
| 76 | LANDLOCK_ACCESS_FS_READ_FILE | | ||
| 77 | LANDLOCK_ACCESS_FS_READ_DIR, | ||
| 78 | }; | ||
| 79 | |||
| 80 | path_beneath.parent_fd = open("/usr", O_PATH | O_CLOEXEC); | ||
| 81 | if (path_beneath.parent_fd < 0) { | ||
| 82 | perror("Failed to open file"); | ||
| 83 | close(ruleset_fd); | ||
| 84 | return 1; | ||
| 85 | } | ||
| 86 | err = landlock_add_rule(ruleset_fd, LANDLOCK_RULE_PATH_BENEATH, | ||
| 87 | &path_beneath, 0); | ||
| 88 | close(path_beneath.parent_fd); | ||
| 89 | if (err) { | ||
| 90 | perror("Failed to update ruleset"); | ||
| 91 | close(ruleset_fd); | ||
| 92 | return 1; | ||
| 93 | } | ||
| 94 | |||
| 95 | We now have a ruleset with one rule allowing read access to ``/usr`` while | ||
| 96 | denying all other handled accesses for the filesystem. The next step is to | ||
| 97 | restrict the current thread from gaining more privileges (e.g. thanks to a SUID | ||
| 98 | binary). | ||
| 99 | |||
| 100 | .. code-block:: c | ||
| 101 | |||
| 102 | if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0)) { | ||
| 103 | perror("Failed to restrict privileges"); | ||
| 104 | close(ruleset_fd); | ||
| 105 | return 1; | ||
| 106 | } | ||
| 107 | |||
| 108 | The current thread is now ready to sandbox itself with the ruleset. | ||
| 109 | |||
| 110 | .. code-block:: c | ||
| 111 | |||
| 112 | if (landlock_restrict_self(ruleset_fd, 0)) { | ||
| 113 | perror("Failed to enforce ruleset"); | ||
| 114 | close(ruleset_fd); | ||
| 115 | return 1; | ||
| 116 | } | ||
| 117 | close(ruleset_fd); | ||
| 118 | |||
| 119 | If the `landlock_restrict_self` system call succeeds, the current thread is now | ||
| 120 | restricted and this policy will be enforced on all its subsequently created | ||
| 121 | children as well. Once a thread is landlocked, there is no way to remove its | ||
| 122 | security policy; only adding more restrictions is allowed. These threads are | ||
| 123 | now in a new Landlock domain, merge of their parent one (if any) with the new | ||
| 124 | ruleset. | ||
| 125 | |||
| 126 | Full working code can be found in `samples/landlock/sandboxer.c`_. | ||
| 127 | |||
| 128 | Layers of file path access rights | ||
| 129 | --------------------------------- | ||
| 130 | |||
| 131 | Each time a thread enforces a ruleset on itself, it updates its Landlock domain | ||
| 132 | with a new layer of policy. Indeed, this complementary policy is stacked with | ||
| 133 | the potentially other rulesets already restricting this thread. A sandboxed | ||
| 134 | thread can then safely add more constraints to itself with a new enforced | ||
| 135 | ruleset. | ||
| 136 | |||
| 137 | One policy layer grants access to a file path if at least one of its rules | ||
| 138 | encountered on the path grants the access. A sandboxed thread can only access | ||
| 139 | a file path if all its enforced policy layers grant the access as well as all | ||
| 140 | the other system access controls (e.g. filesystem DAC, other LSM policies, | ||
| 141 | etc.). | ||
| 142 | |||
| 143 | Bind mounts and OverlayFS | ||
| 144 | ------------------------- | ||
| 145 | |||
| 146 | Landlock enables to restrict access to file hierarchies, which means that these | ||
| 147 | access rights can be propagated with bind mounts (cf. | ||
| 148 | :doc:`/filesystems/sharedsubtree`) but not with :doc:`/filesystems/overlayfs`. | ||
| 149 | |||
| 150 | A bind mount mirrors a source file hierarchy to a destination. The destination | ||
| 151 | hierarchy is then composed of the exact same files, on which Landlock rules can | ||
| 152 | be tied, either via the source or the destination path. These rules restrict | ||
| 153 | access when they are encountered on a path, which means that they can restrict | ||
| 154 | access to multiple file hierarchies at the same time, whether these hierarchies | ||
| 155 | are the result of bind mounts or not. | ||
| 156 | |||
| 157 | An OverlayFS mount point consists of upper and lower layers. These layers are | ||
| 158 | combined in a merge directory, result of the mount point. This merge hierarchy | ||
| 159 | may include files from the upper and lower layers, but modifications performed | ||
| 160 | on the merge hierarchy only reflects on the upper layer. From a Landlock | ||
| 161 | policy point of view, each OverlayFS layers and merge hierarchies are | ||
| 162 | standalone and contains their own set of files and directories, which is | ||
| 163 | different from bind mounts. A policy restricting an OverlayFS layer will not | ||
| 164 | restrict the resulted merged hierarchy, and vice versa. Landlock users should | ||
| 165 | then only think about file hierarchies they want to allow access to, regardless | ||
| 166 | of the underlying filesystem. | ||
| 167 | |||
| 168 | Inheritance | ||
| 169 | ----------- | ||
| 170 | |||
| 171 | Every new thread resulting from a :manpage:`clone(2)` inherits Landlock domain | ||
| 172 | restrictions from its parent. This is similar to the seccomp inheritance (cf. | ||
| 173 | :doc:`/userspace-api/seccomp_filter`) or any other LSM dealing with task's | ||
| 174 | :manpage:`credentials(7)`. For instance, one process's thread may apply | ||
| 175 | Landlock rules to itself, but they will not be automatically applied to other | ||
| 176 | sibling threads (unlike POSIX thread credential changes, cf. | ||
| 177 | :manpage:`nptl(7)`). | ||
| 178 | |||
| 179 | When a thread sandboxes itself, we have the guarantee that the related security | ||
| 180 | policy will stay enforced on all this thread's descendants. This allows | ||
| 181 | creating standalone and modular security policies per application, which will | ||
| 182 | automatically be composed between themselves according to their runtime parent | ||
| 183 | policies. | ||
| 184 | |||
| 185 | Ptrace restrictions | ||
| 186 | ------------------- | ||
| 187 | |||
| 188 | A sandboxed process has less privileges than a non-sandboxed process and must | ||
| 189 | then be subject to additional restrictions when manipulating another process. | ||
| 190 | To be allowed to use :manpage:`ptrace(2)` and related syscalls on a target | ||
| 191 | process, a sandboxed process should have a subset of the target process rules, | ||
| 192 | which means the tracee must be in a sub-domain of the tracer. | ||
| 193 | |||
| 194 | Kernel interface | ||
| 195 | ================ | ||
| 196 | |||
| 197 | Access rights | ||
| 198 | ------------- | ||
| 199 | |||
| 200 | .. kernel-doc:: include/uapi/linux/landlock.h | ||
| 201 | :identifiers: fs_access | ||
| 202 | |||
| 203 | Creating a new ruleset | ||
| 204 | ---------------------- | ||
| 205 | |||
| 206 | .. kernel-doc:: security/landlock/syscalls.c | ||
| 207 | :identifiers: sys_landlock_create_ruleset | ||
| 208 | |||
| 209 | .. kernel-doc:: include/uapi/linux/landlock.h | ||
| 210 | :identifiers: landlock_ruleset_attr | ||
| 211 | |||
| 212 | Extending a ruleset | ||
| 213 | ------------------- | ||
| 214 | |||
| 215 | .. kernel-doc:: security/landlock/syscalls.c | ||
| 216 | :identifiers: sys_landlock_add_rule | ||
| 217 | |||
| 218 | .. kernel-doc:: include/uapi/linux/landlock.h | ||
| 219 | :identifiers: landlock_rule_type landlock_path_beneath_attr | ||
| 220 | |||
| 221 | Enforcing a ruleset | ||
| 222 | ------------------- | ||
| 223 | |||
| 224 | .. kernel-doc:: security/landlock/syscalls.c | ||
| 225 | :identifiers: sys_landlock_restrict_self | ||
| 226 | |||
| 227 | Current limitations | ||
| 228 | =================== | ||
| 229 | |||
| 230 | File renaming and linking | ||
| 231 | ------------------------- | ||
| 232 | |||
| 233 | Because Landlock targets unprivileged access controls, it is needed to properly | ||
| 234 | handle composition of rules. Such property also implies rules nesting. | ||
| 235 | Properly handling multiple layers of ruleset, each one of them able to restrict | ||
| 236 | access to files, also implies to inherit the ruleset restrictions from a parent | ||
| 237 | to its hierarchy. Because files are identified and restricted by their | ||
| 238 | hierarchy, moving or linking a file from one directory to another implies to | ||
| 239 | propagate the hierarchy constraints. To protect against privilege escalations | ||
| 240 | through renaming or linking, and for the sake of simplicity, Landlock currently | ||
| 241 | limits linking and renaming to the same directory. Future Landlock evolutions | ||
| 242 | will enable more flexibility for renaming and linking, with dedicated ruleset | ||
| 243 | flags. | ||
| 244 | |||
| 245 | Filesystem topology modification | ||
| 246 | -------------------------------- | ||
| 247 | |||
| 248 | As for file renaming and linking, a sandboxed thread cannot modify its | ||
| 249 | filesystem topology, whether via :manpage:`mount(2)` or | ||
| 250 | :manpage:`pivot_root(2)`. However, :manpage:`chroot(2)` calls are not denied. | ||
| 251 | |||
| 252 | Special filesystems | ||
| 253 | ------------------- | ||
| 254 | |||
| 255 | Access to regular files and directories can be restricted by Landlock, | ||
| 256 | according to the handled accesses of a ruleset. However, files that do not | ||
| 257 | come from a user-visible filesystem (e.g. pipe, socket), but can still be | ||
| 258 | accessed through ``/proc/<pid>/fd/*``, cannot currently be explicitly | ||
| 259 | restricted. Likewise, some special kernel filesystems such as nsfs, which can | ||
| 260 | be accessed through ``/proc/<pid>/ns/*``, cannot currently be explicitly | ||
| 261 | restricted. However, thanks to the `ptrace restrictions`_, access to such | ||
| 262 | sensitive ``/proc`` files are automatically restricted according to domain | ||
| 263 | hierarchies. Future Landlock evolutions could still enable to explicitly | ||
| 264 | restrict such paths with dedicated ruleset flags. | ||
| 265 | |||
| 266 | Ruleset layers | ||
| 267 | -------------- | ||
| 268 | |||
| 269 | There is a limit of 64 layers of stacked rulesets. This can be an issue for a | ||
| 270 | task willing to enforce a new ruleset in complement to its 64 inherited | ||
| 271 | rulesets. Once this limit is reached, sys_landlock_restrict_self() returns | ||
| 272 | E2BIG. It is then strongly suggested to carefully build rulesets once in the | ||
| 273 | life of a thread, especially for applications able to launch other applications | ||
| 274 | that may also want to sandbox themselves (e.g. shells, container managers, | ||
| 275 | etc.). | ||
| 276 | |||
| 277 | Memory usage | ||
| 278 | ------------ | ||
| 279 | |||
| 280 | Kernel memory allocated to create rulesets is accounted and can be restricted | ||
| 281 | by the :doc:`/admin-guide/cgroup-v1/memory`. | ||
| 282 | |||
| 283 | Questions and answers | ||
| 284 | ===================== | ||
| 285 | |||
| 286 | What about user space sandbox managers? | ||
| 287 | --------------------------------------- | ||
| 288 | |||
| 289 | Using user space process to enforce restrictions on kernel resources can lead | ||
| 290 | to race conditions or inconsistent evaluations (i.e. `Incorrect mirroring of | ||
| 291 | the OS code and state | ||
| 292 | <https://www.ndss-symposium.org/ndss2003/traps-and-pitfalls-practical-problems-system-call-interposition-based-security-tools/>`_). | ||
| 293 | |||
| 294 | What about namespaces and containers? | ||
| 295 | ------------------------------------- | ||
| 296 | |||
| 297 | Namespaces can help create sandboxes but they are not designed for | ||
| 298 | access-control and then miss useful features for such use case (e.g. no | ||
| 299 | fine-grained restrictions). Moreover, their complexity can lead to security | ||
| 300 | issues, especially when untrusted processes can manipulate them (cf. | ||
| 301 | `Controlling access to user namespaces <https://lwn.net/Articles/673597/>`_). | ||
| 302 | |||
| 303 | Additional documentation | ||
| 304 | ======================== | ||
| 305 | |||
| 306 | * :doc:`/security/landlock` | ||
| 307 | * https://landlock.io | ||
| 308 | |||
| 309 | .. Links | ||
| 310 | .. _samples/landlock/sandboxer.c: | ||
| 311 | https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/tree/samples/landlock/sandboxer.c | ||