From patchwork Mon Jun 12 10:27:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Larsson X-Patchwork-Id: 13276251 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D373318AE1 for ; Mon, 12 Jun 2023 10:27:38 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1686565657; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=MOlfdaPnMmUP9g7vcnNIn0Q1D7Ns0mSoof416/Dem7s=; b=Y28Z1cgYlkXmnsXuR4v+iQMOL2jTDxEizXnEpkmEj3v0pu7ciaiK5LHhMGvM0o5tyl79wO MCYoiIkC/MUksMyKcVTxiSN6xfgLsnudCd6jfc1zv/qHJG8lTlkoAwy48PEnP319t/vM7p MlbGa5lVJqvlWFwEK0GnlPiDS8pg5Os= Received: from mail-lf1-f72.google.com (mail-lf1-f72.google.com [209.85.167.72]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-341-piRnNV4JOWWzS1vkbXEnXA-1; Mon, 12 Jun 2023 06:27:36 -0400 X-MC-Unique: piRnNV4JOWWzS1vkbXEnXA-1 Received: by mail-lf1-f72.google.com with SMTP id 2adb3069b0e04-4f517b5309cso2808819e87.1 for ; Mon, 12 Jun 2023 03:27:36 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1686565655; x=1689157655; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=MOlfdaPnMmUP9g7vcnNIn0Q1D7Ns0mSoof416/Dem7s=; b=Y0QeLtbtoSuQPn97rqcEdPGOPILUQpxBSgAgihtTB0YOTA3IfEPaBd9hf8p20VvjO0 x3FhEYgUBAUc+U8CCK25HgCxYoVRv6j+RLJ5M3vZ8/DyOj02zJ7zQpiUYU6p4PHjN9/P DnGZ6tOSAYUc7VuXuY+WXdzxI9ySjlLw1PBF+KoafcY49CTmxPg1PnO/TjFZn9eNm1qG EUoXXGRtifFFzdU5gBBpHTENdFqGz+6bYclPgcqCSdcJGO0iKP+3gwlbbqcMpZcgHLbX eeQJ5pST7QhtoqVK6w8K1aogQH1VG/K6UczsJpUAZ9g6IAaqCjhceWNFWFhnAzfDtW2D YEug== X-Gm-Message-State: AC+VfDzDstgRbr2HsLWPaOJlB3yahHGChDD3K6JUqPwbaGjfccgp5u3b pIQsPw4TM3Haa8JaFOpjkPHLzYqqyjmVj+PIV/GM85iHp+RXX6bFO0XU+AtDx085kakpHU2X1/4 7SkTtv6XquaHBQhA3UgQlY4FJDGw= X-Received: by 2002:a2e:7202:0:b0:2b2:10e2:af0a with SMTP id n2-20020a2e7202000000b002b210e2af0amr2396407ljc.33.1686565654818; Mon, 12 Jun 2023 03:27:34 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ6Tlb2tgmCHslDPEzeAtOL6Icrk3GS4shFBMdzO/O//Sb0hXSor67hV+FKKKU9/Vvd1R6p5OQ== X-Received: by 2002:a2e:7202:0:b0:2b2:10e2:af0a with SMTP id n2-20020a2e7202000000b002b210e2af0amr2396391ljc.33.1686565654453; Mon, 12 Jun 2023 03:27:34 -0700 (PDT) Received: from localhost.localdomain (c-e6a5e255.022-110-73746f36.bbcust.telenor.se. [85.226.165.230]) by smtp.googlemail.com with ESMTPSA id m25-20020a2e8719000000b002b1fc6e70a1sm1709095lji.21.2023.06.12.03.27.33 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 12 Jun 2023 03:27:34 -0700 (PDT) From: Alexander Larsson To: miklos@szeredi.hu Cc: linux-unionfs@vger.kernel.org, amir73il@gmail.com, ebiggers@kernel.org, tytso@mit.edu, fsverity@lists.linux.dev, Alexander Larsson Subject: [PATCH v3 1/4] fsverity: Export fsverity_get_digest Date: Mon, 12 Jun 2023 12:27:16 +0200 Message-Id: X-Mailer: git-send-email 2.40.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Overlayfs needs to call this when built in module form, so we need to export the symbol. This uses EXPORT_SYMBOL_GPL like the other fsverity functions do. Signed-off-by: Alexander Larsson --- fs/verity/measure.c | 1 + 1 file changed, 1 insertion(+) diff --git a/fs/verity/measure.c b/fs/verity/measure.c index 5c79ea1b2468..875d143e0c7e 100644 --- a/fs/verity/measure.c +++ b/fs/verity/measure.c @@ -85,3 +85,4 @@ int fsverity_get_digest(struct inode *inode, *alg = hash_alg->algo_id; return 0; } +EXPORT_SYMBOL_GPL(fsverity_get_digest); From patchwork Mon Jun 12 10:27:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Larsson X-Patchwork-Id: 13276252 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id B6C9918C35 for ; Mon, 12 Jun 2023 10:27:39 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1686565658; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=aeit6h80Zdq6WJHBTSrV8Dc72rDW1CQNTkd48dADSPI=; b=TGTKKlR35lY4ZLU4wHLgn6aPcCoIP22L5Rk/x/I/WQAklf5xwdqpVtrPnmcmPJnh3eyukg a5Z/eTPyVsH+zbUo7kPRTQAqg/u5grn6s8CTtlrveZWfLFWXJQZPDmtZtwL349maI8TCbF 2qUICsNC1uifmnYalKsfupovFaRgIOg= Received: from mail-lf1-f69.google.com (mail-lf1-f69.google.com [209.85.167.69]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-303-zSEcaRhGMx6hs1wp5HwS9A-1; Mon, 12 Jun 2023 06:27:37 -0400 X-MC-Unique: zSEcaRhGMx6hs1wp5HwS9A-1 Received: by mail-lf1-f69.google.com with SMTP id 2adb3069b0e04-4f644a01d7eso2197032e87.0 for ; Mon, 12 Jun 2023 03:27:37 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1686565655; x=1689157655; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=aeit6h80Zdq6WJHBTSrV8Dc72rDW1CQNTkd48dADSPI=; b=KF0G8FlsOwE+PljFM7wXAQc7hL4cb8fJeWayn3jLRjmy6UdowIo5RmD4P+rPxTJEiL sZ1XxPgbj46BlDA3XvuE8+8WShaKje7YwnxAz6FM9DQ/ZR1yH9l/1bRFv91xNYASJwcI B9ZOD/X2JS8msltWKE4mkdyBOSFuOowD6uDoiY6+0HwCZ7QqLhpWRRzpUCUZPEZ58tit JTiwfMwPjXGogZVUoFaTsZBeQsMATT1fKind93nRgHSS6qs8LAZD+7o8MRPbd3qqIpsH iAyD4LOIS9dv5P7uelwq6y5vt66zbm20bY6QeBYb8CRWy/PiAfInMYCyB/+5jP2u5QF2 hGuQ== X-Gm-Message-State: AC+VfDztu2+YLf1tJ6RTUadxP5zXuRbS29jJprWBVeVa7s2Skri6N9IM aCFbPe+i6gf6vkg+SWgdS6YF5KzPiGAD4btb71FlktXZKUBWYMZrjfgxEK9gI3Pa3yct8q2Rx2A LcO+GaA2mB4xfGt504HE= X-Received: by 2002:a05:6512:684:b0:4f4:e509:ef56 with SMTP id t4-20020a056512068400b004f4e509ef56mr2968785lfe.25.1686565655534; Mon, 12 Jun 2023 03:27:35 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ5lB+wiVhTCIhqV88towchIE8U4yntZMAHNAXqQFsjmUqOmCxpi08WOTo51Tt42IlFOQ8XvVg== X-Received: by 2002:a05:6512:684:b0:4f4:e509:ef56 with SMTP id t4-20020a056512068400b004f4e509ef56mr2968781lfe.25.1686565655283; Mon, 12 Jun 2023 03:27:35 -0700 (PDT) Received: from localhost.localdomain (c-e6a5e255.022-110-73746f36.bbcust.telenor.se. [85.226.165.230]) by smtp.googlemail.com with ESMTPSA id m25-20020a2e8719000000b002b1fc6e70a1sm1709095lji.21.2023.06.12.03.27.34 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 12 Jun 2023 03:27:34 -0700 (PDT) From: Alexander Larsson To: miklos@szeredi.hu Cc: linux-unionfs@vger.kernel.org, amir73il@gmail.com, ebiggers@kernel.org, tytso@mit.edu, fsverity@lists.linux.dev, Alexander Larsson Subject: [PATCH v3 2/4] ovl: Add framework for verity support Date: Mon, 12 Jun 2023 12:27:17 +0200 Message-Id: <03ac0ffd82bc1edc3a9baa68d1125f5e8cad93fd.1686565330.git.alexl@redhat.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com This adds the scaffolding (docs, config, mount options) for supporting the new overlay xattr "overlay.verity", which contains a fs-verity digest. This is used for metacopy files, and the actual fs-verity digest of the lowerdata file needs to match it. The mount option "verity" specifies how this xattr is handled. If you enable verity ("verity=on") all existing xattrs are validated before use, and during metacopy we generate verity xattr in the upper metacopy file (if the source file has verity enabled). This means later accesses can guarantee that the same data is used. Additionally you can use "verity=require". In this mode all metacopy files must have a valid verity xattr. For this to work metadata copy-up must be able to create a verity xattr (so that later accesses are validated). Therefore, in this mode, if the lower data file doesn't have fs-verity enabled we fall back to a full copy rather than a metacopy. Actual implementation follows in a separate commit. Signed-off-by: Alexander Larsson --- Documentation/filesystems/overlayfs.rst | 27 +++++++++ fs/overlayfs/ovl_entry.h | 3 + fs/overlayfs/super.c | 74 ++++++++++++++++++++++++- 3 files changed, 102 insertions(+), 2 deletions(-) diff --git a/Documentation/filesystems/overlayfs.rst b/Documentation/filesystems/overlayfs.rst index 4f36b8919f7c..9497988557b9 100644 --- a/Documentation/filesystems/overlayfs.rst +++ b/Documentation/filesystems/overlayfs.rst @@ -406,6 +406,33 @@ when a "metacopy" file in one of the lower layers above it, has a "redirect" to the absolute path of the "lower data" file in the "data-only" lower layer. +fs-verity support +---------------------- + +When metadata copy up is used for a file, then the xattr +"trusted.overlay.verity" may be set on the metacopy file. This +specifies the expected fs-verity digest of the lowerdata file. This +may then be used to verify the content of the source file at the time +the file is opened. During metacopy copy up overlayfs can also set +this xattr. + +This is controlled by the "verity" mount option, which supports +these values: + +- "off": + The verity xattr is never used. This is the default if verity + option is not specified. +- "on": + Whenever a metacopy files specifies an expected digest, the + corresponding data file must match the specified digest. + When generating a metacopy file the verity xattr will be set + from the source file fs-verity digest (if it has one). +- "require": + Same as "on", but additionally all metacopy files must specify a + verity xattr. This means metadata copy up will only be used if + the data file has fs-verity enabled, otherwise a full copy-up is + used. + Sharing and copying layers -------------------------- diff --git a/fs/overlayfs/ovl_entry.h b/fs/overlayfs/ovl_entry.h index c6c7d09b494e..95464a1cb371 100644 --- a/fs/overlayfs/ovl_entry.h +++ b/fs/overlayfs/ovl_entry.h @@ -13,6 +13,9 @@ struct ovl_config { bool redirect_dir; bool redirect_follow; const char *redirect_mode; + bool verity; + bool require_verity; + const char *verity_mode; bool index; bool uuid; bool nfs_export; diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index d9be5d318e1b..f3b51fe59f68 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -244,6 +244,7 @@ static void ovl_free_fs(struct ovl_fs *ofs) kfree(ofs->config.upperdir); kfree(ofs->config.workdir); kfree(ofs->config.redirect_mode); + kfree(ofs->config.verity_mode); if (ofs->creator_cred) put_cred(ofs->creator_cred); kfree(ofs); @@ -334,6 +335,11 @@ static const char *ovl_redirect_mode_def(void) return ovl_redirect_dir_def ? "on" : "off"; } +static const char *ovl_verity_mode_def(void) +{ + return "off"; +} + static const char * const ovl_xino_str[] = { "off", "auto", @@ -383,6 +389,8 @@ static int ovl_show_options(struct seq_file *m, struct dentry *dentry) seq_puts(m, ",volatile"); if (ofs->config.userxattr) seq_puts(m, ",userxattr"); + if (strcmp(ofs->config.verity_mode, ovl_verity_mode_def()) != 0) + seq_printf(m, ",verity=%s", ofs->config.verity_mode); return 0; } @@ -438,6 +446,7 @@ enum { OPT_METACOPY_ON, OPT_METACOPY_OFF, OPT_VOLATILE, + OPT_VERITY, OPT_ERR, }; @@ -460,6 +469,7 @@ static const match_table_t ovl_tokens = { {OPT_METACOPY_ON, "metacopy=on"}, {OPT_METACOPY_OFF, "metacopy=off"}, {OPT_VOLATILE, "volatile"}, + {OPT_VERITY, "verity=%s"}, {OPT_ERR, NULL} }; @@ -509,6 +519,21 @@ static int ovl_parse_redirect_mode(struct ovl_config *config, const char *mode) return 0; } +static int ovl_parse_verity_mode(struct ovl_config *config, const char *mode) +{ + if (strcmp(mode, "on") == 0) { + config->verity = true; + } else if (strcmp(mode, "require") == 0) { + config->verity = true; + config->require_verity = true; + } else if (strcmp(mode, "off") != 0) { + pr_err("bad mount option \"verity=%s\"\n", mode); + return -EINVAL; + } + + return 0; +} + static int ovl_parse_opt(char *opt, struct ovl_config *config) { char *p; @@ -520,6 +545,10 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config) if (!config->redirect_mode) return -ENOMEM; + config->verity_mode = kstrdup(ovl_verity_mode_def(), GFP_KERNEL); + if (!config->verity_mode) + return -ENOMEM; + while ((p = ovl_next_opt(&opt)) != NULL) { int token; substring_t args[MAX_OPT_ARGS]; @@ -620,6 +649,13 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config) config->userxattr = true; break; + case OPT_VERITY: + kfree(config->verity_mode); + config->verity_mode = match_strdup(&args[0]); + if (!config->verity_mode) + return -ENOMEM; + break; + default: pr_err("unrecognized mount option \"%s\" or missing value\n", p); @@ -651,6 +687,22 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config) if (err) return err; + err = ovl_parse_verity_mode(config, config->verity_mode); + if (err) + return err; + + /* Resolve verity -> metacopy dependency */ + if (config->verity && !config->metacopy) { + /* Don't allow explicit specified conflicting combinations */ + if (metacopy_opt) { + pr_err("conflicting options: metacopy=off,verity=%s\n", + config->verity_mode); + return -EINVAL; + } + /* Otherwise automatically enable metacopy. */ + config->metacopy = true; + } + /* * This is to make the logic below simpler. It doesn't make any other * difference, since config->redirect_dir is only used for upper. @@ -665,6 +717,11 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config) config->redirect_mode); return -EINVAL; } + if (config->verity && redirect_opt) { + pr_err("conflicting options: verity=%s,redirect_dir=%s\n", + config->verity_mode, config->redirect_mode); + return -EINVAL; + } if (redirect_opt) { /* * There was an explicit redirect_dir=... that resulted @@ -700,7 +757,7 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config) } } - /* Resolve nfs_export -> !metacopy dependency */ + /* Resolve nfs_export -> !metacopy && !verity dependency */ if (config->nfs_export && config->metacopy) { if (nfs_export_opt && metacopy_opt) { pr_err("conflicting options: nfs_export=on,metacopy=on\n"); @@ -713,6 +770,14 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config) */ pr_info("disabling nfs_export due to metacopy=on\n"); config->nfs_export = false; + } else if (config->verity) { + /* + * There was an explicit verity=.. that resulted + * in this conflict. + */ + pr_info("disabling nfs_export due to verity=%s\n", + config->verity_mode); + config->nfs_export = false; } else { /* * There was an explicit nfs_export=on that resulted @@ -724,7 +789,7 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config) } - /* Resolve userxattr -> !redirect && !metacopy dependency */ + /* Resolve userxattr -> !redirect && !metacopy && !verity dependency */ if (config->userxattr) { if (config->redirect_follow && redirect_opt) { pr_err("conflicting options: userxattr,redirect_dir=%s\n", @@ -735,6 +800,11 @@ static int ovl_parse_opt(char *opt, struct ovl_config *config) pr_err("conflicting options: userxattr,metacopy=on\n"); return -EINVAL; } + if (config->verity) { + pr_err("conflicting options: userxattr,verity=%s\n", + config->verity_mode); + return -EINVAL; + } /* * Silently disable default setting of redirect and metacopy. * This shall be the default in the future as well: these From patchwork Mon Jun 12 10:27:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Larsson X-Patchwork-Id: 13276253 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 513BE18C38 for ; Mon, 12 Jun 2023 10:27:40 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1686565659; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=0mp6ds2De26/2K//5O82azy6nRH4SyaQ6cCRG30Yw5w=; b=Ma3zzz0BF2MeyMkWWdIObiZTjZn7e0Kfai/3YPdQ6jE2VxAgZBWlLqkaewy4E5O+i2axrx MjxFuSIkFcmoOi8YLiUCUsaWL4pD5qN6dcwrnfq/izarXNv+dlkKTUWlmeYn5ZMrSj/dtN lmFy6Sv47aZdm2aaukA7zfauVlQ9bXk= Received: from mail-lj1-f198.google.com (mail-lj1-f198.google.com [209.85.208.198]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-343-T6M7UQhLMYedRjjZcrsGog-1; Mon, 12 Jun 2023 06:27:38 -0400 X-MC-Unique: T6M7UQhLMYedRjjZcrsGog-1 Received: by mail-lj1-f198.google.com with SMTP id 38308e7fff4ca-2b1b845cbdbso25341261fa.0 for ; Mon, 12 Jun 2023 03:27:37 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1686565656; x=1689157656; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=0mp6ds2De26/2K//5O82azy6nRH4SyaQ6cCRG30Yw5w=; b=S1T8jBWEZ1zIIUv3C20vTOEVmZmTDVBaHOdLwFrhxNgI0u+ojLhndni5uROc6JLLWk sRM7bwpvCCzLxNhiZptfQWccTDjb4i4nFWfVTTL3BIG9GTYQH/YvnydBFjnGVKCojW+/ +ZTMHh3Reju0YCILl7oYcnXaoG92rBgHSvxpRKuyxg1dCjzDreCJC+UT3KrxTJ2SItZ6 qGOvDnSjDKDmmRzm+LM2wdFzJG9Qbq1Y94fEIslQhA9Hhys4NB+4ugLrrQiDR95vLWdw nRBByKT8t8Wb68LrCbK+dUfXwElAJIeY8T1PUPyCwGzYKA3Qn3PkoXr29WFnCv1i/AQz EtFw== X-Gm-Message-State: AC+VfDwtiFAL4Gr4mbxKXPLzPWMSHdPW3fv3Ybmgcpi9dnU9QQCsAaz1 OLIf8ZWFN7OT0xgiD37JLJzxy5x401KucqSFIJgiQWwl5CxKNWNAUKR/apcdZ6X+psoY9ViM/Bo CsGrzfS9S4dtYFFVZJFU= X-Received: by 2002:a2e:87c3:0:b0:2b1:a8e9:df4a with SMTP id v3-20020a2e87c3000000b002b1a8e9df4amr2739897ljj.6.1686565656353; Mon, 12 Jun 2023 03:27:36 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ7sIlSkVV2glWnfs1x/iEP+4Z4IjLWRyhFyHtbwoOW5ab9KZZQoYD8Th3/jhXkXlWtMaqa1SQ== X-Received: by 2002:a2e:87c3:0:b0:2b1:a8e9:df4a with SMTP id v3-20020a2e87c3000000b002b1a8e9df4amr2739887ljj.6.1686565656074; Mon, 12 Jun 2023 03:27:36 -0700 (PDT) Received: from localhost.localdomain (c-e6a5e255.022-110-73746f36.bbcust.telenor.se. [85.226.165.230]) by smtp.googlemail.com with ESMTPSA id m25-20020a2e8719000000b002b1fc6e70a1sm1709095lji.21.2023.06.12.03.27.35 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 12 Jun 2023 03:27:35 -0700 (PDT) From: Alexander Larsson To: miklos@szeredi.hu Cc: linux-unionfs@vger.kernel.org, amir73il@gmail.com, ebiggers@kernel.org, tytso@mit.edu, fsverity@lists.linux.dev, Alexander Larsson Subject: [PATCH v3 3/4] ovl: Validate verity xattr when resolving lowerdata Date: Mon, 12 Jun 2023 12:27:18 +0200 Message-Id: X-Mailer: git-send-email 2.40.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com When accessing file data the first time we check the overlay.verity xattr on the metadata inode, and if set verify that the source lowerdata inode matches it (according to the verity options enabled). If the verity check passes we store this info in the inode flags as OVL_VERIFIED, so that we can avoid doing it again if the inode remains in memory. The verification is done in ovl_maybe_validate_verity() which needs to be called in the same places as ovl_maybe_lookup_lowerdata(), so there is a new ovl_verify_lowerdata() helper that calls these in the right order, and all current callers of ovl_maybe_lookup_lowerdata() are changed to call it instead. Signed-off-by: Alexander Larsson --- fs/overlayfs/copy_up.c | 2 +- fs/overlayfs/file.c | 8 ++-- fs/overlayfs/namei.c | 54 +++++++++++++++++++++- fs/overlayfs/overlayfs.h | 9 +++- fs/overlayfs/super.c | 5 ++- fs/overlayfs/util.c | 96 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 166 insertions(+), 8 deletions(-) diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 568f743a5584..68f01fd7f211 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -1078,7 +1078,7 @@ static int ovl_copy_up_flags(struct dentry *dentry, int flags) * not very important to optimize this case, so do lazy lowerdata lookup * before any copy up, so we can do it before taking ovl_inode_lock(). */ - err = ovl_maybe_lookup_lowerdata(dentry); + err = ovl_verify_lowerdata(dentry); if (err) return err; diff --git a/fs/overlayfs/file.c b/fs/overlayfs/file.c index 39737c2aaa84..6583d08fdb7a 100644 --- a/fs/overlayfs/file.c +++ b/fs/overlayfs/file.c @@ -115,8 +115,8 @@ static int ovl_real_fdget_meta(const struct file *file, struct fd *real, if (allow_meta) { ovl_path_real(dentry, &realpath); } else { - /* lazy lookup of lowerdata */ - err = ovl_maybe_lookup_lowerdata(dentry); + /* lazy lookup and verify of lowerdata */ + err = ovl_verify_lowerdata(dentry); if (err) return err; @@ -159,8 +159,8 @@ static int ovl_open(struct inode *inode, struct file *file) struct path realpath; int err; - /* lazy lookup of lowerdata */ - err = ovl_maybe_lookup_lowerdata(dentry); + /* lazy lookup and verify lowerdata */ + err = ovl_verify_lowerdata(dentry); if (err) return err; diff --git a/fs/overlayfs/namei.c b/fs/overlayfs/namei.c index 292b8a948f1a..d91650f71fab 100644 --- a/fs/overlayfs/namei.c +++ b/fs/overlayfs/namei.c @@ -889,8 +889,49 @@ static int ovl_fix_origin(struct ovl_fs *ofs, struct dentry *dentry, return err; } +static int ovl_maybe_validate_verity(struct dentry *dentry) +{ + struct ovl_fs *ofs = dentry->d_sb->s_fs_info; + struct inode *inode = d_inode(dentry); + struct path datapath, metapath; + int err; + + if (!ofs->config.verity || + !ovl_is_metacopy_dentry(dentry) || + ovl_test_flag(OVL_VERIFIED, inode)) + return 0; + + ovl_path_lowerdata(dentry, &datapath); + if (!datapath.dentry) + return -EIO; + + ovl_path_real(dentry, &metapath); + if (!metapath.dentry) + return -EIO; + + err = ovl_inode_lock_interruptible(inode); + if (err) + return err; + + if (!ovl_test_flag(OVL_VERIFIED, inode)) { + const struct cred *old_cred; + + old_cred = ovl_override_creds(dentry->d_sb); + + err = ovl_validate_verity(ofs, &metapath, &datapath); + if (err == 0) + ovl_set_flag(OVL_VERIFIED, inode); + + revert_creds(old_cred); + } + + ovl_inode_unlock(inode); + + return err; +} + /* Lazy lookup of lowerdata */ -int ovl_maybe_lookup_lowerdata(struct dentry *dentry) +static int ovl_maybe_lookup_lowerdata(struct dentry *dentry) { struct inode *inode = d_inode(dentry); const char *redirect = ovl_lowerdata_redirect(inode); @@ -935,6 +976,17 @@ int ovl_maybe_lookup_lowerdata(struct dentry *dentry) goto out; } +int ovl_verify_lowerdata(struct dentry *dentry) +{ + int err; + + err = ovl_maybe_lookup_lowerdata(dentry); + if (err) + return err; + + return ovl_maybe_validate_verity(dentry); +} + struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags) { diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index fcac4e2c56ab..66e3f79ed6d0 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -38,6 +38,7 @@ enum ovl_xattr { OVL_XATTR_UPPER, OVL_XATTR_METACOPY, OVL_XATTR_PROTATTR, + OVL_XATTR_VERITY, }; enum ovl_inode_flag { @@ -49,6 +50,7 @@ enum ovl_inode_flag { OVL_UPPERDATA, /* Inode number will remain constant over copy up. */ OVL_CONST_INO, + OVL_VERIFIED, }; enum ovl_entry_flag { @@ -460,6 +462,11 @@ int ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *upperdir); int ovl_check_metacopy_xattr(struct ovl_fs *ofs, const struct path *path); bool ovl_is_metacopy_dentry(struct dentry *dentry); char *ovl_get_redirect_xattr(struct ovl_fs *ofs, const struct path *path, int padding); +int ovl_get_verity_xattr(struct ovl_fs *ofs, const struct path *path, + u8 *digest_buf, int *buf_length); +int ovl_validate_verity(struct ovl_fs *ofs, + struct path *metapath, + struct path *datapath); int ovl_sync_status(struct ovl_fs *ofs); static inline void ovl_set_flag(unsigned long flag, struct inode *inode) @@ -559,7 +566,7 @@ struct dentry *ovl_get_index_fh(struct ovl_fs *ofs, struct ovl_fh *fh); struct dentry *ovl_lookup_index(struct ovl_fs *ofs, struct dentry *upper, struct dentry *origin, bool verify); int ovl_path_next(int idx, struct dentry *dentry, struct path *path); -int ovl_maybe_lookup_lowerdata(struct dentry *dentry); +int ovl_verify_lowerdata(struct dentry *dentry); struct dentry *ovl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags); bool ovl_lower_positive(struct dentry *dentry); diff --git a/fs/overlayfs/super.c b/fs/overlayfs/super.c index f3b51fe59f68..698f97622030 100644 --- a/fs/overlayfs/super.c +++ b/fs/overlayfs/super.c @@ -63,6 +63,7 @@ static struct dentry *ovl_d_real(struct dentry *dentry, const struct inode *inode) { struct dentry *real = NULL, *lower; + int err; /* It's an overlay file */ if (inode && d_inode(dentry) == inode) @@ -89,7 +90,9 @@ static struct dentry *ovl_d_real(struct dentry *dentry, * uprobes on offset within the file, so lowerdata should be available * when setting the uprobe. */ - ovl_maybe_lookup_lowerdata(dentry); + err = ovl_verify_lowerdata(dentry); + if (err) + goto bug; lower = ovl_dentry_lowerdata(dentry); if (!lower) goto bug; diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index 007ad7e5ba5b..a4666ba3d5a3 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c @@ -10,7 +10,9 @@ #include #include #include +#include #include +#include #include #include #include @@ -706,6 +708,7 @@ bool ovl_path_check_dir_xattr(struct ovl_fs *ofs, const struct path *path, #define OVL_XATTR_UPPER_POSTFIX "upper" #define OVL_XATTR_METACOPY_POSTFIX "metacopy" #define OVL_XATTR_PROTATTR_POSTFIX "protattr" +#define OVL_XATTR_VERITY_POSTFIX "verity" #define OVL_XATTR_TAB_ENTRY(x) \ [x] = { [false] = OVL_XATTR_TRUSTED_PREFIX x ## _POSTFIX, \ @@ -720,6 +723,7 @@ const char *const ovl_xattr_table[][2] = { OVL_XATTR_TAB_ENTRY(OVL_XATTR_UPPER), OVL_XATTR_TAB_ENTRY(OVL_XATTR_METACOPY), OVL_XATTR_TAB_ENTRY(OVL_XATTR_PROTATTR), + OVL_XATTR_TAB_ENTRY(OVL_XATTR_VERITY), }; int ovl_check_setxattr(struct ovl_fs *ofs, struct dentry *upperdentry, @@ -1152,6 +1156,98 @@ char *ovl_get_redirect_xattr(struct ovl_fs *ofs, const struct path *path, int pa return ERR_PTR(res); } +int ovl_get_verity_xattr(struct ovl_fs *ofs, const struct path *path, + u8 *digest_buf, int *buf_length) +{ + int res; + + res = ovl_path_getxattr(ofs, path, OVL_XATTR_VERITY, digest_buf, *buf_length); + if (res == -ENODATA || res == -EOPNOTSUPP) + return -ENODATA; + if (res < 0) { + pr_warn_ratelimited("failed to get digest (%i)\n", res); + return res; + } + + *buf_length = res; + return 0; +} + +/* Call with mounter creds as it may open the file */ +static int ovl_ensure_verity_loaded(struct path *datapath) +{ + struct inode *inode = d_inode(datapath->dentry); + const struct fsverity_info *vi; + struct file *filp; + + vi = fsverity_get_info(inode); + if (vi == NULL && IS_VERITY(inode)) { + /* + * If this inode was not yet opened, the verity info hasn't been + * loaded yet, so we need to do that here to force it into memory. + * We use open_with_fake_path to avoid ENFILE. + */ + filp = open_with_fake_path(datapath, O_RDONLY, inode, current_cred()); + if (IS_ERR(filp)) + return PTR_ERR(filp); + fput(filp); + } + + return 0; +} + +int ovl_validate_verity(struct ovl_fs *ofs, + struct path *metapath, + struct path *datapath) +{ + u8 xattr_data[1+FS_VERITY_MAX_DIGEST_SIZE]; + u8 actual_digest[FS_VERITY_MAX_DIGEST_SIZE]; + enum hash_algo verity_algo; + int xattr_len; + int err; + + if (!ofs->config.verity || + /* Verity only works on regular files */ + !S_ISREG(d_inode(metapath->dentry)->i_mode)) + return 0; + + xattr_len = sizeof(xattr_data); + err = ovl_get_verity_xattr(ofs, metapath, xattr_data, &xattr_len); + if (err == -ENODATA) { + if (ofs->config.require_verity) { + pr_warn_ratelimited("metacopy file '%pd' has no overlay.verity xattr\n", + metapath->dentry); + return -EIO; + } + return 0; + } + if (err < 0) + return err; + + err = ovl_ensure_verity_loaded(datapath); + if (err < 0) { + pr_warn_ratelimited("lower file '%pd' failed to load fs-verity info\n", + datapath->dentry); + return -EIO; + } + + err = fsverity_get_digest(d_inode(datapath->dentry), actual_digest, &verity_algo); + if (err < 0) { + pr_warn_ratelimited("lower file '%pd' has no fs-verity digest\n", datapath->dentry); + return -EIO; + } + + if (xattr_len != 1 + hash_digest_size[verity_algo] || + xattr_data[0] != (u8) verity_algo || + memcmp(xattr_data+1, actual_digest, xattr_len - 1) != 0) { + pr_warn_ratelimited("lower file '%pd' has the wrong fs-verity digest\n", + datapath->dentry); + return -EIO; + } + + return 0; +} + /* * ovl_sync_status() - Check fs sync status for volatile mounts * From patchwork Mon Jun 12 10:28:52 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Larsson X-Patchwork-Id: 13276254 Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id D36B418C35 for ; Mon, 12 Jun 2023 10:29:06 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1686565745; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=iEQmyQNVAzKcTEE74rlVfw4H6L2aXy1KJMuz/Y07SWE=; b=I+4R4wwWkeeaqg7BKSPJ4OQleIw+ci/i/Rh0XGzUtSDeXJjN3tu8R44LNKMrynl8WKZTo4 vBj7yS9hYADhY0O4BYf2LUXsJe/F1KeV/DkX0HTsb1jqJIUZapOG6pwFQ/QcKB8KWaO0P3 DQsjOGX/WMEAQvlbsMyHJPoPHYi2krI= Received: from mail-lf1-f71.google.com (mail-lf1-f71.google.com [209.85.167.71]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-592-ULaZx71IPGmqkNPeC0jcbA-1; Mon, 12 Jun 2023 06:29:04 -0400 X-MC-Unique: ULaZx71IPGmqkNPeC0jcbA-1 Received: by mail-lf1-f71.google.com with SMTP id 2adb3069b0e04-4edbdd8268bso3006274e87.2 for ; Mon, 12 Jun 2023 03:29:04 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1686565743; x=1689157743; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=iEQmyQNVAzKcTEE74rlVfw4H6L2aXy1KJMuz/Y07SWE=; b=R8aQtoOOciCPfmWUN0R8NgJD4uPMb9lw9E4mHQJ8Mset+qse6e9pIN2tOAVTKtSSB8 stHvld6OhmReyeJkleU8bg3STTDCVGU3kq+Bu0Ki7Lbme1hmeS4bhdWjtIkjhX9Uu0BQ jHR6ti1VgbGnEGHlNeij+X959Zpre0y3iJhuAJWfkNctCiS58RwZk4Oje7DMkk6rZA4T vqRimemnE3RttIwAZ2rJN/vO9su5CjtpSg5ybUc1t+KVjpgOxzq4K0DUzeApFvO0YfB8 j+RVI4IDJInqdWKc872+8O3L9cj1DyTcdgl+oS4WmP6qqOHlgGJylSkAGI2YNz8LKEcV 4LXg== X-Gm-Message-State: AC+VfDwCylXOYJfqxXASmX/h9NjbeQ2RB69uFL9mxVIuucDOoiItMHLm kFwswoDYzLEftBFS/AznIk02ixEWAe+djyBQg7crc+hvrYzxwK2OFNHShYOdlTNS4blm0lPFvAm 8nSgMYsIfSXQ07+m7ypo= X-Received: by 2002:a19:6515:0:b0:4f3:8c0d:41c1 with SMTP id z21-20020a196515000000b004f38c0d41c1mr2937997lfb.64.1686565742873; Mon, 12 Jun 2023 03:29:02 -0700 (PDT) X-Google-Smtp-Source: ACHHUZ4QMYjVNGe/8N9i23HxhQDVbprbNNR8UADyWQoKFuA/h466q1uzdiJHgsDGFW0BTgd1MO4BpA== X-Received: by 2002:a19:6515:0:b0:4f3:8c0d:41c1 with SMTP id z21-20020a196515000000b004f38c0d41c1mr2937984lfb.64.1686565742543; Mon, 12 Jun 2023 03:29:02 -0700 (PDT) Received: from localhost.localdomain (c-e6a5e255.022-110-73746f36.bbcust.telenor.se. [85.226.165.230]) by smtp.googlemail.com with ESMTPSA id a16-20020a19f810000000b004f61187363asm1402238lff.66.2023.06.12.03.29.01 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 12 Jun 2023 03:29:02 -0700 (PDT) From: Alexander Larsson To: miklos@szeredi.hu Cc: linux-unionfs@vger.kernel.org, amir73il@gmail.com, ebiggers@kernel.org, tytso@mit.edu, fsverity@lists.linux.dev, Alexander Larsson Subject: [PATCH v3 4/4] ovl: Handle verity during copy-up Date: Mon, 12 Jun 2023 12:28:52 +0200 Message-Id: <4548bcf591f7928606c2f487274292b512927d4f.1686565330.git.alexl@redhat.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: References: Precedence: bulk X-Mailing-List: fsverity@lists.linux.dev List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com During regular metacopy, if lowerdata file has fs-verity enabled, set the new overlay.verity xattr (if enabled). During real data copy up, remove any old overlay.verity xattr. If verity is required, and lowerdata does not have fs-verity enabled, fall back to full copy-up (or the generated metacopy would not validate). Signed-off-by: Alexander Larsson --- fs/overlayfs/copy_up.c | 31 +++++++++++++++++++++++++++++++ fs/overlayfs/overlayfs.h | 3 +++ fs/overlayfs/util.c | 39 ++++++++++++++++++++++++++++++++++++++- 3 files changed, 72 insertions(+), 1 deletion(-) diff --git a/fs/overlayfs/copy_up.c b/fs/overlayfs/copy_up.c index 68f01fd7f211..67c4f14c694c 100644 --- a/fs/overlayfs/copy_up.c +++ b/fs/overlayfs/copy_up.c @@ -19,6 +19,7 @@ #include #include #include +#include #include "overlayfs.h" #define OVL_COPY_UP_CHUNK_SIZE (1 << 20) @@ -643,6 +644,18 @@ static int ovl_copy_up_metadata(struct ovl_copy_up_ctx *c, struct dentry *temp) if (c->metacopy) { err = ovl_check_setxattr(ofs, temp, OVL_XATTR_METACOPY, NULL, 0, -EOPNOTSUPP); + + /* Copy the verity digest if any so we can validate the copy-up later */ + if (!err) { + struct path lowerdatapath; + + ovl_path_lowerdata(c->dentry, &lowerdatapath); + if (WARN_ON_ONCE(lowerdatapath.dentry == NULL)) + err = -EIO; + else + err = ovl_set_verity_xattr_from(ofs, temp, &lowerdatapath); + } + if (err) return err; } @@ -918,6 +931,19 @@ static bool ovl_need_meta_copy_up(struct dentry *dentry, umode_t mode, if (flags && ((OPEN_FMODE(flags) & FMODE_WRITE) || (flags & O_TRUNC))) return false; + /* Fall back to full copy if no fsverity on source data and we require verity */ + if (ofs->config.require_verity) { + struct path lowerdata; + + ovl_path_lowerdata(dentry, &lowerdata); + + if (WARN_ON_ONCE(lowerdata.dentry == NULL) || + ovl_ensure_verity_loaded(&lowerdata) || + !fsverity_get_info(d_inode(lowerdata.dentry))) { + return false; + } + } + return true; } @@ -984,6 +1010,11 @@ static int ovl_copy_up_meta_inode_data(struct ovl_copy_up_ctx *c) if (err) goto out_free; + err = ovl_removexattr(ofs, upperpath.dentry, OVL_XATTR_VERITY); + if (err && err != -ENODATA) + goto out_free; + + err = 0; ovl_set_upperdata(d_inode(c->dentry)); out_free: kfree(capability); diff --git a/fs/overlayfs/overlayfs.h b/fs/overlayfs/overlayfs.h index 66e3f79ed6d0..472bef93cb0b 100644 --- a/fs/overlayfs/overlayfs.h +++ b/fs/overlayfs/overlayfs.h @@ -462,11 +462,14 @@ int ovl_lock_rename_workdir(struct dentry *workdir, struct dentry *upperdir); int ovl_check_metacopy_xattr(struct ovl_fs *ofs, const struct path *path); bool ovl_is_metacopy_dentry(struct dentry *dentry); char *ovl_get_redirect_xattr(struct ovl_fs *ofs, const struct path *path, int padding); +int ovl_ensure_verity_loaded(struct path *path); int ovl_get_verity_xattr(struct ovl_fs *ofs, const struct path *path, u8 *digest_buf, int *buf_length); int ovl_validate_verity(struct ovl_fs *ofs, struct path *metapath, struct path *datapath); +int ovl_set_verity_xattr_from(struct ovl_fs *ofs, struct dentry *dst, + struct path *src); int ovl_sync_status(struct ovl_fs *ofs); static inline void ovl_set_flag(unsigned long flag, struct inode *inode) diff --git a/fs/overlayfs/util.c b/fs/overlayfs/util.c index a4666ba3d5a3..cef907ff66bc 100644 --- a/fs/overlayfs/util.c +++ b/fs/overlayfs/util.c @@ -1174,7 +1174,7 @@ int ovl_get_verity_xattr(struct ovl_fs *ofs, const struct path *path, } /* Call with mounter creds as it may open the file */ -static int ovl_ensure_verity_loaded(struct path *datapath) +int ovl_ensure_verity_loaded(struct path *datapath) { struct inode *inode = d_inode(datapath->dentry); const struct fsverity_info *vi; @@ -1248,6 +1248,43 @@ int ovl_validate_verity(struct ovl_fs *ofs, return 0; } +int ovl_set_verity_xattr_from(struct ovl_fs *ofs, struct dentry *dst, + struct path *src) +{ + int err; + u8 src_digest[1+FS_VERITY_MAX_DIGEST_SIZE]; + enum hash_algo verity_algo; + + if (!ofs->config.verity || !S_ISREG(d_inode(dst)->i_mode)) + return 0; + + err = -EIO; + if (src) { + err = ovl_ensure_verity_loaded(src); + if (err < 0) { + pr_warn_ratelimited("lower file '%pd' failed to load fs-verity info\n", + src->dentry); + return -EIO; + } + + err = fsverity_get_digest(d_inode(src->dentry), src_digest + 1, &verity_algo); + } + if (err == -ENODATA) { + if (ofs->config.require_verity) { + pr_warn_ratelimited("lower file '%pd' has no fs-verity digest\n", + src->dentry); + return -EIO; + } + return 0; + } + if (err < 0) + return err; + + src_digest[0] = (u8)verity_algo; + return ovl_check_setxattr(ofs, dst, OVL_XATTR_VERITY, + src_digest, 1 + hash_digest_size[verity_algo], -EOPNOTSUPP); +} + /* * ovl_sync_status() - Check fs sync status for volatile mounts *