From: sashiko-bot@kernel.org
To: "David Hildenbrand (Arm)" <david@kernel.org>,
"Andrew Morton" <akpm@linux-foundation.org>,
"Gregory Price" <gourry@gourry.net>, "Zi Yan" <ziy@nvidia.com>,
"Joshua Hahn" <joshua.hahnjy@gmail.com>,
"Rakie Kim" <rakie.kim@sk.com>,
"Ying Huang" <ying.huang@linux.alibaba.com>,
"Johannes Weiner" <hannes@cmpxchg.org>,
"Vladimir Davydov" <vdavydov.dev@gmail.com>,
"Michal Hocko" <mhocko@suse.com>,
"Hugh Dickins" <hughd@google.com>,
"Baolin Wang" <baolin.wang@linux.alibaba.com>,
"Lukas Czerner" <lczerner@redhat.com>,
"Carlos Maiolino" <cmaiolino@redhat.com>,
"Christian Brauner" <brauner@kernel.org>,
"Jan Kara" <jack@suse.cz>,
"Daniel Verkamp" <dverkamp@chromium.org>,
"Jeff Xu" <jeffxu@google.com>,
"Muchun Song" <muchun.song@linux.dev>,
"Oscar Salvador" <osalvador@suse.de>,
"David Stevens" <stevensd@chromium.org>,
"Matthew Wilcox (Oracle)" <willy@infradead.org>,
"William Kucharski" <william.kucharski@oracle.com>,
"Chris Li" <chrisl@kernel.org>,
"Kairui Song" <kasong@tencent.com>,
"Nhat Pham" <nphamcs@gmail.com>,
"Miaohe Lin" <linmiaohe@huawei.com>,
"Naoya Horiguchi" <nao.horiguchi@gmail.com>
Cc: linux-mm@kvack.org, "Josef Bacik" <josef@toxicpanda.com>,
"Pedro Falcato" <pfalcato@suse.de>,
"Kiryl Shutsemau (Meta)" <kas@kernel.org>
Subject: Re: [PATCH v3 06/15] mm/shmem: hold off eviction in shmem_writeout()
Date: Wed, 28 Oct 2026 20:35:30 +0000 [thread overview]
Message-ID: <sashiko-outbox-188427@kernel.org> (raw)
In-Reply-To: <20261028-fixes_shmem-v3-6-4ce3baf2db4b@kernel.org>
Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider:
- [High] mm/shmem: use-after-free in shmem_evict_inode() on concurrent swapoff
--
commit bfe337ff80d886d314a9991abae8133932277cd0
Author: Josef Bacik <josef@toxicpanda.com>
mm/shmem: hold off eviction in shmem_writeout()
This commit prevents inode eviction during shmem_writeout() by incrementing
info->stop_eviction before removing the folio from the page cache and
decrementing it after swap_writeout() and any potential page cache
reinsertion complete. It also updates shmem_evict_inode() to always wait at
least once for info->stop_eviction to reach zero even if the inode was
already removed from the swaplist.
> diff --git a/mm/shmem.c b/mm/shmem.c
> index e3e4bbbe1d802..eddd5870be072 100644
> --- a/mm/shmem.c
> +++ b/mm/shmem.c
> @@ -1616,6 +1616,17 @@ static int shmem_setattr(const struct mnt_idmap *idmap,
> return error;
> }
>
> +static void shmem_disallow_eviction(struct shmem_inode_info *info)
> +{
> + atomic_inc(&info->stop_eviction);
> +}
> +
> +static void shmem_allow_eviction(struct shmem_inode_info *info)
> +{
> + if (atomic_dec_and_test(&info->stop_eviction))
> + wake_up_var(&info->stop_eviction);
> +}
> +
> static void shmem_evict_inode(struct inode *inode)
> {
> struct shmem_inode_info *info = SHMEM_I(inode);
> @@ -1628,16 +1639,21 @@ static void shmem_evict_inode(struct inode *inode)
> mapping_set_exiting(inode->i_mapping);
> shmem_truncate_range(inode, 0, (loff_t)-1);
> shmem_unused_huge_del(inode);
> - while (!list_empty(&info->swaplist)) {
> - /* Wait while shmem_unuse() is scanning this inode... */
> + /*
> + * Writeout may still use the inode after swapoff has removed it
> + * from the swaplist, so always wait at least once.
> + */
> + do {
> wait_var_event(&info->stop_eviction,
> !atomic_read(&info->stop_eviction));
> + if (list_empty(&info->swaplist))
> + break;
> spin_lock(&shmem_swaplist_lock);
> /* ...but beware of the race if we peeked too early */
> if (!atomic_read(&info->stop_eviction))
> list_del_init(&info->swaplist);
> spin_unlock(&shmem_swaplist_lock);
> - }
> + } while (!list_empty(&info->swaplist));
[Severity: High]
Can this loop exit in shmem_evict_inode() while a concurrent shmem_unuse()
still holds info->stop_eviction > 0, leading to a use-after-free of info and
its embedded vfs_inode?
Specifically, two swapoff() syscalls on different swap types (typeA and
typeB) can run try_to_unuse() -> shmem_unuse() concurrently while
shmem_evict_inode() is evicting an inode:
1. In shmem_evict_inode(), shmem_truncate_range() -> shmem_undo_range() ->
shmem_recalc_inode() frees the swap entries and sets info->swapped = 0
under info->lock (without shmem_swaplist_lock).
2. Just before info->swapped becomes 0, shmem_unuse(typeA) on another CPU
holds shmem_swaplist_lock, sees info->swapped != 0, and is about to call
shmem_disallow_eviction(info):
mm/shmem.c:shmem_unuse() {
...
list_for_each_entry_safe(info, next, &shmem_swaplist, swaplist) {
if (!info->swapped) {
list_del_init(&info->swaplist);
continue;
}
shmem_disallow_eviction(info);
spin_unlock(&shmem_swaplist_lock);
error = shmem_unuse_inode(&info->vfs_inode, type);
...
}
3. Before shmem_unuse(typeA) increments info->stop_eviction,
shmem_evict_inode() enters the do-while loop and evaluates
wait_var_event(&info->stop_eviction, !atomic_read(&info->stop_eviction)),
which returns immediately because info->stop_eviction is still 0 (the
"peeked too early" race noted in the comment).
4. shmem_unuse(typeA) then calls shmem_disallow_eviction(info) (setting
info->stop_eviction to 1), drops shmem_swaplist_lock, and begins scanning
&info->vfs_inode in shmem_unuse_inode().
5. A second concurrent swapoff running shmem_unuse(typeB) acquires
shmem_swaplist_lock, sees !info->swapped is now true, and removes the
inode from the list via list_del_init(&info->swaplist) without checking
info->stop_eviction.
6. Back in shmem_evict_inode(), list_empty(&info->swaplist) is now true while
info->stop_eviction is 1. Either the new unlocked
if (list_empty(&info->swaplist)) break; exits the loop immediately, or
shmem_evict_inode() takes shmem_swaplist_lock, skips list_del_init()
because atomic_read(&info->stop_eviction) is non-zero, and then exits the
loop because the while (!list_empty(&info->swaplist)) condition is false.
Could shmem_evict_inode() then return and allow the inode to be freed while
shmem_unuse(typeA) is still accessing &info->vfs_inode in shmem_unuse_inode()
and later calling shmem_allow_eviction(info)?
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261028-fixes_shmem-v3-0-4ce3baf2db4b@kernel.org?part=6
next prev parent reply other threads:[~2026-10-28 20:35 UTC|newest]
Thread overview: 26+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-28 9:54 [PATCH v3 00/15] mm/shmem: various (urgent?) fixes David Hildenbrand (Arm)
2026-10-28 9:54 ` [PATCH v3 01/15] mm/mempolicy: charge shared policy nodes David Hildenbrand (Arm)
2026-10-28 10:02 ` Balbir Singh
2026-10-28 10:06 ` David Hildenbrand (Arm)
2026-10-28 9:55 ` [PATCH v3 02/15] tmpfs: keep the quota soft limits of an unused id David Hildenbrand (Arm)
2026-10-28 9:55 ` [PATCH v3 03/15] tmpfs: preserve explicitly disabled quota limits David Hildenbrand (Arm)
2026-10-28 9:55 ` [PATCH v3 04/15] mm/shmem: honour F_SEAL_EXEC when an ACL is set David Hildenbrand (Arm)
2026-10-28 10:06 ` Balbir Singh
2026-10-28 20:37 ` David Hildenbrand (Arm)
2026-10-28 9:55 ` [PATCH v3 05/15] hugetlbfs: enforce F_SEAL_EXEC in setattr David Hildenbrand (Arm)
2026-10-28 10:51 ` Oscar Salvador (SUSE)
2026-10-28 9:55 ` [PATCH v3 06/15] mm/shmem: hold off eviction in shmem_writeout() David Hildenbrand (Arm)
2026-10-28 20:35 ` sashiko-bot [this message]
2026-10-28 20:51 ` David Hildenbrand (Arm)
2026-10-29 9:26 ` David Hildenbrand (Arm)
2026-10-28 9:55 ` [PATCH v3 07/15] mm/shmem: stop retrying folios that cannot be split David Hildenbrand (Arm)
2026-10-28 23:10 ` Balbir Singh
2026-10-28 9:55 ` [PATCH v3 08/15] mm/shmem: preserve data in clean folios when splitting fails David Hildenbrand (Arm)
2026-10-28 9:55 ` [PATCH v3 09/15] mm/shmem: discard whole new large folios on fallocate rollback David Hildenbrand (Arm)
2026-10-28 9:55 ` [PATCH v3 10/15] mm/shmem: rescan after nonuniform folio splitting David Hildenbrand (Arm)
2026-10-28 9:55 ` [PATCH v3 11/15] mm/shmem: fix truncate hang in large swap entry David Hildenbrand (Arm)
2026-10-28 9:55 ` [PATCH v3 12/15] mm/shmem: preserve allocation errors when swapping in large entries David Hildenbrand (Arm)
2026-10-28 9:55 ` [PATCH v3 13/15] mm/shmem: fix truncate loop after boundary swapin failure David Hildenbrand (Arm)
2026-10-28 17:14 ` Nhat Pham
2026-10-28 9:55 ` [PATCH v3 14/15] mm/shmem: fix accounting of swapin-error markers David Hildenbrand (Arm)
2026-10-28 9:55 ` [PATCH v3 15/15] mm/shmem: fix truncation of files containing only " David Hildenbrand (Arm)
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-188427@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=baolin.wang@linux.alibaba.com \
--cc=brauner@kernel.org \
--cc=chrisl@kernel.org \
--cc=cmaiolino@redhat.com \
--cc=david@kernel.org \
--cc=dverkamp@chromium.org \
--cc=gourry@gourry.net \
--cc=hannes@cmpxchg.org \
--cc=hughd@google.com \
--cc=jack@suse.cz \
--cc=jeffxu@google.com \
--cc=josef@toxicpanda.com \
--cc=joshua.hahnjy@gmail.com \
--cc=kas@kernel.org \
--cc=kasong@tencent.com \
--cc=lczerner@redhat.com \
--cc=linmiaohe@huawei.com \
--cc=linux-mm@kvack.org \
--cc=mhocko@suse.com \
--cc=muchun.song@linux.dev \
--cc=nao.horiguchi@gmail.com \
--cc=nphamcs@gmail.com \
--cc=osalvador@suse.de \
--cc=pfalcato@suse.de \
--cc=rakie.kim@sk.com \
--cc=sashiko-reviews@lists.linux.dev \
--cc=stevensd@chromium.org \
--cc=vdavydov.dev@gmail.com \
--cc=william.kucharski@oracle.com \
--cc=willy@infradead.org \
--cc=ying.huang@linux.alibaba.com \
--cc=ziy@nvidia.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.