From: Jan Kara jack@suse.cz
[ Upstream commit 1a11201668e8635602577dcf06f2e96c591d8819 ]
Verify that number of partition maps isn't insanely high which can lead to large allocation in udf_sb_alloc_partition_maps(). All partition maps have to fit in the LVD which is in a single block.
Reported-by: syzbot+478f2c1a6f0f447a46bb@syzkaller.appspotmail.com Signed-off-by: Jan Kara jack@suse.cz Signed-off-by: Sasha Levin sashal@kernel.org ---
LLM Generated explanations, may be completely bogus:
**Backport Status: YES**
This commit should be backported to stable kernel trees based on the following analysis:
1. **Security Fix**: The commit addresses a security vulnerability reported by syzbot (syzbot+478f2c1a6f0f447a46bb@syzkaller.appspotmail.com), indicating this is fixing a real bug discovered through fuzzing. The issue could lead to excessive memory allocation in `udf_sb_alloc_partition_maps()`.
2. **Integer Overflow/Memory Exhaustion Prevention**: The code adds a crucial bounds check that prevents potentially huge allocations. Without this check, a malformed UDF filesystem could specify an arbitrarily large `numPartitionMaps` value, causing `kcalloc()` in `udf_sb_alloc_partition_maps()` to allocate excessive memory or fail.
3. **Small, Contained Fix**: The change is minimal - only 11 lines added and 2 modified. It adds a simple validation check: ```c if (part_map_count > table_len / sizeof(struct genericPartitionMap1)) ``` This ensures the partition map count doesn't exceed what can physically fit in the table.
4. **Clear Bug Fix Pattern**: The fix follows a standard pattern of input validation before allocation, which is a well-understood security best practice. The logic is straightforward: all partition maps must fit within the Logical Volume Descriptor (LVD) block.
5. **No Feature Changes**: This is purely a defensive check that prevents invalid input from causing problems. It doesn't change any functionality for valid UDF filesystems.
6. **Affects User-Facing Code**: UDF filesystem mounting is user-facing functionality that could be triggered by inserting malicious media or mounting crafted filesystem images, making this an important security boundary.
7. **Low Risk of Regression**: The added check only rejects invalid filesystems that would likely cause problems anyway. Valid UDF filesystems will pass this check without issue.
The commit follows stable kernel rules by fixing an important bug (potential DoS through memory exhaustion) with minimal, low-risk changes to a filesystem that handles untrusted input.
fs/udf/super.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-)
diff --git a/fs/udf/super.c b/fs/udf/super.c index 9f2de5e7c6e1..361bc8acfb0f 100644 --- a/fs/udf/super.c +++ b/fs/udf/super.c @@ -1417,7 +1417,7 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block, struct genericPartitionMap *gpm; uint16_t ident; struct buffer_head *bh; - unsigned int table_len; + unsigned int table_len, part_map_count; int ret;
bh = udf_read_tagged(sb, block, block, &ident); @@ -1438,7 +1438,16 @@ static int udf_load_logicalvol(struct super_block *sb, sector_t block, "logical volume"); if (ret) goto out_bh; - ret = udf_sb_alloc_partition_maps(sb, le32_to_cpu(lvd->numPartitionMaps)); + + part_map_count = le32_to_cpu(lvd->numPartitionMaps); + if (part_map_count > table_len / sizeof(struct genericPartitionMap1)) { + udf_err(sb, "error loading logical volume descriptor: " + "Too many partition maps (%u > %u)\n", part_map_count, + table_len / (unsigned)sizeof(struct genericPartitionMap1)); + ret = -EIO; + goto out_bh; + } + ret = udf_sb_alloc_partition_maps(sb, part_map_count); if (ret) goto out_bh;