Description: Detect other software using embedding area When embedding the core image in a post-MBR gap, check for and avoid sectors matching any of the signatures in embed_signatures. Author: Colin Watson Origin: upstream, http://bzr.sv.gnu.org/r/grub/branches/embed-sectors/ Forwarded: http://lists.gnu.org/archive/html/grub-devel/2010-08/msg00137.html Last-Update: 2011-04-21 Index: b/ChangeLog.embed-sectors =================================================================== --- /dev/null +++ b/ChangeLog.embed-sectors @@ -0,0 +1,12 @@ +2011-03-14 Colin Watson + + * include/grub/partition.h (grub_partition_map): Change prototype of + embed to take a maximum value for nsectors. + * grub-core/partmap/msdos.c (embed_signatures): New array. + (pc_partition_map_embed): Check for and avoid sectors matching any + of the signatures in embed_signatures, up to max_nsectors. + * grub-core/partmap/gpt.c (gpt_partition_map_embed): Restrict + returned sector map to max_nsectors. + * util/grub-setup.c (setup): Allow for the embedding area being + split into multiple blocklists. Tell dest_partmap->embed the + maximum number of sectors we care about. Index: b/grub-core/partmap/gpt.c =================================================================== --- a/grub-core/partmap/gpt.c +++ b/grub-core/partmap/gpt.c @@ -127,6 +127,7 @@ #ifdef GRUB_UTIL static grub_err_t gpt_partition_map_embed (struct grub_disk *disk, unsigned int *nsectors, + unsigned int max_nsectors, grub_embed_type_t embed_type, grub_disk_addr_t **sectors) { @@ -176,6 +177,8 @@ " embedding won't be possible!"); *nsectors = len; + if (*nsectors > max_nsectors) + *nsectors = max_nsectors; *sectors = grub_malloc (*nsectors * sizeof (**sectors)); if (!*sectors) return grub_errno; Index: b/grub-core/partmap/msdos.c =================================================================== --- a/grub-core/partmap/msdos.c +++ b/grub-core/partmap/msdos.c @@ -29,6 +29,66 @@ static struct grub_partition_map grub_msdos_partition_map; +#ifdef GRUB_UTIL +#include + +struct embed_signature +{ + const char *name; + const char *signature; + int signature_len; + enum { TYPE_SOFTWARE, TYPE_RAID } type; +}; + +const char message_warn[][200] = { + [TYPE_RAID] = "Sector %llu is already in use by %s; avoiding it. " + "Please ask the manufacturer not to store data in MBR gap", + [TYPE_SOFTWARE] = "Sector %llu is already in use by %s; avoiding it. " + "This software may cause boot or other problems in " + "future. Please ask its authors not to store data " + "in the boot track" +}; + + +/* Signatures of other software that may be using sectors in the embedding + area. */ +struct embed_signature embed_signatures[] = + { + { + .name = "ZISD", + .signature = "ZISD", + .signature_len = 4, + .type = TYPE_SOFTWARE + }, + { + .name = "FlexNet", + .signature = "\xd4\x41\xa0\xf5\x03\x00\x03\x00", + .signature_len = 8, + .type = TYPE_SOFTWARE + }, + { + .name = "FlexNet", + .signature = "\xd8\x41\xa0\xf5\x02\x00\x02\x00", + .signature_len = 8, + .type = TYPE_SOFTWARE + }, + { + /* from Ryan Perkins */ + .name = "HP Backup and Recovery Manager (?)", + .signature = "\x70\x8a\x5d\x46\x35\xc5\x1b\x93" + "\xae\x3d\x86\xfd\xb1\x55\x3e\xe0", + .signature_len = 16, + .type = TYPE_SOFTWARE + }, + { + .name = "HighPoint RAID controller", + .signature = "ycgl", + .signature_len = 4, + .type = TYPE_RAID + } + }; +#endif + grub_err_t grub_partition_msdos_iterate (grub_disk_t disk, int (*hook) (grub_disk_t disk, @@ -148,6 +208,7 @@ #ifdef GRUB_UTIL static grub_err_t pc_partition_map_embed (struct grub_disk *disk, unsigned int *nsectors, + unsigned int max_nsectors, grub_embed_type_t embed_type, grub_disk_addr_t **sectors) { @@ -236,13 +297,65 @@ if (end >= *nsectors + 2) { - unsigned i; + unsigned i, j; + char *embed_signature_check; + unsigned int orig_nsectors, avail_nsectors; + + orig_nsectors = *nsectors; *nsectors = end - 2; + avail_nsectors = *nsectors; + if (*nsectors > max_nsectors) + *nsectors = max_nsectors; *sectors = grub_malloc (*nsectors * sizeof (**sectors)); if (!*sectors) return grub_errno; for (i = 0; i < *nsectors; i++) (*sectors)[i] = 1 + i; + + /* Check for software that is already using parts of the embedding + * area. + */ + embed_signature_check = grub_malloc (GRUB_DISK_SECTOR_SIZE); + for (i = 0; i < *nsectors; i++) + { + if (grub_disk_read (disk, (*sectors)[i], 0, GRUB_DISK_SECTOR_SIZE, + embed_signature_check)) + continue; + + for (j = 0; j < ARRAY_SIZE (embed_signatures); j++) + if (! grub_memcmp (embed_signatures[j].signature, + embed_signature_check, + embed_signatures[j].signature_len)) + break; + if (j == ARRAY_SIZE (embed_signatures)) + continue; + grub_util_warn (message_warn[embed_signatures[j].type], + (*sectors)[i], embed_signatures[j].name); + avail_nsectors--; + if (avail_nsectors < *nsectors) + *nsectors = avail_nsectors; + + /* Avoid this sector. */ + for (j = i; j < *nsectors; j++) + (*sectors)[j]++; + + /* Have we run out of space? */ + if (avail_nsectors < orig_nsectors) + break; + + /* Make sure to check the next sector. */ + i--; + } + grub_free (embed_signature_check); + + if (*nsectors < orig_nsectors) + return grub_error (GRUB_ERR_OUT_OF_RANGE, + "Other software is using the embedding area, and " + "there is not enough room for core.img. Such " + "software is often trying to store data in a way " + "that avoids detection. We recommend you " + "investigate."); + return GRUB_ERR_NONE; } Index: b/include/grub/partition.h =================================================================== --- a/include/grub/partition.h +++ b/include/grub/partition.h @@ -49,6 +49,7 @@ #ifdef GRUB_UTIL /* Determine sectors available for embedding. */ grub_err_t (*embed) (struct grub_disk *disk, unsigned int *nsectors, + unsigned int max_nsectors, grub_embed_type_t embed_type, grub_disk_addr_t **sectors); #endif Index: b/util/grub-setup.c =================================================================== --- a/util/grub-setup.c +++ b/util/grub-setup.c @@ -428,10 +428,8 @@ } nsec = core_sectors; - err = dest_partmap->embed (dest_dev->disk, &nsec, + err = dest_partmap->embed (dest_dev->disk, &nsec, 2 * core_sectors, GRUB_EMBED_PCBIOS, §ors); - if (nsec > 2 * core_sectors) - nsec = 2 * core_sectors; if (err) { @@ -460,6 +458,13 @@ save_blocklists (sectors[i] + grub_partition_get_start (container), 0, GRUB_DISK_SECTOR_SIZE); + /* Make sure that the last blocklist is a terminator. */ + if (block == first_block) + block--; + block->start = 0; + block->len = 0; + block->segment = 0; + write_rootdev (core_img, root_dev, boot_img, first_sector); core_img = realloc (core_img, nsec * GRUB_DISK_SECTOR_SIZE); @@ -476,12 +481,6 @@ nsec * GRUB_DISK_SECTOR_SIZE - core_size); - /* Make sure that the second blocklist is a terminator. */ - block = first_block - 1; - block->start = 0; - block->len = 0; - block->segment = 0; - /* Write the core image onto the disk. */ for (i = 0; i < nsec; i++) grub_disk_write (dest_dev->disk, sectors[i], 0,