Skip to content

Commit

Permalink
udf: prevent integer overflow in udf_bitmap_free_blocks()
Browse files Browse the repository at this point in the history
[ Upstream commit 56e69e5 ]

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]>
Signed-off-by: Sasha Levin <[email protected]>
  • Loading branch information
Roman Smirnov authored and Sasha Levin committed Aug 14, 2024
1 parent 4b4bece commit 6864bf0
Showing 1 changed file with 13 additions and 23 deletions.
36 changes: 13 additions & 23 deletions fs/udf/balloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "udfdecl.h"

#include <linux/bitops.h>
#include <linux/overflow.h>

#include "udf_i.h"
#include "udf_sb.h"
Expand Down Expand Up @@ -140,7 +141,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;
Expand All @@ -149,19 +149,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);
Expand Down Expand Up @@ -391,7 +381,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;
Expand All @@ -400,16 +389,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);

Expand Down Expand Up @@ -684,6 +663,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,
Expand Down

0 comments on commit 6864bf0

Please sign in to comment.