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

udf: prevent integer overflow in udf_bitmap_free_blocks()

An overflow may occur if the function is called with the last
block and an offset greater than zero. It is necessary to add
a check to avoid this.

Found by Linux Verification Center (linuxtesting.org) with Svace.

[JK: Make test cover also unalloc table freeing]

Link: https://patch.msgid.link/20240620072413.7448-1-r.smirnov@omp.ru
Suggested-by: Jan Kara <jack@suse.com>
Signed-off-by: Roman Smirnov <r.smirnov@omp.ru>
Signed-off-by: Jan Kara <jack@suse.cz>

authored by

Roman Smirnov and committed by
Jan Kara
56e69e59 ebbe26fd

+13 -23
+13 -23
fs/udf/balloc.c
··· 18 18 #include "udfdecl.h" 19 19 20 20 #include <linux/bitops.h> 21 + #include <linux/overflow.h> 21 22 22 23 #include "udf_i.h" 23 24 #include "udf_sb.h" ··· 124 123 { 125 124 struct udf_sb_info *sbi = UDF_SB(sb); 126 125 struct buffer_head *bh = NULL; 127 - struct udf_part_map *partmap; 128 126 unsigned long block; 129 127 unsigned long block_group; 130 128 unsigned long bit; ··· 132 132 unsigned long overflow; 133 133 134 134 mutex_lock(&sbi->s_alloc_mutex); 135 - partmap = &sbi->s_partmaps[bloc->partitionReferenceNum]; 136 - if (bloc->logicalBlockNum + count < count || 137 - (bloc->logicalBlockNum + count) > partmap->s_partition_len) { 138 - udf_debug("%u < %d || %u + %u > %u\n", 139 - bloc->logicalBlockNum, 0, 140 - bloc->logicalBlockNum, count, 141 - partmap->s_partition_len); 142 - goto error_return; 143 - } 144 - 135 + /* We make sure this cannot overflow when mounting the filesystem */ 145 136 block = bloc->logicalBlockNum + offset + 146 137 (sizeof(struct spaceBitmapDesc) << 3); 147 - 148 138 do { 149 139 overflow = 0; 150 140 block_group = block >> (sb->s_blocksize_bits + 3); ··· 364 374 uint32_t count) 365 375 { 366 376 struct udf_sb_info *sbi = UDF_SB(sb); 367 - struct udf_part_map *partmap; 368 377 uint32_t start, end; 369 378 uint32_t elen; 370 379 struct kernel_lb_addr eloc; ··· 372 383 struct udf_inode_info *iinfo; 373 384 374 385 mutex_lock(&sbi->s_alloc_mutex); 375 - partmap = &sbi->s_partmaps[bloc->partitionReferenceNum]; 376 - if (bloc->logicalBlockNum + count < count || 377 - (bloc->logicalBlockNum + count) > partmap->s_partition_len) { 378 - udf_debug("%u < %d || %u + %u > %u\n", 379 - bloc->logicalBlockNum, 0, 380 - bloc->logicalBlockNum, count, 381 - partmap->s_partition_len); 382 - goto error_return; 383 - } 384 - 385 386 iinfo = UDF_I(table); 386 387 udf_add_free_space(sb, sbi->s_partition, count); 387 388 ··· 646 667 { 647 668 uint16_t partition = bloc->partitionReferenceNum; 648 669 struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition]; 670 + uint32_t blk; 671 + 672 + if (check_add_overflow(bloc->logicalBlockNum, offset, &blk) || 673 + check_add_overflow(blk, count, &blk) || 674 + bloc->logicalBlockNum + count > map->s_partition_len) { 675 + udf_debug("Invalid request to free blocks: (%d, %u), off %u, " 676 + "len %u, partition len %u\n", 677 + partition, bloc->logicalBlockNum, offset, count, 678 + map->s_partition_len); 679 + return; 680 + } 649 681 650 682 if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) { 651 683 udf_bitmap_free_blocks(sb, map->s_uspace.s_bitmap,