Skip to content

Commit a82634e

Browse files
committed
Merge: epoll: be better about file lifetimes
MR: https://gitlab.com/redhat/centos-stream/src/kernel/centos-stream-9/-/merge_requests/4543 JIRA: https://issues.redhat.com/browse/RHEL-44083 CVE: CVE-2024-38580 Signed-off-by: Pavel Reichl <preichl@redhat.com> Approved-by: Brian Foster <bfoster@redhat.com> Approved-by: Andrey Albershteyn <aalbersh@redhat.com> Approved-by: Carlos Maiolino <cmaiolino@redhat.com> Approved-by: CKI KWF Bot <cki-ci-bot+kwf-gitlab-com@redhat.com> Merged-by: Lucas Zampieri <lzampier@redhat.com>
2 parents 19155aa + 62e94ff commit a82634e

File tree

1 file changed

+37
-1
lines changed

1 file changed

+37
-1
lines changed

fs/eventpoll.c

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -876,6 +876,34 @@ static __poll_t __ep_eventpoll_poll(struct file *file, poll_table *wait, int dep
876876
return res;
877877
}
878878

879+
/*
880+
* The ffd.file pointer may be in the process of being torn down due to
881+
* being closed, but we may not have finished eventpoll_release() yet.
882+
*
883+
* Normally, even with the atomic_long_inc_not_zero, the file may have
884+
* been free'd and then gotten re-allocated to something else (since
885+
* files are not RCU-delayed, they are SLAB_TYPESAFE_BY_RCU).
886+
*
887+
* But for epoll, users hold the ep->mtx mutex, and as such any file in
888+
* the process of being free'd will block in eventpoll_release_file()
889+
* and thus the underlying file allocation will not be free'd, and the
890+
* file re-use cannot happen.
891+
*
892+
* For the same reason we can avoid a rcu_read_lock() around the
893+
* operation - 'ffd.file' cannot go away even if the refcount has
894+
* reached zero (but we must still not call out to ->poll() functions
895+
* etc).
896+
*/
897+
static struct file *epi_fget(const struct epitem *epi)
898+
{
899+
struct file *file;
900+
901+
file = epi->ffd.file;
902+
if (!atomic_long_inc_not_zero(&file->f_count))
903+
file = NULL;
904+
return file;
905+
}
906+
879907
/*
880908
* Differs from ep_eventpoll_poll() in that internal callers already have
881909
* the ep->mtx so we need to start from depth=1, such that mutex_lock_nested()
@@ -884,14 +912,22 @@ static __poll_t __ep_eventpoll_poll(struct file *file, poll_table *wait, int dep
884912
static __poll_t ep_item_poll(const struct epitem *epi, poll_table *pt,
885913
int depth)
886914
{
887-
struct file *file = epi->ffd.file;
915+
struct file *file = epi_fget(epi);
888916
__poll_t res;
889917

918+
/*
919+
* We could return EPOLLERR | EPOLLHUP or something, but let's
920+
* treat this more as "file doesn't exist, poll didn't happen".
921+
*/
922+
if (!file)
923+
return 0;
924+
890925
pt->_key = epi->event.events;
891926
if (!is_file_epoll(file))
892927
res = vfs_poll(file, pt);
893928
else
894929
res = __ep_eventpoll_poll(file, pt, depth);
930+
fput(file);
895931
return res & epi->event.events;
896932
}
897933

0 commit comments

Comments
 (0)