]> Projects (at) Tadryanom (dot) Me - AdrOS.git/commitdiff
security: fix ext2 superblock/GDT validation (C6)
authorTulio A M Mendes <[email protected]>
Tue, 26 May 2026 04:57:27 +0000 (01:57 -0300)
committerTulio A M Mendes <[email protected]>
Wed, 3 Jun 2026 05:52:27 +0000 (02:52 -0300)
src/kernel/ext2.c

index 371ff64dcf1c8220a10160bb3f58c94f572a1a7d..ca2dd10d877e3f9bf028afe6c360191bcc262f1f 100644 (file)
@@ -1460,9 +1460,23 @@ vfs_mount_result_t ext2_mount(block_device_t* bdev, uint32_t partition_lba) {
         return result;
     }
 
+    /* Validate s_blocks_per_group and s_inodes_per_group are non-zero */
+    if (sb.s_blocks_per_group == 0) {
+        kprintf("[EXT2] Invalid s_blocks_per_group: 0\n");
+        kfree(em);
+        return result;
+    }
+    if (sb.s_inodes_per_group == 0) {
+        kprintf("[EXT2] Invalid s_inodes_per_group: 0\n");
+        kfree(em);
+        return result;
+    }
+
     em->block_size = 1024U << sb.s_log_block_size;
-    if (em->block_size > 4096) {
-        kprintf("[EXT2] Unsupported block size %u\n", em->block_size);
+    /* Validate block_size is power of 2 and >= 1024 */
+    if (em->block_size < 1024 || em->block_size > 4096 ||
+        (em->block_size & (em->block_size - 1)) != 0) {
+        kprintf("[EXT2] Invalid block size %u (must be power of 2, 1024-4096)\n", em->block_size);
         kfree(em);
         return result;
     }
@@ -1475,16 +1489,46 @@ vfs_mount_result_t ext2_mount(block_device_t* bdev, uint32_t partition_lba) {
 
     if (sb.s_rev_level >= 1 && sb.s_inode_size != 0) {
         em->inode_size = sb.s_inode_size;
+        /* Validate inode size is reasonable */
+        if (em->inode_size < 128 || em->inode_size > 4096) {
+            kprintf("[EXT2] Invalid inode size %u\n", em->inode_size);
+            kfree(em);
+            return result;
+        }
     } else {
         em->inode_size = 128;
     }
 
+    /* Validate num_groups calculation doesn't overflow */
+    if (sb.s_blocks_per_group == 0) {
+        kprintf("[EXT2] Division by zero in num_groups calculation\n");
+        kfree(em);
+        return result;
+    }
     em->num_groups = (sb.s_blocks_count + sb.s_blocks_per_group - 1) / sb.s_blocks_per_group;
 
     /* Read Group Descriptor Table */
+    /* Validate gdt_bytes doesn't overflow */
+    if (em->num_groups > 65536) {  /* Reasonable limit for num_groups */
+        kprintf("[EXT2] Invalid num_groups: %u\n", em->num_groups);
+        kfree(em);
+        return result;
+    }
     em->gdt_blocks = (em->num_groups * (uint32_t)sizeof(struct ext2_group_desc) +
                           em->block_size - 1) / em->block_size;
     uint32_t gdt_bytes = em->num_groups * (uint32_t)sizeof(struct ext2_group_desc);
+    /* Validate gdt_bytes doesn't overflow and is reasonable */
+    if (gdt_bytes > 16 * 1024 * 1024) {  /* Max 16MB for GDT */
+        kprintf("[EXT2] GDT too large: %u bytes\n", gdt_bytes);
+        kfree(em);
+        return result;
+    }
+    /* Validate gdt_blocks against device size */
+    if (em->gdt_blocks > em->total_blocks) {
+        kprintf("[EXT2] GDT blocks %u exceed total blocks %u\n", em->gdt_blocks, em->total_blocks);
+        kfree(em);
+        return result;
+    }
     em->gdt = (struct ext2_group_desc*)kmalloc(gdt_bytes);
     if (!em->gdt) {
         kprintf("[EXT2] Failed to allocate GDT (%u bytes)\n", gdt_bytes);