Bug 2554405

Summary: CVE-2026-89085 parted: parted: Heap-based buffer overflow via crafted FAT32 filesystem image [fedora-all]
Product: [Fedora] Fedora Reporter: Marco Benatto <mbenatto>
Component: partedAssignee: Brian Lane <bcl>
Status: CLOSED RAWHIDE QA Contact: Fedora Extras Quality Assurance <extras-qa>
Severity: medium Docs Contact:
Priority: medium    
Version: rawhideCC: bcl
Target Milestone: ---Keywords: Security, SecurityTracking
Target Release: ---   
Hardware: Unspecified   
OS: Unspecified   
Whiteboard: {"flaws": ["198a5eef-77ae-40f2-a868-f5957b3e0656"]}
Fixed In Version: parted-3.7.13-1 Doc Type: ---
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2026-10-19 17:45:51 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Bug Depends On:    
Bug Blocks: 2466034    

Description Marco Benatto 2026-10-16 19:37:10 UTC
Disclaimer: Community trackers are created by Red Hat Product Security team on a best effort basis. Package maintainers are required to ascertain if the flaw indeed affects their package, before starting the update process.

AI_ONLY_REPORT
package: parted-3.6-7.el10
------
Summary: Heap Buffer Overflow in FAT Resize/Open Path (`_init_fats` /  
`fat_table_read`) via Integer Truncation: a crafted FAT32 image can declare  
a FAT large enough to truncate the computed table allocation size, after  
which the full on-disk FAT is read into the undersized heap buffer.
Requirements to exploit: An attacker must supply a crafted FAT32 filesystem  
image or block device and have it opened through the `libparted-fs-resize`  
FAT open path on a non-`DEBUG` build. Reachability also depends on using a  
backing geometry large enough for the declared FAT length to be accepted  
and read.
Component affected: `parted-3.6-7.el10`; FAT resize/open path in  
`libparted-fs-resize`, specifically `_init_fats` and `fat_table_read`
Version affected: `parted-3.6-7.el10`; reachable when the FAT resize/open  
path is used to open attacker-controlled FAT32 media or images on  
non-`DEBUG` builds
Patch available: no released package fix established; proposed patch  
included below
Version fixed: unknown
Upstream coordination: Not notified.
CVSS: CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:H - 7.1 (HIGH)
AV:L - The attacker supplies a local disk image or removable media  
rather than exploiting a network-reachable service.
AC:L - The malformed FAT metadata is straightforward to construct once  
the vulnerable code path is known.
PR:N - No privileges are required to create or provide the crafted  
filesystem.
UI:R - A user or consuming application must open or inspect the crafted  
filesystem through the affected path.
S:U - The corruption occurs within the privileges and security scope of  
the consuming process.
C:L - Memory corruption may expose limited process memory, but broader  
confidentiality impact is not established from the available evidence.
I:L - Memory corruption may permit limited in-process data corruption,  
but stronger integrity impact is not demonstrated here.
A:H - The available evidence supports a reliable crash or other severe  
availability impact when the oversized FAT is read.
Impact: Moderate. This is a real heap overflow in a filesystem parsing  
path, but the attack vector is local and user-assisted, and exploitation  
depends on the `libparted-fs-resize` FAT open path being exercised against  
attacker-controlled media. The available evidence firmly supports denial of  
service and heap corruption; broader compromise is plausible but not  
demonstrated. That combination is more consistent with Red Hat's Moderate  
classification than Important or Critical.
Embargo: no
Reason: The issue is local, requires user interaction or an application  
opening crafted media, and affects a specific parser path rather than a  
default remote service. Public remediation without embargo is proportionate.
Acknowledgement: Aisle Research
Vulnerability Details: In the FAT resize/open path, the computed FAT table  
size is derived from attacker-controlled on-disk metadata and stored in a  
32-bit `FatCluster` without a bounds check. For FAT32,  
`fs_info->fat_sectors` comes from the boot sector `fat_length` field:
```c
/* libparted/fs/r/fat/bootsector.c */
fs_info->fat_sectors = PED_LE32_TO_CPU (bs->u.fat32.fat_length)
fs_info->logical_sector_size;
```


That value is then used to compute the FAT table allocation in `_init_fats`:
```c
/* libparted/fs/r/fat/fat.c */
static int
_init_fats (PedFileSystem* fs)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
FatCluster   table_size;
table_size = fs_info->fat_sectors * 512
/ fat_table_entry_size (fs_info->fat_type);
fs_info->fat = fat_table_new (fs_info->fat_type, table_size);
...
if (!fat_table_read (fs_info->fat, fs, 0))
...
}
```
Later, `fat_table_read` reads `fs_info->fat_sectors` sectors into the  
allocated table buffer. The only size check shown in the affected path is a  
`PED_ASSERT`, which is not a runtime protection in non-`DEBUG` builds:
```c
/* libparted/fs/r/fat/table.c */
PED_ASSERT (ft->raw_size >= fs_info->fat_sectors * 512);
if (!ped_geometry_read (fs->geom, (void *) ft->table,
fs_info->fat_offset + table_num *  
fs_info->fat_sectors,
fs_info->fat_sectors))
return 0;
```
The result is an undersized-allocation plus oversized-read condition. When  
the computed table size truncates during assignment to `FatCluster`,  
`fat_table_new()` can allocate a smaller heap buffer than  
`fat_table_read()` later fills. In the observed path, this is reachable  
when the filesystem is opened through `ped_file_system_open()` into  
`fat_open()`, which in turn calls `_init_fats()` and then  
`fat_table_read()`.
Steps to reproduce:
1. Build the affected code in a non-`DEBUG` configuration with ASan or  
another memory safety checker.
2. Create a sufficiently large sparse disk image or backing geometry so  
FAT32 probe/open checks can succeed.
3. Craft a FAT32 boot sector with valid signature and required fields, and  
set `u.fat32.fat_length = 0x02000000`.
4. Trigger `ped_file_system_open()` on that geometry so execution reaches  
`fat_open()`, `_init_fats()`, and then `fat_table_read()`.
5. Observe that the allocation size is derived from truncated 32-bit  
`table_size`, while the read size still uses the full  
`fs_info->fat_sectors` value.
6. Under ASan, expect a heap out-of-bounds report during FAT table loading.
Mitigation: Until a fix is available, avoid opening untrusted FAT32 media  
or disk images through the `libparted-fs-resize` FAT open path. If such  
parsing is required, isolate it in a sandboxed helper process and reject  
filesystems whose declared FAT length is implausibly large before passing  
them to this code.
Proposed Fix: Add explicit range checks before converting the computed FAT  
size to `FatCluster`, and replace the `PED_ASSERT`-only buffer size check  
in `fat_table_read` with a runtime error path.
```diff
diff --git a/libparted/fs/r/fat/fat.c b/libparted/fs/r/fat/fat.c
@@ -141,9 +141,22 @@ _init_fats (PedFileSystem* fs)
{
FatSpecific* fs_info = FAT_SPECIFIC (fs);
FatCluster   table_size;
+    uint64_t     fat_bytes;
+    uint64_t     table_size64;
+    int          entry_size;
   table_size = fs_info->fat_sectors * 512

                / fat_table_entry_size (fs_info->fat_type);
+    entry_size = fat_table_entry_size (fs_info->fat_type);
+    fat_bytes = (uint64_t) fs_info->fat_sectors * 512ULL;
+    table_size64 = fat_bytes / (uint64_t) entry_size;
+    if (table_size64 > UINT32_MAX) {
+        ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+                             _("FAT table is too large."));
+        return 0;
+    }
+    table_size = (FatCluster) table_size64;
+
      fs_info->fat = fat_table_new (fs_info->fat_type, table_size);
      if (!fs_info->fat)
          goto error;
diff --git a/libparted/fs/r/fat/table.c b/libparted/fs/r/fat/table.c
@@ -121,7 +121,13 @@ fat_table_read (FatTable* ft, const PedFileSystem* fs,  
int table_num)
  {
      FatSpecific* fs_info = FAT_SPECIFIC (fs);
+    uint64_t need = (uint64_t) fs_info->fat_sectors * 512ULL;


   PED_ASSERT (ft->raw_size >= fs_info->fat_sectors * 512);
+    if ((uint64_t) ft->raw_size < need) {
+        ped_exception_throw (PED_EXCEPTION_ERROR, PED_EXCEPTION_CANCEL,
+                             _("FAT table buffer smaller than on-disk  
FAT."));
+        return 0;
+    }


memset (ft->table, 0, ft->raw_size);
```
------
This report was generated using AI technology. Always review AI-generated  
content prior to use