The cylinder summary buffer is allocated with the on-disc fs_cssize value in ufs_read_cylinder_structures(), but it is indexed through fs_cs(i), which expands to s_csp[i], with the independent on-disc cylinder group count uspi->s_ncg as the only upper bound - see for example ufs_new_inode(), ufs_free_inode() and the block allocation paths. Nothing requires cssize to be large enough to hold ncg entries of struct ufs_csum, so on a crafted filesystem image where cssize is small and ncg is large, every fs_cs() access is an out-of-bounds access: a read when scanning for free inodes, and a 32-bit increment or decrement past the end of the kmalloc()ed buffer when an inode or block is allocated or freed. Since the summary arrays are only set up for writable mounts, triggering the out-of-bounds writes requires nothing more than mounting a crafted image read-write and then creating or deleting a file. Validate at mount time that cssize covers all ncg cylinder group summary entries, and reject the image otherwise. Fixes: 1da177e4c3f4 ("Linux-2.6.12-rc2") Cc: stable@vger.kernel.org Signed-off-by: Vamsi Krishna Kattamuri --- fs/ufs/super.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/fs/ufs/super.c b/fs/ufs/super.c index 3569ac92b065..2052d5225d03 100644 --- a/fs/ufs/super.c +++ b/fs/ufs/super.c @@ -1139,6 +1139,11 @@ static int ufs_fill_super(struct super_block *sb, struct fs_context *fc) uspi->s_csaddr = fs32_to_cpu(sb, usb1->fs_csaddr); uspi->s_cssize = fs32_to_cpu(sb, usb1->fs_cssize); + if (uspi->s_cssize < (u64)uspi->s_ncg * sizeof(struct ufs_csum)) { + pr_err("%s(): cylinder summary size %u is too small for %u cylinder groups\n", + __func__, uspi->s_cssize, uspi->s_ncg); + goto failed; + } uspi->s_cgsize = fs32_to_cpu(sb, usb1->fs_cgsize); uspi->s_ntrak = fs32_to_cpu(sb, usb1->fs_ntrak); uspi->s_nsect = fs32_to_cpu(sb, usb1->fs_nsect); -- 2.47.3