diff --git a/ChangeLog b/ChangeLog index 752bde8..eac8b8a 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +2009-07-25 Vladimir Serbinenko + + * partmap/pc.c (pc_partition_map_iterate): Detect and break loops. + 2009-07-25 Felix Zielcke * kern/file.c (grub_file_open): Revert to previous check with diff --git a/partmap/pc.c b/partmap/pc.c index 6f68ecf..e64f118 100644 --- a/partmap/pc.c +++ b/partmap/pc.c @@ -97,6 +97,9 @@ pc_partition_map_iterate (grub_disk_t disk, struct grub_pc_partition_mbr mbr; struct grub_pc_partition_disk_label label; struct grub_disk raw; + int labeln = 1, lastlabeln = 1; + /* Just not zero. It will be overwritten during first iteration. */ + grub_disk_addr_t lastaddr = 0x1; /* Enforce raw disk access. */ raw = *disk; @@ -117,6 +120,21 @@ pc_partition_map_iterate (grub_disk_t disk, if (grub_disk_read (&raw, p.offset, 0, sizeof (mbr), &mbr)) goto finish; + /* This is our loop-detection algorithm. It works the following way: + It saves last position which was a power of two. Then it compares the + saved value with a current one. This way it's guaranteed that the loop + will be broken by at most third walk. + */ + if (lastaddr == p.offset) + return grub_error (GRUB_ERR_BAD_PART_TABLE, "loop detected"); + + labeln++; + if (labeln == (lastlabeln << 1)) + { + lastaddr = p.offset; + lastlabeln <<= 1; + } + /* Check if it is valid. */ if (mbr.signature != grub_cpu_to_le16 (GRUB_PC_PARTITION_SIGNATURE)) return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature");