Skip to content

Commit 7653b9d

Browse files
chaseyuJaegeuk Kim
authored andcommitted
f2fs: fix potential .flags overflow on 32bit architecture
f2fs_inode_info.flags is unsigned long variable, it has 32 bits in 32bit architecture, since we introduced FI_MMAP_FILE flag when we support data compression, we may access memory cross the border of .flags field, corrupting .i_sem field, result in below deadlock. To fix this issue, let's expand .flags as an array to grab enough space to store new flags. Call Trace: __schedule+0x8d0/0x13fc ? mark_held_locks+0xac/0x100 schedule+0xcc/0x260 rwsem_down_write_slowpath+0x3ab/0x65d down_write+0xc7/0xe0 f2fs_drop_nlink+0x3d/0x600 [f2fs] f2fs_delete_inline_entry+0x300/0x440 [f2fs] f2fs_delete_entry+0x3a1/0x7f0 [f2fs] f2fs_unlink+0x500/0x790 [f2fs] vfs_unlink+0x211/0x490 do_unlinkat+0x483/0x520 sys_unlink+0x4a/0x70 do_fast_syscall_32+0x12b/0x683 entry_SYSENTER_32+0xaa/0x102 Fixes: 4c8ff70 ("f2fs: support data compression") Tested-by: Ondrej Jirman <[email protected]> Signed-off-by: Chao Yu <[email protected]> Signed-off-by: Jaegeuk Kim <[email protected]>
1 parent 79bbefb commit 7653b9d

File tree

2 files changed

+50
-51
lines changed

2 files changed

+50
-51
lines changed

fs/f2fs/f2fs.h

Lines changed: 49 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -678,6 +678,44 @@ enum {
678678
MAX_GC_FAILURE
679679
};
680680

681+
/* used for f2fs_inode_info->flags */
682+
enum {
683+
FI_NEW_INODE, /* indicate newly allocated inode */
684+
FI_DIRTY_INODE, /* indicate inode is dirty or not */
685+
FI_AUTO_RECOVER, /* indicate inode is recoverable */
686+
FI_DIRTY_DIR, /* indicate directory has dirty pages */
687+
FI_INC_LINK, /* need to increment i_nlink */
688+
FI_ACL_MODE, /* indicate acl mode */
689+
FI_NO_ALLOC, /* should not allocate any blocks */
690+
FI_FREE_NID, /* free allocated nide */
691+
FI_NO_EXTENT, /* not to use the extent cache */
692+
FI_INLINE_XATTR, /* used for inline xattr */
693+
FI_INLINE_DATA, /* used for inline data*/
694+
FI_INLINE_DENTRY, /* used for inline dentry */
695+
FI_APPEND_WRITE, /* inode has appended data */
696+
FI_UPDATE_WRITE, /* inode has in-place-update data */
697+
FI_NEED_IPU, /* used for ipu per file */
698+
FI_ATOMIC_FILE, /* indicate atomic file */
699+
FI_ATOMIC_COMMIT, /* indicate the state of atomical committing */
700+
FI_VOLATILE_FILE, /* indicate volatile file */
701+
FI_FIRST_BLOCK_WRITTEN, /* indicate #0 data block was written */
702+
FI_DROP_CACHE, /* drop dirty page cache */
703+
FI_DATA_EXIST, /* indicate data exists */
704+
FI_INLINE_DOTS, /* indicate inline dot dentries */
705+
FI_DO_DEFRAG, /* indicate defragment is running */
706+
FI_DIRTY_FILE, /* indicate regular/symlink has dirty pages */
707+
FI_NO_PREALLOC, /* indicate skipped preallocated blocks */
708+
FI_HOT_DATA, /* indicate file is hot */
709+
FI_EXTRA_ATTR, /* indicate file has extra attribute */
710+
FI_PROJ_INHERIT, /* indicate file inherits projectid */
711+
FI_PIN_FILE, /* indicate file should not be gced */
712+
FI_ATOMIC_REVOKE_REQUEST, /* request to drop atomic data */
713+
FI_VERITY_IN_PROGRESS, /* building fs-verity Merkle tree */
714+
FI_COMPRESSED_FILE, /* indicate file's data can be compressed */
715+
FI_MMAP_FILE, /* indicate file was mmapped */
716+
FI_MAX, /* max flag, never be used */
717+
};
718+
681719
struct f2fs_inode_info {
682720
struct inode vfs_inode; /* serve a vfs inode */
683721
unsigned long i_flags; /* keep an inode flags for ioctl */
@@ -690,7 +728,7 @@ struct f2fs_inode_info {
690728
umode_t i_acl_mode; /* keep file acl mode temporarily */
691729

692730
/* Use below internally in f2fs*/
693-
unsigned long flags; /* use to pass per-file flags */
731+
unsigned long flags[BITS_TO_LONGS(FI_MAX)]; /* use to pass per-file flags */
694732
struct rw_semaphore i_sem; /* protect fi info */
695733
atomic_t dirty_pages; /* # of dirty pages */
696734
f2fs_hash_t chash; /* hash value of given file name */
@@ -2522,43 +2560,6 @@ static inline __u32 f2fs_mask_flags(umode_t mode, __u32 flags)
25222560
return flags & F2FS_OTHER_FLMASK;
25232561
}
25242562

2525-
/* used for f2fs_inode_info->flags */
2526-
enum {
2527-
FI_NEW_INODE, /* indicate newly allocated inode */
2528-
FI_DIRTY_INODE, /* indicate inode is dirty or not */
2529-
FI_AUTO_RECOVER, /* indicate inode is recoverable */
2530-
FI_DIRTY_DIR, /* indicate directory has dirty pages */
2531-
FI_INC_LINK, /* need to increment i_nlink */
2532-
FI_ACL_MODE, /* indicate acl mode */
2533-
FI_NO_ALLOC, /* should not allocate any blocks */
2534-
FI_FREE_NID, /* free allocated nide */
2535-
FI_NO_EXTENT, /* not to use the extent cache */
2536-
FI_INLINE_XATTR, /* used for inline xattr */
2537-
FI_INLINE_DATA, /* used for inline data*/
2538-
FI_INLINE_DENTRY, /* used for inline dentry */
2539-
FI_APPEND_WRITE, /* inode has appended data */
2540-
FI_UPDATE_WRITE, /* inode has in-place-update data */
2541-
FI_NEED_IPU, /* used for ipu per file */
2542-
FI_ATOMIC_FILE, /* indicate atomic file */
2543-
FI_ATOMIC_COMMIT, /* indicate the state of atomical committing */
2544-
FI_VOLATILE_FILE, /* indicate volatile file */
2545-
FI_FIRST_BLOCK_WRITTEN, /* indicate #0 data block was written */
2546-
FI_DROP_CACHE, /* drop dirty page cache */
2547-
FI_DATA_EXIST, /* indicate data exists */
2548-
FI_INLINE_DOTS, /* indicate inline dot dentries */
2549-
FI_DO_DEFRAG, /* indicate defragment is running */
2550-
FI_DIRTY_FILE, /* indicate regular/symlink has dirty pages */
2551-
FI_NO_PREALLOC, /* indicate skipped preallocated blocks */
2552-
FI_HOT_DATA, /* indicate file is hot */
2553-
FI_EXTRA_ATTR, /* indicate file has extra attribute */
2554-
FI_PROJ_INHERIT, /* indicate file inherits projectid */
2555-
FI_PIN_FILE, /* indicate file should not be gced */
2556-
FI_ATOMIC_REVOKE_REQUEST, /* request to drop atomic data */
2557-
FI_VERITY_IN_PROGRESS, /* building fs-verity Merkle tree */
2558-
FI_COMPRESSED_FILE, /* indicate file's data can be compressed */
2559-
FI_MMAP_FILE, /* indicate file was mmapped */
2560-
};
2561-
25622563
static inline void __mark_inode_dirty_flag(struct inode *inode,
25632564
int flag, bool set)
25642565
{
@@ -2579,20 +2580,18 @@ static inline void __mark_inode_dirty_flag(struct inode *inode,
25792580

25802581
static inline void set_inode_flag(struct inode *inode, int flag)
25812582
{
2582-
if (!test_bit(flag, &F2FS_I(inode)->flags))
2583-
set_bit(flag, &F2FS_I(inode)->flags);
2583+
test_and_set_bit(flag, F2FS_I(inode)->flags);
25842584
__mark_inode_dirty_flag(inode, flag, true);
25852585
}
25862586

25872587
static inline int is_inode_flag_set(struct inode *inode, int flag)
25882588
{
2589-
return test_bit(flag, &F2FS_I(inode)->flags);
2589+
return test_bit(flag, F2FS_I(inode)->flags);
25902590
}
25912591

25922592
static inline void clear_inode_flag(struct inode *inode, int flag)
25932593
{
2594-
if (test_bit(flag, &F2FS_I(inode)->flags))
2595-
clear_bit(flag, &F2FS_I(inode)->flags);
2594+
test_and_clear_bit(flag, F2FS_I(inode)->flags);
25962595
__mark_inode_dirty_flag(inode, flag, false);
25972596
}
25982597

@@ -2683,19 +2682,19 @@ static inline void get_inline_info(struct inode *inode, struct f2fs_inode *ri)
26832682
struct f2fs_inode_info *fi = F2FS_I(inode);
26842683

26852684
if (ri->i_inline & F2FS_INLINE_XATTR)
2686-
set_bit(FI_INLINE_XATTR, &fi->flags);
2685+
set_bit(FI_INLINE_XATTR, fi->flags);
26872686
if (ri->i_inline & F2FS_INLINE_DATA)
2688-
set_bit(FI_INLINE_DATA, &fi->flags);
2687+
set_bit(FI_INLINE_DATA, fi->flags);
26892688
if (ri->i_inline & F2FS_INLINE_DENTRY)
2690-
set_bit(FI_INLINE_DENTRY, &fi->flags);
2689+
set_bit(FI_INLINE_DENTRY, fi->flags);
26912690
if (ri->i_inline & F2FS_DATA_EXIST)
2692-
set_bit(FI_DATA_EXIST, &fi->flags);
2691+
set_bit(FI_DATA_EXIST, fi->flags);
26932692
if (ri->i_inline & F2FS_INLINE_DOTS)
2694-
set_bit(FI_INLINE_DOTS, &fi->flags);
2693+
set_bit(FI_INLINE_DOTS, fi->flags);
26952694
if (ri->i_inline & F2FS_EXTRA_ATTR)
2696-
set_bit(FI_EXTRA_ATTR, &fi->flags);
2695+
set_bit(FI_EXTRA_ATTR, fi->flags);
26972696
if (ri->i_inline & F2FS_PIN_FILE)
2698-
set_bit(FI_PIN_FILE, &fi->flags);
2697+
set_bit(FI_PIN_FILE, fi->flags);
26992698
}
27002699

27012700
static inline void set_raw_inline(struct inode *inode, struct f2fs_inode *ri)

fs/f2fs/inode.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ static int do_read_inode(struct inode *inode)
362362
fi->i_flags = le32_to_cpu(ri->i_flags);
363363
if (S_ISREG(inode->i_mode))
364364
fi->i_flags &= ~F2FS_PROJINHERIT_FL;
365-
fi->flags = 0;
365+
bitmap_zero(fi->flags, FI_MAX);
366366
fi->i_advise = ri->i_advise;
367367
fi->i_pino = le32_to_cpu(ri->i_pino);
368368
fi->i_dir_level = ri->i_dir_level;

0 commit comments

Comments
 (0)