Skip to content

Commit ab3ee6b

Browse files
oleg-nesterovgregkh
authored andcommitted
epoll: fix race between ep_poll_callback(POLLFREE) and ep_free()/ep_remove()
commit 138e4ad67afd5c6c318b056b4d17c17f2c0ca5c0 upstream. The race was introduced by me in commit 971316f ("epoll: ep_unregister_pollwait() can use the freed pwq->whead"). I did not realize that nothing can protect eventpoll after ep_poll_callback() sets ->whead = NULL, only whead->lock can save us from the race with ep_free() or ep_remove(). Move ->whead = NULL to the end of ep_poll_callback() and add the necessary barriers. TODO: cleanup the ewake/EPOLLEXCLUSIVE logic, it was confusing even before this patch. Hopefully this explains use-after-free reported by syzcaller: BUG: KASAN: use-after-free in debug_spin_lock_before ... _raw_spin_lock_irqsave+0x4a/0x60 kernel/locking/spinlock.c:159 ep_poll_callback+0x29f/0xff0 fs/eventpoll.c:1148 this is spin_lock(eventpoll->lock), ... Freed by task 17774: ... kfree+0xe8/0x2c0 mm/slub.c:3883 ep_free+0x22c/0x2a0 fs/eventpoll.c:865 Fixes: 971316f ("epoll: ep_unregister_pollwait() can use the freed pwq->whead") Reported-by: 范龙飞 <long7573@126.com> Signed-off-by: Oleg Nesterov <oleg@redhat.com> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent 628212c commit ab3ee6b

1 file changed

Lines changed: 24 additions & 13 deletions

File tree

fs/eventpoll.c

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -518,8 +518,13 @@ static void ep_remove_wait_queue(struct eppoll_entry *pwq)
518518
wait_queue_head_t *whead;
519519

520520
rcu_read_lock();
521-
/* If it is cleared by POLLFREE, it should be rcu-safe */
522-
whead = rcu_dereference(pwq->whead);
521+
/*
522+
* If it is cleared by POLLFREE, it should be rcu-safe.
523+
* If we read NULL we need a barrier paired with
524+
* smp_store_release() in ep_poll_callback(), otherwise
525+
* we rely on whead->lock.
526+
*/
527+
whead = smp_load_acquire(&pwq->whead);
523528
if (whead)
524529
remove_wait_queue(whead, &pwq->wait);
525530
rcu_read_unlock();
@@ -1003,17 +1008,6 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k
10031008
struct epitem *epi = ep_item_from_wait(wait);
10041009
struct eventpoll *ep = epi->ep;
10051010

1006-
if ((unsigned long)key & POLLFREE) {
1007-
ep_pwq_from_wait(wait)->whead = NULL;
1008-
/*
1009-
* whead = NULL above can race with ep_remove_wait_queue()
1010-
* which can do another remove_wait_queue() after us, so we
1011-
* can't use __remove_wait_queue(). whead->lock is held by
1012-
* the caller.
1013-
*/
1014-
list_del_init(&wait->task_list);
1015-
}
1016-
10171011
spin_lock_irqsave(&ep->lock, flags);
10181012

10191013
/*
@@ -1078,6 +1072,23 @@ static int ep_poll_callback(wait_queue_t *wait, unsigned mode, int sync, void *k
10781072
if (pwake)
10791073
ep_poll_safewake(&ep->poll_wait);
10801074

1075+
1076+
if ((unsigned long)key & POLLFREE) {
1077+
/*
1078+
* If we race with ep_remove_wait_queue() it can miss
1079+
* ->whead = NULL and do another remove_wait_queue() after
1080+
* us, so we can't use __remove_wait_queue().
1081+
*/
1082+
list_del_init(&wait->task_list);
1083+
/*
1084+
* ->whead != NULL protects us from the race with ep_free()
1085+
* or ep_remove(), ep_remove_wait_queue() takes whead->lock
1086+
* held by the caller. Once we nullify it, nothing protects
1087+
* ep/epi or even wait.
1088+
*/
1089+
smp_store_release(&ep_pwq_from_wait(wait)->whead, NULL);
1090+
}
1091+
10811092
return 1;
10821093
}
10831094

0 commit comments

Comments
 (0)