Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

bfs: Reconstruct file type when loading from disk

syzbot is reporting that S_IFMT bits of inode->i_mode can become bogus when
the S_IFMT bits of the 32bits "mode" field loaded from disk are corrupted
or when the 32bits "attributes" field loaded from disk are corrupted.

A documentation says that BFS uses only lower 9 bits of the "mode" field.
But I can't find an explicit explanation that the unused upper 23 bits
(especially, the S_IFMT bits) are initialized with 0.

Therefore, ignore the S_IFMT bits of the "mode" field loaded from disk.
Also, verify that the value of the "attributes" field loaded from disk is
either BFS_VREG or BFS_VDIR (because BFS supports only regular files and
the root directory).

Reported-by: syzbot+895c23f6917da440ed0d@syzkaller.appspotmail.com
Closes: https://syzkaller.appspot.com/bug?extid=895c23f6917da440ed0d
Signed-off-by: Tetsuo Handa <penguin-kernel@I-love.SAKURA.ne.jp>
Link: https://patch.msgid.link/fabce673-d5b9-4038-8287-0fd65d80203b@I-love.SAKURA.ne.jp
Reviewed-by: Tigran Aivazian <aivazian.tigran@gmail.com>
Signed-off-by: Christian Brauner <brauner@kernel.org>

authored by

Tetsuo Handa and committed by
Christian Brauner
34ab4c75 330e2c51

+18 -1
+18 -1
fs/bfs/inode.c
··· 61 61 off = (ino - BFS_ROOT_INO) % BFS_INODES_PER_BLOCK; 62 62 di = (struct bfs_inode *)bh->b_data + off; 63 63 64 - inode->i_mode = 0x0000FFFF & le32_to_cpu(di->i_mode); 64 + /* 65 + * https://martin.hinner.info/fs/bfs/bfs-structure.html explains that 66 + * BFS in SCO UnixWare environment used only lower 9 bits of di->i_mode 67 + * value. This means that, although bfs_write_inode() saves whole 68 + * inode->i_mode bits (which include S_IFMT bits and S_IS{UID,GID,VTX} 69 + * bits), middle 7 bits of di->i_mode value can be garbage when these 70 + * bits were not saved by bfs_write_inode(). 71 + * Since we can't tell whether middle 7 bits are garbage, use only 72 + * lower 12 bits (i.e. tolerate S_IS{UID,GID,VTX} bits possibly being 73 + * garbage) and reconstruct S_IFMT bits for Linux environment from 74 + * di->i_vtype value. 75 + */ 76 + inode->i_mode = 0x00000FFF & le32_to_cpu(di->i_mode); 65 77 if (le32_to_cpu(di->i_vtype) == BFS_VDIR) { 66 78 inode->i_mode |= S_IFDIR; 67 79 inode->i_op = &bfs_dir_inops; ··· 83 71 inode->i_op = &bfs_file_inops; 84 72 inode->i_fop = &bfs_file_operations; 85 73 inode->i_mapping->a_ops = &bfs_aops; 74 + } else { 75 + brelse(bh); 76 + printf("Unknown vtype=%u %s:%08lx\n", 77 + le32_to_cpu(di->i_vtype), inode->i_sb->s_id, ino); 78 + goto error; 86 79 } 87 80 88 81 BFS_I(inode)->i_sblock = le32_to_cpu(di->i_sblock);