mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-12-25 12:04:46 +08:00
udf: prevent integer overflow in udf_bitmap_free_blocks()
[ Upstream commit 56e69e5975
]
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
0233195256
commit
22cc7323f0
@ -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 New Issue
Block a user