Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit ea635c64 authored by Al Viro's avatar Al Viro
Browse files

Fix racy use of anon_inode_getfd() in perf_event.c



once anon_inode_getfd() is called, you can't expect *anything* about
struct file that descriptor points to - another thread might be doing
whatever it likes with descriptor table at that point.

Cc: stable <stable@kernel.org>
Signed-off-by: default avatarAl Viro <viro@zeniv.linux.org.uk>
parent d7065da0
Loading
Loading
Loading
Loading
+22 −18
Original line number Diff line number Diff line
@@ -4999,8 +4999,8 @@ SYSCALL_DEFINE5(perf_event_open,
	struct perf_event_context *ctx;
	struct file *event_file = NULL;
	struct file *group_file = NULL;
	int event_fd;
	int fput_needed = 0;
	int fput_needed2 = 0;
	int err;

	/* for future expandability... */
@@ -5021,12 +5021,18 @@ SYSCALL_DEFINE5(perf_event_open,
			return -EINVAL;
	}

	event_fd = get_unused_fd_flags(O_RDWR);
	if (event_fd < 0)
		return event_fd;

	/*
	 * Get the target context (task or percpu):
	 */
	ctx = find_get_context(pid, cpu);
	if (IS_ERR(ctx))
		return PTR_ERR(ctx);
	if (IS_ERR(ctx)) {
		err = PTR_ERR(ctx);
		goto err_fd;
	}

	/*
	 * Look up the group leader (we will attach this event to it):
@@ -5066,13 +5072,11 @@ SYSCALL_DEFINE5(perf_event_open,
	if (IS_ERR(event))
		goto err_put_context;

	err = anon_inode_getfd("[perf_event]", &perf_fops, event, O_RDWR);
	if (err < 0)
		goto err_free_put_context;

	event_file = fget_light(err, &fput_needed2);
	if (!event_file)
	event_file = anon_inode_getfile("[perf_event]", &perf_fops, event, O_RDWR);
	if (IS_ERR(event_file)) {
		err = PTR_ERR(event_file);
		goto err_free_put_context;
	}

	if (flags & PERF_FLAG_FD_OUTPUT) {
		err = perf_event_set_output(event, group_fd);
@@ -5093,19 +5097,19 @@ SYSCALL_DEFINE5(perf_event_open,
	list_add_tail(&event->owner_entry, &current->perf_event_list);
	mutex_unlock(&current->perf_event_mutex);

err_fput_free_put_context:
	fput_light(event_file, fput_needed2);
	fput_light(group_file, fput_needed);
	fd_install(event_fd, event_file);
	return event_fd;

err_fput_free_put_context:
	fput(event_file);
err_free_put_context:
	if (err < 0)
	free_event(event);

err_put_context:
	if (err < 0)
		put_ctx(ctx);

	fput_light(group_file, fput_needed);

	put_ctx(ctx);
err_fd:
	put_unused_fd(event_fd);
	return err;
}