From: Siddh Raman Pant code@siddh.me
mainline inclusion from mainline-v6.5-rc1 commit 11509910c599cbd04585ec35a6d5e1a0053d84c1 category: bugfix bugzilla: https://gitee.com/src-openeuler/kernel/issues/I9RFEZ CVE: CVE-2023-52810
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?i...
--------------------------------
In jfs_dmap.c at line 381, BLKTODMAP is used to get a logical block number inside dbFree(). db_l2nbperpage, which is the log2 number of blocks per page, is passed as an argument to BLKTODMAP which uses it for shifting.
Syzbot reported a shift out-of-bounds crash because db_l2nbperpage is too big. This happens because the large value is set without any validation in dbMount() at line 181.
Thus, make sure that db_l2nbperpage is correct while mounting.
Max number of blocks per page = Page size / Min block size => log2(Max num_block per page) = log2(Page size / Min block size) = log2(Page size) - log2(Min block size)
=> Max db_l2nbperpage = L2PSIZE - L2MINBLOCKSIZE
Reported-and-tested-by: syzbot+d2cd27dcf8e04b232eb2@syzkaller.appspotmail.com Closes: https://syzkaller.appspot.com/bug?id=2a70a453331db32ed491f5cbb07e81bf2d22571... Cc: stable@vger.kernel.org Suggested-by: Dave Kleikamp dave.kleikamp@oracle.com Signed-off-by: Siddh Raman Pant code@siddh.me Signed-off-by: Dave Kleikamp dave.kleikamp@oracle.com Conflicts: fs/jfs/jfs_dmap.c [ Mainline commit changed context: 2cc7cc01c15f ("jfs: fix divide error in dbNextAG") 898f70669568 ("fs: jfs: fix shift-out-of-bounds in dbAllocAG") ] Signed-off-by: Li Nan linan122@huawei.com --- fs/jfs/jfs_filsys.h | 2 ++ fs/jfs/jfs_dmap.c | 6 ++++++ 2 files changed, 8 insertions(+)
diff --git a/fs/jfs/jfs_filsys.h b/fs/jfs/jfs_filsys.h index b67d64671bb4..064dec8aa831 100644 --- a/fs/jfs/jfs_filsys.h +++ b/fs/jfs/jfs_filsys.h @@ -135,7 +135,9 @@ #define NUM_INODE_PER_IAG INOSPERIAG
#define MINBLOCKSIZE 512 +#define L2MINBLOCKSIZE 9 #define MAXBLOCKSIZE 4096 +#define L2MAXBLOCKSIZE 12 #define MAXFILESIZE ((s64)1 << 52)
#define JFS_LINK_MAX 0xffffffff diff --git a/fs/jfs/jfs_dmap.c b/fs/jfs/jfs_dmap.c index 0c10dd93cb74..13ea05d8498a 100644 --- a/fs/jfs/jfs_dmap.c +++ b/fs/jfs/jfs_dmap.c @@ -190,7 +190,13 @@ int dbMount(struct inode *ipbmap) dbmp_le = (struct dbmap_disk *) mp->data; bmp->db_mapsize = le64_to_cpu(dbmp_le->dn_mapsize); bmp->db_nfree = le64_to_cpu(dbmp_le->dn_nfree); + bmp->db_l2nbperpage = le32_to_cpu(dbmp_le->dn_l2nbperpage); + if (bmp->db_l2nbperpage > L2PSIZE - L2MINBLOCKSIZE) { + err = -EINVAL; + goto err_release_metapage; + } + bmp->db_numag = le32_to_cpu(dbmp_le->dn_numag); bmp->db_maxlevel = le32_to_cpu(dbmp_le->dn_maxlevel); bmp->db_maxag = le32_to_cpu(dbmp_le->dn_maxag);