Пример #1
0
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;
}
Пример #2
0
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;
}
Пример #3
0
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;
}
Пример #4
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_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;
}
Пример #5
0
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.");
}
Пример #6
0
  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;
  }
Пример #7
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;
}