From patchwork Fri Nov 3 15:57:11 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?G=C3=BCnther_Noack?= X-Patchwork-Id: 13444636 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 51B3AC4167B for ; Fri, 3 Nov 2023 15:57:39 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S230110AbjKCP5k (ORCPT ); Fri, 3 Nov 2023 11:57:40 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34316 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230175AbjKCP5j (ORCPT ); Fri, 3 Nov 2023 11:57:39 -0400 Received: from mail-ed1-x54a.google.com (mail-ed1-x54a.google.com [IPv6:2a00:1450:4864:20::54a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id D7F63D4E for ; Fri, 3 Nov 2023 08:57:36 -0700 (PDT) Received: by mail-ed1-x54a.google.com with SMTP id 4fb4d7f45d1cf-5411a36a37fso2719538a12.0 for ; Fri, 03 Nov 2023 08:57:36 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1699027055; x=1699631855; darn=vger.kernel.org; h=content-transfer-encoding:cc:to:from:subject:references :mime-version:message-id:in-reply-to:date:from:to:cc:subject:date :message-id:reply-to; bh=s6BXobpp4sPDST4BqTcqb5616NyPMhrIjRqGtfUtN18=; b=Dt3Yl9HCsrU4amyJChUBftK0tRbst+rdHzunPbnYQ3/XGSMcbTu7HvW+HSoLuvQhV4 NgrPRGJvpbIDJpmObu30fwrJ1E408u2qLDpjXZa55JFlNQl6fm89IBxb+/hCUtknQzbT p6mTdvMs/yz04Fpp9qQ4+KO2nelZOaB59Rs0jrvZ8My7epn6yDmLqB8HrykwEEopUArU HRBCxXwc2rKrxJYVgsM3O4mDGCFuEN6IpKQEAn+m+0XNQj0JBv8YHF++hNFLaedJGzPb v9UBbA7trUJn9uhpoK+nM0bgWHJSpySMpRh3ZOy0oLW0sEHAAgujwvLpONx254ip3jW4 j9ug== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1699027055; x=1699631855; h=content-transfer-encoding:cc:to:from:subject:references :mime-version:message-id:in-reply-to:date:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=s6BXobpp4sPDST4BqTcqb5616NyPMhrIjRqGtfUtN18=; b=qIsyLvr0ms3HG3IeuNawZe5jPoE2Azn3IXCyLTLr1L5AxdMf8inqmbaDn5XNGDKqxf j6wqT6k5qNeGBmzD4D+lIFfhigMULOtHKtfRXvblJbgHJ6UhrQWsko2+iYhLx8gSkOMG iMSkX9/1uxSxNW70DQyThdcZeCqTOya8xMtUNLGVw4wrC4DB/+fFI7uZR4TCMILrPOBX 6EWvTm7I5y+FMQ2y0G3DrDTRv/nl+4x+4klotIudJOMVfSx5M2XfVSHKwePbZEsehRkM i93YQ/h+b+Xyj64fCHm8zvV5uX+VA8exWL8SrI6RuVxAhp3eHqxpFyjaToMCjxlQsE78 aWXQ== X-Gm-Message-State: AOJu0YwaWjs/ZyZhHqrz8j36bovMGIlWlqD8ciuPhhZuYXaLXaVBvMIa M4DCisfgItncPQ4t/lxluoCH8YRPyWHd3xgsphb2CygZMHHGaZwPaBu2gim0ig6SekFDK0irU0h VK21VPieRef/A6Wj3gfTlzQ5O1rBc9ebMOyILiAMNkGugEvutMFOMCBfoAFujtJOg+6ZNhJSh7h 7bMmIh+Q== X-Google-Smtp-Source: AGHT+IH3Zh4iRAyCpfHS5ZF+J3OqKDW0BOVI3/9VrmNUI86MZogwKLyG6Lha7P7zVEEk42aQQZEi3QTPqkQ= X-Received: from sport.zrh.corp.google.com ([2a00:79e0:9d:4:7ddd:bc72:7a4a:ba94]) (user=gnoack job=sendgmr) by 2002:aa7:ce03:0:b0:53d:ad8a:b0bd with SMTP id d3-20020aa7ce03000000b0053dad8ab0bdmr36531edv.3.1699027055268; Fri, 03 Nov 2023 08:57:35 -0700 (PDT) Date: Fri, 3 Nov 2023 16:57:11 +0100 In-Reply-To: <20231103155717.78042-1-gnoack@google.com> Message-Id: <20231103155717.78042-2-gnoack@google.com> Mime-Version: 1.0 References: <20231103155717.78042-1-gnoack@google.com> X-Mailer: git-send-email 2.42.0.869.gea05f2083d-goog Subject: [PATCH v4 1/7] landlock: Optimize the number of calls to get_access_mask slightly From: " =?utf-8?q?G=C3=BCnther_Noack?= " To: linux-security-module@vger.kernel.org, " =?utf-8?q?Micka=C3=ABl_Sala?= =?utf-8?q?=C3=BCn?= " Cc: Jeff Xu , Jorge Lucangeli Obes , Allen Webb , Dmitry Torokhov , Paul Moore , Konstantin Meskhidze , Matt Bobrowski , linux-fsdevel@vger.kernel.org, " =?utf-8?q?G=C3=BCnther_Noack?= " Precedence: bulk List-ID: This call is now going through a function pointer, and it is not as obvious any more that it will be inlined. Signed-off-by: Günther Noack --- security/landlock/ruleset.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/security/landlock/ruleset.c b/security/landlock/ruleset.c index ffedc99f2b68..fd348633281c 100644 --- a/security/landlock/ruleset.c +++ b/security/landlock/ruleset.c @@ -724,10 +724,11 @@ landlock_init_layer_masks(const struct landlock_ruleset *const domain, for (layer_level = 0; layer_level < domain->num_layers; layer_level++) { const unsigned long access_req = access_request; unsigned long access_bit; + access_mask_t access_mask = + get_access_mask(domain, layer_level); for_each_set_bit(access_bit, &access_req, num_access) { - if (BIT_ULL(access_bit) & - get_access_mask(domain, layer_level)) { + if (BIT_ULL(access_bit) & access_mask) { (*layer_masks)[access_bit] |= BIT_ULL(layer_level); handled_accesses |= BIT_ULL(access_bit); From patchwork Fri Nov 3 15:57:12 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?G=C3=BCnther_Noack?= X-Patchwork-Id: 13444638 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5B437C4167B for ; Fri, 3 Nov 2023 15:57:44 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S234309AbjKCP5p (ORCPT ); Fri, 3 Nov 2023 11:57:45 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34330 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S230175AbjKCP5o (ORCPT ); Fri, 3 Nov 2023 11:57:44 -0400 Received: from mail-yw1-x114a.google.com (mail-yw1-x114a.google.com [IPv6:2607:f8b0:4864:20::114a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 9F2AE111 for ; Fri, 3 Nov 2023 08:57:39 -0700 (PDT) Received: by mail-yw1-x114a.google.com with SMTP id 00721157ae682-5a7bbe0a453so29711187b3.0 for ; Fri, 03 Nov 2023 08:57:39 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1699027059; x=1699631859; darn=vger.kernel.org; h=content-transfer-encoding:cc:to:from:subject:references :mime-version:message-id:in-reply-to:date:from:to:cc:subject:date :message-id:reply-to; bh=YzeG8MD6N/WIiNo2un1jd4u7MnqtipFegLOFtiVvH70=; b=uG+FOPctAUXbv4g8jFz5DdPu2l4pCk1sYKH2m8tbJtAXuYacg77ixV4uJpNHSZVIh1 m66kY+9cdZW8dopmOmlFVhY0WlWsb9bA/Mj2MXnjcPq+pNI1VIcsmKiomU/t2gour9vT 6GvXLFfVkZjx1bsSPpBS1y9rGkJ62D283t3dS4DR2ulHBopLha0ViKDeAPL/14T3v/gS 5+2LI3tGtEDK8KH07XgGooKzLLjd/qVkI7A3oV2qfWOlMmXAodgoHO56gvD3suYeadSU 0nXdyOAMwb8H0RH0Uaz2o3c/YK+eMkmzJxGDPotr3TL8ZI3dbV69Am51gdZGcD5crtQD AfBw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1699027059; x=1699631859; h=content-transfer-encoding:cc:to:from:subject:references :mime-version:message-id:in-reply-to:date:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=YzeG8MD6N/WIiNo2un1jd4u7MnqtipFegLOFtiVvH70=; b=F6UWkal9TYR+t9RUZ+H65NjVzn8u4lj8ESVagGDoMi9fUzs0h9JDj59p74VLiSPaHW vuJXlXvQYR2jqUR4v/Aw5XBiylVSuIpeMm6HVwdr/iw+aE9FJw2SXWVzX+CQIyeeBmeY VXHK5pLJIAK4TSJQNxxQBmDkoUN3BZfZGGIDtHTeZHKK3tWa95rzmGW0E4o2fYqQ96CW clGyynvppZChuJjGYVjVcz3CGf64tFx4I/ImPe0hHhOP3qz4rBzzqPrwdTbNuvnz9wPR l1gjxa5eWnU8wSb0lu6kw/JoFTiBLtgdZmH0gfgxngFgOcRU2NoLnCD/G/1Q30Y4zETY PCLw== X-Gm-Message-State: AOJu0YxoFGG0SICj4fQ+g5j0IFlCUbnfcwXTGpG+c+sSWVdU/u/JRAl6 LKf0XYa9/kwNXidhZKCC4Hy+todemuv+k1vsA97LFVhd7DxmhRshUEtY10dAc1MafkJxJ8LWtNr w1gKCQB3FZQQnzocym6Ti+vULLzkhhMiX0f8uyAe9DJJVrBXrDLmdDaCNFPszBMJLTbCWfUByPN +Vdj4gDQ== X-Google-Smtp-Source: AGHT+IHatHk6FCkLf0/gKhX7MmgaJIXF9vcEUQCbXwS3+kxJowRhTAmJrZ4arZPoE7gD35Im8qCFMLJy8xE= X-Received: from sport.zrh.corp.google.com ([2a00:79e0:9d:4:7ddd:bc72:7a4a:ba94]) (user=gnoack job=sendgmr) by 2002:a81:5215:0:b0:5a7:acc1:5142 with SMTP id g21-20020a815215000000b005a7acc15142mr61937ywb.8.1699027058095; Fri, 03 Nov 2023 08:57:38 -0700 (PDT) Date: Fri, 3 Nov 2023 16:57:12 +0100 In-Reply-To: <20231103155717.78042-1-gnoack@google.com> Message-Id: <20231103155717.78042-3-gnoack@google.com> Mime-Version: 1.0 References: <20231103155717.78042-1-gnoack@google.com> X-Mailer: git-send-email 2.42.0.869.gea05f2083d-goog Subject: [PATCH v4 2/7] landlock: Add IOCTL access right From: " =?utf-8?q?G=C3=BCnther_Noack?= " To: linux-security-module@vger.kernel.org, " =?utf-8?q?Micka=C3=ABl_Sala?= =?utf-8?q?=C3=BCn?= " Cc: Jeff Xu , Jorge Lucangeli Obes , Allen Webb , Dmitry Torokhov , Paul Moore , Konstantin Meskhidze , Matt Bobrowski , linux-fsdevel@vger.kernel.org, " =?utf-8?q?G=C3=BCnther_Noack?= " Precedence: bulk List-ID: Introduces the LANDLOCK_ACCESS_FS_IOCTL access right and increments the Landlock ABI version to 5. Like the truncate right, these rights are associated with a file descriptor at the time of open(2), and get respected even when the file descriptor is used outside of the thread which it was originally opened in. A newly enabled Landlock policy therefore does not apply to file descriptors which are already open. If the LANDLOCK_ACCESS_FS_IOCTL right is handled, only a small number of safe IOCTL commands will be permitted on newly opened files. The permitted IOCTLs can be configured through the ruleset in limited ways now. (See documentation for details.) Noteworthy scenarios which require special attention: TTY devices support IOCTLs like TIOCSTI and TIOCLINUX, which can be used to control shell processes on the same terminal which run at different privilege levels, which may make it possible to escape a sandbox. Because stdin, stdout and stderr are normally inherited rather than newly opened, IOCTLs are usually permitted on them even after the Landlock policy is enforced. Some legitimate file system features, like setting up fscrypt, are exposed as IOCTL commands on regular files and directories -- users of Landlock are advised to double check that the sandboxed process does not need to invoke these IOCTLs. Known limitations: The LANDLOCK_ACCESS_FS_IOCTL access right is a coarse-grained control over IOCTL commands. Future work will enable a more fine-grained access control for IOCTLs. In the meantime, Landlock users may use path-based restrictions in combination with their knowledge about the file system layout to control what IOCTLs can be done. Mounting file systems with the nodev option can help to distinguish regular files and devices, and give guarantees about the affected files, which Landlock alone can not give yet. Signed-off-by: Günther Noack --- include/uapi/linux/landlock.h | 31 +++++--- security/landlock/fs.c | 74 ++++++++++++++++++-- security/landlock/limits.h | 10 ++- security/landlock/ruleset.h | 53 +++++++++++++- security/landlock/syscalls.c | 6 +- tools/testing/selftests/landlock/base_test.c | 2 +- tools/testing/selftests/landlock/fs_test.c | 5 +- 7 files changed, 161 insertions(+), 20 deletions(-) diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h index 25c8d7677539..6d41c059e910 100644 --- a/include/uapi/linux/landlock.h +++ b/include/uapi/linux/landlock.h @@ -128,7 +128,7 @@ struct landlock_net_port_attr { * files and directories. Files or directories opened before the sandboxing * are not subject to these restrictions. * - * A file can only receive these access rights: + * The following access rights apply only to files: * * - %LANDLOCK_ACCESS_FS_EXECUTE: Execute a file. * - %LANDLOCK_ACCESS_FS_WRITE_FILE: Open a file with write access. Note that @@ -138,12 +138,13 @@ struct landlock_net_port_attr { * - %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``. Whether an opened file can be truncated with - * :manpage:`ftruncate(2)` is determined during :manpage:`open(2)`, in the - * same way as read and write permissions are checked during - * :manpage:`open(2)` using %LANDLOCK_ACCESS_FS_READ_FILE and - * %LANDLOCK_ACCESS_FS_WRITE_FILE. This access right is available since the - * third version of the Landlock ABI. + * ``O_TRUNC``. This access right is available since the third version of the + * Landlock ABI. + * + * Whether an opened file can be truncated with :manpage:`ftruncate(2)` or used + * with `ioctl(2)` is determined during :manpage:`open(2)`, in the same way as + * read and write permissions are checked during :manpage:`open(2)` using + * %LANDLOCK_ACCESS_FS_READ_FILE and %LANDLOCK_ACCESS_FS_WRITE_FILE. * * A directory can receive access rights related to files or directories. The * following access right is applied to the directory itself, and the @@ -198,13 +199,26 @@ struct landlock_net_port_attr { * If multiple requirements are not met, the ``EACCES`` error code takes * precedence over ``EXDEV``. * + * The following access right applies both to files and directories: + * + * - %LANDLOCK_ACCESS_FS_IOCTL: Invoke :manpage:`ioctl(2)` commands on an opened + * file or directory. + * + * This access right applies to all :manpage:`ioctl(2)` commands, except of + * ``FIOCLEX``, ``FIONCLEX``, ``FIONBIO``, ``FIOASYNC`` and ``FIONREAD``. + * These commands continue to be invokable independent of the + * %LANDLOCK_ACCESS_FS_IOCTL access right. + * + * This access right is available since the fourth version of the Landlock + * ABI. + * * .. warning:: * * It is currently not possible to restrict some file-related actions * accessible through these syscall families: :manpage:`chdir(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:`fcntl(2)`, :manpage:`access(2)`. * Future Landlock evolutions will enable to restrict them. */ /* clang-format off */ @@ -223,6 +237,7 @@ struct landlock_net_port_attr { #define LANDLOCK_ACCESS_FS_MAKE_SYM (1ULL << 12) #define LANDLOCK_ACCESS_FS_REFER (1ULL << 13) #define LANDLOCK_ACCESS_FS_TRUNCATE (1ULL << 14) +#define LANDLOCK_ACCESS_FS_IOCTL (1ULL << 15) /* clang-format on */ /** diff --git a/security/landlock/fs.c b/security/landlock/fs.c index bc7c126deea2..aa54970c235f 100644 --- a/security/landlock/fs.c +++ b/security/landlock/fs.c @@ -7,12 +7,14 @@ * Copyright © 2021-2022 Microsoft Corporation */ +#include #include #include #include #include #include #include +#include #include #include #include @@ -28,6 +30,7 @@ #include #include #include +#include #include #include "common.h" @@ -147,7 +150,8 @@ static struct landlock_object *get_inode_object(struct inode *const inode) LANDLOCK_ACCESS_FS_EXECUTE | \ LANDLOCK_ACCESS_FS_WRITE_FILE | \ LANDLOCK_ACCESS_FS_READ_FILE | \ - LANDLOCK_ACCESS_FS_TRUNCATE) + LANDLOCK_ACCESS_FS_TRUNCATE | \ + LANDLOCK_ACCESS_FS_IOCTL) /* clang-format on */ /* @@ -157,6 +161,7 @@ int landlock_append_fs_rule(struct landlock_ruleset *const ruleset, const struct path *const path, access_mask_t access_rights) { + access_mask_t handled; int err; struct landlock_id id = { .type = LANDLOCK_KEY_INODE, @@ -169,9 +174,11 @@ int landlock_append_fs_rule(struct landlock_ruleset *const ruleset, if (WARN_ON_ONCE(ruleset->num_layers != 1)) return -EINVAL; + handled = landlock_get_fs_access_mask(ruleset, 0); + /* Expands the synthetic IOCTL groups. */ + access_rights |= expand_all_ioctl(handled, access_rights); /* Transforms relative access rights to absolute ones. */ - access_rights |= LANDLOCK_MASK_ACCESS_FS & - ~landlock_get_fs_access_mask(ruleset, 0); + access_rights |= LANDLOCK_MASK_ACCESS_FS & ~handled; id.key.object = get_inode_object(d_backing_inode(path->dentry)); if (IS_ERR(id.key.object)) return PTR_ERR(id.key.object); @@ -1123,7 +1130,9 @@ static int hook_file_open(struct file *const file) { layer_mask_t layer_masks[LANDLOCK_NUM_ACCESS_FS] = {}; access_mask_t open_access_request, full_access_request, allowed_access; - const access_mask_t optional_access = LANDLOCK_ACCESS_FS_TRUNCATE; + const access_mask_t optional_access = + LANDLOCK_ACCESS_FS_TRUNCATE | LANDLOCK_ACCESS_FS_IOCTL | + IOCTL_CMD_G1 | IOCTL_CMD_G2 | IOCTL_CMD_G3 | IOCTL_CMD_G4; const struct landlock_ruleset *const dom = get_current_fs_domain(); if (!dom) @@ -1196,6 +1205,62 @@ static int hook_file_truncate(struct file *const file) return -EACCES; } +static access_mask_t required_ioctl_access(unsigned int cmd) +{ + switch (cmd) { + case FIOQSIZE: + return IOCTL_CMD_G1; + case FS_IOC_FIEMAP: + case FIBMAP: + case FIGETBSZ: + return IOCTL_CMD_G2; + case FIONREAD: + case FIDEDUPERANGE: + return IOCTL_CMD_G3; + case FICLONE: + case FICLONERANGE: + case FS_IOC_RESVSP: + case FS_IOC_RESVSP64: + case FS_IOC_UNRESVSP: + case FS_IOC_UNRESVSP64: + case FS_IOC_ZERO_RANGE: + return IOCTL_CMD_G4; + case FIOCLEX: + case FIONCLEX: + case FIONBIO: + case FIOASYNC: + /* + * FIOCLEX, FIONCLEX, FIONBIO and FIOASYNC manipulate the FD's + * close-on-exec and the file's buffered-IO and async flags. + * These operations are also available through fcntl(2), + * and are unconditionally permitted in Landlock. + */ + return 0; + default: + /* + * Other commands are guarded by the catch-all access right. + */ + return LANDLOCK_ACCESS_FS_IOCTL; + } +} + +static int hook_file_ioctl(struct file *file, unsigned int cmd, + unsigned long arg) +{ + access_mask_t required_access = required_ioctl_access(cmd); + access_mask_t allowed_access = landlock_file(file)->allowed_access; + + /* + * It is the access rights at the time of opening the file which + * determine whether ioctl can be used on the opened file later. + * + * The access right is attached to the opened file in hook_file_open(). + */ + if ((allowed_access & required_access) == required_access) + return 0; + return -EACCES; +} + static struct security_hook_list landlock_hooks[] __ro_after_init = { LSM_HOOK_INIT(inode_free_security, hook_inode_free_security), @@ -1218,6 +1283,7 @@ static struct security_hook_list landlock_hooks[] __ro_after_init = { LSM_HOOK_INIT(file_alloc_security, hook_file_alloc_security), LSM_HOOK_INIT(file_open, hook_file_open), LSM_HOOK_INIT(file_truncate, hook_file_truncate), + LSM_HOOK_INIT(file_ioctl, hook_file_ioctl), }; __init void landlock_add_fs_hooks(void) diff --git a/security/landlock/limits.h b/security/landlock/limits.h index 93c9c6f91556..d0a95169ba3f 100644 --- a/security/landlock/limits.h +++ b/security/landlock/limits.h @@ -18,7 +18,15 @@ #define LANDLOCK_MAX_NUM_LAYERS 16 #define LANDLOCK_MAX_NUM_RULES U32_MAX -#define LANDLOCK_LAST_ACCESS_FS LANDLOCK_ACCESS_FS_TRUNCATE +#define LANDLOCK_LAST_PUBLIC_ACCESS_FS LANDLOCK_ACCESS_FS_IOCTL +#define LANDLOCK_MASK_PUBLIC_ACCESS_FS ((LANDLOCK_LAST_PUBLIC_ACCESS_FS << 1) - 1) + +#define IOCTL_CMD_G1 (LANDLOCK_LAST_PUBLIC_ACCESS_FS << 1) +#define IOCTL_CMD_G2 (LANDLOCK_LAST_PUBLIC_ACCESS_FS << 2) +#define IOCTL_CMD_G3 (LANDLOCK_LAST_PUBLIC_ACCESS_FS << 3) +#define IOCTL_CMD_G4 (LANDLOCK_LAST_PUBLIC_ACCESS_FS << 4) + +#define LANDLOCK_LAST_ACCESS_FS IOCTL_CMD_G4 #define LANDLOCK_MASK_ACCESS_FS ((LANDLOCK_LAST_ACCESS_FS << 1) - 1) #define LANDLOCK_NUM_ACCESS_FS __const_hweight64(LANDLOCK_MASK_ACCESS_FS) #define LANDLOCK_SHIFT_ACCESS_FS 0 diff --git a/security/landlock/ruleset.h b/security/landlock/ruleset.h index c7f1526784fd..58d96aff3980 100644 --- a/security/landlock/ruleset.h +++ b/security/landlock/ruleset.h @@ -30,7 +30,7 @@ LANDLOCK_ACCESS_FS_REFER) /* clang-format on */ -typedef u16 access_mask_t; +typedef u32 access_mask_t; /* Makes sure all filesystem access rights can be stored. */ static_assert(BITS_PER_TYPE(access_mask_t) >= LANDLOCK_NUM_ACCESS_FS); /* Makes sure all network access rights can be stored. */ @@ -256,6 +256,54 @@ static inline void landlock_get_ruleset(struct landlock_ruleset *const ruleset) refcount_inc(&ruleset->usage); } +/** + * expand_ioctl - return the dst flags from either the src flag or the + * LANDLOCK_ACCESS_FS_IOCTL flag, depending on whether the + * LANDLOCK_ACCESS_FS_IOCTL and src access rights are handled or not. + * + * @handled: Handled access rights + * @access: The access mask to copy values from + * @src: A single access right to copy from in @access. + * @dst: One or more access rights to copy to + * + * Returns: + * @dst, or 0 + */ +static inline access_mask_t expand_ioctl(access_mask_t handled, + access_mask_t access, + access_mask_t src, access_mask_t dst) +{ + if (!(handled & LANDLOCK_ACCESS_FS_IOCTL)) + return 0; + + access_mask_t copy_from = (handled & src) ? src : + LANDLOCK_ACCESS_FS_IOCTL; + if (access & copy_from) + return dst; + return 0; +} + +/** + * Returns @access with the synthetic IOCTL group flags enabled if necessary. + * + * @handled: Handled FS access rights. + * @access: FS access rights to expand. + * + * Returns: + * @access expanded by the necessary flags for the synthetic IOCTL access rights. + */ +static inline access_mask_t expand_all_ioctl(access_mask_t handled, + access_mask_t access) +{ + return access | + expand_ioctl(handled, access, LANDLOCK_ACCESS_FS_WRITE_FILE, + IOCTL_CMD_G1 | IOCTL_CMD_G2 | IOCTL_CMD_G4) | + expand_ioctl(handled, access, LANDLOCK_ACCESS_FS_READ_FILE, + IOCTL_CMD_G1 | IOCTL_CMD_G2 | IOCTL_CMD_G3) | + expand_ioctl(handled, access, LANDLOCK_ACCESS_FS_READ_DIR, + IOCTL_CMD_G1); +} + static inline void landlock_add_fs_access_mask(struct landlock_ruleset *const ruleset, const access_mask_t fs_access_mask, @@ -265,6 +313,9 @@ landlock_add_fs_access_mask(struct landlock_ruleset *const ruleset, /* Should already be checked in sys_landlock_create_ruleset(). */ WARN_ON_ONCE(fs_access_mask != fs_mask); + + fs_mask = expand_all_ioctl(fs_mask, fs_mask); + ruleset->access_masks[layer_level] |= (fs_mask << LANDLOCK_SHIFT_ACCESS_FS); } diff --git a/security/landlock/syscalls.c b/security/landlock/syscalls.c index 898358f57fa0..67121cf7165d 100644 --- a/security/landlock/syscalls.c +++ b/security/landlock/syscalls.c @@ -137,7 +137,7 @@ static const struct file_operations ruleset_fops = { .write = fop_dummy_write, }; -#define LANDLOCK_ABI_VERSION 4 +#define LANDLOCK_ABI_VERSION 5 /** * sys_landlock_create_ruleset - Create a new ruleset @@ -192,8 +192,8 @@ SYSCALL_DEFINE3(landlock_create_ruleset, return err; /* Checks content (and 32-bits cast). */ - if ((ruleset_attr.handled_access_fs | LANDLOCK_MASK_ACCESS_FS) != - LANDLOCK_MASK_ACCESS_FS) + if ((ruleset_attr.handled_access_fs | LANDLOCK_MASK_PUBLIC_ACCESS_FS) != + LANDLOCK_MASK_PUBLIC_ACCESS_FS) return -EINVAL; /* Checks network content (and 32-bits cast). */ diff --git a/tools/testing/selftests/landlock/base_test.c b/tools/testing/selftests/landlock/base_test.c index 646f778dfb1e..d292b419ccba 100644 --- a/tools/testing/selftests/landlock/base_test.c +++ b/tools/testing/selftests/landlock/base_test.c @@ -75,7 +75,7 @@ TEST(abi_version) const struct landlock_ruleset_attr ruleset_attr = { .handled_access_fs = LANDLOCK_ACCESS_FS_READ_FILE, }; - ASSERT_EQ(4, landlock_create_ruleset(NULL, 0, + ASSERT_EQ(5, landlock_create_ruleset(NULL, 0, LANDLOCK_CREATE_RULESET_VERSION)); ASSERT_EQ(-1, landlock_create_ruleset(&ruleset_attr, 0, diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c index 18e1f86a6234..256cd9a96eb7 100644 --- a/tools/testing/selftests/landlock/fs_test.c +++ b/tools/testing/selftests/landlock/fs_test.c @@ -525,9 +525,10 @@ TEST_F_FORK(layout1, inval) LANDLOCK_ACCESS_FS_EXECUTE | \ LANDLOCK_ACCESS_FS_WRITE_FILE | \ LANDLOCK_ACCESS_FS_READ_FILE | \ - LANDLOCK_ACCESS_FS_TRUNCATE) + LANDLOCK_ACCESS_FS_TRUNCATE | \ + LANDLOCK_ACCESS_FS_IOCTL) -#define ACCESS_LAST LANDLOCK_ACCESS_FS_TRUNCATE +#define ACCESS_LAST LANDLOCK_ACCESS_FS_IOCTL #define ACCESS_ALL ( \ ACCESS_FILE | \ From patchwork Fri Nov 3 15:57:13 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?G=C3=BCnther_Noack?= X-Patchwork-Id: 13444640 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5FFCCC41535 for ; Fri, 3 Nov 2023 15:57:49 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1343939AbjKCP5t (ORCPT ); Fri, 3 Nov 2023 11:57:49 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:34340 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234319AbjKCP5q (ORCPT ); Fri, 3 Nov 2023 11:57:46 -0400 Received: from mail-ed1-x549.google.com (mail-ed1-x549.google.com [IPv6:2a00:1450:4864:20::549]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id C3AACD50 for ; Fri, 3 Nov 2023 08:57:42 -0700 (PDT) Received: by mail-ed1-x549.google.com with SMTP id 4fb4d7f45d1cf-53df95eaebfso1676212a12.2 for ; Fri, 03 Nov 2023 08:57:42 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1699027061; x=1699631861; darn=vger.kernel.org; h=content-transfer-encoding:cc:to:from:subject:references :mime-version:message-id:in-reply-to:date:from:to:cc:subject:date :message-id:reply-to; bh=hIkX2sSSMSpzm9AseoWophCpMuQMVEAX5yjrMIC/NSk=; b=YFMtKztfhomYixsACPteQezyj2PyE1ElwBkTAPD/xRUN1I0Z5joDp21OCKWVDRXk3v j5C0VYrZqgLvlNWPFJh87vZ9OeAr+SZr8JRXjJ8SsX5VCrSPyDUii9FUuFD1Wf1maYEW gO3/WK+34rYgAv3R4HWJUnnTNCUoCsrWFmJvRNASeIUpifl6vlc3/3cDO2o+0Sa6Rsnz c3xuo6tgWy3H5NEK1HqIsuGwJxR+8NUlJvuoBCMQi//YV/siPtXNWYoEzovgGIyj5LZ5 4O9ax2Q6yIkSN5spaRDDW9x5M0KLdNYhgPqAWYcDUMRobmuKzRSwBEhYkghnHiIbpCGG kMhA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1699027061; x=1699631861; h=content-transfer-encoding:cc:to:from:subject:references :mime-version:message-id:in-reply-to:date:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=hIkX2sSSMSpzm9AseoWophCpMuQMVEAX5yjrMIC/NSk=; b=hauW3Ii5/0VI6bWXWlC+NLGl0FP3FCRrnMh/7209bycw6KT1XhiYKQKEprQUechbPL i6Q4Im660pVfOlcRTYSEuaAAUDXNuJs4J2plRKVoN4cQO46ekgCZnVwNyje9aqcb5d+Q ems9b3evEQfp/WhvVGSc59pJjQjZ+i6veF3I4MGKkzoz+QreMr5glSUGsp7VyxrQ/Hfm NhtRj/hti39BAP1XI6w8aGHNTtVc5BxFaUQw7eShHOCIo8MYUmcKAn0bIg3aExdJg/Wv OWhhapYIr1n9mgMtW0AhVnPBuUGiNIAyW9se8OXAebr0Xw6iBVJOJMEjbx1TWuAIWcsm W2oQ== X-Gm-Message-State: AOJu0YxdIyntDdrzZzK+VQhVLkuW1fhjP78RdXuBBxuUU222A14jw7sI kmHP5PJy3GvwWEp49Ncnl2gdNPCAqmO50Qj3DqWZ2dEQfGKtPJaGXR6nXXdC5fWQyw13SSEwlfB 8ypBpD2wHLHIJSyyWrKq0FDKeiIEP9LZkyxvs4kV7A03w+z+8mrUkX8OGVaNEUnLANVZG2Ymiz2 HQo6qDyA== X-Google-Smtp-Source: AGHT+IHSEq7/+4pbRy0e7hCxy3hlzzXGoxGhPtNIOr57vzBMKTla/rN7/88KsEeMBeKj/dd1HPvaY3Eh22E= X-Received: from sport.zrh.corp.google.com ([2a00:79e0:9d:4:7ddd:bc72:7a4a:ba94]) (user=gnoack job=sendgmr) by 2002:a05:6402:370f:b0:543:6cd3:b3b9 with SMTP id ek15-20020a056402370f00b005436cd3b3b9mr115347edb.3.1699027060865; Fri, 03 Nov 2023 08:57:40 -0700 (PDT) Date: Fri, 3 Nov 2023 16:57:13 +0100 In-Reply-To: <20231103155717.78042-1-gnoack@google.com> Message-Id: <20231103155717.78042-4-gnoack@google.com> Mime-Version: 1.0 References: <20231103155717.78042-1-gnoack@google.com> X-Mailer: git-send-email 2.42.0.869.gea05f2083d-goog Subject: [PATCH v4 3/7] selftests/landlock: Test IOCTL support From: " =?utf-8?q?G=C3=BCnther_Noack?= " To: linux-security-module@vger.kernel.org, " =?utf-8?q?Micka=C3=ABl_Sala?= =?utf-8?q?=C3=BCn?= " Cc: Jeff Xu , Jorge Lucangeli Obes , Allen Webb , Dmitry Torokhov , Paul Moore , Konstantin Meskhidze , Matt Bobrowski , linux-fsdevel@vger.kernel.org, " =?utf-8?q?G=C3=BCnther_Noack?= " Precedence: bulk List-ID: Exercises Landlock's IOCTL feature in different combinations of handling and permitting the rights LANDLOCK_ACCESS_FS_IOCTL, LANDLOCK_ACCESS_FS_READ_FILE, LANDLOCK_ACCESS_FS_WRITE_FILE and LANDLOCK_ACCESS_FS_READ_DIR, and in different combinations of using files and directories. Signed-off-by: Günther Noack --- tools/testing/selftests/landlock/fs_test.c | 423 ++++++++++++++++++++- 1 file changed, 420 insertions(+), 3 deletions(-) diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c index 256cd9a96eb7..564e73087e08 100644 --- a/tools/testing/selftests/landlock/fs_test.c +++ b/tools/testing/selftests/landlock/fs_test.c @@ -9,6 +9,7 @@ #define _GNU_SOURCE #include +#include #include #include #include @@ -3380,7 +3381,7 @@ TEST_F_FORK(layout1, truncate_unhandled) LANDLOCK_ACCESS_FS_WRITE_FILE; int ruleset_fd; - /* Enable Landlock. */ + /* Enables Landlock. */ ruleset_fd = create_ruleset(_metadata, handled, rules); ASSERT_LE(0, ruleset_fd); @@ -3463,7 +3464,7 @@ TEST_F_FORK(layout1, truncate) LANDLOCK_ACCESS_FS_TRUNCATE; int ruleset_fd; - /* Enable Landlock. */ + /* Enables Landlock. */ ruleset_fd = create_ruleset(_metadata, handled, rules); ASSERT_LE(0, ruleset_fd); @@ -3690,7 +3691,7 @@ TEST_F_FORK(ftruncate, open_and_ftruncate) }; int fd, ruleset_fd; - /* Enable Landlock. */ + /* Enables Landlock. */ ruleset_fd = create_ruleset(_metadata, variant->handled, rules); ASSERT_LE(0, ruleset_fd); enforce_ruleset(_metadata, ruleset_fd); @@ -3767,6 +3768,16 @@ TEST_F_FORK(ftruncate, open_and_ftruncate_in_different_processes) ASSERT_EQ(0, close(socket_fds[1])); } +/* Invokes the FS_IOC_GETFLAGS IOCTL and returns its errno or 0. */ +static int test_fs_ioc_getflags_ioctl(int fd) +{ + uint32_t flags; + + if (ioctl(fd, FS_IOC_GETFLAGS, &flags) < 0) + return errno; + return 0; +} + TEST(memfd_ftruncate) { int fd; @@ -3783,6 +3794,412 @@ TEST(memfd_ftruncate) ASSERT_EQ(0, close(fd)); } +/* clang-format off */ +FIXTURE(ioctl) {}; +/* clang-format on */ + +FIXTURE_SETUP(ioctl) +{ + prepare_layout(_metadata); + create_file(_metadata, file1_s1d1); +} + +FIXTURE_TEARDOWN(ioctl) +{ + EXPECT_EQ(0, remove_path(file1_s1d1)); + cleanup_layout(_metadata); +} + +FIXTURE_VARIANT(ioctl) +{ + const __u64 handled; + const __u64 permitted; + const mode_t open_mode; + /* + * These are the expected IOCTL results for a representative IOCTL from + * each of the IOCTL groups. We only distinguish the 0 and EACCES + * results here, and treat other errors as 0. + */ + const int expected_fioqsize_result; /* G1 */ + const int expected_fibmap_result; /* G2 */ + const int expected_fionread_result; /* G3 */ + const int expected_fs_ioc_zero_range_result; /* G4 */ + const int expected_fs_ioc_getflags_result; /* other */ +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(ioctl, ioctl_handled_i_permitted_none) { + /* clang-format on */ + .handled = LANDLOCK_ACCESS_FS_EXECUTE | LANDLOCK_ACCESS_FS_IOCTL, + .permitted = LANDLOCK_ACCESS_FS_EXECUTE, + .open_mode = O_RDWR, + .expected_fioqsize_result = EACCES, + .expected_fibmap_result = EACCES, + .expected_fionread_result = EACCES, + .expected_fs_ioc_zero_range_result = EACCES, + .expected_fs_ioc_getflags_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(ioctl, ioctl_handled_i_permitted_i) { + /* clang-format on */ + .handled = LANDLOCK_ACCESS_FS_IOCTL, + .permitted = LANDLOCK_ACCESS_FS_IOCTL, + .open_mode = O_RDWR, + .expected_fioqsize_result = 0, + .expected_fibmap_result = 0, + .expected_fionread_result = 0, + .expected_fs_ioc_zero_range_result = 0, + .expected_fs_ioc_getflags_result = 0, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(ioctl, ioctl_unhandled) { + /* clang-format on */ + .handled = LANDLOCK_ACCESS_FS_EXECUTE, + .permitted = LANDLOCK_ACCESS_FS_EXECUTE, + .open_mode = O_RDWR, + .expected_fioqsize_result = 0, + .expected_fibmap_result = 0, + .expected_fionread_result = 0, + .expected_fs_ioc_zero_range_result = 0, + .expected_fs_ioc_getflags_result = 0, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(ioctl, ioctl_handled_rwd_permitted_r) { + /* clang-format on */ + .handled = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_READ_DIR, + .permitted = LANDLOCK_ACCESS_FS_READ_FILE, + .open_mode = O_RDONLY, + /* If LANDLOCK_ACCESS_FS_IOCTL is not handled, all IOCTLs work. */ + .expected_fioqsize_result = 0, + .expected_fibmap_result = 0, + .expected_fionread_result = 0, + .expected_fs_ioc_zero_range_result = 0, + .expected_fs_ioc_getflags_result = 0, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(ioctl, ioctl_handled_rwd_permitted_w) { + /* clang-format on */ + .handled = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_READ_DIR, + .permitted = LANDLOCK_ACCESS_FS_WRITE_FILE, + .open_mode = O_WRONLY, + /* If LANDLOCK_ACCESS_FS_IOCTL is not handled, all IOCTLs work. */ + .expected_fioqsize_result = 0, + .expected_fibmap_result = 0, + .expected_fionread_result = 0, + .expected_fs_ioc_zero_range_result = 0, + .expected_fs_ioc_getflags_result = 0, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(ioctl, ioctl_handled_ri_permitted_r) { + /* clang-format on */ + .handled = LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_IOCTL, + .permitted = LANDLOCK_ACCESS_FS_READ_FILE, + .open_mode = O_RDONLY, + .expected_fioqsize_result = 0, + .expected_fibmap_result = 0, + .expected_fionread_result = 0, + .expected_fs_ioc_zero_range_result = EACCES, + .expected_fs_ioc_getflags_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(ioctl, ioctl_handled_wi_permitted_w) { + /* clang-format on */ + .handled = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_IOCTL, + .permitted = LANDLOCK_ACCESS_FS_WRITE_FILE, + .open_mode = O_WRONLY, + .expected_fioqsize_result = 0, + .expected_fibmap_result = 0, + .expected_fionread_result = EACCES, + .expected_fs_ioc_zero_range_result = 0, + .expected_fs_ioc_getflags_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(ioctl, ioctl_handled_di_permitted_d) { + /* clang-format on */ + .handled = LANDLOCK_ACCESS_FS_READ_DIR | LANDLOCK_ACCESS_FS_IOCTL, + .permitted = LANDLOCK_ACCESS_FS_READ_DIR, + .open_mode = O_RDWR, + .expected_fioqsize_result = 0, + .expected_fibmap_result = EACCES, + .expected_fionread_result = EACCES, + .expected_fs_ioc_zero_range_result = EACCES, + .expected_fs_ioc_getflags_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(ioctl, ioctl_handled_rwi_permitted_rw) { + /* clang-format on */ + .handled = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_IOCTL, + .permitted = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_WRITE_FILE, + .open_mode = O_RDWR, + .expected_fioqsize_result = 0, + .expected_fibmap_result = 0, + .expected_fionread_result = 0, + .expected_fs_ioc_zero_range_result = 0, + .expected_fs_ioc_getflags_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(ioctl, ioctl_handled_rwi_permitted_r) { + /* clang-format on */ + .handled = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_IOCTL, + .permitted = LANDLOCK_ACCESS_FS_READ_FILE, + .open_mode = O_RDONLY, + .expected_fioqsize_result = 0, + .expected_fibmap_result = 0, + .expected_fionread_result = 0, + .expected_fs_ioc_zero_range_result = EACCES, + .expected_fs_ioc_getflags_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(ioctl, ioctl_handled_rwi_permitted_ri) { + /* clang-format on */ + .handled = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_IOCTL, + .permitted = LANDLOCK_ACCESS_FS_READ_FILE | LANDLOCK_ACCESS_FS_IOCTL, + .open_mode = O_RDONLY, + .expected_fioqsize_result = 0, + .expected_fibmap_result = 0, + .expected_fionread_result = 0, + .expected_fs_ioc_zero_range_result = EACCES, + .expected_fs_ioc_getflags_result = 0, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(ioctl, ioctl_handled_rwi_permitted_w) { + /* clang-format on */ + .handled = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_IOCTL, + .permitted = LANDLOCK_ACCESS_FS_WRITE_FILE, + .open_mode = O_WRONLY, + .expected_fioqsize_result = 0, + .expected_fibmap_result = 0, + .expected_fionread_result = EACCES, + .expected_fs_ioc_zero_range_result = 0, + .expected_fs_ioc_getflags_result = EACCES, +}; + +/* clang-format off */ +FIXTURE_VARIANT_ADD(ioctl, ioctl_handled_rwi_permitted_wi) { + /* clang-format on */ + .handled = LANDLOCK_ACCESS_FS_READ_FILE | + LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_IOCTL, + .permitted = LANDLOCK_ACCESS_FS_WRITE_FILE | LANDLOCK_ACCESS_FS_IOCTL, + .open_mode = O_WRONLY, + .expected_fioqsize_result = 0, + .expected_fibmap_result = 0, + .expected_fionread_result = EACCES, + .expected_fs_ioc_zero_range_result = 0, + .expected_fs_ioc_getflags_result = 0, +}; + +static int test_fioqsize_ioctl(int fd) +{ + size_t sz; + + if (ioctl(fd, FIOQSIZE, &sz) < 0) + return errno; + return 0; +} + +static int test_fibmap_ioctl(int fd) +{ + int blk = 0; + + /* + * We only want to distinguish here whether Landlock already caught it, + * so we treat anything but EACCESS as success. (It commonly returns + * EPERM when missing CAP_SYS_RAWIO.) + */ + if (ioctl(fd, FIBMAP, &blk) < 0 && errno == EACCES) + return errno; + return 0; +} + +static int test_fionread_ioctl(int fd) +{ + size_t sz = 0; + + if (ioctl(fd, FIONREAD, &sz) < 0 && errno == EACCES) + return errno; + return 0; +} + +#define FS_IOC_ZERO_RANGE _IOW('X', 57, struct space_resv) + +static int test_fs_ioc_zero_range_ioctl(int fd) +{ + struct space_resv { + __s16 l_type; + __s16 l_whence; + __s64 l_start; + __s64 l_len; /* len == 0 means until end of file */ + __s32 l_sysid; + __u32 l_pid; + __s32 l_pad[4]; /* reserved area */ + } reservation = {}; + /* + * This can fail for various reasons, but we only want to distinguish + * here whether Landlock already caught it, so we treat anything but + * EACCES as success. + */ + if (ioctl(fd, FS_IOC_ZERO_RANGE, &reservation) < 0 && errno == EACCES) + return errno; + return 0; +} + +TEST_F_FORK(ioctl, handle_dir_access_file) +{ + const int flag = 0; + const struct rule rules[] = { + { + .path = dir_s1d1, + .access = variant->permitted, + }, + {}, + }; + int fd, ruleset_fd; + + /* Enables Landlock. */ + ruleset_fd = create_ruleset(_metadata, variant->handled, rules); + ASSERT_LE(0, ruleset_fd); + enforce_ruleset(_metadata, ruleset_fd); + ASSERT_EQ(0, close(ruleset_fd)); + + fd = open(file1_s1d1, variant->open_mode); + ASSERT_LE(0, fd); + + /* + * Checks that IOCTL commands in each IOCTL group return the expected + * errors. + */ + EXPECT_EQ(variant->expected_fioqsize_result, test_fioqsize_ioctl(fd)); + EXPECT_EQ(variant->expected_fibmap_result, test_fibmap_ioctl(fd)); + EXPECT_EQ(variant->expected_fionread_result, test_fionread_ioctl(fd)); + EXPECT_EQ(variant->expected_fs_ioc_zero_range_result, + test_fs_ioc_zero_range_ioctl(fd)); + EXPECT_EQ(variant->expected_fs_ioc_getflags_result, + test_fs_ioc_getflags_ioctl(fd)); + + /* Checks that unrestrictable commands are unrestricted. */ + EXPECT_EQ(0, ioctl(fd, FIOCLEX)); + EXPECT_EQ(0, ioctl(fd, FIONCLEX)); + EXPECT_EQ(0, ioctl(fd, FIONBIO, &flag)); + EXPECT_EQ(0, ioctl(fd, FIOASYNC, &flag)); + + ASSERT_EQ(0, close(fd)); +} + +TEST_F_FORK(ioctl, handle_dir_access_dir) +{ + const char *const path = dir_s1d1; + const int flag = 0; + const struct rule rules[] = { + { + .path = path, + .access = variant->permitted, + }, + {}, + }; + int fd, ruleset_fd; + + /* Enables Landlock. */ + ruleset_fd = create_ruleset(_metadata, variant->handled, rules); + ASSERT_LE(0, ruleset_fd); + enforce_ruleset(_metadata, ruleset_fd); + ASSERT_EQ(0, close(ruleset_fd)); + + /* + * Ignore variant->open_mode for this test, as we intend to open a + * directory. If the directory can not be opened, the variant is + * infeasible to test with an opened directory. + */ + fd = open(path, O_RDONLY); + if (fd < 0) + return; + + /* + * Checks that IOCTL commands in each IOCTL group return the expected + * errors. + */ + EXPECT_EQ(variant->expected_fioqsize_result, test_fioqsize_ioctl(fd)); + EXPECT_EQ(variant->expected_fibmap_result, test_fibmap_ioctl(fd)); + EXPECT_EQ(variant->expected_fionread_result, test_fionread_ioctl(fd)); + EXPECT_EQ(variant->expected_fs_ioc_zero_range_result, + test_fs_ioc_zero_range_ioctl(fd)); + EXPECT_EQ(variant->expected_fs_ioc_getflags_result, + test_fs_ioc_getflags_ioctl(fd)); + + /* Checks that unrestrictable commands are unrestricted. */ + EXPECT_EQ(0, ioctl(fd, FIOCLEX)); + EXPECT_EQ(0, ioctl(fd, FIONCLEX)); + EXPECT_EQ(0, ioctl(fd, FIONBIO, &flag)); + EXPECT_EQ(0, ioctl(fd, FIOASYNC, &flag)); + + ASSERT_EQ(0, close(fd)); +} + +TEST_F_FORK(ioctl, handle_file_access_file) +{ + const char *const path = file1_s1d1; + const int flag = 0; + const struct rule rules[] = { + { + .path = path, + .access = variant->permitted, + }, + {}, + }; + int fd, ruleset_fd; + + if (variant->permitted & LANDLOCK_ACCESS_FS_READ_DIR) { + /* This access right can not be granted on files. */ + return; + } + + /* Enables Landlock. */ + ruleset_fd = create_ruleset(_metadata, variant->handled, rules); + ASSERT_LE(0, ruleset_fd); + enforce_ruleset(_metadata, ruleset_fd); + ASSERT_EQ(0, close(ruleset_fd)); + + fd = open(path, variant->open_mode); + ASSERT_LE(0, fd); + + /* + * Checks that IOCTL commands in each IOCTL group return the expected + * errors. + */ + EXPECT_EQ(variant->expected_fioqsize_result, test_fioqsize_ioctl(fd)); + EXPECT_EQ(variant->expected_fibmap_result, test_fibmap_ioctl(fd)); + EXPECT_EQ(variant->expected_fionread_result, test_fionread_ioctl(fd)); + EXPECT_EQ(variant->expected_fs_ioc_zero_range_result, + test_fs_ioc_zero_range_ioctl(fd)); + EXPECT_EQ(variant->expected_fs_ioc_getflags_result, + test_fs_ioc_getflags_ioctl(fd)); + + /* Checks that unrestrictable commands are unrestricted. */ + EXPECT_EQ(0, ioctl(fd, FIOCLEX)); + EXPECT_EQ(0, ioctl(fd, FIONCLEX)); + EXPECT_EQ(0, ioctl(fd, FIONBIO, &flag)); + EXPECT_EQ(0, ioctl(fd, FIOASYNC, &flag)); + + ASSERT_EQ(0, close(fd)); +} + /* clang-format off */ FIXTURE(layout1_bind) {}; /* clang-format on */ From patchwork Fri Nov 3 15:57:14 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?G=C3=BCnther_Noack?= X-Patchwork-Id: 13444639 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A62E2C4167B for ; Fri, 3 Nov 2023 15:57:50 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344047AbjKCP5u (ORCPT ); Fri, 3 Nov 2023 11:57:50 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39016 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S234329AbjKCP5s (ORCPT ); Fri, 3 Nov 2023 11:57:48 -0400 Received: from mail-ed1-x54a.google.com (mail-ed1-x54a.google.com [IPv6:2a00:1450:4864:20::54a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 53356D52 for ; Fri, 3 Nov 2023 08:57:45 -0700 (PDT) Received: by mail-ed1-x54a.google.com with SMTP id 4fb4d7f45d1cf-5411a36a37fso2719676a12.0 for ; Fri, 03 Nov 2023 08:57:45 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1699027064; x=1699631864; darn=vger.kernel.org; h=content-transfer-encoding:cc:to:from:subject:references :mime-version:message-id:in-reply-to:date:from:to:cc:subject:date :message-id:reply-to; bh=mxvKLDLDIIL6ajW+0JhrE5ylNn+Ttpm+mn9PCmHiykk=; b=fAxkO+gZSeRX/WXvqNNZ3MLD8qy+cxPtBNEB81iFM97oNC9nk5G8zMIAtS3tRsJqec wfaJvFLVrDLsEl6D3yhkjGO7H0IfVgrWOgQrf+EKGzc9Rrc3GqNmpgmDhWLk+dN06HV4 BC2GZgrYNk7VmlRt+VX05BFA1cH1G4Yt3guZlSKJUnDuZ1jdvIsG9S2rblY0nH1sPljC hIqSLK6MADHfrcwYJIC07GykRy5cI1AX4KcxywCVfWoIqVUiOoTzvuP7YguIb5cNmr3P yQdNssDi5lEvD/w4eVWCsz/iXj5alg5qh3pIb5jn3N89h4LhjtVo/hNnS4HnCRItCksz xxFA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1699027064; x=1699631864; h=content-transfer-encoding:cc:to:from:subject:references :mime-version:message-id:in-reply-to:date:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=mxvKLDLDIIL6ajW+0JhrE5ylNn+Ttpm+mn9PCmHiykk=; b=dP9WutfuRcZV+tXdseVwSjXLHD18saYDSNnEThHNCB/+TPYTlcFMXCNzn00N/izrCP 9wAg4vTAToUTjldtUuO0145WBQgeCqKIQwr/Rkh0gei/88a61uCRfRCKYWNpipxhQd6l W5Z2RGZJgetcyeCZifmA+qQGaiqwK8EjBCISFIYHyWrdA5dvgGwW3PFfrAuUUGH86RGX ada6UsRUDk7sZZoYJvxQJz/PVHSrqnbovp3/TsBplj1ACxwS83Q8iyd5mxmfCz2PyA8x tzcDZHOHGH0fjNTpUVw6jt3YWo7cUoeRa2NmAYd/6IuxV4WFTV2SGwz8GUrGjWODMPKU ZvYA== X-Gm-Message-State: AOJu0YxRvWtWYgVutAzVbFkW/jN6UFpiBW5xhLq/EP7M5VtkPqPVWzKP qa+in0ke65PFWvrwenFRBoBfSikwZZVWZwAjCy7F8HsAlbDlZN8+QMzvd2aJgSb95Gmp9Z9OwPw CtSufb76Yg5uvURd3lhyfY3NrAG5qVMqv8mTDL5+KUOWrBwqgQeKNZEXuqDZVbqkEdAM6W7FqzP hKOW0vRA== X-Google-Smtp-Source: AGHT+IFO+w+kful6dHdJwQ+/Cw0YmHCA5rEGgf/6cHbgOUGhXEwdbnuAVb7H1JRbhvDByeR1+AK4NhIbL2c= X-Received: from sport.zrh.corp.google.com ([2a00:79e0:9d:4:7ddd:bc72:7a4a:ba94]) (user=gnoack job=sendgmr) by 2002:aa7:d5d1:0:b0:53e:227d:727f with SMTP id d17-20020aa7d5d1000000b0053e227d727fmr32488eds.2.1699027063815; Fri, 03 Nov 2023 08:57:43 -0700 (PDT) Date: Fri, 3 Nov 2023 16:57:14 +0100 In-Reply-To: <20231103155717.78042-1-gnoack@google.com> Message-Id: <20231103155717.78042-5-gnoack@google.com> Mime-Version: 1.0 References: <20231103155717.78042-1-gnoack@google.com> X-Mailer: git-send-email 2.42.0.869.gea05f2083d-goog Subject: [PATCH v4 4/7] selftests/landlock: Test IOCTL with memfds From: " =?utf-8?q?G=C3=BCnther_Noack?= " To: linux-security-module@vger.kernel.org, " =?utf-8?q?Micka=C3=ABl_Sala?= =?utf-8?q?=C3=BCn?= " Cc: Jeff Xu , Jorge Lucangeli Obes , Allen Webb , Dmitry Torokhov , Paul Moore , Konstantin Meskhidze , Matt Bobrowski , linux-fsdevel@vger.kernel.org, " =?utf-8?q?G=C3=BCnther_Noack?= " Precedence: bulk List-ID: Because the LANDLOCK_ACCESS_FS_IOCTL right is associated with the opened file during open(2), IOCTLs are supposed to work with files which are opened by means other than open(2). Signed-off-by: Günther Noack --- tools/testing/selftests/landlock/fs_test.c | 36 ++++++++++++++++------ 1 file changed, 27 insertions(+), 9 deletions(-) diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c index 564e73087e08..8a244c9cd030 100644 --- a/tools/testing/selftests/landlock/fs_test.c +++ b/tools/testing/selftests/landlock/fs_test.c @@ -3778,20 +3778,38 @@ static int test_fs_ioc_getflags_ioctl(int fd) return 0; } -TEST(memfd_ftruncate) +TEST(memfd_ftruncate_and_ioctl) { - int fd; - - fd = memfd_create("name", MFD_CLOEXEC); - ASSERT_LE(0, fd); + const struct landlock_ruleset_attr attr = { + .handled_access_fs = ACCESS_ALL, + }; + int ruleset_fd, fd, i; /* - * Checks that ftruncate is permitted on file descriptors that are - * created in ways other than open(2). + * We exercise the same test both with and without Landlock enabled, to + * ensure that it behaves the same in both cases. */ - EXPECT_EQ(0, test_ftruncate(fd)); + for (i = 0; i < 2; i++) { + /* Creates a new memfd. */ + fd = memfd_create("name", MFD_CLOEXEC); + ASSERT_LE(0, fd); - ASSERT_EQ(0, close(fd)); + /* + * Checks that operations associated with the opened file + * (ftruncate, ioctl) are permitted on file descriptors that are + * created in ways other than open(2). + */ + EXPECT_EQ(0, test_ftruncate(fd)); + EXPECT_EQ(0, test_fs_ioc_getflags_ioctl(fd)); + + ASSERT_EQ(0, close(fd)); + + /* Enables Landlock. */ + ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0); + ASSERT_LE(0, ruleset_fd); + enforce_ruleset(_metadata, ruleset_fd); + ASSERT_EQ(0, close(ruleset_fd)); + } } /* clang-format off */ From patchwork Fri Nov 3 15:57:15 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?G=C3=BCnther_Noack?= X-Patchwork-Id: 13444642 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id B1122C4332F for ; Fri, 3 Nov 2023 15:57:56 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344095AbjKCP54 (ORCPT ); Fri, 3 Nov 2023 11:57:56 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39042 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344108AbjKCP5w (ORCPT ); Fri, 3 Nov 2023 11:57:52 -0400 Received: from mail-ej1-x649.google.com (mail-ej1-x649.google.com [IPv6:2a00:1450:4864:20::649]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 08DE7D50 for ; Fri, 3 Nov 2023 08:57:48 -0700 (PDT) Received: by mail-ej1-x649.google.com with SMTP id a640c23a62f3a-9d4b8735f48so156457866b.1 for ; Fri, 03 Nov 2023 08:57:47 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1699027066; x=1699631866; darn=vger.kernel.org; h=content-transfer-encoding:cc:to:from:subject:references :mime-version:message-id:in-reply-to:date:from:to:cc:subject:date :message-id:reply-to; bh=p4UZ/Kc+lRwWA7nYggLhLN0g2SyGgzuCpunnNbgZX4k=; b=tGhAnidSl5C9XtMZB/R72TI3V1ulpsK5a2d/QHYqXPNdIWF58/iVsKa9zcHl53pL+R fqejD+7EIM9Hsy8ZQ+zmDgXIYIB7toXlHwS5mgykffJsrjE+w7HLmW+8BET302Qqam4p SVSxezOO2uUuq/A8owsFFbc+Jd2xcvm0oyUsOqB/OhNWZPzZWNO7J/ceQePFYa9DToG5 xekQ+rcEJujLb2wDpE3+RV5SrYbWH/VHqyYX6WPvOna9Jmqs4NlDSqoL107sUZ6YAM4J RgH+cgtxkXIvLpv2WsrCaeH35cLTm/FYIlvlLNHOBEOjbqaeaH+74FelxLuMNjYb0Hn0 G5gA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1699027066; x=1699631866; h=content-transfer-encoding:cc:to:from:subject:references :mime-version:message-id:in-reply-to:date:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=p4UZ/Kc+lRwWA7nYggLhLN0g2SyGgzuCpunnNbgZX4k=; b=v2Pl0VH5t8E5W2W+eGrtDmQsaangxr0bHZvuEq/QQ+zood6nzhzcu4aQu3I20FGfDd xLxBJGCRoeoabdpIjlT6j4+I86yJjAV4dVc049Lnx1u/BeQj9CyIpokHwRn54huGeGcU Ho5GRU15Tc+E1LrBAgynKHtJGarnF0EZJAca27JgbWCpg4MN9+ZPP0qubTBopJF/gsI4 SQpFCJjAXrjpMDNgtTaquP3MK35foD3GA5viP+tSywBPU9HS7BtSWthOAyHIhzyAsHl+ Fl4GgkLdYD8kvggbuzOIJH51iwZ+7/xoiQMskZK3IGl59E3tqYVPuA9QPce2R59+yTUR k1TA== X-Gm-Message-State: AOJu0YwyO6LTNd3ZL91wJeQF1U2ykb1gcSBh1pNLrjxJFm7xrZYQ1m43 wAZGoIiWItikdG9zUS8Trj+YLynUq0oRTpLzWpPE78BUKchB/Q8FkQDcuNTOQTqaf1gPuetTsWm 0Cz4OcEQbUffLjvcachCOCjBmbDlApEwbqkdAVWVDkFavtcpgwXZ7Nl7cfzsPmLfSW1Nb3ZB4iu iG9wwFrA== X-Google-Smtp-Source: AGHT+IGVzbVzowF2B2fGNgQgbqnZM9+eSt7APbm+XXebbcm7Cet2bq9r24REnItIAZa1So9zyVWNUTegqsQ= X-Received: from sport.zrh.corp.google.com ([2a00:79e0:9d:4:7ddd:bc72:7a4a:ba94]) (user=gnoack job=sendgmr) by 2002:a17:907:3907:b0:9dd:9857:85e with SMTP id so7-20020a170907390700b009dd9857085emr9777ejc.13.1699027066427; Fri, 03 Nov 2023 08:57:46 -0700 (PDT) Date: Fri, 3 Nov 2023 16:57:15 +0100 In-Reply-To: <20231103155717.78042-1-gnoack@google.com> Message-Id: <20231103155717.78042-6-gnoack@google.com> Mime-Version: 1.0 References: <20231103155717.78042-1-gnoack@google.com> X-Mailer: git-send-email 2.42.0.869.gea05f2083d-goog Subject: [PATCH v4 5/7] selftests/landlock: Test ioctl(2) and ftruncate(2) with open(O_PATH) From: " =?utf-8?q?G=C3=BCnther_Noack?= " To: linux-security-module@vger.kernel.org, " =?utf-8?q?Micka=C3=ABl_Sala?= =?utf-8?q?=C3=BCn?= " Cc: Jeff Xu , Jorge Lucangeli Obes , Allen Webb , Dmitry Torokhov , Paul Moore , Konstantin Meskhidze , Matt Bobrowski , linux-fsdevel@vger.kernel.org, " =?utf-8?q?G=C3=BCnther_Noack?= " Precedence: bulk List-ID: ioctl(2) and ftruncate(2) operations on files opened with O_PATH should always return EBADF, independent of the LANDLOCK_ACCESS_FS_TRUNCATE and LANDLOCK_ACCESS_FS_IOCTL access rights in that file hierarchy. Signed-off-by: Günther Noack Suggested-by: Mickaël Salaün --- tools/testing/selftests/landlock/fs_test.c | 40 ++++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/tools/testing/selftests/landlock/fs_test.c b/tools/testing/selftests/landlock/fs_test.c index 8a244c9cd030..06c47c816c51 100644 --- a/tools/testing/selftests/landlock/fs_test.c +++ b/tools/testing/selftests/landlock/fs_test.c @@ -3812,6 +3812,46 @@ TEST(memfd_ftruncate_and_ioctl) } } +TEST_F_FORK(layout1, o_path_ftruncate_and_ioctl) +{ + const struct landlock_ruleset_attr attr = { + .handled_access_fs = ACCESS_ALL, + }; + int ruleset_fd, fd; + + /* + * Checks that for files opened with O_PATH, both ioctl(2) and + * ftruncate(2) yield EBADF, as it is documented in open(2) for the + * O_PATH flag. + */ + fd = open(dir_s1d1, O_PATH | O_CLOEXEC); + ASSERT_LE(0, fd); + + EXPECT_EQ(EBADF, test_ftruncate(fd)); + EXPECT_EQ(EBADF, test_fs_ioc_getflags_ioctl(fd)); + + ASSERT_EQ(0, close(fd)); + + /* Enables Landlock. */ + ruleset_fd = landlock_create_ruleset(&attr, sizeof(attr), 0); + ASSERT_LE(0, ruleset_fd); + enforce_ruleset(_metadata, ruleset_fd); + ASSERT_EQ(0, close(ruleset_fd)); + + /* + * Checks that after enabling Landlock, + * - the file can still be opened with O_PATH + * - both ioctl and truncate still yield EBADF (not EACCES). + */ + fd = open(dir_s1d1, O_PATH | O_CLOEXEC); + ASSERT_LE(0, fd); + + EXPECT_EQ(EBADF, test_ftruncate(fd)); + EXPECT_EQ(EBADF, test_fs_ioc_getflags_ioctl(fd)); + + ASSERT_EQ(0, close(fd)); +} + /* clang-format off */ FIXTURE(ioctl) {}; /* clang-format on */ From patchwork Fri Nov 3 15:57:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?G=C3=BCnther_Noack?= X-Patchwork-Id: 13444641 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id A63A3C4167D for ; Fri, 3 Nov 2023 15:57:58 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344379AbjKCP57 (ORCPT ); Fri, 3 Nov 2023 11:57:59 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39060 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344165AbjKCP5x (ORCPT ); Fri, 3 Nov 2023 11:57:53 -0400 Received: from mail-ej1-x649.google.com (mail-ej1-x649.google.com [IPv6:2a00:1450:4864:20::649]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 6BA46D58 for ; Fri, 3 Nov 2023 08:57:50 -0700 (PDT) Received: by mail-ej1-x649.google.com with SMTP id a640c23a62f3a-9bea60bd1adso370522666b.0 for ; Fri, 03 Nov 2023 08:57:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1699027069; x=1699631869; darn=vger.kernel.org; h=content-transfer-encoding:cc:to:from:subject:references :mime-version:message-id:in-reply-to:date:from:to:cc:subject:date :message-id:reply-to; bh=xOCNSi1HIkBnaTYGa33qWxOS2ibI+ZQHcixXpo/0924=; b=itzsqItwgIX/RNyhHk3m1S18cQ282d/vKlq8rAbXwh3qt7LiZxVlcXGgbhqwL4y9ka wQoGfpH1wpEF1efWNDlBw4Us6i6Eb3Sd38xA/pXuGg/F8GZkCKSsQAe3gNULo0CqmFAM NhdpVy8oMXfEV4I51wtwTXQ7sy3WZz8l0PhBMYVK+CUX4s8or/TUdoTfQxRRSwlCqw+F oH/J2RQ+QoyjdzkOPWT4BFokAcMOOMlShvid/bRASg1FDiYvesfOOIGtrGlgKBQxyNfL CIbH0OpSojMNwHt0bHM+wJlKWbK3Yo48KY1mBVUbjUjStIghP1dhNpEn6FuqowehveH0 N+Zw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1699027069; x=1699631869; h=content-transfer-encoding:cc:to:from:subject:references :mime-version:message-id:in-reply-to:date:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=xOCNSi1HIkBnaTYGa33qWxOS2ibI+ZQHcixXpo/0924=; b=vp24LpvDVfSq2lNs6gQw0tly+mErXSlE+1d35OGOPTyviva1Ko4WaEcXmDBLYcELm9 Bddg1ZPPFYfAx6C5u4RJkTqjrzEtP65AA18m/nCWmJOL0FlWBEVswDhGoTZIP0tWAKW2 L83lmZAJP/a3N4Dbrt25c31g1i2b/zABsugNg2R4Ru+YjZ+rztsww8WQg7V14RyDZr6U rxZru4I93UOQBK5LYhFd8fe1UsfjeIgn++jKBXGaTVh6GG9FDiDHhbJZzTb2Jh3BEh7D 5jI9vyHGaOH4mWI9cvQUkP7aOh/ZmaUyI1T9cleMUYslbIdEhJrv6Ub6asM9iALWVt+3 cPeA== X-Gm-Message-State: AOJu0Ywti01XhIT8rqJf2VGXvbeL63jpUD2ScB77bx5ZPsuzSYM6g9p7 7j1oBNIdNXhndZ8eTxTbCuAyI0NT3cYSwwkHrT9KlI2P9Focvs0p6Q6BD13hPSbHRwswz/dH4gf XHACgz5AHnAgOlEinuDsqDi8D85CBECuYIHCSCCIWByiOaWKWms9WwgUHwwm6q/hsmdHkszXLlD sITFdb3A== X-Google-Smtp-Source: AGHT+IEkjzZ+rWUnr2Uwoa4MxxIej/VkJvLcmZBXO+gs6KbP6tb8ZrfPNm41/EtPvHWpnRUgCLiFbgdH7YE= X-Received: from sport.zrh.corp.google.com ([2a00:79e0:9d:4:7ddd:bc72:7a4a:ba94]) (user=gnoack job=sendgmr) by 2002:a17:906:e285:b0:9cd:8a9e:c90d with SMTP id gg5-20020a170906e28500b009cd8a9ec90dmr25450ejb.6.1699027068990; Fri, 03 Nov 2023 08:57:48 -0700 (PDT) Date: Fri, 3 Nov 2023 16:57:16 +0100 In-Reply-To: <20231103155717.78042-1-gnoack@google.com> Message-Id: <20231103155717.78042-7-gnoack@google.com> Mime-Version: 1.0 References: <20231103155717.78042-1-gnoack@google.com> X-Mailer: git-send-email 2.42.0.869.gea05f2083d-goog Subject: [PATCH v4 6/7] samples/landlock: Add support for LANDLOCK_ACCESS_FS_IOCTL From: " =?utf-8?q?G=C3=BCnther_Noack?= " To: linux-security-module@vger.kernel.org, " =?utf-8?q?Micka=C3=ABl_Sala?= =?utf-8?q?=C3=BCn?= " Cc: Jeff Xu , Jorge Lucangeli Obes , Allen Webb , Dmitry Torokhov , Paul Moore , Konstantin Meskhidze , Matt Bobrowski , linux-fsdevel@vger.kernel.org, " =?utf-8?q?G=C3=BCnther_Noack?= " Precedence: bulk List-ID: Add ioctl support to the Landlock sample tool. The ioctl right is grouped with the read-write rights in the sample tool, as some ioctl requests provide features that mutate state. Signed-off-by: Günther Noack --- samples/landlock/sandboxer.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/samples/landlock/sandboxer.c b/samples/landlock/sandboxer.c index 08596c0ef070..a4b2bebaf203 100644 --- a/samples/landlock/sandboxer.c +++ b/samples/landlock/sandboxer.c @@ -81,7 +81,8 @@ static int parse_path(char *env_path, const char ***const path_list) LANDLOCK_ACCESS_FS_EXECUTE | \ LANDLOCK_ACCESS_FS_WRITE_FILE | \ LANDLOCK_ACCESS_FS_READ_FILE | \ - LANDLOCK_ACCESS_FS_TRUNCATE) + LANDLOCK_ACCESS_FS_TRUNCATE | \ + LANDLOCK_ACCESS_FS_IOCTL) /* clang-format on */ @@ -199,7 +200,8 @@ static int populate_ruleset_net(const char *const env_var, const int ruleset_fd, LANDLOCK_ACCESS_FS_MAKE_BLOCK | \ LANDLOCK_ACCESS_FS_MAKE_SYM | \ LANDLOCK_ACCESS_FS_REFER | \ - LANDLOCK_ACCESS_FS_TRUNCATE) + LANDLOCK_ACCESS_FS_TRUNCATE | \ + LANDLOCK_ACCESS_FS_IOCTL) /* clang-format on */ @@ -317,6 +319,10 @@ int main(const int argc, char *const argv[], char *const *const envp) ruleset_attr.handled_access_net &= ~(LANDLOCK_ACCESS_NET_BIND_TCP | LANDLOCK_ACCESS_NET_CONNECT_TCP); + case 4: + /* Removes LANDLOCK_ACCESS_FS_IOCTL for ABI < 5 */ + ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_IOCTL; + fprintf(stderr, "Hint: You should update the running kernel " "to leverage Landlock features " From patchwork Fri Nov 3 15:57:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Patchwork-Submitter: =?utf-8?q?G=C3=BCnther_Noack?= X-Patchwork-Id: 13444643 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from vger.kernel.org (vger.kernel.org [23.128.96.18]) by smtp.lore.kernel.org (Postfix) with ESMTP id 35226C4167B for ; Fri, 3 Nov 2023 15:58:00 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1344024AbjKCP6A (ORCPT ); Fri, 3 Nov 2023 11:58:00 -0400 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:39100 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1344318AbjKCP54 (ORCPT ); Fri, 3 Nov 2023 11:57:56 -0400 Received: from mail-yb1-xb49.google.com (mail-yb1-xb49.google.com [IPv6:2607:f8b0:4864:20::b49]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id DE903D5B for ; Fri, 3 Nov 2023 08:57:52 -0700 (PDT) Received: by mail-yb1-xb49.google.com with SMTP id 3f1490d57ef6-d86dac81f8fso2644926276.1 for ; Fri, 03 Nov 2023 08:57:52 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20230601; t=1699027072; x=1699631872; darn=vger.kernel.org; h=content-transfer-encoding:cc:to:from:subject:references :mime-version:message-id:in-reply-to:date:from:to:cc:subject:date :message-id:reply-to; bh=4VOiCN8o/DjtYXboLphKkKFmrLlTPpPKQqRg+hd9A94=; b=LgLw/V/Wpi1268LB78IzmbPKykgAJUWCtQri41hqjerWJpDQH5e+h56sXIBVRnYJ6K cHxl+3s5srCAoQ2ZrpqML85U6g3ar5nHi+B2X2Hrk2JfbRSrIUIH3gLIwBEts2nV8dmn ZYYP6i+Zxf81DPYyYchDRv+k3caoL0mBtPYgVtpZ5arpoHDMRPsL6emAOlft9i2x4Tjv 7oKVGu57VCY3xEpf81/pPxiJgABeQN7jUYWJqtrp0DT16h1EK1029Tbh3sCdLBvesmtj y57IpV8Us8Rr3MC0WHp6hS2Nz1V2bqtwI3a+iDBFQBESmpRb5cuOeO1dY6AnRxPtnMTh TVvQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1699027072; x=1699631872; h=content-transfer-encoding:cc:to:from:subject:references :mime-version:message-id:in-reply-to:date:x-gm-message-state:from:to :cc:subject:date:message-id:reply-to; bh=4VOiCN8o/DjtYXboLphKkKFmrLlTPpPKQqRg+hd9A94=; b=V8KJzrDB8mP8Yfug/CQXGg6qzxvBrP8HeiqGH+fdbKsNmrH5mRF5NfLlyfZ+R6aKns f6CeuWNbKWYrNKVLXuiD/7dMDO+umfXFQS098ZFl7hg4xLD5lG6SsX6bnBRqrSSH1Mb2 CJnUfWAvJLrmIYmbCHEpWlOZ3LkdLoLsye67wUiMQatSxWK7F35JEJ1Jck27xSO+7i3d W3uHk5YzXGDKS9C8fvjQ1h79Ta8ilNcoL92IKKyO7g88SGRSiKxrJ4fjgTLYgPodgy3b 4CDeF2FWf2AmxVddikoi05AvGKU6OHZ6vlAte9CeFmLrN1HPZKPdNWVXSUrFAlv+czzb Uf+w== X-Gm-Message-State: AOJu0YySe859APw+XEn4U+iiUEpUm5CVrpLAcINCRAB4BW0P632FddKN 4o3IcvY6PxrZcKbz/lwS/0us5ss82Amp2QGCmIR0QFxPOMVCXZyrTLLbuIJO6s/OE4qq7IsB717 zR0BmDHy57gevUVQOglssUlYfHm7q+NS0YFXdg4Yo1vqmCx9t9XBN6WKQpbtB73TKHXjYxqTEeG eWv3bTRg== X-Google-Smtp-Source: AGHT+IFafpyzF7d3cKv64Oaba1Jzq343m+7zJQytbaFGf4dNJ0KJO1thYwDC/DTpnsIZR6dNC02aPGCv2FY= X-Received: from sport.zrh.corp.google.com ([2a00:79e0:9d:4:7ddd:bc72:7a4a:ba94]) (user=gnoack job=sendgmr) by 2002:a25:bc90:0:b0:d9c:c9a8:8c27 with SMTP id e16-20020a25bc90000000b00d9cc9a88c27mr427171ybk.13.1699027071630; Fri, 03 Nov 2023 08:57:51 -0700 (PDT) Date: Fri, 3 Nov 2023 16:57:17 +0100 In-Reply-To: <20231103155717.78042-1-gnoack@google.com> Message-Id: <20231103155717.78042-8-gnoack@google.com> Mime-Version: 1.0 References: <20231103155717.78042-1-gnoack@google.com> X-Mailer: git-send-email 2.42.0.869.gea05f2083d-goog Subject: [PATCH v4 7/7] landlock: Document IOCTL support From: " =?utf-8?q?G=C3=BCnther_Noack?= " To: linux-security-module@vger.kernel.org, " =?utf-8?q?Micka=C3=ABl_Sala?= =?utf-8?q?=C3=BCn?= " Cc: Jeff Xu , Jorge Lucangeli Obes , Allen Webb , Dmitry Torokhov , Paul Moore , Konstantin Meskhidze , Matt Bobrowski , linux-fsdevel@vger.kernel.org, " =?utf-8?q?G=C3=BCnther_Noack?= " Precedence: bulk List-ID: In the paragraph above the fallback logic, use the shorter phrasing from the landlock(7) man page. Signed-off-by: Günther Noack --- Documentation/userspace-api/landlock.rst | 74 +++++++++++++++++++----- include/uapi/linux/landlock.h | 28 +++++++-- 2 files changed, 83 insertions(+), 19 deletions(-) diff --git a/Documentation/userspace-api/landlock.rst b/Documentation/userspace-api/landlock.rst index 2e3822677061..c64f315d5a2e 100644 --- a/Documentation/userspace-api/landlock.rst +++ b/Documentation/userspace-api/landlock.rst @@ -75,7 +75,8 @@ to be explicit about the denied-by-default access rights. LANDLOCK_ACCESS_FS_MAKE_BLOCK | LANDLOCK_ACCESS_FS_MAKE_SYM | LANDLOCK_ACCESS_FS_REFER | - LANDLOCK_ACCESS_FS_TRUNCATE, + LANDLOCK_ACCESS_FS_TRUNCATE | + LANDLOCK_ACCESS_FS_IOCTL, .handled_access_net = LANDLOCK_ACCESS_NET_BIND_TCP | LANDLOCK_ACCESS_NET_CONNECT_TCP, @@ -84,10 +85,10 @@ to be explicit about the denied-by-default access rights. Because we may not know on which kernel version an application will be executed, it is safer to follow a best-effort security approach. Indeed, we 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 access rights which are only supported in higher versions of the ABI. +using. + +To be compatible with older Linux versions, we detect the available Landlock ABI +version, and only use the available subset of access rights: .. code-block:: c @@ -113,6 +114,10 @@ remove access rights which are only supported in higher versions of the ABI. ruleset_attr.handled_access_net &= ~(LANDLOCK_ACCESS_NET_BIND_TCP | LANDLOCK_ACCESS_NET_CONNECT_TCP); + __attribute__((fallthrough)); + case 4: + /* Removes LANDLOCK_ACCESS_FS_IOCTL for ABI < 5 */ + ruleset_attr.handled_access_fs &= ~LANDLOCK_ACCESS_FS_IOCTL; } This enables to create an inclusive ruleset that will contain our rules. @@ -224,6 +229,7 @@ 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). + 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, @@ -317,18 +323,24 @@ It should also be noted that truncating files does not require the system call, this can also be done through :manpage:`open(2)` with the flags ``O_RDONLY | O_TRUNC``. -When opening a file, the availability of the ``LANDLOCK_ACCESS_FS_TRUNCATE`` -right is associated with the newly created file descriptor and will be used for -subsequent truncation attempts using :manpage:`ftruncate(2)`. The behavior is -similar to opening a file for reading or writing, where permissions are checked -during :manpage:`open(2)`, but not during the subsequent :manpage:`read(2)` and +The truncate right is associated with the opened file (see below). + +Rights associated with file descriptors +--------------------------------------- + +When opening a file, the availability of the ``LANDLOCK_ACCESS_FS_TRUNCATE`` and +``LANDLOCK_ACCESS_FS_IOCTL`` rights is associated with the newly created file +descriptor and will be used for subsequent truncation and ioctl attempts using +:manpage:`ftruncate(2)` and :manpage:`ioctl(2)`. The behavior is similar to +opening a file for reading or writing, where permissions are checked during +:manpage:`open(2)`, but not during the subsequent :manpage:`read(2)` and :manpage:`write(2)` calls. -As a consequence, it is possible to have multiple open file descriptors for the -same file, where one grants the right to truncate the file and the other does -not. It is also possible to pass such file descriptors between processes, -keeping their Landlock properties, even when these processes do not have an -enforced Landlock ruleset. +As a consequence, it is possible to have multiple open file descriptors +referring to the same file, where one grants the truncate or ioctl right and the +other does not. It is also possible to pass such file descriptors between +processes, keeping their Landlock properties, even when these processes do not +have an enforced Landlock ruleset. Compatibility ============= @@ -457,6 +469,28 @@ Memory usage Kernel memory allocated to create rulesets is accounted and can be restricted by the Documentation/admin-guide/cgroup-v1/memory.rst. +IOCTL support +------------- + +The ``LANDLOCK_ACCESS_FS_IOCTL`` access right restricts the use of +:manpage:`ioctl(2)`, but it only applies to newly opened files. This means +specifically that pre-existing file descriptors like stdin, stdout and stderr +are unaffected. + +Users should be aware that TTY devices have traditionally permitted to control +other processes on the same TTY through the ``TIOCSTI`` and ``TIOCLINUX`` IOCTL +commands. It is therefore recommended to close inherited TTY file descriptors, +or to reopen them from ``/proc/self/fd/*`` without the +``LANDLOCK_ACCESS_FS_IOCTL`` right, if possible. The :manpage:`isatty(3)` +function checks whether a given file descriptor is a TTY. + +Landlock's IOCTL support is coarse-grained at the moment, but may become more +fine-grained in the future. Until then, users are advised to establish the +guarantees that they need through the file hierarchy, by only permitting the +``LANDLOCK_ACCESS_FS_IOCTL`` right on files where it is really harmless. In +cases where you can control the mounts, the ``nodev`` mount option can help to +rule out that device files can be accessed. + Previous limitations ==================== @@ -494,6 +528,16 @@ bind and connect actions to only a set of allowed ports thanks to the new ``LANDLOCK_ACCESS_NET_BIND_TCP`` and ``LANDLOCK_ACCESS_NET_CONNECT_TCP`` access rights. +Ioctl (ABI < 5) +--------------- + +IOCTL operations could not be denied before the fourth Landlock ABI, so +:manpage:`ioctl(2)` is always allowed when using a kernel that only supports an +earlier ABI. + +Starting with the Landlock ABI version 4, it is possible to restrict the use of +:manpage:`ioctl(2)` using the new ``LANDLOCK_ACCESS_FS_IOCTL`` access right. + .. _kernel_support: Kernel support diff --git a/include/uapi/linux/landlock.h b/include/uapi/linux/landlock.h index 6d41c059e910..3af0b1590f1b 100644 --- a/include/uapi/linux/landlock.h +++ b/include/uapi/linux/landlock.h @@ -205,11 +205,31 @@ struct landlock_net_port_attr { * file or directory. * * This access right applies to all :manpage:`ioctl(2)` commands, except of - * ``FIOCLEX``, ``FIONCLEX``, ``FIONBIO``, ``FIOASYNC`` and ``FIONREAD``. - * These commands continue to be invokable independent of the - * %LANDLOCK_ACCESS_FS_IOCTL access right. + * ``FIOCLEX``, ``FIONCLEX``, ``FIONBIO`` and ``FIOASYNC``. These commands + * continue to be invokable independent of the %LANDLOCK_ACCESS_FS_IOCTL + * access right. * - * This access right is available since the fourth version of the Landlock + * When certain other access rights are handled in the ruleset, in addition to + * %LANDLOCK_ACCESS_FS_IOCTL, granting these access rights will unlock access + * to additional groups of IOCTL commands, on the affected files: + * + * * %LANDLOCK_ACCESS_FS_READ_FILE unlocks access to ``FIOQSIZE``, + * ``FS_IOC_FIEMAP``, ``FIBMAP``, ``FIGETBSZ``, ``FIONREAD``, + * ``FIDEDUPRANGE``. + * + * * %LANDLOCK_ACCESS_FS_WRITE_FILE unlocks access to ``FIOQSIZE``, + * ``FS_IOC_FIEMAP``, ``FIBMAP``, ``FIGETBSZ``, ``FICLONE``, + * ``FICLONERANGE``, ``FS_IOC_RESVSP``, ``FS_IOC_RESVSP64``, + * ``FS_IOC_UNRESVSP``, ``FS_IOC_UNRESVSP64``, ``FS_IOC_ZERO_RANGE``. + * + * * %LANDLOCK_ACCESS_FS_READ_DIR unlocks access to ``FIOQSIZE``, + * ``FS_IOC_FIEMAP``, ``FIBMAP``, ``FIGETBSZ``. + * + * When these access rights are handled in the ruleset, the availability of + * the affected IOCTL commands is not governed by %LANDLOCK_ACCESS_FS_IOCTL + * any more, but by the respective access right. + * + * This access right is available since the fifth version of the Landlock * ABI. * * .. warning::