grub_elf_t grub_xen_file (grub_file_t file) { grub_elf_t elf; struct linux_kernel_header lh; grub_file_t off_file; elf = grub_elf_file (file, file->name); if (elf) return elf; grub_errno = GRUB_ERR_NONE; if (grub_file_seek (file, 0) == (grub_off_t) -1) goto fail; if (grub_file_read (file, &lh, sizeof (lh)) != sizeof (lh)) goto fail; if (lh.boot_flag != grub_cpu_to_le16 (0xaa55) || lh.header != grub_cpu_to_le32 (GRUB_LINUX_MAGIC_SIGNATURE) || grub_le_to_cpu16 (lh.version) < 0x0208) { grub_error (GRUB_ERR_BAD_OS, "version too old for xen boot"); return NULL; } if (lh.payload_length < 4) { grub_error (GRUB_ERR_BAD_OS, "payload too short"); return NULL; } grub_dprintf ("xen", "found bzimage payload 0x%llx-0x%llx\n", (unsigned long long) (lh.setup_sects + 1) * 512 + lh.payload_offset, (unsigned long long) lh.payload_length - 4); off_file = grub_file_offset_open (file, (lh.setup_sects + 1) * 512 + lh.payload_offset, lh.payload_length - 4); if (!off_file) goto fail; elf = grub_elf_file (off_file, file->name); if (elf) return elf; grub_file_offset_close (off_file); fail: grub_error (GRUB_ERR_BAD_OS, "not xen image"); return NULL; }
static grub_err_t grub_cmd_linux (grub_command_t cmd __attribute__ ((unused)), int argc, char *argv[]) { grub_file_t file = 0; struct linux_kernel_header lh; grub_ssize_t len, start, filelen; void *kernel = NULL; grub_dl_ref (my_mod); if (argc == 0) { grub_error (GRUB_ERR_BAD_ARGUMENT, N_("filename expected")); goto fail; } file = grub_file_open (argv[0]); if (! file) goto fail; filelen = grub_file_size (file); kernel = grub_malloc(filelen); if (!kernel) { grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("cannot allocate kernel buffer")); goto fail; } if (grub_file_read (file, kernel, filelen) != filelen) { grub_error (GRUB_ERR_FILE_READ_ERROR, N_("Can't read kernel %s"), argv[0]); goto fail; } grub_tpm_measure (kernel, filelen, GRUB_KERNEL_PCR); if (! grub_linuxefi_secure_validate (kernel, filelen)) { grub_error (GRUB_ERR_INVALID_COMMAND, N_("%s has invalid signature"), argv[0]); grub_free (kernel); goto fail; } params = grub_efi_allocate_pages_max (0x3fffffff, BYTES_TO_PAGES(16384)); if (! params) { grub_error (GRUB_ERR_OUT_OF_MEMORY, "cannot allocate kernel parameters"); goto fail; } grub_memset (params, 0, 16384); grub_memcpy (&lh, kernel, sizeof (lh)); if (lh.boot_flag != grub_cpu_to_le16 (0xaa55)) { grub_error (GRUB_ERR_BAD_OS, N_("invalid magic number")); goto fail; } if (lh.setup_sects > GRUB_LINUX_MAX_SETUP_SECTS) { grub_error (GRUB_ERR_BAD_OS, N_("too many setup sectors")); goto fail; } if (lh.version < grub_cpu_to_le16 (0x020b)) { grub_error (GRUB_ERR_BAD_OS, N_("kernel too old")); goto fail; } if (!lh.handover_offset) { grub_error (GRUB_ERR_BAD_OS, N_("kernel doesn't support EFI handover")); goto fail; } linux_cmdline = grub_efi_allocate_pages_max(0x3fffffff, BYTES_TO_PAGES(lh.cmdline_size + 1)); if (!linux_cmdline) { grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate cmdline")); goto fail; } grub_memcpy (linux_cmdline, LINUX_IMAGE, sizeof (LINUX_IMAGE)); grub_create_loader_cmdline (argc, argv, linux_cmdline + sizeof (LINUX_IMAGE) - 1, lh.cmdline_size - (sizeof (LINUX_IMAGE) - 1)); grub_pass_verity_hash(&lh, linux_cmdline); lh.cmd_line_ptr = (grub_uint32_t)(grub_uint64_t)linux_cmdline; handover_offset = lh.handover_offset; start = (lh.setup_sects + 1) * 512; len = grub_file_size(file) - start; kernel_mem = grub_efi_allocate_pages(lh.pref_address, BYTES_TO_PAGES(lh.init_size)); if (!kernel_mem) kernel_mem = grub_efi_allocate_pages_max(0x3fffffff, BYTES_TO_PAGES(lh.init_size)); if (!kernel_mem) { grub_error (GRUB_ERR_OUT_OF_MEMORY, N_("can't allocate kernel")); goto fail; } grub_memcpy (kernel_mem, (char *)kernel + start, len); grub_loader_set (grub_linuxefi_boot, grub_linuxefi_unload, 0); loaded=1; lh.code32_start = (grub_uint32_t)(grub_uint64_t) kernel_mem; grub_memcpy (params, &lh, 2 * 512); params->type_of_loader = 0x21; fail: if (file) grub_file_close (file); if (kernel) grub_free (kernel); if (grub_errno != GRUB_ERR_NONE) { grub_dl_unref (my_mod); loaded = 0; } if (linux_cmdline && !loaded) grub_efi_free_pages((grub_efi_physical_address_t)linux_cmdline, BYTES_TO_PAGES(lh.cmdline_size + 1)); if (kernel_mem && !loaded) grub_efi_free_pages((grub_efi_physical_address_t)kernel_mem, BYTES_TO_PAGES(kernel_size)); if (params && !loaded) grub_efi_free_pages((grub_efi_physical_address_t)params, BYTES_TO_PAGES(16384)); return grub_errno; }
static grub_err_t bsdlabel_partition_map_iterate (grub_disk_t disk, int (*hook) (grub_disk_t disk, const grub_partition_t partition)) { struct grub_partition_bsd_disk_label label; struct grub_partition p; grub_disk_addr_t delta = 0; unsigned pos; /* Read the BSD label. */ if (grub_disk_read (disk, GRUB_PC_PARTITION_BSD_LABEL_SECTOR, 0, sizeof (label), &label)) return grub_errno; /* Check if it is valid. */ if (label.magic != grub_cpu_to_le32 (GRUB_PC_PARTITION_BSD_LABEL_MAGIC)) return grub_error (GRUB_ERR_BAD_PART_TABLE, "no signature"); /* A kludge to determine a base of be.offset. */ if (GRUB_PC_PARTITION_BSD_LABEL_WHOLE_DISK_PARTITION < grub_cpu_to_le16 (label.num_partitions)) { struct grub_partition_bsd_entry whole_disk_be; pos = sizeof (label) + GRUB_PC_PARTITION_BSD_LABEL_SECTOR * GRUB_DISK_SECTOR_SIZE + sizeof (struct grub_partition_bsd_entry) * GRUB_PC_PARTITION_BSD_LABEL_WHOLE_DISK_PARTITION; if (grub_disk_read (disk, pos / GRUB_DISK_SECTOR_SIZE, pos % GRUB_DISK_SECTOR_SIZE, sizeof (whole_disk_be), &whole_disk_be)) return grub_errno; delta = grub_le_to_cpu32 (whole_disk_be.offset); } pos = sizeof (label) + GRUB_PC_PARTITION_BSD_LABEL_SECTOR * GRUB_DISK_SECTOR_SIZE; for (p.number = 0; p.number < grub_cpu_to_le16 (label.num_partitions); p.number++, pos += sizeof (struct grub_partition_bsd_entry)) { struct grub_partition_bsd_entry be; if (p.number == GRUB_PC_PARTITION_BSD_LABEL_WHOLE_DISK_PARTITION) continue; p.offset = pos / GRUB_DISK_SECTOR_SIZE; p.index = pos % GRUB_DISK_SECTOR_SIZE; if (grub_disk_read (disk, p.offset, p.index, sizeof (be), &be)) return grub_errno; p.start = grub_le_to_cpu32 (be.offset); 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 (p.len == 0) continue; if (p.start < delta) { #ifdef GRUB_UTIL char *partname; #endif 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); #ifdef GRUB_UTIL /* disk->partition != NULL as 0 < delta */ partname = grub_partition_get_name (disk->partition); grub_util_warn ("Discarding improperly nested partition (%s,%s,%s%d)", disk->name, partname, p.partmap->name, p.number + 1); grub_free (partname); #endif continue; } p.start -= delta; if (hook (disk, &p)) return grub_errno; } return GRUB_ERR_NONE; }
static grub_err_t pc_partition_map_iterate (grub_disk_t disk, int (*hook) (grub_disk_t disk, const grub_partition_t partition)) { struct grub_partition p; struct grub_msdos_partition_mbr mbr; int labeln = 0; grub_disk_addr_t lastaddr; grub_disk_addr_t ext_offset; p.offset = 0; ext_offset = 0; p.number = -1; p.partmap = &grub_msdos_partition_map; /* Any value different than `p.offset' will satisfy the check during first loop. */ lastaddr = !p.offset; while (1) { int i; struct grub_msdos_partition_entry *e; /* Read the MBR. */ if (grub_disk_read (disk, 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 (labeln && lastaddr == p.offset) return grub_error (GRUB_ERR_BAD_PART_TABLE, "loop detected"); labeln++; if ((labeln & (labeln - 1)) == 0) lastaddr = p.offset; /* 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"); for (i = 0; i < 4; i++) if (mbr.entries[i].flag & 0x7f) return grub_error (GRUB_ERR_BAD_PART_TABLE, "bad boot flag"); /* Analyze DOS partitions. */ for (p.index = 0; p.index < 4; p.index++) { e = mbr.entries + p.index; p.start = p.offset + grub_le_to_cpu32 (e->start); p.len = grub_le_to_cpu32 (e->length); grub_dprintf ("partition", "partition %d: flag 0x%x, type 0x%x, start 0x%llx, len 0x%llx\n", p.index, e->flag, e->type, (unsigned long long) p.start, (unsigned long long) p.len); /* If this is a GPT partition, this MBR is just a dummy. */ if (e->type == GRUB_PC_PARTITION_TYPE_GPT_DISK && p.index == 0) return grub_error (GRUB_ERR_BAD_PART_TABLE, "dummy mbr"); /* If this partition is a normal one, call the hook. */ if (! grub_msdos_partition_is_empty (e->type) && ! grub_msdos_partition_is_extended (e->type)) { p.number++; if (hook (disk, &p)) return grub_errno; } else if (p.number < 4) /* If this partition is a logical one, shouldn't increase the partition number. */ p.number++; } /* Find an extended partition. */ for (i = 0; i < 4; i++) { e = mbr.entries + i; if (grub_msdos_partition_is_extended (e->type)) { p.offset = ext_offset + grub_le_to_cpu32 (e->start); if (! ext_offset) ext_offset = p.offset; break; } } /* If no extended partition, the end. */ if (i == 4) break; } finish: return grub_errno; }
static grub_err_t pc_partition_map_embed (struct grub_disk *disk, unsigned int *nsectors, grub_embed_type_t embed_type, grub_disk_addr_t **sectors) { grub_disk_addr_t end = ~0ULL; struct grub_msdos_partition_mbr mbr; int labeln = 0; /* Any value different than `p.offset' will satisfy the check during first loop. */ grub_disk_addr_t lastaddr = 1; grub_disk_addr_t ext_offset = 0; grub_disk_addr_t offset = 0; if (embed_type != GRUB_EMBED_PCBIOS) return grub_error (GRUB_ERR_NOT_IMPLEMENTED_YET, "PC-style partitions curently support " "only PC-BIOS embedding"); if (disk->partition) return grub_error (GRUB_ERR_OUT_OF_RANGE, "Embedding on MSDOS subpartition isn't supported"); while (1) { int i; struct grub_msdos_partition_entry *e; grub_err_t err; /* Read the MBR. */ err = grub_disk_read (disk, offset, 0, sizeof (mbr), &mbr); if (err) return err; /* 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 (labeln && lastaddr == offset) return grub_error (GRUB_ERR_BAD_PART_TABLE, "loop detected"); labeln++; if ((labeln & (labeln - 1)) == 0) lastaddr = offset; /* 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"); for (i = 0; i < 4; i++) if (mbr.entries[i].flag & 0x7f) return grub_error (GRUB_ERR_BAD_PART_TABLE, "bad boot flag"); /* Analyze DOS partitions. */ for (i = 0; i < 4; i++) { e = mbr.entries + i; if (!grub_msdos_partition_is_empty (e->type) && end > offset + grub_le_to_cpu32 (e->start)) end = offset + grub_le_to_cpu32 (e->start); /* If this is a GPT partition, this MBR is just a dummy. */ if (e->type == GRUB_PC_PARTITION_TYPE_GPT_DISK && i == 0) return grub_error (GRUB_ERR_BAD_PART_TABLE, "dummy mbr"); } /* Find an extended partition. */ for (i = 0; i < 4; i++) { e = mbr.entries + i; if (grub_msdos_partition_is_extended (e->type)) { offset = ext_offset + grub_le_to_cpu32 (e->start); if (! ext_offset) ext_offset = offset; break; } } /* If no extended partition, the end. */ if (i == 4) break; } if (end >= *nsectors + 2) { unsigned i; *nsectors = end - 2; *sectors = grub_malloc (*nsectors * sizeof (**sectors)); if (!*sectors) return grub_errno; for (i = 0; i < *nsectors; i++) (*sectors)[i] = 1 + i; return GRUB_ERR_NONE; } if (end <= 1) return grub_error (GRUB_ERR_FILE_NOT_FOUND, "This msdos-style partition label has no " "post-MBR gap; embedding won't be possible!"); if (*nsectors > 62) return grub_error (GRUB_ERR_OUT_OF_RANGE, "Your core.img is unusually large. " "It won't fit in the embedding area."); return grub_error (GRUB_ERR_OUT_OF_RANGE, "Your embedding area is unusually small. " "core.img won't fit in it."); }
int iterate_env (struct grub_env_var *var) { char *guid, *attr, *name, *varname; struct efi_variable *efivar; int len = 0; int i; grub_uint64_t guidcomp; if (grub_memcmp (var->name, "EfiEmu.pnvram.", sizeof ("EfiEmu.pnvram.") - 1) != 0) return 0; guid = var->name + sizeof ("EfiEmu.pnvram.") - 1; attr = grub_strchr (guid, '.'); if (!attr) return 0; attr++; name = grub_strchr (attr, '.'); if (!name) return 0; name++; efivar = (struct efi_variable *) nvramptr; if (nvramptr - nvram + sizeof (struct efi_variable) > nvramsize) { grub_error (GRUB_ERR_OUT_OF_MEMORY, "too many NVRAM variables for reserved variable space." " Try increasing EfiEmu.pnvram.size"); return 1; } nvramptr += sizeof (struct efi_variable); efivar->guid.data1 = grub_cpu_to_le32 (grub_strtoul (guid, &guid, 16)); if (*guid != '-') return 0; guid++; efivar->guid.data2 = grub_cpu_to_le16 (grub_strtoul (guid, &guid, 16)); if (*guid != '-') return 0; guid++; efivar->guid.data3 = grub_cpu_to_le16 (grub_strtoul (guid, &guid, 16)); if (*guid != '-') return 0; guid++; guidcomp = grub_strtoull (guid, 0, 16); for (i = 0; i < 8; i++) efivar->guid.data4[i] = (guidcomp >> (56 - 8 * i)) & 0xff; efivar->attributes = grub_strtoull (attr, 0, 16); varname = grub_malloc (grub_strlen (name) + 1); if (! varname) return 1; if (unescape (name, varname, varname + grub_strlen (name) + 1, &len)) return 1; len = grub_utf8_to_utf16 ((grub_uint16_t *) nvramptr, (nvramsize - (nvramptr - nvram)) / 2, (grub_uint8_t *) varname, len, NULL); nvramptr += 2 * len; *((grub_uint16_t *) nvramptr) = 0; nvramptr += 2; efivar->namelen = 2 * len + 2; if (unescape (var->value, nvramptr, nvram + nvramsize, &len)) { efivar->namelen = 0; return 1; } nvramptr += len; efivar->size = len; return 0; }
static grub_err_t pc_partition_map_iterate (grub_disk_t disk, int (*hook) (grub_disk_t disk, const grub_partition_t partition)) { struct grub_partition p; struct grub_pc_partition pcdata; struct grub_pc_partition_mbr mbr; struct grub_pc_partition_disk_label label; struct grub_disk raw; /* Enforce raw disk access. */ raw = *disk; raw.partition = 0; p.offset = 0; pcdata.ext_offset = 0; pcdata.dos_part = -1; p.data = &pcdata; p.partmap = &grub_pc_partition_map; while (1) { int i; struct grub_pc_partition_entry *e; /* Read the MBR. */ if (grub_disk_read (&raw, p.offset, 0, sizeof (mbr), (char *) &mbr)) goto finish; /* 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"); /* Analyze DOS partitions. */ for (p.index = 0; p.index < 4; p.index++) { e = mbr.entries + p.index; p.start = p.offset + grub_le_to_cpu32 (e->start); p.len = grub_le_to_cpu32 (e->length); pcdata.bsd_part = -1; pcdata.dos_type = e->type; pcdata.bsd_type = -1; grub_dprintf ("partition", "partition %d: flag 0x%x, type 0x%x, start 0x%llx, len 0x%llx\n", p.index, e->flag, pcdata.dos_type, (unsigned long long) p.start, (unsigned long long) p.len); /* If this is a GPT partition, this MBR is just a dummy. */ if (e->type == GRUB_PC_PARTITION_TYPE_GPT_DISK && p.index == 0) return grub_error (GRUB_ERR_BAD_PART_TABLE, "dummy mbr"); /* If this partition is a normal one, call the hook. */ if (! grub_pc_partition_is_empty (e->type) && ! grub_pc_partition_is_extended (e->type)) { pcdata.dos_part++; if (hook (disk, &p)) return 1; /* Check if this is a BSD partition. */ if (grub_pc_partition_is_bsd (e->type)) { /* Check if the BSD label is within the DOS partition. */ if (p.len <= GRUB_PC_PARTITION_BSD_LABEL_SECTOR) return grub_error (GRUB_ERR_BAD_PART_TABLE, "no space for disk label"); /* Read the BSD label. */ if (grub_disk_read (&raw, (p.start + GRUB_PC_PARTITION_BSD_LABEL_SECTOR), 0, sizeof (label), (char *) &label)) goto finish; /* Check if it is valid. */ if (label.magic != grub_cpu_to_le32 (GRUB_PC_PARTITION_BSD_LABEL_MAGIC)) return grub_error (GRUB_ERR_BAD_PART_TABLE, "invalid disk label magic 0x%x", label.magic); for (pcdata.bsd_part = 0; pcdata.bsd_part < grub_cpu_to_le16 (label.num_partitions); pcdata.bsd_part++) { struct grub_pc_partition_bsd_entry *be = label.entries + pcdata.bsd_part; p.start = grub_le_to_cpu32 (be->offset); p.len = grub_le_to_cpu32 (be->size); pcdata.bsd_type = be->fs_type; if (be->fs_type != GRUB_PC_PARTITION_BSD_TYPE_UNUSED) if (hook (disk, &p)) return 1; } } } else if (pcdata.dos_part < 4) /* If this partition is a logical one, shouldn't increase the partition number. */ pcdata.dos_part++; } /* Find an extended partition. */ for (i = 0; i < 4; i++) { e = mbr.entries + i; if (grub_pc_partition_is_extended (e->type)) { p.offset = pcdata.ext_offset + grub_le_to_cpu32 (e->start); if (! pcdata.ext_offset) pcdata.ext_offset = p.offset; break; } } /* If no extended partition, the end. */ if (i == 4) break; } finish: return grub_errno; }