Skip to content

Commit 56e69e5

Browse files
RSmirnov512jankara
authored andcommitted
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/[email protected] Suggested-by: Jan Kara <[email protected]> Signed-off-by: Roman Smirnov <[email protected]> Signed-off-by: Jan Kara <[email protected]>
1 parent ebbe26f commit 56e69e5

File tree

1 file changed

+13
-23
lines changed

1 file changed

+13
-23
lines changed

fs/udf/balloc.c

Lines changed: 13 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#include "udfdecl.h"
1919

2020
#include <linux/bitops.h>
21+
#include <linux/overflow.h>
2122

2223
#include "udf_i.h"
2324
#include "udf_sb.h"
@@ -123,7 +124,6 @@ static void udf_bitmap_free_blocks(struct super_block *sb,
123124
{
124125
struct udf_sb_info *sbi = UDF_SB(sb);
125126
struct buffer_head *bh = NULL;
126-
struct udf_part_map *partmap;
127127
unsigned long block;
128128
unsigned long block_group;
129129
unsigned long bit;
@@ -132,19 +132,9 @@ static void udf_bitmap_free_blocks(struct super_block *sb,
132132
unsigned long overflow;
133133

134134
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 */
145136
block = bloc->logicalBlockNum + offset +
146137
(sizeof(struct spaceBitmapDesc) << 3);
147-
148138
do {
149139
overflow = 0;
150140
block_group = block >> (sb->s_blocksize_bits + 3);
@@ -374,7 +364,6 @@ static void udf_table_free_blocks(struct super_block *sb,
374364
uint32_t count)
375365
{
376366
struct udf_sb_info *sbi = UDF_SB(sb);
377-
struct udf_part_map *partmap;
378367
uint32_t start, end;
379368
uint32_t elen;
380369
struct kernel_lb_addr eloc;
@@ -383,16 +372,6 @@ static void udf_table_free_blocks(struct super_block *sb,
383372
struct udf_inode_info *iinfo;
384373

385374
mutex_lock(&sbi->s_alloc_mutex);
386-
partmap = &sbi->s_partmaps[bloc->partitionReferenceNum];
387-
if (bloc->logicalBlockNum + count < count ||
388-
(bloc->logicalBlockNum + count) > partmap->s_partition_len) {
389-
udf_debug("%u < %d || %u + %u > %u\n",
390-
bloc->logicalBlockNum, 0,
391-
bloc->logicalBlockNum, count,
392-
partmap->s_partition_len);
393-
goto error_return;
394-
}
395-
396375
iinfo = UDF_I(table);
397376
udf_add_free_space(sb, sbi->s_partition, count);
398377

@@ -667,6 +646,17 @@ void udf_free_blocks(struct super_block *sb, struct inode *inode,
667646
{
668647
uint16_t partition = bloc->partitionReferenceNum;
669648
struct udf_part_map *map = &UDF_SB(sb)->s_partmaps[partition];
649+
uint32_t blk;
650+
651+
if (check_add_overflow(bloc->logicalBlockNum, offset, &blk) ||
652+
check_add_overflow(blk, count, &blk) ||
653+
bloc->logicalBlockNum + count > map->s_partition_len) {
654+
udf_debug("Invalid request to free blocks: (%d, %u), off %u, "
655+
"len %u, partition len %u\n",
656+
partition, bloc->logicalBlockNum, offset, count,
657+
map->s_partition_len);
658+
return;
659+
}
670660

671661
if (map->s_partition_flags & UDF_PART_FLAG_UNALLOC_BITMAP) {
672662
udf_bitmap_free_blocks(sb, map->s_uspace.s_bitmap,

0 commit comments

Comments
 (0)