Skip to content

Commit 3986868

Browse files
Zhiguo NiuJaegeuk Kim
authored andcommitted
f2fs: compress: fix UAF of f2fs_inode_info in f2fs_free_dic
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/[email protected] Cc: Daeho Jeong <[email protected]> Fixes: bff139b ("f2fs: handle decompress only post processing in softirq") Signed-off-by: Zhiguo Niu <[email protected]> Signed-off-by: Baocong Liu <[email protected]> Reviewed-by: Chao Yu <[email protected]> Signed-off-by: Jaegeuk Kim <[email protected]>
1 parent 8e2a9b6 commit 3986868

File tree

2 files changed

+22
-20
lines changed

2 files changed

+22
-20
lines changed

fs/f2fs/compress.c

Lines changed: 20 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -214,13 +214,13 @@ static int lzo_decompress_pages(struct decompress_io_ctx *dic)
214214
ret = lzo1x_decompress_safe(dic->cbuf->cdata, dic->clen,
215215
dic->rbuf, &dic->rlen);
216216
if (ret != LZO_E_OK) {
217-
f2fs_err_ratelimited(F2FS_I_SB(dic->inode),
217+
f2fs_err_ratelimited(dic->sbi,
218218
"lzo decompress failed, ret:%d", ret);
219219
return -EIO;
220220
}
221221

222222
if (dic->rlen != PAGE_SIZE << dic->log_cluster_size) {
223-
f2fs_err_ratelimited(F2FS_I_SB(dic->inode),
223+
f2fs_err_ratelimited(dic->sbi,
224224
"lzo invalid rlen:%zu, expected:%lu",
225225
dic->rlen, PAGE_SIZE << dic->log_cluster_size);
226226
return -EIO;
@@ -294,13 +294,13 @@ static int lz4_decompress_pages(struct decompress_io_ctx *dic)
294294
ret = LZ4_decompress_safe(dic->cbuf->cdata, dic->rbuf,
295295
dic->clen, dic->rlen);
296296
if (ret < 0) {
297-
f2fs_err_ratelimited(F2FS_I_SB(dic->inode),
297+
f2fs_err_ratelimited(dic->sbi,
298298
"lz4 decompress failed, ret:%d", ret);
299299
return -EIO;
300300
}
301301

302302
if (ret != PAGE_SIZE << dic->log_cluster_size) {
303-
f2fs_err_ratelimited(F2FS_I_SB(dic->inode),
303+
f2fs_err_ratelimited(dic->sbi,
304304
"lz4 invalid ret:%d, expected:%lu",
305305
ret, PAGE_SIZE << dic->log_cluster_size);
306306
return -EIO;
@@ -422,13 +422,13 @@ static int zstd_init_decompress_ctx(struct decompress_io_ctx *dic)
422422

423423
workspace_size = zstd_dstream_workspace_bound(max_window_size);
424424

425-
workspace = f2fs_vmalloc(F2FS_I_SB(dic->inode), workspace_size);
425+
workspace = f2fs_vmalloc(dic->sbi, workspace_size);
426426
if (!workspace)
427427
return -ENOMEM;
428428

429429
stream = zstd_init_dstream(max_window_size, workspace, workspace_size);
430430
if (!stream) {
431-
f2fs_err_ratelimited(F2FS_I_SB(dic->inode),
431+
f2fs_err_ratelimited(dic->sbi,
432432
"%s zstd_init_dstream failed", __func__);
433433
vfree(workspace);
434434
return -EIO;
@@ -464,14 +464,14 @@ static int zstd_decompress_pages(struct decompress_io_ctx *dic)
464464

465465
ret = zstd_decompress_stream(stream, &outbuf, &inbuf);
466466
if (zstd_is_error(ret)) {
467-
f2fs_err_ratelimited(F2FS_I_SB(dic->inode),
467+
f2fs_err_ratelimited(dic->sbi,
468468
"%s zstd_decompress_stream failed, ret: %d",
469469
__func__, zstd_get_error_code(ret));
470470
return -EIO;
471471
}
472472

473473
if (dic->rlen != outbuf.pos) {
474-
f2fs_err_ratelimited(F2FS_I_SB(dic->inode),
474+
f2fs_err_ratelimited(dic->sbi,
475475
"%s ZSTD invalid rlen:%zu, expected:%lu",
476476
__func__, dic->rlen,
477477
PAGE_SIZE << dic->log_cluster_size);
@@ -733,7 +733,7 @@ static void f2fs_release_decomp_mem(struct decompress_io_ctx *dic,
733733

734734
void f2fs_decompress_cluster(struct decompress_io_ctx *dic, bool in_task)
735735
{
736-
struct f2fs_sb_info *sbi = F2FS_I_SB(dic->inode);
736+
struct f2fs_sb_info *sbi = dic->sbi;
737737
struct f2fs_inode_info *fi = F2FS_I(dic->inode);
738738
const struct f2fs_compress_ops *cops =
739739
f2fs_cops[fi->i_compress_algorithm];
@@ -806,7 +806,7 @@ void f2fs_end_read_compressed_page(struct page *page, bool failed,
806806
{
807807
struct decompress_io_ctx *dic =
808808
(struct decompress_io_ctx *)page_private(page);
809-
struct f2fs_sb_info *sbi = F2FS_I_SB(dic->inode);
809+
struct f2fs_sb_info *sbi = dic->sbi;
810810

811811
dec_page_count(sbi, F2FS_RD_DATA);
812812

@@ -1632,14 +1632,13 @@ static inline bool allow_memalloc_for_decomp(struct f2fs_sb_info *sbi,
16321632
static int f2fs_prepare_decomp_mem(struct decompress_io_ctx *dic,
16331633
bool pre_alloc)
16341634
{
1635-
const struct f2fs_compress_ops *cops =
1636-
f2fs_cops[F2FS_I(dic->inode)->i_compress_algorithm];
1635+
const struct f2fs_compress_ops *cops = f2fs_cops[dic->compress_algorithm];
16371636
int i;
16381637

1639-
if (!allow_memalloc_for_decomp(F2FS_I_SB(dic->inode), pre_alloc))
1638+
if (!allow_memalloc_for_decomp(dic->sbi, pre_alloc))
16401639
return 0;
16411640

1642-
dic->tpages = page_array_alloc(F2FS_I_SB(dic->inode), dic->cluster_size);
1641+
dic->tpages = page_array_alloc(dic->sbi, dic->cluster_size);
16431642
if (!dic->tpages)
16441643
return -ENOMEM;
16451644

@@ -1669,10 +1668,9 @@ static int f2fs_prepare_decomp_mem(struct decompress_io_ctx *dic,
16691668
static void f2fs_release_decomp_mem(struct decompress_io_ctx *dic,
16701669
bool bypass_destroy_callback, bool pre_alloc)
16711670
{
1672-
const struct f2fs_compress_ops *cops =
1673-
f2fs_cops[F2FS_I(dic->inode)->i_compress_algorithm];
1671+
const struct f2fs_compress_ops *cops = f2fs_cops[dic->compress_algorithm];
16741672

1675-
if (!allow_memalloc_for_decomp(F2FS_I_SB(dic->inode), pre_alloc))
1673+
if (!allow_memalloc_for_decomp(dic->sbi, pre_alloc))
16761674
return;
16771675

16781676
if (!bypass_destroy_callback && cops->destroy_decompress_ctx)
@@ -1707,6 +1705,8 @@ struct decompress_io_ctx *f2fs_alloc_dic(struct compress_ctx *cc)
17071705

17081706
dic->magic = F2FS_COMPRESSED_PAGE_MAGIC;
17091707
dic->inode = cc->inode;
1708+
dic->sbi = sbi;
1709+
dic->compress_algorithm = F2FS_I(cc->inode)->i_compress_algorithm;
17101710
atomic_set(&dic->remaining_pages, cc->nr_cpages);
17111711
dic->cluster_idx = cc->cluster_idx;
17121712
dic->cluster_size = cc->cluster_size;
@@ -1750,7 +1750,8 @@ static void f2fs_free_dic(struct decompress_io_ctx *dic,
17501750
bool bypass_destroy_callback)
17511751
{
17521752
int i;
1753-
struct f2fs_sb_info *sbi = F2FS_I_SB(dic->inode);
1753+
/* use sbi in dic to avoid UFA of dic->inode*/
1754+
struct f2fs_sb_info *sbi = dic->sbi;
17541755

17551756
f2fs_release_decomp_mem(dic, bypass_destroy_callback, true);
17561757

@@ -1793,8 +1794,7 @@ static void f2fs_put_dic(struct decompress_io_ctx *dic, bool in_task)
17931794
f2fs_free_dic(dic, false);
17941795
} else {
17951796
INIT_WORK(&dic->free_work, f2fs_late_free_dic);
1796-
queue_work(F2FS_I_SB(dic->inode)->post_read_wq,
1797-
&dic->free_work);
1797+
queue_work(dic->sbi->post_read_wq, &dic->free_work);
17981798
}
17991799
}
18001800
}

fs/f2fs/f2fs.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1536,6 +1536,7 @@ struct compress_io_ctx {
15361536
struct decompress_io_ctx {
15371537
u32 magic; /* magic number to indicate page is compressed */
15381538
struct inode *inode; /* inode the context belong to */
1539+
struct f2fs_sb_info *sbi; /* f2fs_sb_info pointer */
15391540
pgoff_t cluster_idx; /* cluster index number */
15401541
unsigned int cluster_size; /* page count in cluster */
15411542
unsigned int log_cluster_size; /* log of cluster size */
@@ -1576,6 +1577,7 @@ struct decompress_io_ctx {
15761577

15771578
bool failed; /* IO error occurred before decompression? */
15781579
bool need_verity; /* need fs-verity verification after decompression? */
1580+
unsigned char compress_algorithm; /* backup algorithm type */
15791581
void *private; /* payload buffer for specified decompression algorithm */
15801582
void *private2; /* extra payload buffer */
15811583
struct work_struct verity_work; /* work to verify the decompressed pages */

0 commit comments

Comments
 (0)