Skip to content

Commit 7d3ae21

Browse files
chaseyugregkh
authored andcommitted
f2fs: atomic: fix UAF issue on f2fs_inode_info.atomic_inode
[ Upstream commit e028858 ] - ioctl(F2FS_IOC_GARBAGE_COLLECT_RANGE) - shrink - f2fs_gc - gc_data_segment - ra_data_block(cow_inode) - mapping = F2FS_I(inode)->atomic_inode->i_mapping : f2fs_is_cow_file(cow_inode) is true - f2fs_evict_inode(atomic_inode) - clear_inode_flag(fi->cow_inode, FI_COW_FILE) - F2FS_I(fi->cow_inode)->atomic_inode = NULL ... - truncate_inode_pages_final(atomic_inode) - f2fs_grab_cache_folio(mapping) : create folio in atomic_inode->mapping - clear_inode(atomic_inode) - BUG_ON(atomic_inode->i_data.nrpages) We need to add a reference on fi->atomic_inode before using its mapping field during garbage collection, otherwise, it will cause UAF issue. Cc: stable@kernel.org Cc: Daeho Jeong <daehojeong@google.com> Cc: Sunmin Jeong <s_min.jeong@samsung.com> Fixes: 3db1de0 ("f2fs: change the current atomic write way") Fixes: f18d007 ("f2fs: use meta inode for GC of COW file") Signed-off-by: Chao Yu <chao@kernel.org> Signed-off-by: Jaegeuk Kim <jaegeuk@kernel.org> Signed-off-by: Sasha Levin <sashal@kernel.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
1 parent d2f2361 commit 7d3ae21

2 files changed

Lines changed: 50 additions & 11 deletions

File tree

fs/f2fs/gc.c

Lines changed: 42 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1173,8 +1173,8 @@ static bool is_alive(struct f2fs_sb_info *sbi, struct f2fs_summary *sum,
11731173
static int ra_data_block(struct inode *inode, pgoff_t index)
11741174
{
11751175
struct f2fs_sb_info *sbi = F2FS_I_SB(inode);
1176-
struct address_space *mapping = f2fs_is_cow_file(inode) ?
1177-
F2FS_I(inode)->atomic_inode->i_mapping : inode->i_mapping;
1176+
struct address_space *mapping = inode->i_mapping;
1177+
struct inode *atomic_inode = NULL;
11781178
struct dnode_of_data dn;
11791179
struct page *page;
11801180
struct f2fs_io_info fio = {
@@ -1189,9 +1189,22 @@ static int ra_data_block(struct inode *inode, pgoff_t index)
11891189
};
11901190
int err;
11911191

1192+
f2fs_down_read(&F2FS_I(inode)->i_sem);
1193+
if (f2fs_is_cow_file(inode)) {
1194+
atomic_inode = igrab(F2FS_I(inode)->atomic_inode);
1195+
if (!atomic_inode) {
1196+
f2fs_up_read(&F2FS_I(inode)->i_sem);
1197+
return -EBUSY;
1198+
}
1199+
mapping = atomic_inode->i_mapping;
1200+
}
1201+
f2fs_up_read(&F2FS_I(inode)->i_sem);
1202+
11921203
page = f2fs_grab_cache_page(mapping, index, true);
1193-
if (!page)
1194-
return -ENOMEM;
1204+
if (!page) {
1205+
err = -ENOMEM;
1206+
goto out_iput;
1207+
}
11951208

11961209
if (f2fs_lookup_read_extent_cache_block(inode, index,
11971210
&dn.data_blkaddr)) {
@@ -1250,11 +1263,16 @@ static int ra_data_block(struct inode *inode, pgoff_t index)
12501263
f2fs_update_iostat(sbi, inode, FS_DATA_READ_IO, F2FS_BLKSIZE);
12511264
f2fs_update_iostat(sbi, NULL, FS_GDATA_READ_IO, F2FS_BLKSIZE);
12521265

1266+
if (atomic_inode)
1267+
iput(atomic_inode);
12531268
return 0;
12541269
put_encrypted_page:
12551270
f2fs_put_page(fio.encrypted_page, 1);
12561271
put_page:
12571272
f2fs_put_page(page, 1);
1273+
out_iput:
1274+
if (atomic_inode)
1275+
iput(atomic_inode);
12581276
return err;
12591277
}
12601278

@@ -1265,8 +1283,8 @@ static int ra_data_block(struct inode *inode, pgoff_t index)
12651283
static int move_data_block(struct inode *inode, block_t bidx,
12661284
int gc_type, unsigned int segno, int off)
12671285
{
1268-
struct address_space *mapping = f2fs_is_cow_file(inode) ?
1269-
F2FS_I(inode)->atomic_inode->i_mapping : inode->i_mapping;
1286+
struct address_space *mapping = inode->i_mapping;
1287+
struct inode *atomic_inode = NULL;
12701288
struct f2fs_io_info fio = {
12711289
.sbi = F2FS_I_SB(inode),
12721290
.ino = inode->i_ino,
@@ -1288,10 +1306,23 @@ static int move_data_block(struct inode *inode, block_t bidx,
12881306
(fio.sbi->gc_mode != GC_URGENT_HIGH) ?
12891307
CURSEG_ALL_DATA_ATGC : CURSEG_COLD_DATA;
12901308

1309+
f2fs_down_read(&F2FS_I(inode)->i_sem);
1310+
if (f2fs_is_cow_file(inode)) {
1311+
atomic_inode = igrab(F2FS_I(inode)->atomic_inode);
1312+
if (!atomic_inode) {
1313+
f2fs_up_read(&F2FS_I(inode)->i_sem);
1314+
return -EBUSY;
1315+
}
1316+
mapping = atomic_inode->i_mapping;
1317+
}
1318+
f2fs_up_read(&F2FS_I(inode)->i_sem);
1319+
12911320
/* do not read out */
12921321
page = f2fs_grab_cache_page(mapping, bidx, false);
1293-
if (!page)
1294-
return -ENOMEM;
1322+
if (!page) {
1323+
err = -ENOMEM;
1324+
goto out_iput;
1325+
}
12951326

12961327
if (!check_valid_map(F2FS_I_SB(inode), segno, off)) {
12971328
err = -ENOENT;
@@ -1413,6 +1444,9 @@ static int move_data_block(struct inode *inode, block_t bidx,
14131444
f2fs_put_dnode(&dn);
14141445
out:
14151446
f2fs_put_page(page, 1);
1447+
out_iput:
1448+
if (atomic_inode)
1449+
iput(atomic_inode);
14161450
return err;
14171451
}
14181452

fs/f2fs/inode.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -842,10 +842,15 @@ void f2fs_evict_inode(struct inode *inode)
842842
f2fs_abort_atomic_write(inode, true);
843843

844844
if (fi->cow_inode && f2fs_is_cow_file(fi->cow_inode)) {
845-
clear_inode_flag(fi->cow_inode, FI_COW_FILE);
846-
F2FS_I(fi->cow_inode)->atomic_inode = NULL;
847-
iput(fi->cow_inode);
845+
struct inode *cow_inode = fi->cow_inode;
846+
847+
f2fs_down_write(&F2FS_I(cow_inode)->i_sem);
848+
clear_inode_flag(cow_inode, FI_COW_FILE);
849+
F2FS_I(cow_inode)->atomic_inode = NULL;
848850
fi->cow_inode = NULL;
851+
f2fs_up_write(&F2FS_I(cow_inode)->i_sem);
852+
853+
iput(cow_inode);
849854
}
850855

851856
trace_f2fs_evict_inode(inode);

0 commit comments

Comments
 (0)