From: Sasha Levin Date: Tue, 12 May 2026 14:35:34 +0000 (-0400) Subject: Fixes for all trees X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=72863d2c940b3d68eed060069667c5febb316543;p=thirdparty%2Fkernel%2Fstable-queue.git Fixes for all trees Signed-off-by: Sasha Levin --- diff --git a/queue-6.1/f2fs-compress-change-the-first-parameter-of-page_arr.patch b/queue-6.1/f2fs-compress-change-the-first-parameter-of-page_arr.patch new file mode 100644 index 0000000000..ccda2c6f57 --- /dev/null +++ b/queue-6.1/f2fs-compress-change-the-first-parameter-of-page_arr.patch @@ -0,0 +1,196 @@ +From 4e9ef60e9ca5da5e617b13449657c7569a38e1ce Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 15:50:09 +0800 +Subject: f2fs: compress: change the first parameter of page_array_{alloc,free} + to sbi + +From: Zhiguo Niu + +[ Upstream commit 8e2a9b656474d67c55010f2c003ea2cf889a19ff ] + +No logic changes, just cleanup and prepare for fixing the UAF issue +in f2fs_free_dic. + +Signed-off-by: Zhiguo Niu +Signed-off-by: Baocong Liu +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +Signed-off-by: Bin Lan +Signed-off-by: Sasha Levin +--- + fs/f2fs/compress.c | 40 ++++++++++++++++++++-------------------- + 1 file changed, 20 insertions(+), 20 deletions(-) + +diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c +index 4dcd0870e0c74..1e90286212866 100644 +--- a/fs/f2fs/compress.c ++++ b/fs/f2fs/compress.c +@@ -23,20 +23,18 @@ + static struct kmem_cache *cic_entry_slab; + static struct kmem_cache *dic_entry_slab; + +-static void *page_array_alloc(struct inode *inode, int nr) ++static void *page_array_alloc(struct f2fs_sb_info *sbi, int nr) + { +- struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + unsigned int size = sizeof(struct page *) * nr; + + if (likely(size <= sbi->page_array_slab_size)) + return f2fs_kmem_cache_alloc(sbi->page_array_slab, +- GFP_F2FS_ZERO, false, F2FS_I_SB(inode)); ++ GFP_F2FS_ZERO, false, sbi); + return f2fs_kzalloc(sbi, size, GFP_NOFS); + } + +-static void page_array_free(struct inode *inode, void *pages, int nr) ++static void page_array_free(struct f2fs_sb_info *sbi, void *pages, int nr) + { +- struct f2fs_sb_info *sbi = F2FS_I_SB(inode); + unsigned int size = sizeof(struct page *) * nr; + + if (!pages) +@@ -145,13 +143,13 @@ int f2fs_init_compress_ctx(struct compress_ctx *cc) + if (cc->rpages) + return 0; + +- cc->rpages = page_array_alloc(cc->inode, cc->cluster_size); ++ cc->rpages = page_array_alloc(F2FS_I_SB(cc->inode), cc->cluster_size); + return cc->rpages ? 0 : -ENOMEM; + } + + void f2fs_destroy_compress_ctx(struct compress_ctx *cc, bool reuse) + { +- page_array_free(cc->inode, cc->rpages, cc->cluster_size); ++ page_array_free(F2FS_I_SB(cc->inode), cc->rpages, cc->cluster_size); + cc->rpages = NULL; + cc->nr_rpages = 0; + cc->nr_cpages = 0; +@@ -640,6 +638,7 @@ static void *f2fs_vmap(struct page **pages, unsigned int count) + + static int f2fs_compress_pages(struct compress_ctx *cc) + { ++ struct f2fs_sb_info *sbi = F2FS_I_SB(cc->inode); + struct f2fs_inode_info *fi = F2FS_I(cc->inode); + const struct f2fs_compress_ops *cops = + f2fs_cops[fi->i_compress_algorithm]; +@@ -660,7 +659,7 @@ static int f2fs_compress_pages(struct compress_ctx *cc) + cc->nr_cpages = DIV_ROUND_UP(max_len, PAGE_SIZE); + cc->valid_nr_cpages = cc->nr_cpages; + +- cc->cpages = page_array_alloc(cc->inode, cc->nr_cpages); ++ cc->cpages = page_array_alloc(sbi, cc->nr_cpages); + if (!cc->cpages) { + ret = -ENOMEM; + goto destroy_compress_ctx; +@@ -742,7 +741,7 @@ static int f2fs_compress_pages(struct compress_ctx *cc) + if (cc->cpages[i]) + f2fs_compress_free_page(cc->cpages[i]); + } +- page_array_free(cc->inode, cc->cpages, cc->nr_cpages); ++ page_array_free(sbi, cc->cpages, cc->nr_cpages); + cc->cpages = NULL; + destroy_compress_ctx: + if (cops->destroy_compress_ctx) +@@ -1308,7 +1307,7 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc, + cic->magic = F2FS_COMPRESSED_PAGE_MAGIC; + cic->inode = inode; + atomic_set(&cic->pending_pages, cc->valid_nr_cpages); +- cic->rpages = page_array_alloc(cc->inode, cc->cluster_size); ++ cic->rpages = page_array_alloc(sbi, cc->cluster_size); + if (!cic->rpages) + goto out_put_cic; + +@@ -1401,13 +1400,13 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc, + spin_unlock(&fi->i_size_lock); + + f2fs_put_rpages(cc); +- page_array_free(cc->inode, cc->cpages, cc->nr_cpages); ++ page_array_free(sbi, cc->cpages, cc->nr_cpages); + cc->cpages = NULL; + f2fs_destroy_compress_ctx(cc, false); + return 0; + + out_destroy_crypt: +- page_array_free(cc->inode, cic->rpages, cc->cluster_size); ++ page_array_free(sbi, cic->rpages, cc->cluster_size); + + for (--i; i >= 0; i--) + fscrypt_finalize_bounce_page(&cc->cpages[i]); +@@ -1425,7 +1424,7 @@ static int f2fs_write_compressed_pages(struct compress_ctx *cc, + f2fs_compress_free_page(cc->cpages[i]); + cc->cpages[i] = NULL; + } +- page_array_free(cc->inode, cc->cpages, cc->nr_cpages); ++ page_array_free(sbi, cc->cpages, cc->nr_cpages); + cc->cpages = NULL; + return -EAGAIN; + } +@@ -1455,7 +1454,7 @@ void f2fs_compress_write_end_io(struct bio *bio, struct page *page) + end_page_writeback(cic->rpages[i]); + } + +- page_array_free(cic->inode, cic->rpages, cic->nr_rpages); ++ page_array_free(sbi, cic->rpages, cic->nr_rpages); + kmem_cache_free(cic_entry_slab, cic); + + /* +@@ -1601,7 +1600,7 @@ static int f2fs_prepare_decomp_mem(struct decompress_io_ctx *dic, + if (!allow_memalloc_for_decomp(F2FS_I_SB(dic->inode), pre_alloc)) + return 0; + +- dic->tpages = page_array_alloc(dic->inode, dic->cluster_size); ++ dic->tpages = page_array_alloc(F2FS_I_SB(dic->inode), dic->cluster_size); + if (!dic->tpages) + return -ENOMEM; + +@@ -1663,7 +1662,7 @@ struct decompress_io_ctx *f2fs_alloc_dic(struct compress_ctx *cc) + if (!dic) + return ERR_PTR(-ENOMEM); + +- dic->rpages = page_array_alloc(cc->inode, cc->cluster_size); ++ dic->rpages = page_array_alloc(sbi, cc->cluster_size); + if (!dic->rpages) { + kmem_cache_free(dic_entry_slab, dic); + return ERR_PTR(-ENOMEM); +@@ -1684,7 +1683,7 @@ struct decompress_io_ctx *f2fs_alloc_dic(struct compress_ctx *cc) + dic->rpages[i] = cc->rpages[i]; + dic->nr_rpages = cc->cluster_size; + +- dic->cpages = page_array_alloc(dic->inode, dic->nr_cpages); ++ dic->cpages = page_array_alloc(sbi, dic->nr_cpages); + if (!dic->cpages) { + ret = -ENOMEM; + goto out_free; +@@ -1719,6 +1718,7 @@ static void f2fs_free_dic(struct decompress_io_ctx *dic, + bool bypass_destroy_callback) + { + int i; ++ struct f2fs_sb_info *sbi = F2FS_I_SB(dic->inode); + + f2fs_release_decomp_mem(dic, bypass_destroy_callback, true); + +@@ -1730,7 +1730,7 @@ static void f2fs_free_dic(struct decompress_io_ctx *dic, + continue; + f2fs_compress_free_page(dic->tpages[i]); + } +- page_array_free(dic->inode, dic->tpages, dic->cluster_size); ++ page_array_free(sbi, dic->tpages, dic->cluster_size); + } + + if (dic->cpages) { +@@ -1739,10 +1739,10 @@ static void f2fs_free_dic(struct decompress_io_ctx *dic, + continue; + f2fs_compress_free_page(dic->cpages[i]); + } +- page_array_free(dic->inode, dic->cpages, dic->nr_cpages); ++ page_array_free(sbi, dic->cpages, dic->nr_cpages); + } + +- page_array_free(dic->inode, dic->rpages, dic->nr_rpages); ++ page_array_free(sbi, dic->rpages, dic->nr_rpages); + kmem_cache_free(dic_entry_slab, dic); + } + +-- +2.53.0 + diff --git a/queue-6.1/f2fs-compress-fix-uaf-of-f2fs_inode_info-in-f2fs_fre.patch b/queue-6.1/f2fs-compress-fix-uaf-of-f2fs_inode_info-in-f2fs_fre.patch new file mode 100644 index 0000000000..66ca85142b --- /dev/null +++ b/queue-6.1/f2fs-compress-fix-uaf-of-f2fs_inode_info-in-f2fs_fre.patch @@ -0,0 +1,233 @@ +From d4f6e8256fcab674acc8e3f0bcda071dcf451a18 Mon Sep 17 00:00:00 2001 +From: Sasha Levin +Date: Tue, 12 May 2026 15:50:10 +0800 +Subject: f2fs: compress: fix UAF of f2fs_inode_info in f2fs_free_dic + +From: Zhiguo Niu + +[ Upstream commit 39868685c2a94a70762bc6d77dc81d781d05bff5 ] + +The decompress_io_ctx may be released asynchronously after +I/O completion. If this file is deleted immediately after read, +and the kworker of processing post_read_wq has not been executed yet +due to high workloads, It is possible that the inode(f2fs_inode_info) +is evicted and freed before it is used f2fs_free_dic. + + The UAF case as below: + Thread A Thread B + - f2fs_decompress_end_io + - f2fs_put_dic + - queue_work + add free_dic work to post_read_wq + - do_unlink + - iput + - evict + - call_rcu + This file is deleted after read. + + Thread C kworker to process post_read_wq + - rcu_do_batch + - f2fs_free_inode + - kmem_cache_free + inode is freed by rcu + - process_scheduled_works + - f2fs_late_free_dic + - f2fs_free_dic + - f2fs_release_decomp_mem + read (dic->inode)->i_compress_algorithm + +This patch store compress_algorithm and sbi in dic to avoid inode UAF. + +In addition, the previous solution is deprecated in [1] may cause system hang. +[1] https://lore.kernel.org/all/c36ab955-c8db-4a8b-a9d0-f07b5f426c3f@kernel.org + +Cc: Daeho Jeong +Fixes: bff139b49d9f ("f2fs: handle decompress only post processing in softirq") +Signed-off-by: Zhiguo Niu +Signed-off-by: Baocong Liu +Reviewed-by: Chao Yu +Signed-off-by: Jaegeuk Kim +[ No changes are made to the code logic; F2FS_I_SB(dic->inode) is +replaced with dic->sbi in v6.1. ] +Signed-off-by: Bin Lan +Signed-off-by: Sasha Levin +--- + fs/f2fs/compress.c | 40 ++++++++++++++++++++-------------------- + fs/f2fs/f2fs.h | 2 ++ + 2 files changed, 22 insertions(+), 20 deletions(-) + +diff --git a/fs/f2fs/compress.c b/fs/f2fs/compress.c +index 1e90286212866..5d0c41abb4050 100644 +--- a/fs/f2fs/compress.c ++++ b/fs/f2fs/compress.c +@@ -211,14 +211,14 @@ static int lzo_decompress_pages(struct decompress_io_ctx *dic) + dic->rbuf, &dic->rlen); + if (ret != LZO_E_OK) { + printk_ratelimited("%sF2FS-fs (%s): lzo decompress failed, ret:%d\n", +- KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id, ret); ++ KERN_ERR, dic->sbi->sb->s_id, ret); + return -EIO; + } + + if (dic->rlen != PAGE_SIZE << dic->log_cluster_size) { + printk_ratelimited("%sF2FS-fs (%s): lzo invalid rlen:%zu, " + "expected:%lu\n", KERN_ERR, +- F2FS_I_SB(dic->inode)->sb->s_id, ++ dic->sbi->sb->s_id, + dic->rlen, + PAGE_SIZE << dic->log_cluster_size); + return -EIO; +@@ -307,14 +307,14 @@ static int lz4_decompress_pages(struct decompress_io_ctx *dic) + dic->clen, dic->rlen); + if (ret < 0) { + printk_ratelimited("%sF2FS-fs (%s): lz4 decompress failed, ret:%d\n", +- KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id, ret); ++ KERN_ERR, dic->sbi->sb->s_id, ret); + return -EIO; + } + + if (ret != PAGE_SIZE << dic->log_cluster_size) { + printk_ratelimited("%sF2FS-fs (%s): lz4 invalid ret:%d, " + "expected:%lu\n", KERN_ERR, +- F2FS_I_SB(dic->inode)->sb->s_id, ret, ++ dic->sbi->sb->s_id, ret, + PAGE_SIZE << dic->log_cluster_size); + return -EIO; + } +@@ -437,7 +437,7 @@ static int zstd_init_decompress_ctx(struct decompress_io_ctx *dic) + + workspace_size = zstd_dstream_workspace_bound(max_window_size); + +- workspace = f2fs_kvmalloc(F2FS_I_SB(dic->inode), ++ workspace = f2fs_kvmalloc(dic->sbi, + workspace_size, GFP_NOFS); + if (!workspace) + return -ENOMEM; +@@ -445,7 +445,7 @@ static int zstd_init_decompress_ctx(struct decompress_io_ctx *dic) + stream = zstd_init_dstream(max_window_size, workspace, workspace_size); + if (!stream) { + printk_ratelimited("%sF2FS-fs (%s): %s zstd_init_dstream failed\n", +- KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id, ++ KERN_ERR, dic->sbi->sb->s_id, + __func__); + kvfree(workspace); + return -EIO; +@@ -482,7 +482,7 @@ static int zstd_decompress_pages(struct decompress_io_ctx *dic) + ret = zstd_decompress_stream(stream, &outbuf, &inbuf); + if (zstd_is_error(ret)) { + printk_ratelimited("%sF2FS-fs (%s): %s zstd_decompress_stream failed, ret: %d\n", +- KERN_ERR, F2FS_I_SB(dic->inode)->sb->s_id, ++ KERN_ERR, dic->sbi->sb->s_id, + __func__, zstd_get_error_code(ret)); + return -EIO; + } +@@ -490,7 +490,7 @@ static int zstd_decompress_pages(struct decompress_io_ctx *dic) + if (dic->rlen != outbuf.pos) { + printk_ratelimited("%sF2FS-fs (%s): %s ZSTD invalid rlen:%zu, " + "expected:%lu\n", KERN_ERR, +- F2FS_I_SB(dic->inode)->sb->s_id, ++ dic->sbi->sb->s_id, + __func__, dic->rlen, + PAGE_SIZE << dic->log_cluster_size); + return -EIO; +@@ -759,7 +759,7 @@ static void f2fs_release_decomp_mem(struct decompress_io_ctx *dic, + + void f2fs_decompress_cluster(struct decompress_io_ctx *dic, bool in_task) + { +- struct f2fs_sb_info *sbi = F2FS_I_SB(dic->inode); ++ struct f2fs_sb_info *sbi = dic->sbi; + struct f2fs_inode_info *fi = F2FS_I(dic->inode); + const struct f2fs_compress_ops *cops = + f2fs_cops[fi->i_compress_algorithm]; +@@ -832,7 +832,7 @@ void f2fs_end_read_compressed_page(struct page *page, bool failed, + { + struct decompress_io_ctx *dic = + (struct decompress_io_ctx *)page_private(page); +- struct f2fs_sb_info *sbi = F2FS_I_SB(dic->inode); ++ struct f2fs_sb_info *sbi = dic->sbi; + + dec_page_count(sbi, F2FS_RD_DATA); + +@@ -1593,14 +1593,13 @@ static inline bool allow_memalloc_for_decomp(struct f2fs_sb_info *sbi, + static int f2fs_prepare_decomp_mem(struct decompress_io_ctx *dic, + bool pre_alloc) + { +- const struct f2fs_compress_ops *cops = +- f2fs_cops[F2FS_I(dic->inode)->i_compress_algorithm]; ++ const struct f2fs_compress_ops *cops = f2fs_cops[dic->compress_algorithm]; + int i; + +- if (!allow_memalloc_for_decomp(F2FS_I_SB(dic->inode), pre_alloc)) ++ if (!allow_memalloc_for_decomp(dic->sbi, pre_alloc)) + return 0; + +- dic->tpages = page_array_alloc(F2FS_I_SB(dic->inode), dic->cluster_size); ++ dic->tpages = page_array_alloc(dic->sbi, dic->cluster_size); + if (!dic->tpages) + return -ENOMEM; + +@@ -1632,10 +1631,9 @@ static int f2fs_prepare_decomp_mem(struct decompress_io_ctx *dic, + static void f2fs_release_decomp_mem(struct decompress_io_ctx *dic, + bool bypass_destroy_callback, bool pre_alloc) + { +- const struct f2fs_compress_ops *cops = +- f2fs_cops[F2FS_I(dic->inode)->i_compress_algorithm]; ++ const struct f2fs_compress_ops *cops = f2fs_cops[dic->compress_algorithm]; + +- if (!allow_memalloc_for_decomp(F2FS_I_SB(dic->inode), pre_alloc)) ++ if (!allow_memalloc_for_decomp(dic->sbi, pre_alloc)) + return; + + if (!bypass_destroy_callback && cops->destroy_decompress_ctx) +@@ -1670,6 +1668,8 @@ struct decompress_io_ctx *f2fs_alloc_dic(struct compress_ctx *cc) + + dic->magic = F2FS_COMPRESSED_PAGE_MAGIC; + dic->inode = cc->inode; ++ dic->sbi = sbi; ++ dic->compress_algorithm = F2FS_I(cc->inode)->i_compress_algorithm; + atomic_set(&dic->remaining_pages, cc->nr_cpages); + dic->cluster_idx = cc->cluster_idx; + dic->cluster_size = cc->cluster_size; +@@ -1718,7 +1718,8 @@ static void f2fs_free_dic(struct decompress_io_ctx *dic, + bool bypass_destroy_callback) + { + int i; +- struct f2fs_sb_info *sbi = F2FS_I_SB(dic->inode); ++ /* use sbi in dic to avoid UFA of dic->inode*/ ++ struct f2fs_sb_info *sbi = dic->sbi; + + f2fs_release_decomp_mem(dic, bypass_destroy_callback, true); + +@@ -1761,8 +1762,7 @@ static void f2fs_put_dic(struct decompress_io_ctx *dic, bool in_task) + f2fs_free_dic(dic, false); + } else { + INIT_WORK(&dic->free_work, f2fs_late_free_dic); +- queue_work(F2FS_I_SB(dic->inode)->post_read_wq, +- &dic->free_work); ++ queue_work(dic->sbi->post_read_wq, &dic->free_work); + } + } + } +diff --git a/fs/f2fs/f2fs.h b/fs/f2fs/f2fs.h +index bbb86e2156989..faa6efe1ceaf5 100644 +--- a/fs/f2fs/f2fs.h ++++ b/fs/f2fs/f2fs.h +@@ -1546,6 +1546,7 @@ struct compress_io_ctx { + struct decompress_io_ctx { + u32 magic; /* magic number to indicate page is compressed */ + struct inode *inode; /* inode the context belong to */ ++ struct f2fs_sb_info *sbi; /* f2fs_sb_info pointer */ + pgoff_t cluster_idx; /* cluster index number */ + unsigned int cluster_size; /* page count in cluster */ + unsigned int log_cluster_size; /* log of cluster size */ +@@ -1586,6 +1587,7 @@ struct decompress_io_ctx { + + bool failed; /* IO error occurred before decompression? */ + bool need_verity; /* need fs-verity verification after decompression? */ ++ unsigned char compress_algorithm; /* backup algorithm type */ + void *private; /* payload buffer for specified decompression algorithm */ + void *private2; /* extra payload buffer */ + struct work_struct verity_work; /* work to verify the decompressed pages */ +-- +2.53.0 + diff --git a/queue-6.1/series b/queue-6.1/series index 1051169a23..b4c0454293 100644 --- a/queue-6.1/series +++ b/queue-6.1/series @@ -383,3 +383,5 @@ f2fs-fix-incorrect-multidevice-info-in-trace_f2fs_map_blocks.patch kvm-arm64-vgic-fix-iidr-revision-field-extracted-from-wrong-value.patch loongarch-fix-potential-ade-in-loongson_gpu_fixup_dma_hang.patch loongarch-use-per-root-bridge-pcih-flag-to-skip-mem-resource-fixup.patch +f2fs-compress-change-the-first-parameter-of-page_arr.patch +f2fs-compress-fix-uaf-of-f2fs_inode_info-in-f2fs_fre.patch