From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id BCDC34A3D45; Tue, 8 Sep 2026 08:51:38 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788857507; cv=none; b=uyOHCBuYF2Zi7v0xRGXVeEZbjWLcxXVdndRRc0EbqPyBPLMcary+WLVryFKe2QutGqWlVgh5pdxaVzATHC5Fp+dt2bYPbOiqxKUq42l4WfM2jiFbe+j1jvKKKxAGylCg7BBJgDmBzxr1+BMqIpRyazzFv68CsfFqzoSLDt9XnVQ= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788857507; c=relaxed/simple; bh=Oa4GdHHa/xani16K8uH5EpKcQPLy9pbsdCb8bNT/GFE=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=ZUIHUlbW47Ofr6LbgsIu8zD47B+yAisTNHZfXxg9pS1Ov4Hmns5jazG/EHcW1ZTwyt83b1Shg0pxMulM5aK/q8czBnyIsXgk+eULBjw5VjjZleZRkgKgBPRV9RL+pgkapbK6/FxwkPF/mydqUgY6Cwj4mUz+6NxuJJJtEwuKlzs= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=ZYgyc0ak; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="ZYgyc0ak" Received: by smtp.kernel.org (Postfix) with ESMTPSA id D256C1F00A3A; Tue, 8 Sep 2026 08:51:31 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1788857495; bh=VjicZH7wrPLFXwvICbHn6vlqgfhaU015taNAE+UpZXY=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=ZYgyc0akS7XZXtDvQv6rnJQdfiGn0Mzm4D5AxKs/h60xzZnnXqp59FM7SejrYD0ey zjyaLpxASU6sHpdt80lsB8/qnYSjHftzmGxzp7pCLyhhbY2RSaXDtBCnMTyLaaq5Hw zAiIuI2uulhn2U2HQogpddcsBk7HthRIZndSvhYaIOHQ94PlSDLR4tqdk/Az74afD+ +b9RVA0VZA0I69oItXZCyS1aSKQuEY8tmo2Q8ZzddXR0xoY7yl7kYY2AhlI0YP3Dmv 47mQDJYnGaFBmOUzT1cnLJtfF0S69/irkPmvtPQKX3jSUdUOfcxRmyq//9Znxmobuo 2UrwYlsY31VDg== From: Lee Jones To: lee@kernel.org, Alexander Viro , Greg Kroah-Hartman , Sasha Levin , Jeff Layton , Wentao Guan , Josef Bacik , Christian Brauner , Peter Zijlstra , Eric Dumazet , Andrew Morton , Paolo Abeni , Soheil Hassas Yeganeh , Davidlohr Bueso , linux-fsdevel@vger.kernel.org, linux-kernel@vger.kernel.org Cc: stable@vger.kernel.org, Quentin Schulz Subject: [STABLE v5.15.y 4/8] eventpoll: kill __ep_remove() Date: Tue, 8 Sep 2026 09:51:00 +0100 Message-ID: <20260908085113.3960814-4-lee@kernel.org> X-Mailer: git-send-email 2.55.0.979.g7e5102b832-goog In-Reply-To: <20260908085113.3960814-1-lee@kernel.org> References: <20260908085113.3960814-1-lee@kernel.org> Precedence: bulk X-Mailing-List: linux-fsdevel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: Christian Brauner [ Upstream commit e9e5cd40d7c403e19f21d0f7b8b8ba3a76b58330 ] Remove the boolean conditional in __ep_remove() and restructure the code so the check for racing with eventpoll_release_file() are only done in the ep_remove_safe() path where they belong. Link: https://patch.msgid.link/20260423-work-epoll-uaf-v1-3-2470f9eec0f5@kernel.org Signed-off-by: Christian Brauner (Amutable) Stable-dep-of: a6dc643c6931 ("eventpoll: fix ep_remove struct eventpoll / struct file UAF") Signed-off-by: Quentin Schulz Signed-off-by: Wentao Guan Signed-off-by: Greg Kroah-Hartman (cherry picked from commit 13e8b6ab5fd34129b2a4a1b2c00b4921dde462cd) Signed-off-by: Lee Jones --- fs/eventpoll.c | 68 +++++++++++++++++++++++--------------------------- 1 file changed, 31 insertions(+), 37 deletions(-) diff --git a/fs/eventpoll.c b/fs/eventpoll.c index 693ad9826e32..3d0cad2592a1 100644 --- a/fs/eventpoll.c +++ b/fs/eventpoll.c @@ -708,49 +708,18 @@ static void ep_free(struct eventpoll *ep) kfree_rcu(ep, rcu); } -static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi, struct file *file); -static bool __ep_remove_epi(struct eventpoll *ep, struct epitem *epi); - -/* - * Removes a "struct epitem" from the eventpoll RB tree and deallocates - * all the associated resources. Must be called with "mtx" held. - * If the dying flag is set, do the removal only if force is true. - * This prevents ep_clear_and_put() from dropping all the ep references - * while running concurrently with eventpoll_release_file(). - * Returns true if the eventpoll can be disposed. - */ -static bool __ep_remove(struct eventpoll *ep, struct epitem *epi, bool force) -{ - struct file *file = epi->ffd.file; - - lockdep_assert_irqs_enabled(); - - /* - * Removes poll wait queue hooks. - */ - ep_unregister_pollwait(ep, epi); - - /* Remove the current item from the list of epoll hooks */ - spin_lock(&file->f_lock); - if (epi->dying && !force) { - spin_unlock(&file->f_lock); - return false; - } - - __ep_remove_file(ep, epi, file); - return __ep_remove_epi(ep, epi); -} - /* * Called with &file->f_lock held, * returns with it released */ -static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi, struct file *file) +static void __ep_remove_file(struct eventpoll *ep, struct epitem *epi, + struct file *file) { struct epitems_head *to_free = NULL; struct hlist_head *head = file->f_ep; lockdep_assert_held(&ep->mtx); + lockdep_assert_held(&file->f_lock); if (hlist_is_singular_node(&epi->fllink, head)) { /* See eventpoll_release() for details. */ @@ -797,7 +766,26 @@ static bool __ep_remove_epi(struct eventpoll *ep, struct epitem *epi) */ static void ep_remove_safe(struct eventpoll *ep, struct epitem *epi) { - WARN_ON_ONCE(__ep_remove(ep, epi, false)); + struct file *file = epi->ffd.file; + + lockdep_assert_irqs_enabled(); + lockdep_assert_held(&ep->mtx); + + ep_unregister_pollwait(ep, epi); + + /* sync with eventpoll_release_file() */ + if (unlikely(READ_ONCE(epi->dying))) + return; + + spin_lock(&file->f_lock); + if (epi->dying) { + spin_unlock(&file->f_lock); + return; + } + __ep_remove_file(ep, epi, file); + + if (__ep_remove_epi(ep, epi)) + WARN_ON_ONCE(ep_refcount_dec_and_test(ep)); } static void ep_clear_and_put(struct eventpoll *ep) @@ -1008,7 +996,7 @@ void eventpoll_release_file(struct file *file) spin_lock(&file->f_lock); if (file->f_ep && file->f_ep->first) { epi = hlist_entry(file->f_ep->first, struct epitem, fllink); - epi->dying = true; + WRITE_ONCE(epi->dying, true); spin_unlock(&file->f_lock); /* @@ -1017,7 +1005,13 @@ void eventpoll_release_file(struct file *file) */ ep = epi->ep; mutex_lock(&ep->mtx); - dispose = __ep_remove(ep, epi, true); + + ep_unregister_pollwait(ep, epi); + + spin_lock(&file->f_lock); + __ep_remove_file(ep, epi, file); + dispose = __ep_remove_epi(ep, epi); + mutex_unlock(&ep->mtx); if (dispose) -- 2.55.0.979.g7e5102b832-goog