From: Stefan Berger stefanb@linux.ibm.com
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/?i...
--------------------------------
->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: Al Viro viro@zeniv.linux.org.uk Signed-off-by: Stefan Berger stefanb@linux.ibm.com Signed-off-by: Mimi 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 230c6402b1b3 ("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: GONG, Ruiqi gongruiqi1@huawei.com --- security/integrity/ima/ima_api.c | 16 ++++++++++++---- security/integrity/ima/ima_template_lib.c | 17 ++++++++++++++--- 2 files changed, 26 insertions(+), 7 deletions(-)
diff --git a/security/integrity/ima/ima_api.c b/security/integrity/ima/ima_api.c index a02c5acfd403..dad7136cbd3f 100644 --- a/security/integrity/ima/ima_api.c +++ b/security/integrity/ima/ima_api.c @@ -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; }
diff --git a/security/integrity/ima/ima_template_lib.c b/security/integrity/ima/ima_template_lib.c index 48c5a1be88ac..37b8fada853f 100644 --- a/security/integrity/ima/ima_template_lib.c +++ b/security/integrity/ima/ima_template_lib.c @@ -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, - DATA_FMT_STRING, field_data); + 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; }
/*