Hi, This is the reworked version of the patch.
There are few ramifications of this patch. First of all some partitions which are just barely outside of the host partition will lead to something like "partition not found" errors in grub-probe. This message should be more informative (the easiest way is to issue a warning in grub-probe if partitions are discarded except some cases where it's known not to affect the functionality like 'd' "subpartitions", probably such a warning in grub proper would be too annoying though).
There is now a grub_dprintf where the partition is discarded.
Then if you check partitions when iterating no need to recheck in adjust_range.
I simplified the check in grub_disk_adjust_range: no need to check for the ``ancestor'' partitions, but we still check for the given partition.
The patch still accepts sub-partitions that start at the same (absolute) offset as the parent. For instance, in the above example, ls -l in grub gives both (hd1,msdos1) and (hd1,msdos1,bsd1). Should we discard (hd0,msdos1,bsd1), i.e. require that sub-partitions start at a strictly positive relative offset?
I left this out. Even if it introduces redundancy, it's actually nice to see (hd1,msdos1,bsd1) in ls -l (e.g., if bsd1 is the only partition in the bsd label). Grégoire
=== added file 'ChangeLog.strict-partition-nesting' --- ChangeLog.strict-partition-nesting 1970-01-01 00:00:00 +0000 +++ ChangeLog.strict-partition-nesting 2010-07-06 21:25:28 +0000 @@ -0,0 +1,14 @@ +2010-07-06 Grégoire Sutre <gregoire.su...@gmail.com> + + * kern/partition.c (grub_partition_validate): New function to check + that a partition is physically contained in its parent. Since offsets + are relative (and non-negative), this reduces to checking that the + partition ends before its parent. + (grub_partition_map_probe): Discard invalid partitions. + (grub_partition_iterate): Likewise. + * kern/disk.c (grub_disk_adjust_range): Simplify out-of-partition + check (partitions are assumed to be properly nested). + * include/grub/partition.h (grub_partition_map): Slightly more detailed + comments. + * partmap/bsdlabel.c (bsdlabel_partition_map_iterate): Discard + partitions that start before their parent, and add debug printfs. === modified file 'include/grub/partition.h' --- include/grub/partition.h 2010-06-12 13:33:09 +0000 +++ include/grub/partition.h 2010-07-06 21:16:05 +0000 @@ -48,7 +48,7 @@ struct grub_partition /* The partition number. */ int number; - /* The start sector. */ + /* The start sector (relative to parent). */ grub_disk_addr_t start; /* The length in sector units. */ @@ -60,7 +60,7 @@ struct grub_partition /* The index of this partition in the partition table. */ int index; - /* Parent partition map. */ + /* Parent partition (physically contains this partition). */ struct grub_partition *parent; /* The type partition map. */ === modified file 'kern/disk.c' --- kern/disk.c 2010-02-07 00:48:38 +0000 +++ kern/disk.c 2010-07-06 21:22:27 +0000 @@ -361,12 +361,10 @@ grub_disk_adjust_range (grub_disk_t disk *sector += *offset >> GRUB_DISK_SECTOR_BITS; *offset &= GRUB_DISK_SECTOR_SIZE - 1; - for (part = disk->partition; part; part = part->parent) + part = disk->partition; + if (part) { - grub_disk_addr_t start; grub_uint64_t len; - - start = part->start; len = part->len; if (*sector >= len @@ -374,7 +372,7 @@ grub_disk_adjust_range (grub_disk_t disk >> GRUB_DISK_SECTOR_BITS)) return grub_error (GRUB_ERR_OUT_OF_RANGE, "out of partition"); - *sector += start; + *sector += grub_partition_get_start (part); } if (disk->total_sectors <= *sector === modified file 'kern/partition.c' --- kern/partition.c 2010-02-06 20:00:53 +0000 +++ kern/partition.c 2010-07-06 21:20:04 +0000 @@ -23,6 +23,23 @@ grub_partition_map_t grub_partition_map_list; +/* + * Checks that a partition is contained in its parent. + */ +static int +grub_partition_validate (const grub_disk_t disk, + const grub_partition_t partition) +{ + grub_disk_addr_t parent_len; + + if (disk->partition) + parent_len = grub_partition_get_len (disk->partition); + else + parent_len = disk->total_sectors; + + return (partition->start + partition->len <= parent_len); +} + static grub_partition_t grub_partition_map_probe (const grub_partition_map_t partmap, grub_disk_t disk, int partnum) @@ -31,20 +48,26 @@ grub_partition_map_probe (const grub_par auto int find_func (grub_disk_t d, const grub_partition_t partition); - int find_func (grub_disk_t d __attribute__ ((unused)), + int find_func (grub_disk_t dsk, const grub_partition_t partition) { - if (partnum == partition->number) - { - p = (grub_partition_t) grub_malloc (sizeof (*p)); - if (! p) - return 1; + if (partnum != partition->number) + return 0; - grub_memcpy (p, partition, sizeof (*p)); - return 1; + if (!(grub_partition_validate (dsk, partition))) + { + grub_dprintf ("partition", "Invalid (sub-)partition %s%d (%s).\n", + partition->partmap->name, partition->number + 1, + "out of range"); + return 0; } - return 0; + p = (grub_partition_t) grub_malloc (sizeof (*p)); + if (! p) + return 1; + + grub_memcpy (p, partition, sizeof (*p)); + return 1; } partmap->iterate (disk, find_func); @@ -138,6 +161,15 @@ grub_partition_iterate (struct grub_disk const grub_partition_t partition) { struct grub_partition p = *partition; + + if (!(grub_partition_validate (dsk, partition))) + { + grub_dprintf ("partition", "Invalid (sub-)partition %s%d (%s).\n", + partition->partmap->name, partition->number + 1, + "out of range"); + return 0; + } + p.parent = dsk->partition; dsk->partition = 0; if (hook (dsk, &p)) === modified file 'partmap/bsdlabel.c' --- partmap/bsdlabel.c 2010-03-26 14:44:13 +0000 +++ partmap/bsdlabel.c 2010-07-06 21:15:19 +0000 @@ -54,7 +54,7 @@ bsdlabel_partition_map_iterate (grub_dis for (p.number = 0; p.number < grub_cpu_to_le16 (label.num_partitions); - p.number++) + p.number++, pos += sizeof (struct grub_partition_bsd_entry)) { struct grub_partition_bsd_entry be; @@ -64,15 +64,29 @@ bsdlabel_partition_map_iterate (grub_dis if (grub_disk_read (disk, p.offset, p.index, sizeof (be), &be)) return grub_errno; - p.start = grub_le_to_cpu32 (be.offset) - delta; + p.start = grub_le_to_cpu32 (be.offset); + if (p.start < delta) + { + grub_dprintf ("partition", + "partition %d: invalid start (found 0x%llx, wanted >= 0x%llx)\n", + p.number, + (unsigned long long) p.start, + (unsigned long long) delta); + continue; + } + p.start -= delta; p.len = grub_le_to_cpu32 (be.size); p.partmap = &grub_bsdlabel_partition_map; + grub_dprintf ("partition", + "partition %d: type 0x%x, start 0x%llx, len 0x%llx\n", + p.number, be.fs_type, + (unsigned long long) p.start, + (unsigned long long) p.len); + if (be.fs_type != GRUB_PC_PARTITION_BSD_TYPE_UNUSED) if (hook (disk, &p)) return grub_errno; - - pos += sizeof (struct grub_partition_bsd_entry); } return GRUB_ERR_NONE;
_______________________________________________ Grub-devel mailing list Grub-devel@gnu.org http://lists.gnu.org/mailman/listinfo/grub-devel