* [f2fs-dev] [PATCH] f2fs: fix use-after-free of sbi in f2fs_compress_write_end_io()
2026-03-23 7:46 ` Greg KH
@ 2026-03-23 9:03 ` George Saad
2026-03-23 9:32 ` Greg KH
2026-03-23 9:38 ` [f2fs-dev] [PATCH v2] " George Saad
` (2 subsequent siblings)
3 siblings, 1 reply; 11+ messages in thread
From: George Saad @ 2026-03-23 9:03 UTC (permalink / raw)
To: Greg KH; +Cc: Jaegeuk Kim, George Saad, linux-f2fs-devel
In f2fs_compress_write_end_io(), dec_page_count(sbi, type) at line 1492
can bring the F2FS_WB_CP_DATA counter to zero, unblocking
f2fs_wait_on_all_pages() in f2fs_put_super() on a concurrent unmount
CPU. The unmount path then proceeds to call
f2fs_destroy_page_array_cache(sbi) and kfree(sbi). Meanwhile, the bio
completion callback is still executing: when it reaches
page_array_free(sbi, ...), it dereferences sbi->page_array_slab_size
and sbi->page_array_slab within the now-freed f2fs_sb_info structure.
This is the same class of bug as CVE-2026-23234 (which fixed the
equivalent race in f2fs_write_end_io() in data.c), but in the
compressed writeback completion path that was not covered by that fix.
Fix this by caching sbi->page_array_slab and sbi->page_array_slab_size
into local variables at function entry, before dec_page_count(). At
function entry, sbi is guaranteed valid because the F2FS_WB_CP_DATA
counter is still nonzero (this invocation has not yet decremented it),
preventing the unmount path from proceeding past
f2fs_wait_on_all_pages(). The cached values are then used in place of
the post-decrement sbi dereference.
Fixes: 4c8ff709c6 ("f2fs: support data compression")
Signed-off-by: George Saad <geoo115@gmail.com>
---
fs/f2fs/compress.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
index 7b68bf229..c3d837df3 100644
--- a/fs/f2fs/compress.c
+++ b/fs/f2fs/compress.c
@@ -1479,11 +1479,20 @@ void f2fs_compress_write_end_io(struct bio *bio, struct folio *folio)
{
struct page *page = &folio->page;
struct f2fs_sb_info *sbi = bio->bi_private;
+ struct kmem_cache *pa_slab = sbi->page_array_slab;
+ unsigned int pa_slab_size = sbi->page_array_slab_size;
struct compress_io_ctx *cic = folio->private;
enum count_type type = WB_DATA_TYPE(folio,
f2fs_is_compressed_page(folio));
int i;
+ /*
+ * Cache sbi fields before dec_page_count(), which may unblock
+ * f2fs_wait_on_all_pages() in the unmount path, allowing
+ * f2fs_put_super() to free sbi. At this point sbi is still
+ * valid because the F2FS_WB_CP_DATA counter is nonzero.
+ */
+
if (unlikely(bio->bi_status != BLK_STS_OK))
mapping_set_error(cic->inode->i_mapping, -EIO);
@@ -1500,7 +1509,10 @@ void f2fs_compress_write_end_io(struct bio *bio, struct folio *folio)
end_page_writeback(cic->rpages[i]);
}
- page_array_free(sbi, cic->rpages, cic->nr_rpages);
+ if (likely(sizeof(struct page *) * cic->nr_rpages <= pa_slab_size))
+ kmem_cache_free(pa_slab, cic->rpages);
+ else
+ kfree(cic->rpages);
kmem_cache_free(cic_entry_slab, cic);
}
--
2.53.0
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [f2fs-dev] [PATCH] f2fs: fix use-after-free of sbi in f2fs_compress_write_end_io()
2026-03-23 9:03 ` [f2fs-dev] [PATCH] f2fs: fix use-after-free of sbi " George Saad
@ 2026-03-23 9:32 ` Greg KH
0 siblings, 0 replies; 11+ messages in thread
From: Greg KH @ 2026-03-23 9:32 UTC (permalink / raw)
To: George Saad; +Cc: Jaegeuk Kim, linux-f2fs-devel
On Mon, Mar 23, 2026 at 09:03:06AM +0000, George Saad wrote:
> In f2fs_compress_write_end_io(), dec_page_count(sbi, type) at line 1492
> can bring the F2FS_WB_CP_DATA counter to zero, unblocking
> f2fs_wait_on_all_pages() in f2fs_put_super() on a concurrent unmount
> CPU. The unmount path then proceeds to call
> f2fs_destroy_page_array_cache(sbi) and kfree(sbi). Meanwhile, the bio
> completion callback is still executing: when it reaches
> page_array_free(sbi, ...), it dereferences sbi->page_array_slab_size
> and sbi->page_array_slab within the now-freed f2fs_sb_info structure.
>
> This is the same class of bug as CVE-2026-23234 (which fixed the
> equivalent race in f2fs_write_end_io() in data.c), but in the
> compressed writeback completion path that was not covered by that fix.
>
> Fix this by caching sbi->page_array_slab and sbi->page_array_slab_size
> into local variables at function entry, before dec_page_count(). At
> function entry, sbi is guaranteed valid because the F2FS_WB_CP_DATA
> counter is still nonzero (this invocation has not yet decremented it),
> preventing the unmount path from proceeding past
> f2fs_wait_on_all_pages(). The cached values are then used in place of
> the post-decrement sbi dereference.
>
> Fixes: 4c8ff709c6 ("f2fs: support data compression")
This commit id is not in Linus's tree, are you sure it is correct?
thanks,
greg k-h
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply [flat|nested] 11+ messages in thread
* [f2fs-dev] [PATCH v2] f2fs: fix use-after-free of sbi in f2fs_compress_write_end_io()
2026-03-23 7:46 ` Greg KH
2026-03-23 9:03 ` [f2fs-dev] [PATCH] f2fs: fix use-after-free of sbi " George Saad
@ 2026-03-23 9:38 ` George Saad
2026-03-23 10:38 ` Greg KH
2026-03-23 10:44 ` [f2fs-dev] [PATCH v3] " George Saad
2026-03-23 11:21 ` [f2fs-dev] [PATCH v4] " George Saad
3 siblings, 1 reply; 11+ messages in thread
From: George Saad @ 2026-03-23 9:38 UTC (permalink / raw)
To: Greg KH; +Cc: Jaegeuk Kim, George Saad, linux-f2fs-devel
In f2fs_compress_write_end_io(), dec_page_count(sbi, type) at line 1492
can bring the F2FS_WB_CP_DATA counter to zero, unblocking
f2fs_wait_on_all_pages() in f2fs_put_super() on a concurrent unmount
CPU. The unmount path then proceeds to call
f2fs_destroy_page_array_cache(sbi) and kfree(sbi). Meanwhile, the bio
completion callback is still executing: when it reaches
page_array_free(sbi, ...), it dereferences sbi->page_array_slab_size
and sbi->page_array_slab within the now-freed f2fs_sb_info structure.
This is the same class of bug as CVE-2026-23234 (which fixed the
equivalent race in f2fs_write_end_io() in data.c), but in the
compressed writeback completion path that was not covered by that fix.
Fix this by caching sbi->page_array_slab and sbi->page_array_slab_size
into local variables at function entry, before dec_page_count(). At
function entry, sbi is guaranteed valid because the F2FS_WB_CP_DATA
counter is still nonzero (this invocation has not yet decremented it),
preventing the unmount path from proceeding past
f2fs_wait_on_all_pages(). The cached values are then used in place of
the post-decrement sbi dereference.
Fixes: 4c8ff7095bef ("f2fs: support data compression")
Signed-off-by: George Saad <geoo115@gmail.com>
---
fs/f2fs/compress.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
index 7b68bf229..c3d837df3 100644
--- a/fs/f2fs/compress.c
+++ b/fs/f2fs/compress.c
@@ -1479,11 +1479,20 @@ void f2fs_compress_write_end_io(struct bio *bio, struct folio *folio)
{
struct page *page = &folio->page;
struct f2fs_sb_info *sbi = bio->bi_private;
+ struct kmem_cache *pa_slab = sbi->page_array_slab;
+ unsigned int pa_slab_size = sbi->page_array_slab_size;
struct compress_io_ctx *cic = folio->private;
enum count_type type = WB_DATA_TYPE(folio,
f2fs_is_compressed_page(folio));
int i;
+ /*
+ * Cache sbi fields before dec_page_count(), which may unblock
+ * f2fs_wait_on_all_pages() in the unmount path, allowing
+ * f2fs_put_super() to free sbi. At this point sbi is still
+ * valid because the F2FS_WB_CP_DATA counter is nonzero.
+ */
+
if (unlikely(bio->bi_status != BLK_STS_OK))
mapping_set_error(cic->inode->i_mapping, -EIO);
@@ -1500,7 +1509,10 @@ void f2fs_compress_write_end_io(struct bio *bio, struct folio *folio)
end_page_writeback(cic->rpages[i]);
}
- page_array_free(sbi, cic->rpages, cic->nr_rpages);
+ if (likely(sizeof(struct page *) * cic->nr_rpages <= pa_slab_size))
+ kmem_cache_free(pa_slab, cic->rpages);
+ else
+ kfree(cic->rpages);
kmem_cache_free(cic_entry_slab, cic);
}
--
2.53.0
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [f2fs-dev] [PATCH v2] f2fs: fix use-after-free of sbi in f2fs_compress_write_end_io()
2026-03-23 9:38 ` [f2fs-dev] [PATCH v2] " George Saad
@ 2026-03-23 10:38 ` Greg KH
0 siblings, 0 replies; 11+ messages in thread
From: Greg KH @ 2026-03-23 10:38 UTC (permalink / raw)
To: George Saad; +Cc: Jaegeuk Kim, linux-f2fs-devel
On Mon, Mar 23, 2026 at 09:38:28AM +0000, George Saad wrote:
> In f2fs_compress_write_end_io(), dec_page_count(sbi, type) at line 1492
> can bring the F2FS_WB_CP_DATA counter to zero, unblocking
> f2fs_wait_on_all_pages() in f2fs_put_super() on a concurrent unmount
> CPU. The unmount path then proceeds to call
> f2fs_destroy_page_array_cache(sbi) and kfree(sbi). Meanwhile, the bio
> completion callback is still executing: when it reaches
> page_array_free(sbi, ...), it dereferences sbi->page_array_slab_size
> and sbi->page_array_slab within the now-freed f2fs_sb_info structure.
>
> This is the same class of bug as CVE-2026-23234 (which fixed the
> equivalent race in f2fs_write_end_io() in data.c), but in the
> compressed writeback completion path that was not covered by that fix.
>
> Fix this by caching sbi->page_array_slab and sbi->page_array_slab_size
> into local variables at function entry, before dec_page_count(). At
> function entry, sbi is guaranteed valid because the F2FS_WB_CP_DATA
> counter is still nonzero (this invocation has not yet decremented it),
> preventing the unmount path from proceeding past
> f2fs_wait_on_all_pages(). The cached values are then used in place of
> the post-decrement sbi dereference.
>
> Fixes: 4c8ff7095bef ("f2fs: support data compression")
> Signed-off-by: George Saad <geoo115@gmail.com>
> ---
> fs/f2fs/compress.c | 14 +++++++++++++-
> 1 file changed, 13 insertions(+), 1 deletion(-)
>
> diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
> index 7b68bf229..c3d837df3 100644
> --- a/fs/f2fs/compress.c
> +++ b/fs/f2fs/compress.c
> @@ -1479,11 +1479,20 @@ void f2fs_compress_write_end_io(struct bio *bio, struct folio *folio)
> {
> struct page *page = &folio->page;
> struct f2fs_sb_info *sbi = bio->bi_private;
> + struct kmem_cache *pa_slab = sbi->page_array_slab;
> + unsigned int pa_slab_size = sbi->page_array_slab_size;
> struct compress_io_ctx *cic = folio->private;
> enum count_type type = WB_DATA_TYPE(folio,
> f2fs_is_compressed_page(folio));
> int i;
>
> + /*
> + * Cache sbi fields before dec_page_count(), which may unblock
> + * f2fs_wait_on_all_pages() in the unmount path, allowing
> + * f2fs_put_super() to free sbi. At this point sbi is still
> + * valid because the F2FS_WB_CP_DATA counter is nonzero.
> + */
> +
> if (unlikely(bio->bi_status != BLK_STS_OK))
> mapping_set_error(cic->inode->i_mapping, -EIO);
>
> @@ -1500,7 +1509,10 @@ void f2fs_compress_write_end_io(struct bio *bio, struct folio *folio)
> end_page_writeback(cic->rpages[i]);
> }
>
> - page_array_free(sbi, cic->rpages, cic->nr_rpages);
> + if (likely(sizeof(struct page *) * cic->nr_rpages <= pa_slab_size))
> + kmem_cache_free(pa_slab, cic->rpages);
> + else
> + kfree(cic->rpages);
> kmem_cache_free(cic_entry_slab, cic);
> }
>
> --
> 2.53.0
>
Hi,
This is the friendly patch-bot of Greg Kroah-Hartman. You have sent him
a patch that has triggered this response. He used to manually respond
to these common problems, but in order to save his sanity (he kept
writing the same thing over and over, yet to different people), I was
created. Hopefully you will not take offence and will fix the problem
in your patch and resubmit it so that it can be accepted into the Linux
kernel tree.
You are receiving this message because of the following common error(s)
as indicated below:
- This looks like a new version of a previously submitted patch, but you
did not list below the --- line any changes from the previous version.
Please read the section entitled "The canonical patch format" in the
kernel file, Documentation/process/submitting-patches.rst for what
needs to be done here to properly describe this.
- You have marked a patch with a "Fixes:" tag for a commit that is in an
older released kernel, yet you do not have a cc: stable line in the
signed-off-by area at all, which means that the patch will not be
applied to any older kernel releases. To properly fix this, please
follow the documented rules in the
Documentation/process/stable-kernel-rules.rst file for how to resolve
this.
If you wish to discuss this problem further, or you have questions about
how to resolve this issue, please feel free to respond to this email and
Greg will reply once he has dug out from the pending patches received
from other developers.
thanks,
greg k-h's patch email bot
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply [flat|nested] 11+ messages in thread
* [f2fs-dev] [PATCH v3] f2fs: fix use-after-free of sbi in f2fs_compress_write_end_io()
2026-03-23 7:46 ` Greg KH
2026-03-23 9:03 ` [f2fs-dev] [PATCH] f2fs: fix use-after-free of sbi " George Saad
2026-03-23 9:38 ` [f2fs-dev] [PATCH v2] " George Saad
@ 2026-03-23 10:44 ` George Saad
2026-03-23 11:06 ` Chao Yu via Linux-f2fs-devel
2026-03-23 11:21 ` [f2fs-dev] [PATCH v4] " George Saad
3 siblings, 1 reply; 11+ messages in thread
From: George Saad @ 2026-03-23 10:44 UTC (permalink / raw)
To: Greg KH; +Cc: Jaegeuk Kim, George Saad, stable, linux-f2fs-devel
In f2fs_compress_write_end_io(), dec_page_count(sbi, type) at line 1492
can bring the F2FS_WB_CP_DATA counter to zero, unblocking
f2fs_wait_on_all_pages() in f2fs_put_super() on a concurrent unmount
CPU. The unmount path then proceeds to call
f2fs_destroy_page_array_cache(sbi) and kfree(sbi). Meanwhile, the bio
completion callback is still executing: when it reaches
page_array_free(sbi, ...), it dereferences sbi->page_array_slab_size
and sbi->page_array_slab within the now-freed f2fs_sb_info structure.
This is the same class of bug as CVE-2026-23234 (which fixed the
equivalent race in f2fs_write_end_io() in data.c), but in the
compressed writeback completion path that was not covered by that fix.
Fix this by caching sbi->page_array_slab and sbi->page_array_slab_size
into local variables at function entry, before dec_page_count(). At
function entry, sbi is guaranteed valid because the F2FS_WB_CP_DATA
counter is still nonzero (this invocation has not yet decremented it),
preventing the unmount path from proceeding past
f2fs_wait_on_all_pages(). The cached values are then used in place of
the post-decrement sbi dereference.
Fixes: 4c8ff7095bef ("f2fs: support data compression")
Cc: stable@vger.kernel.org
Signed-off-by: George Saad <geoo115@gmail.com>
---
Changes in v3:
- Add Cc: stable@vger.kernel.org for backport to affected stable kernels
Changes in v2:
- Fix Fixes: tag commit hash (4c8ff7095bef, verified in Linus's tree)
fs/f2fs/compress.c | 14 +++++++++++++-
1 file changed, 13 insertions(+), 1 deletion(-)
diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
index 7b68bf229..c3d837df3 100644
--- a/fs/f2fs/compress.c
+++ b/fs/f2fs/compress.c
@@ -1479,11 +1479,20 @@ void f2fs_compress_write_end_io(struct bio *bio, struct folio *folio)
{
struct page *page = &folio->page;
struct f2fs_sb_info *sbi = bio->bi_private;
+ struct kmem_cache *pa_slab = sbi->page_array_slab;
+ unsigned int pa_slab_size = sbi->page_array_slab_size;
struct compress_io_ctx *cic = folio->private;
enum count_type type = WB_DATA_TYPE(folio,
f2fs_is_compressed_page(folio));
int i;
+ /*
+ * Cache sbi fields before dec_page_count(), which may unblock
+ * f2fs_wait_on_all_pages() in the unmount path, allowing
+ * f2fs_put_super() to free sbi. At this point sbi is still
+ * valid because the F2FS_WB_CP_DATA counter is nonzero.
+ */
+
if (unlikely(bio->bi_status != BLK_STS_OK))
mapping_set_error(cic->inode->i_mapping, -EIO);
@@ -1500,7 +1509,10 @@ void f2fs_compress_write_end_io(struct bio *bio, struct folio *folio)
end_page_writeback(cic->rpages[i]);
}
- page_array_free(sbi, cic->rpages, cic->nr_rpages);
+ if (likely(sizeof(struct page *) * cic->nr_rpages <= pa_slab_size))
+ kmem_cache_free(pa_slab, cic->rpages);
+ else
+ kfree(cic->rpages);
kmem_cache_free(cic_entry_slab, cic);
}
--
2.53.0
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [f2fs-dev] [PATCH v3] f2fs: fix use-after-free of sbi in f2fs_compress_write_end_io()
2026-03-23 10:44 ` [f2fs-dev] [PATCH v3] " George Saad
@ 2026-03-23 11:06 ` Chao Yu via Linux-f2fs-devel
0 siblings, 0 replies; 11+ messages in thread
From: Chao Yu via Linux-f2fs-devel @ 2026-03-23 11:06 UTC (permalink / raw)
To: George Saad, Greg KH; +Cc: Jaegeuk Kim, stable, linux-f2fs-devel
On 3/23/26 18:44, George Saad wrote:
> In f2fs_compress_write_end_io(), dec_page_count(sbi, type) at line 1492
> can bring the F2FS_WB_CP_DATA counter to zero, unblocking
> f2fs_wait_on_all_pages() in f2fs_put_super() on a concurrent unmount
> CPU. The unmount path then proceeds to call
> f2fs_destroy_page_array_cache(sbi) and kfree(sbi). Meanwhile, the bio
> completion callback is still executing: when it reaches
> page_array_free(sbi, ...), it dereferences sbi->page_array_slab_size
> and sbi->page_array_slab within the now-freed f2fs_sb_info structure.
>
> This is the same class of bug as CVE-2026-23234 (which fixed the
> equivalent race in f2fs_write_end_io() in data.c), but in the
> compressed writeback completion path that was not covered by that fix.
>
> Fix this by caching sbi->page_array_slab and sbi->page_array_slab_size
> into local variables at function entry, before dec_page_count(). At
> function entry, sbi is guaranteed valid because the F2FS_WB_CP_DATA
> counter is still nonzero (this invocation has not yet decremented it),
> preventing the unmount path from proceeding past
> f2fs_wait_on_all_pages(). The cached values are then used in place of
> the post-decrement sbi dereference.
>
> Fixes: 4c8ff7095bef ("f2fs: support data compression")
> Cc: stable@vger.kernel.org
> Signed-off-by: George Saad <geoo115@gmail.com>
> ---
> Changes in v3:
> - Add Cc: stable@vger.kernel.org for backport to affected stable kernels
>
> Changes in v2:
> - Fix Fixes: tag commit hash (4c8ff7095bef, verified in Linus's tree)
>
> fs/f2fs/compress.c | 14 +++++++++++++-
> 1 file changed, 13 insertions(+), 1 deletion(-)
>
> diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
> index 7b68bf229..c3d837df3 100644
> --- a/fs/f2fs/compress.c
> +++ b/fs/f2fs/compress.c
> @@ -1479,11 +1479,20 @@ void f2fs_compress_write_end_io(struct bio *bio, struct folio *folio)
> {
> struct page *page = &folio->page;
> struct f2fs_sb_info *sbi = bio->bi_private;
> + struct kmem_cache *pa_slab = sbi->page_array_slab;
> + unsigned int pa_slab_size = sbi->page_array_slab_size;
> struct compress_io_ctx *cic = folio->private;
> enum count_type type = WB_DATA_TYPE(folio,
> f2fs_is_compressed_page(folio));
> int i;
>
> + /*
> + * Cache sbi fields before dec_page_count(), which may unblock
> + * f2fs_wait_on_all_pages() in the unmount path, allowing
> + * f2fs_put_super() to free sbi. At this point sbi is still
> + * valid because the F2FS_WB_CP_DATA counter is nonzero.
> + */
> +
> if (unlikely(bio->bi_status != BLK_STS_OK))
> mapping_set_error(cic->inode->i_mapping, -EIO);
>
> @@ -1500,7 +1509,10 @@ void f2fs_compress_write_end_io(struct bio *bio, struct folio *folio)
> end_page_writeback(cic->rpages[i]);
> }
>
> - page_array_free(sbi, cic->rpages, cic->nr_rpages);
> + if (likely(sizeof(struct page *) * cic->nr_rpages <= pa_slab_size))
> + kmem_cache_free(pa_slab, cic->rpages);
After sbi is freed, sbi->page_array_slab should be destroyed as well, so
pa_slab points to a freed memory, right?
Thanks,
> + else
> + kfree(cic->rpages);
> kmem_cache_free(cic_entry_slab, cic);
> }
>
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply [flat|nested] 11+ messages in thread
* [f2fs-dev] [PATCH v4] f2fs: fix use-after-free of sbi in f2fs_compress_write_end_io()
2026-03-23 7:46 ` Greg KH
` (2 preceding siblings ...)
2026-03-23 10:44 ` [f2fs-dev] [PATCH v3] " George Saad
@ 2026-03-23 11:21 ` George Saad
2026-03-23 11:30 ` Chao Yu via Linux-f2fs-devel
2026-03-24 17:32 ` patchwork-bot+f2fs--- via Linux-f2fs-devel
3 siblings, 2 replies; 11+ messages in thread
From: George Saad @ 2026-03-23 11:21 UTC (permalink / raw)
To: Greg KH; +Cc: Jaegeuk Kim, George Saad, stable, linux-f2fs-devel
In f2fs_compress_write_end_io(), dec_page_count(sbi, type) can bring
the F2FS_WB_CP_DATA counter to zero, unblocking
f2fs_wait_on_all_pages() in f2fs_put_super() on a concurrent unmount
CPU. The unmount path then proceeds to call
f2fs_destroy_page_array_cache(sbi), which destroys
sbi->page_array_slab via kmem_cache_destroy(), and eventually
kfree(sbi). Meanwhile, the bio completion callback is still executing:
when it reaches page_array_free(sbi, ...), it dereferences
sbi->page_array_slab — a destroyed slab cache — to call
kmem_cache_free(), causing a use-after-free.
This is the same class of bug as CVE-2026-23234 (which fixed the
equivalent race in f2fs_write_end_io() in data.c), but in the
compressed writeback completion path that was not covered by that fix.
Fix this by moving dec_page_count() to after page_array_free(), so
that all sbi accesses complete before the counter decrement that can
unblock unmount. For non-last folios (where atomic_dec_return on
cic->pending_pages is nonzero), dec_page_count is called immediately
before returning — page_array_free is not reached on this path, so
there is no post-decrement sbi access. For the last folio,
page_array_free runs while the F2FS_WB_CP_DATA counter is still
nonzero (this folio has not yet decremented it), keeping sbi alive,
and dec_page_count runs as the final operation.
Fixes: 4c8ff7095bef ("f2fs: support data compression")
Cc: stable@vger.kernel.org
Signed-off-by: George Saad <geoo115@gmail.com>
---
Changes in v4:
- Rewrite fix: instead of caching sbi->page_array_slab (which is
destroyed by kmem_cache_destroy before kfree(sbi)), move
dec_page_count() to after page_array_free() so all sbi accesses
complete before the counter decrement can unblock unmount
(Chao Yu)
Changes in v3:
- Add Cc: stable@vger.kernel.org for backport to affected stable kernels
Changes in v2:
- Fix Fixes: tag commit hash (4c8ff7095bef, verified in Linus's tree)
fs/f2fs/compress.c | 14 +++++++++++---
1 file changed, 11 insertions(+), 3 deletions(-)
diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c
index 7b68bf229..d9d105efa 100644
--- a/fs/f2fs/compress.c
+++ b/fs/f2fs/compress.c
@@ -1489,10 +1489,10 @@ void f2fs_compress_write_end_io(struct bio *bio, struct folio *folio)
f2fs_compress_free_page(page);
- dec_page_count(sbi, type);
-
- if (atomic_dec_return(&cic->pending_pages))
+ if (atomic_dec_return(&cic->pending_pages)) {
+ dec_page_count(sbi, type);
return;
+ }
for (i = 0; i < cic->nr_rpages; i++) {
WARN_ON(!cic->rpages[i]);
@@ -1502,6 +1502,14 @@ void f2fs_compress_write_end_io(struct bio *bio, struct folio *folio)
page_array_free(sbi, cic->rpages, cic->nr_rpages);
kmem_cache_free(cic_entry_slab, cic);
+
+ /*
+ * Make sure dec_page_count() is the last access to sbi.
+ * Once it drops the F2FS_WB_CP_DATA counter to zero, the
+ * unmount thread can proceed to destroy sbi and
+ * sbi->page_array_slab.
+ */
+ dec_page_count(sbi, type);
}
static int f2fs_write_raw_pages(struct compress_ctx *cc,
--
2.53.0
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply related [flat|nested] 11+ messages in thread* Re: [f2fs-dev] [PATCH v4] f2fs: fix use-after-free of sbi in f2fs_compress_write_end_io()
2026-03-23 11:21 ` [f2fs-dev] [PATCH v4] " George Saad
@ 2026-03-23 11:30 ` Chao Yu via Linux-f2fs-devel
2026-03-24 17:32 ` patchwork-bot+f2fs--- via Linux-f2fs-devel
1 sibling, 0 replies; 11+ messages in thread
From: Chao Yu via Linux-f2fs-devel @ 2026-03-23 11:30 UTC (permalink / raw)
To: George Saad, Greg KH; +Cc: Jaegeuk Kim, stable, linux-f2fs-devel
On 3/23/26 19:21, George Saad wrote:
> In f2fs_compress_write_end_io(), dec_page_count(sbi, type) can bring
> the F2FS_WB_CP_DATA counter to zero, unblocking
> f2fs_wait_on_all_pages() in f2fs_put_super() on a concurrent unmount
> CPU. The unmount path then proceeds to call
> f2fs_destroy_page_array_cache(sbi), which destroys
> sbi->page_array_slab via kmem_cache_destroy(), and eventually
> kfree(sbi). Meanwhile, the bio completion callback is still executing:
> when it reaches page_array_free(sbi, ...), it dereferences
> sbi->page_array_slab — a destroyed slab cache — to call
> kmem_cache_free(), causing a use-after-free.
>
> This is the same class of bug as CVE-2026-23234 (which fixed the
> equivalent race in f2fs_write_end_io() in data.c), but in the
> compressed writeback completion path that was not covered by that fix.
>
> Fix this by moving dec_page_count() to after page_array_free(), so
> that all sbi accesses complete before the counter decrement that can
> unblock unmount. For non-last folios (where atomic_dec_return on
> cic->pending_pages is nonzero), dec_page_count is called immediately
> before returning — page_array_free is not reached on this path, so
> there is no post-decrement sbi access. For the last folio,
> page_array_free runs while the F2FS_WB_CP_DATA counter is still
> nonzero (this folio has not yet decremented it), keeping sbi alive,
> and dec_page_count runs as the final operation.
>
> Fixes: 4c8ff7095bef ("f2fs: support data compression")
> Cc: stable@vger.kernel.org
> Signed-off-by: George Saad <geoo115@gmail.com>
Reviewed-by: Chao Yu <chao@kernel.org>
Thanks,
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply [flat|nested] 11+ messages in thread* Re: [f2fs-dev] [PATCH v4] f2fs: fix use-after-free of sbi in f2fs_compress_write_end_io()
2026-03-23 11:21 ` [f2fs-dev] [PATCH v4] " George Saad
2026-03-23 11:30 ` Chao Yu via Linux-f2fs-devel
@ 2026-03-24 17:32 ` patchwork-bot+f2fs--- via Linux-f2fs-devel
1 sibling, 0 replies; 11+ messages in thread
From: patchwork-bot+f2fs--- via Linux-f2fs-devel @ 2026-03-24 17:32 UTC (permalink / raw)
To: George Saad; +Cc: gregkh, linux-f2fs-devel, stable, jaegeuk
Hello:
This patch was applied to jaegeuk/f2fs.git (dev)
by Jaegeuk Kim <jaegeuk@kernel.org>:
On Mon, 23 Mar 2026 11:21:23 +0000 you wrote:
> In f2fs_compress_write_end_io(), dec_page_count(sbi, type) can bring
> the F2FS_WB_CP_DATA counter to zero, unblocking
> f2fs_wait_on_all_pages() in f2fs_put_super() on a concurrent unmount
> CPU. The unmount path then proceeds to call
> f2fs_destroy_page_array_cache(sbi), which destroys
> sbi->page_array_slab via kmem_cache_destroy(), and eventually
> kfree(sbi). Meanwhile, the bio completion callback is still executing:
> when it reaches page_array_free(sbi, ...), it dereferences
> sbi->page_array_slab — a destroyed slab cache — to call
> kmem_cache_free(), causing a use-after-free.
>
> [...]
Here is the summary with links:
- [f2fs-dev,v4] f2fs: fix use-after-free of sbi in f2fs_compress_write_end_io()
https://git.kernel.org/jaegeuk/f2fs/c/39d4ee19c1e7
You are awesome, thank you!
--
Deet-doot-dot, I am a bot.
https://korg.docs.kernel.org/patchwork/pwbot.html
_______________________________________________
Linux-f2fs-devel mailing list
Linux-f2fs-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/linux-f2fs-devel
^ permalink raw reply [flat|nested] 11+ messages in thread