udf: prevent integer overflow in udf_bitmap_free_blocks()
[ Upstream commit 56e69e59751d20993f243fb7dd6991c4e522424c ] 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> Signed-off-by: Sasha Levin <sashal@kernel.org>
This commit is contained in:
parent
215fb39ad0
commit
fa0edfa148
1 changed files with 13 additions and 23 deletions
|
@ -22,6 +22,7 @@
|
|||
#include "udfdecl.h"
|
||||
|
||||
#include <linux/bitops.h>
|
||||
#include <linux/overflow.h>
|
||||
|
||||
#include "udf_i.h"
|
||||
#include "udf_sb.h"
|
||||
|
@ -144,7 +145,6 @@ static void udf_bitmap_free_blocks(struct super_block *sb,
|
|||
{
|
||||
struct udf_sb_info *sbi = UDF_SB(sb);
|
||||
struct buffer_head *bh = NULL;
|
||||
struct udf_part_map *partmap;
|
||||
unsigned long block;
|
||||
unsigned long block_group;
|
||||
unsigned long bit;
|
||||
|
@ -153,19 +153,9 @@ static void udf_bitmap_free_blocks(struct super_block *sb,
|
|||
unsigned long overflow;
|
||||
|
||||
mutex_lock(&sbi->s_alloc_mutex);
|
||||
partmap = &sbi->s_partmaps[bloc->partitionReferenceNum];
|
||||
if (bloc->logicalBlockNum + count < count ||
|
||||
(bloc->logicalBlockNum + count) > partmap->s_partition_len) {
|
||||
udf_debug("%u < %d || %u + %u > %u\n",
|
||||
bloc->logicalBlockNum, 0,
|
||||
bloc->logicalBlockNum, count,
|
||||
partmap->s_partition_len);
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
/* We make sure this cannot overflow when mounting the filesystem */
|
||||
block = bloc->logicalBlockNum + offset +
|
||||
(sizeof(struct spaceBitmapDesc) << 3);
|
||||
|
||||
do {
|
||||
overflow = 0;
|
||||
block_group = block >> (sb->s_blocksize_bits + 3);
|
||||
|
@ -395,7 +385,6 @@ static void udf_table_free_blocks(struct super_block *sb,
|
|||
uint32_t count)
|
||||
{
|
||||
struct udf_sb_info *sbi = UDF_SB(sb);
|
||||
struct udf_part_map *partmap;
|
||||
uint32_t start, end;
|
||||
uint32_t elen;
|
||||
struct kernel_lb_addr eloc;
|
||||
|
@ -404,16 +393,6 @@ static void udf_table_free_blocks(struct super_block *sb,
|
|||
struct udf_inode_info *iinfo;
|
||||
|
||||
mutex_lock(&sbi->s_alloc_mutex);
|
||||
partmap = &sbi->s_partmaps[bloc->partitionReferenceNum];
|
||||
if (bloc->logicalBlockNum + count < count ||
|
||||
(bloc->logicalBlockNum + count) > partmap->s_partition_len) {
|
||||
udf_debug("%u < %d || %u + %u > %u\n",
|
||||
bloc->logicalBlockNum, 0,
|
||||
bloc->logicalBlockNum, count,
|
||||
partmap->s_partition_len);
|
||||
goto error_return;
|
||||
}
|
||||
|
||||
iinfo = UDF_I(table);
|
||||
udf_add_free_space(sb, sbi->s_partition, count);
|
||||
|
||||
|
@ -688,6 +667,17 @@ void udf_free_blocks(struct super_block *sb, struct inode *inode,
|
|||
{
|
||||
uint16_t partition = bloc->partitionReferenceNum;
|
||||
struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition];
|
||||
uint32_t blk;
|
||||
|
||||
if (check_add_overflow(bloc->logicalBlockNum, offset, &blk) ||
|
||||
check_add_overflow(blk, count, &blk) ||
|
||||
bloc->logicalBlockNum + count > map->s_partition_len) {
|
||||
udf_debug("Invalid request to free blocks: (%d, %u), off %u, "
|
||||
"len %u, partition len %u\n",
|
||||
partition, bloc->logicalBlockNum, offset, count,
|
||||
map->s_partition_len);
|
||||
return;
|
||||
}
|
||||
|
||||
if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) {
|
||||
udf_bitmap_free_blocks(sb, map->s_uspace.s_bitmap,
|
||||
|
|
Loading…
Reference in a new issue