Unverified Commit 261e0bd2 authored by openeuler-ci-bot's avatar openeuler-ci-bot Committed by Gitee
Browse files

!15606 Fix instance dir use-after-free in tracefs

Merge Pull Request from: @ci-robot 
 
PR sync from: Tengda Wu <wutengda2@huawei.com>
https://mailweb.openeuler.org/archives/list/kernel@openeuler.org/message/DTNAT2VFPHXSFEVGAXDZQKDF3LDNDLUK/ 
This patch series is used to fix uaf in tracefs.

Tengda Wu (2):
  tracing: Avoid use-after-free in tracing_open_file_tr()
  tracing: Fix illegal address access of trace_event_file in
    tracing_release_file_tr()

 
https://gitee.com/openeuler/kernel/issues/IBRD5T 
 
Link:https://gitee.com/openeuler/kernel/pulls/15606

 

Reviewed-by: default avatarLi Nan <linan122@huawei.com>
Reviewed-by: default avatarYe Weihua <yeweihua4@huawei.com>
Reviewed-by: default avatarXu Kuohai <xukuohai@huawei.com>
Signed-off-by: default avatarLi Nan <linan122@huawei.com>
parents b83e5eba 72d03091
Loading
Loading
Loading
Loading
+13 −6
Original line number Diff line number Diff line
@@ -4508,14 +4508,21 @@ int tracing_open_generic_tr(struct inode *inode, struct file *filp)
 */
int tracing_open_file_tr(struct inode *inode, struct file *filp)
{
	struct trace_event_file *file = inode->i_private;
	struct trace_event_file *file;
	int ret;

	mutex_lock(&event_mutex);
	file = inode->i_private;
	if (!file) {
		mutex_unlock(&event_mutex);
		return -ENODEV;
	}

	ret = tracing_check_open_get_tr(file->tr);
	if (ret)
	if (ret) {
		mutex_unlock(&event_mutex);
		return ret;

	mutex_lock(&event_mutex);
	}

	/* Fail if the file is marked for removal */
	if (file->flags & EVENT_FILE_FL_FREED) {
@@ -4529,14 +4536,14 @@ int tracing_open_file_tr(struct inode *inode, struct file *filp)
	if (ret)
		return ret;

	filp->private_data = inode->i_private;
	filp->private_data = file;

	return 0;
}

int tracing_release_file_tr(struct inode *inode, struct file *filp)
{
	struct trace_event_file *file = inode->i_private;
	struct trace_event_file *file = filp->private_data;

	trace_array_put(file->tr);
	event_file_put(file);
+32 −0
Original line number Diff line number Diff line
@@ -764,9 +764,41 @@ void event_file_put(struct trace_event_file *file)
	}
}

static bool file_op_depends_on_i_priv(const struct dentry *dentry)
{
	const struct file_operations *fop = NULL;

	if (!d_really_is_positive(dentry) || !d_inode(dentry)->i_fop)
		return false;

	fop = d_inode(dentry)->i_fop;
	if (fop->open == tracing_open_file_tr)
		return true;
#ifdef CONFIG_HIST_TRIGGERS
	if (fop == &event_hist_fops)
		return true;
#endif
#ifdef CONFIG_HIST_TRIGGERS_DEBUG
	if (fop == &event_hist_debug_fops)
		return true;
#endif

	return false;
}

static void remove_event_file_dir(struct trace_event_file *file)
{
	struct dentry *dir = file->dir;
	struct dentry *child;

	if (dir) {
		spin_lock(&dir->d_lock);	/* probably unneeded */
		list_for_each_entry(child, &dir->d_subdirs, d_child) {
			if (file_op_depends_on_i_priv(child))
				d_inode(child)->i_private = NULL;
		}
		spin_unlock(&dir->d_lock);
	}

	tracefs_remove(dir);

+54 −8
Original line number Diff line number Diff line
@@ -4794,15 +4794,21 @@ static void hist_trigger_show(struct seq_file *m,
		   n_entries, (u64)atomic64_read(&hist_data->map->drops));
}

struct hist_file_data {
	struct file *file;
	struct trace_event_file *event_file;
};

static int hist_show(struct seq_file *m, void *v)
{
	struct hist_file_data *hist_file = m->private;
	struct event_trigger_data *data;
	struct trace_event_file *event_file;
	int n = 0, ret = 0;

	mutex_lock(&event_mutex);

	event_file = event_file_data(m->private);
	event_file = event_file_data(hist_file->file);
	if (unlikely(!event_file)) {
		ret = -ENODEV;
		goto out_unlock;
@@ -4819,24 +4825,50 @@ static int hist_show(struct seq_file *m, void *v)
	return ret;
}

static int tracing_release_hist_file_tr(struct inode *inode, struct file *file)
{
	struct seq_file *m = file->private_data;
	struct hist_file_data *hist_file = m->private;
	struct trace_event_file *event_file = hist_file->event_file;

	trace_array_put(event_file->tr);
	event_file_put(event_file);
	kfree(hist_file);

	return single_release(inode, file);
}

static int event_hist_open(struct inode *inode, struct file *file)
{
	struct hist_file_data *hist_file;
	int ret;

	hist_file = kzalloc(sizeof(*hist_file), GFP_KERNEL);
	if (!hist_file)
		return -ENOMEM;

	ret = tracing_open_file_tr(inode, file);
	if (ret)
	if (ret) {
		kfree(hist_file);
		return ret;
	}

	hist_file->file = file;
	hist_file->event_file = file->private_data;

	/* Clear private_data to avoid warning in single_open() */
	file->private_data = NULL;
	return single_open(file, hist_show, file);
	ret = single_open(file, hist_show, hist_file);
	if (ret)
		kfree(hist_file);
	return ret;
}

const struct file_operations event_hist_fops = {
	.open = event_hist_open,
	.read = seq_read,
	.llseek = seq_lseek,
	.release = tracing_single_release_file_tr,
	.release = tracing_release_hist_file_tr,
};

#ifdef CONFIG_HIST_TRIGGERS_DEBUG
@@ -5070,13 +5102,14 @@ static void hist_trigger_debug_show(struct seq_file *m,

static int hist_debug_show(struct seq_file *m, void *v)
{
	struct hist_file_data *hist_file = m->private;
	struct event_trigger_data *data;
	struct trace_event_file *event_file;
	int n = 0, ret = 0;

	mutex_lock(&event_mutex);

	event_file = event_file_data(m->private);
	event_file = event_file_data(hist_file->file);
	if (unlikely(!event_file)) {
		ret = -ENODEV;
		goto out_unlock;
@@ -5095,22 +5128,35 @@ static int hist_debug_show(struct seq_file *m, void *v)

static int event_hist_debug_open(struct inode *inode, struct file *file)
{
	struct hist_file_data *hist_file;
	int ret;

	hist_file = kzalloc(sizeof(*hist_file), GFP_KERNEL);
	if (!hist_file)
		return -ENOMEM;

	ret = tracing_open_file_tr(inode, file);
	if (ret)
	if (ret) {
		kfree(hist_file);
		return ret;
	}

	hist_file->file = file;
	hist_file->event_file = file->private_data;

	/* Clear private_data to avoid warning in single_open() */
	file->private_data = NULL;
	return single_open(file, hist_debug_show, file);
	ret = single_open(file, hist_debug_show, hist_file);
	if (ret)
		kfree(hist_file);
	return ret;
}

const struct file_operations event_hist_debug_fops = {
	.open = event_hist_debug_open,
	.read = seq_read,
	.llseek = seq_lseek,
	.release = tracing_single_release_file_tr,
	.release = tracing_release_hist_file_tr,
};
#endif