Commit a411c510 authored by Stefan Berger's avatar Stefan Berger Committed by GONG, Ruiqi
Browse files

ima: Fix use-after-free on a dentry's dname.name

mainline inclusion
from mainline-v6.10-rc1
commit be84f32bb2c981ca670922e047cdde1488b233de
category: bugfix
bugzilla: https://gitee.com/src-openeuler/kernel/issues/IAD0O1
CVE: CVE-2024-39494

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=be84f32bb2c981ca670922e047cdde1488b233de

--------------------------------

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

Link: https://lore.kernel.org/all/20240202182732.GE2087318@ZenIV/


Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
Signed-off-by: default avatarStefan Berger <stefanb@linux.ibm.com>
Signed-off-by: default avatarMimi Zohar <zohar@linux.ibm.com>
Conflicts:
	security/integrity/ima/ima_api.c
	security/integrity/ima/ima_template_lib.c
[Context conflicts, and changes from `filename.name.name` to `filename.name`
since commit 230c6402 ("ovl_lookup_real_one(): don't bother with
strlen()") from v5.2-rc1 is not merged in this branch, and therefore struct
name_snapshot doesn't have `struct qstr name` as its member.]
Signed-off-by: default avatarGONG, Ruiqi <gongruiqi1@huawei.com>
parent 9441eee4
Loading
Loading
Loading
Loading
+12 −4
Original line number Diff line number Diff line
@@ -201,7 +201,7 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
{
	const char *audit_cause = "failed";
	struct inode *inode = file_inode(file);
	const char *filename = file->f_path.dentry->d_name.name;
	struct name_snapshot filename;
	int result = 0;
	int length;
	void *tmpbuf;
@@ -252,9 +252,13 @@ int ima_collect_measurement(struct integrity_iint_cache *iint,
		if (file->f_flags & O_DIRECT)
			audit_cause = "failed(directio)";

		take_dentry_name_snapshot(&filename, file->f_path.dentry);

		integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
				    filename, "collect_data", audit_cause,
				    result, 0);
				    filename.name, "collect_data",
				    audit_cause, result, 0);

		release_dentry_name_snapshot(&filename);
	}
	return result;
}
@@ -356,6 +360,7 @@ void ima_audit_measurement(struct integrity_iint_cache *iint,
 */
const char *ima_d_path(const struct path *path, char **pathbuf, char *namebuf)
{
	struct name_snapshot filename;
	char *pathname = NULL;

	*pathbuf = __getname();
@@ -369,7 +374,10 @@ const char *ima_d_path(const struct path *path, char **pathbuf, char *namebuf)
	}

	if (!pathname) {
		strlcpy(namebuf, path->dentry->d_name.name, NAME_MAX);
		take_dentry_name_snapshot(&filename, path->dentry);
		strscpy(namebuf, filename.name, NAME_MAX);
		release_dentry_name_snapshot(&filename);

		pathname = namebuf;
	}

+14 −3
Original line number Diff line number Diff line
@@ -348,7 +348,10 @@ static int ima_eventname_init_common(struct ima_event_data *event_data,
				     bool size_limit)
{
	const char *cur_filename = NULL;
	struct name_snapshot filename;
	u32 cur_filename_len = 0;
	bool snapshot = false;
	int ret;

	BUG_ON(event_data->filename == NULL && event_data->file == NULL);

@@ -361,7 +364,10 @@ static int ima_eventname_init_common(struct ima_event_data *event_data,
	}

	if (event_data->file) {
		cur_filename = event_data->file->f_path.dentry->d_name.name;
		take_dentry_name_snapshot(&filename,
					  event_data->file->f_path.dentry);
		snapshot = true;
		cur_filename = filename.name;
		cur_filename_len = strlen(cur_filename);
	} else
		/*
@@ -370,8 +376,13 @@ static int ima_eventname_init_common(struct ima_event_data *event_data,
		 */
		cur_filename_len = IMA_EVENT_NAME_LEN_MAX;
out:
	return ima_write_template_field_data(cur_filename, cur_filename_len,
	ret = ima_write_template_field_data(cur_filename, cur_filename_len,
					    DATA_FMT_STRING, field_data);

	if (snapshot)
		release_dentry_name_snapshot(&filename);

	return ret;
}

/*