From: Christian Brauner <brauner@kernel.org>
To: Amir Goldstein <amir73il@gmail.com>, linux-fsdevel@vger.kernel.org
Cc: Chris Down <chris@chrisdown.name>,
Miklos Szeredi <mszeredi@redhat.com>,
linux-unionfs@vger.kernel.org, linux-kernel@vger.kernel.org,
bpf@vger.kernel.org, linux-trace-kernel@vger.kernel.org,
linux-integrity@vger.kernel.org,
linux-security-module@vger.kernel.org, linux-mm@kvack.org,
"Christian Brauner (Amutable)" <brauner@kernel.org>
Subject: [PATCH 06/13] ima: handle errors from resolving the real inode
Date: Sun, 15 Nov 2026 15:01:36 +0100 [thread overview]
Message-ID: <20261115-work-ovl-d_real-v1-6-ca155efbcb2e@kernel.org> (raw)
In-Reply-To: <20261115-work-ovl-d_real-v1-0-ca155efbcb2e@kernel.org>
d_real() is about to be able to fail for D_REAL_DATA. So switch IMA
from d_real_inode() to d_real_data_inode() and deal with the error.
Currently, if overlayfs fails to resolve the data of a file it hands
back the overlayfs inode. process_measurement() then sees
real_inode == inode, skips the detection of changes in the backing file
and returns the cached verdict. That's the wrong default. With
metacopy and verity this isn't limited to files nobody opened yet
either. A metadata-only copy-up of an open file makes overlayfs validate
the verity digest of the data again on the next D_REAL_DATA lookup and
that can fail.
So if the inode hosting the data can't be resolved in
process_measurement() we can't tell whether the data changed. Treat it
like a change and clear IMA_DONE_MASK and measured_pcrs so the file is
evaluated again. The metadata check for EVM stays independent of that.
This is a no-op until d_real() can actually fail.
Signed-off-by: Christian Brauner (Amutable) <brauner@kernel.org>
---
security/integrity/ima/ima_api.c | 17 +++++++++++++----
security/integrity/ima/ima_main.c | 8 +++++---
2 files changed, 18 insertions(+), 7 deletions(-)
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index 45701f04ba62f..f8c3437559943 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -246,7 +246,7 @@ int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file,
{
const char *audit_cause = "failed";
struct inode *inode = file_inode(file);
- struct inode *real_inode = d_real_inode(file_dentry(file));
+ struct inode *real_inode;
struct ima_max_digest_data hash;
struct ima_digest_data *hash_hdr = container_of(&hash.hdr,
struct ima_digest_data, hdr);
@@ -268,6 +268,13 @@ int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file,
if (iint->flags & IMA_COLLECTED)
goto out;
+ /*
+ * On stacked filesystems the inode hosting the data may have to be
+ * looked up and that can fail. Treat it like failing to calculate
+ * the hash.
+ */
+ real_inode = d_real_data_inode(file_dentry(file));
+
/*
* Detect file change based on STATX_CHANGE_COOKIE, when supported,
* and fallback to detecting file change based on i_version.
@@ -280,7 +287,7 @@ int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file,
AT_STATX_SYNC_AS_STAT);
if (!result && (stat.result_mask & STATX_CHANGE_COOKIE))
i_version = stat.change_cookie;
- else if (IS_I_VERSION(real_inode))
+ else if (!IS_ERR(real_inode) && IS_I_VERSION(real_inode))
i_version = inode_peek_iversion(real_inode);
hash.hdr.algo = algo;
@@ -289,7 +296,9 @@ int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file,
/* Initialize hash digest to 0's in case of failure */
memset(&hash.digest, 0, sizeof(hash.digest));
- if (iint->flags & IMA_VERITY_REQUIRED) {
+ if (IS_ERR(real_inode)) {
+ result = PTR_ERR(real_inode);
+ } else if (iint->flags & IMA_VERITY_REQUIRED) {
if (!ima_get_verity_digest(iint, inode, &hash)) {
audit_cause = "no-verity-digest";
result = -ENODATA;
@@ -314,7 +323,7 @@ int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file,
memcpy(iint->ima_hash, &hash, length);
if (real_inode == inode)
iint->real_inode.version = i_version;
- else
+ else if (!IS_ERR(real_inode))
integrity_inode_attrs_store(&iint->real_inode, i_version,
real_inode);
diff --git a/security/integrity/ima/ima_main.c b/security/integrity/ima/ima_main.c
index fed80da3ee096..e463cfc1e3f43 100644
--- a/security/integrity/ima/ima_main.c
+++ b/security/integrity/ima/ima_main.c
@@ -342,12 +342,14 @@ static int process_measurement(struct file *file, const struct cred *cred,
/*
* On stacked filesystems, detect and re-evaluate file data and
- * metadata changes.
+ * metadata changes. If the inode hosting the data can't be resolved
+ * we can't tell whether the data changed. Re-evaluate the file then
+ * and let ima_collect_measurement() fail.
*/
- real_inode = d_real_inode(file_dentry(file));
+ real_inode = d_real_data_inode(file_dentry(file));
if (real_inode != inode &&
(action & IMA_DO_MASK) && (iint->flags & IMA_DONE_MASK)) {
- if (!IS_I_VERSION(real_inode) ||
+ if (IS_ERR(real_inode) || !IS_I_VERSION(real_inode) ||
integrity_inode_attrs_changed(&iint->real_inode,
real_inode)) {
iint->flags &= ~IMA_DONE_MASK;
--
2.53.0
next prev parent reply other threads:[~2026-11-15 14:02 UTC|newest]
Thread overview: 15+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-15 14:01 [PATCH 00/13] fs: let d_real() fail Christian Brauner
2026-11-15 14:01 ` [PATCH 01/13] ovl: don't warn when the lazy lowerdata lookup fails in ovl_d_real() Christian Brauner
2026-11-15 14:01 ` [PATCH 02/13] fs: add d_real_data_inode() and d_real_metadata_inode() Christian Brauner
2026-11-15 14:01 ` [PATCH 03/13] tracing/uprobes: handle errors from resolving the real inode Christian Brauner
2026-11-15 14:01 ` [PATCH 04/13] bpf: handle errors from resolving the real inode in uprobe_multi Christian Brauner
2026-11-15 14:01 ` [PATCH 05/13] selftests/bpf: handle d_real_data_inode() errors in bpf_testmod Christian Brauner
2026-11-15 14:01 ` Christian Brauner [this message]
2026-11-15 14:01 ` [PATCH 07/13] ima,evm: use d_real_metadata_inode() Christian Brauner
2026-11-15 14:01 ` [PATCH 08/13] ipe: handle errors from resolving the real inode Christian Brauner
2026-11-15 14:37 ` bot+bpf-ci
2026-11-15 14:01 ` [PATCH 09/13] bpf: return NULL from bpf_real_data_inode() on errors Christian Brauner
2026-11-15 14:01 ` [PATCH 10/13] ovl: return the error from the lazy lowerdata lookup in ovl_d_real() Christian Brauner
2026-11-15 14:01 ` [PATCH 11/13] fs: remove d_real_inode() Christian Brauner
2026-11-15 14:01 ` [PATCH 12/13] selftests/ftrace: add uprobe tests on overlayfs Christian Brauner
2026-11-15 14:01 ` [PATCH 13/13] selftests/bpf: add uprobe_multi test on overlayfs without data Christian Brauner
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20261115-work-ovl-d_real-v1-6-ca155efbcb2e@kernel.org \
--to=brauner@kernel.org \
--cc=amir73il@gmail.com \
--cc=bpf@vger.kernel.org \
--cc=chris@chrisdown.name \
--cc=linux-fsdevel@vger.kernel.org \
--cc=linux-integrity@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-mm@kvack.org \
--cc=linux-security-module@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=linux-unionfs@vger.kernel.org \
--cc=mszeredi@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox
all inboxes | Powered by JetHome®