]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
ima: Fix use-after-free on a dentry's dname.name
authorStefan Berger <stefanb@linux.ibm.com>
Fri, 22 Mar 2024 14:03:12 +0000 (10:03 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 13 Mar 2025 11:47:24 +0000 (12:47 +0100)
commit be84f32bb2c981ca670922e047cdde1488b233de upstream.

->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>
[ Samasth: bp to fix CVE-2024-39494; Minor conflict resolved due to code context change ]
Signed-off-by: Samasth Norway Ananda <samasth.norway.ananda@oracle.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
security/integrity/ima/ima_api.c
security/integrity/ima/ima_template_lib.c

index 70efd4aa1bd11ff0a890509b78a74a0910ea9a40..285d6069c32f7307f2386e599d0ecb33050f8d5f 100644 (file)
@@ -213,7 +213,7 @@ 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 name_snapshot filename;
        int result = 0;
        int length;
        void *tmpbuf;
@@ -276,9 +276,13 @@ out:
                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.name, "collect_data",
+                                   audit_cause, result, 0);
+
+               release_dentry_name_snapshot(&filename);
        }
        return result;
 }
@@ -391,6 +395,7 @@ out:
  */
 const char *ima_d_path(const struct path *path, char **pathbuf, char *namebuf)
 {
+       struct name_snapshot filename;
        char *pathname = NULL;
 
        *pathbuf = __getname();
@@ -404,7 +409,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, NAME_MAX);
+               release_dentry_name_snapshot(&filename);
+
                pathname = namebuf;
        }
 
index c022ee9e2a4e626fe11b63d2b55503295f088fd9..f72a2564fd05a0882a2b4568fcb9040a9b7c7b42 100644 (file)
@@ -385,7 +385,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);
 
@@ -398,7 +401,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.name;
                cur_filename_len = strlen(cur_filename);
        } else
                /*
@@ -407,8 +413,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;
 }
 
 /*