Hi Greg,
Here's the backport for a couple of epoll fixes that don't cleanly backport to anything older than 5.7. These backports cleanly apply from 5.4 all the way to 4.4.
Thanks,
M.
Al Viro (1): do_epoll_ctl(): clean the failure exits up a bit
Marc Zyngier (1): epoll: Keep a reference on files added to the check list
fs/eventpoll.c | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-)
Commit a9ed4a6560b8562b7e2e2bed9527e88001f7b682 upstream.
When adding a new fd to an epoll, and that this new fd is an epoll fd itself, we recursively scan the fds attached to it to detect cycles, and add non-epool files to a "check list" that gets subsequently parsed.
However, this check list isn't completely safe when deletions can happen concurrently. To sidestep the issue, make sure that a struct file placed on the check list sees its f_count increased, ensuring that a concurrent deletion won't result in the file disapearing from under our feet.
Cc: stable@vger.kernel.org Signed-off-by: Marc Zyngier maz@kernel.org Signed-off-by: Al Viro viro@zeniv.linux.org.uk Signed-off-by: Marc Zyngier maz@kernel.org --- fs/eventpoll.c | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-)
diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 6307c1d883e0..b53ae571f064 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -1991,9 +1991,11 @@ static int ep_loop_check_proc(void *priv, void *cookie, int call_nests) * not already there, and calling reverse_path_check() * during ep_insert(). */ - if (list_empty(&epi->ffd.file->f_tfile_llink)) + if (list_empty(&epi->ffd.file->f_tfile_llink)) { + get_file(epi->ffd.file); list_add(&epi->ffd.file->f_tfile_llink, &tfile_check_list); + } } } mutex_unlock(&ep->mtx); @@ -2037,6 +2039,7 @@ static void clear_tfile_check_list(void) file = list_first_entry(&tfile_check_list, struct file, f_tfile_llink); list_del_init(&file->f_tfile_llink); + fput(file); } INIT_LIST_HEAD(&tfile_check_list); } @@ -2196,9 +2199,11 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, clear_tfile_check_list(); goto error_tgt_fput; } - } else + } else { + get_file(tf.file); list_add(&tf.file->f_tfile_llink, &tfile_check_list); + } mutex_lock_nested(&ep->mtx, 0); if (is_file_epoll(tf.file)) { tep = tf.file->private_data;
From: Al Viro viro@zeniv.linux.org.uk
Commit 52c479697c9b73f628140dcdfcd39ea302d05482 upstream.
Signed-off-by: Al Viro viro@zeniv.linux.org.uk Signed-off-by: Marc Zyngier maz@kernel.org --- fs/eventpoll.c | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-)
diff --git a/fs/eventpoll.c b/fs/eventpoll.c index b53ae571f064..0d9b1e2b9da7 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -2195,10 +2195,8 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, mutex_lock(&epmutex); if (is_file_epoll(tf.file)) { error = -ELOOP; - if (ep_loop_check(ep, tf.file) != 0) { - clear_tfile_check_list(); + if (ep_loop_check(ep, tf.file) != 0) goto error_tgt_fput; - } } else { get_file(tf.file); list_add(&tf.file->f_tfile_llink, @@ -2227,8 +2225,6 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, error = ep_insert(ep, &epds, tf.file, fd, full_check); } else error = -EEXIST; - if (full_check) - clear_tfile_check_list(); break; case EPOLL_CTL_DEL: if (epi) @@ -2251,8 +2247,10 @@ SYSCALL_DEFINE4(epoll_ctl, int, epfd, int, op, int, fd, mutex_unlock(&ep->mtx);
error_tgt_fput: - if (full_check) + if (full_check) { + clear_tfile_check_list(); mutex_unlock(&epmutex); + }
fdput(tf); error_fput:
On Mon, Aug 24, 2020 at 09:02:09AM +0100, Marc Zyngier wrote:
Hi Greg,
Here's the backport for a couple of epoll fixes that don't cleanly backport to anything older than 5.7. These backports cleanly apply from 5.4 all the way to 4.4.
All now queued up, thanks for the backports!
greg k-h
linux-stable-mirror@lists.linaro.org