linux-fsdevel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Al Viro <viro@zeniv.linux.org.uk>
To: Stefan Berger <stefanb@linux.ibm.com>
Cc: Amir Goldstein <amir73il@gmail.com>,
	Miklos Szeredi <miklos@szeredi.hu>,
	Christian Brauner <brauner@kernel.org>,
	Mimi Zohar <zohar@linux.ibm.com>,
	linux-unionfs@vger.kernel.org, linux-integrity@vger.kernel.org,
	linux-fsdevel@vger.kernel.org
Subject: Re: [PATCH 2/2] fs: remove the inode argument to ->d_real() method
Date: Fri, 2 Feb 2024 18:27:32 +0000	[thread overview]
Message-ID: <20240202182732.GE2087318@ZenIV> (raw)
In-Reply-To: <063577b8-3d7f-4a7f-8ed7-332601c98122@linux.ibm.com>

On Fri, Feb 02, 2024 at 12:34:15PM -0500, Stefan Berger wrote:

> I suppose this would provide a stable name?
> 
> diff --git a/security/integrity/ima/ima_api.c
> b/security/integrity/ima/ima_api.c
> index 597ea0c4d72f..48ae6911139b 100644
> --- a/security/integrity/ima/ima_api.c
> +++ b/security/integrity/ima/ima_api.c
> @@ -244,7 +244,6 @@ int ima_collect_measurement(struct integrity_iint_cache
> *iint,
>         const char *audit_cause = "failed";
>         struct inode *inode = file_inode(file);
>         struct inode *real_inode = d_real_inode(file_dentry(file));
> -       const char *filename = file->f_path.dentry->d_name.name;
>         struct ima_max_digest_data hash;
>         struct kstat stat;
>         int result = 0;
> @@ -313,11 +312,17 @@ int ima_collect_measurement(struct
> integrity_iint_cache *iint,
>                 iint->flags |= IMA_COLLECTED;
>  out:
>         if (result) {
> +               struct qstr *qstr = &file->f_path.dentry->d_name;
> +               char buf[NAME_MAX + 1];
> +
>                 if (file->f_flags & O_DIRECT)
>                         audit_cause = "failed(directio)";
> 
> +               memcpy(buf, qstr->name, qstr->len);
> +               buf[qstr->len] = 0;

	Think what happens if you fetch ->len in state prior to
rename and ->name - after.  memcpy() from one memory object
with length that matches another, UAF right there.

	If you want to take a snapshot of the name, just use
take_dentry_name_snapshot() - that will copy name if it's
short or grab a reference to external name if the length is
>= 40, all of that under ->d_lock to stabilize things.

	Paired with release_dentry_name_snapshot(), to
drop the reference to external name if one had been taken.
No need to copy in long case (external names are never
rewritten) and it's kinder on the stack footprint that
way (56 bytes vs. 256).

	Something like this (completely untested):

fix a UAF in ima_collect_measurement()

->d_name.name can change on rename and the earlier value can get freed;
there are conditions sufficient to stabilize it (->d_lock on denty,
->d_lock on its parent, ->i_rwsem exclusive on the parent's inode,
rename_lock), but none of those are met in ima_collect_measurement().
Take a stable snapshot of name instead.

Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
---
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c
index 597ea0c4d72f..d8be2280d97b 100644
--- a/security/integrity/ima/ima_api.c
+++ b/security/integrity/ima/ima_api.c
@@ -244,7 +244,6 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
 	const char *audit_cause = "failed";
 	struct inode *inode = file_inode(file);
 	struct inode *real_inode = d_real_inode(file_dentry(file));
-	const char *filename = file->f_path.dentry->d_name.name;
 	struct ima_max_digest_data hash;
 	struct kstat stat;
 	int result = 0;
@@ -313,12 +312,16 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
 		iint->flags |= IMA_COLLECTED;
 out:
 	if (result) {
+		struct name_snapshot filename;
+
+		take_dentry_name_snapshot(&filename, file->f_path.dentry);
 		if (file->f_flags & O_DIRECT)
 			audit_cause = "failed(directio)";
 
 		integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
-				    filename, "collect_data", audit_cause,
-				    result, 0);
+				    filename.name.name, "collect_data",
+				    audit_cause, result, 0);
+		release_dentry_name_snapshot(&filename);
 	}
 	return result;
 }

  reply	other threads:[~2024-02-02 18:27 UTC|newest]

Thread overview: 17+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-02-02 11:01 [PATCH 0/2] Decomplicate file_dentry() Amir Goldstein
2024-02-02 11:01 ` [PATCH 1/2] fs: make file_dentry() a simple accessor Amir Goldstein
2024-02-02 15:16   ` Stefan Berger
2024-02-02 11:01 ` [PATCH 2/2] fs: remove the inode argument to ->d_real() method Amir Goldstein
2024-02-02 12:19   ` Miklos Szeredi
2024-02-02 12:41     ` Amir Goldstein
2024-02-02 13:54       ` Christian Brauner
2024-02-06 15:28         ` Amir Goldstein
2024-02-02 15:17   ` Stefan Berger
2024-02-02 16:05   ` Al Viro
2024-02-02 16:16     ` Al Viro
2024-02-02 17:34       ` Stefan Berger
2024-02-02 18:27         ` Al Viro [this message]
2024-02-02 18:32           ` Stefan Berger
2024-02-02 18:50             ` Al Viro
2024-02-02 18:38           ` Al Viro
2024-02-06 16:02 ` [PATCH 0/2] Decomplicate file_dentry() 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=20240202182732.GE2087318@ZenIV \
    --to=viro@zeniv.linux.org.uk \
    --cc=amir73il@gmail.com \
    --cc=brauner@kernel.org \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-integrity@vger.kernel.org \
    --cc=linux-unionfs@vger.kernel.org \
    --cc=miklos@szeredi.hu \
    --cc=stefanb@linux.ibm.com \
    --cc=zohar@linux.ibm.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;
as well as URLs for NNTP newsgroup(s).