1

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

->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>
This commit is contained in:
Stefan Berger 2024-03-22 10:03:12 -04:00 committed by Mimi Zohar
parent fec50db703
commit be84f32bb2
2 changed files with 26 additions and 7 deletions

View File

@ -245,8 +245,8 @@ int ima_collect_measurement(struct ima_iint_cache *iint, struct file *file,
const char *audit_cause = "failed"; const char *audit_cause = "failed";
struct inode *inode = file_inode(file); struct inode *inode = file_inode(file);
struct inode *real_inode = d_real_inode(file_dentry(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 ima_max_digest_data hash;
struct name_snapshot filename;
struct kstat stat; struct kstat stat;
int result = 0; int result = 0;
int length; int length;
@ -317,9 +317,13 @@ out:
if (file->f_flags & O_DIRECT) if (file->f_flags & O_DIRECT)
audit_cause = "failed(directio)"; audit_cause = "failed(directio)";
take_dentry_name_snapshot(&filename, file->f_path.dentry);
integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode, integrity_audit_msg(AUDIT_INTEGRITY_DATA, inode,
filename, "collect_data", audit_cause, filename.name.name, "collect_data",
result, 0); audit_cause, result, 0);
release_dentry_name_snapshot(&filename);
} }
return result; return result;
} }
@ -432,6 +436,7 @@ out:
*/ */
const char *ima_d_path(const struct path *path, char **pathbuf, char *namebuf) const char *ima_d_path(const struct path *path, char **pathbuf, char *namebuf)
{ {
struct name_snapshot filename;
char *pathname = NULL; char *pathname = NULL;
*pathbuf = __getname(); *pathbuf = __getname();
@ -445,7 +450,10 @@ const char *ima_d_path(const struct path *path, char **pathbuf, char *namebuf)
} }
if (!pathname) { if (!pathname) {
strscpy(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; pathname = namebuf;
} }

View File

@ -483,7 +483,10 @@ static int ima_eventname_init_common(struct ima_event_data *event_data,
bool size_limit) bool size_limit)
{ {
const char *cur_filename = NULL; const char *cur_filename = NULL;
struct name_snapshot filename;
u32 cur_filename_len = 0; u32 cur_filename_len = 0;
bool snapshot = false;
int ret;
BUG_ON(event_data->filename == NULL && event_data->file == NULL); BUG_ON(event_data->filename == NULL && event_data->file == NULL);
@ -496,7 +499,10 @@ static int ima_eventname_init_common(struct ima_event_data *event_data,
} }
if (event_data->file) { 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); cur_filename_len = strlen(cur_filename);
} else } else
/* /*
@ -505,8 +511,13 @@ static int ima_eventname_init_common(struct ima_event_data *event_data,
*/ */
cur_filename_len = IMA_EVENT_NAME_LEN_MAX; cur_filename_len = IMA_EVENT_NAME_LEN_MAX;
out: 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); DATA_FMT_STRING, field_data);
if (snapshot)
release_dentry_name_snapshot(&filename);
return ret;
} }
/* /*