elf.c 5.46 KB
Newer Older
1 2 3
/* elf.c - load ELF files */
/*
 *  GRUB  --  GRand Unified Bootloader
4
 *  Copyright (C) 2003,2004,2005,2006,2007,2008,2009  Free Software Foundation, Inc.
5
 *
6
 *  GRUB is free software: you can redistribute it and/or modify
7
 *  it under the terms of the GNU General Public License as published by
8
 *  the Free Software Foundation, either version 3 of the License, or
9 10
 *  (at your option) any later version.
 *
11
 *  GRUB is distributed in the hope that it will be useful,
12 13 14 15 16
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
17
 *  along with GRUB.  If not, see <http://www.gnu.org/licenses/>.
18 19 20 21 22 23 24 25
 */

#include <grub/err.h>
#include <grub/elf.h>
#include <grub/elfload.h>
#include <grub/file.h>
#include <grub/misc.h>
#include <grub/mm.h>
26
#include <grub/dl.h>
27
#include <grub/i18n.h>
28 29

GRUB_MOD_LICENSE ("GPLv3+");
30

31 32
#pragma GCC diagnostic ignored "-Wcast-align"

33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
#if defined(__powerpc__) && defined(GRUB_MACHINE_IEEE1275)
#define GRUB_ELF_ENABLE_BI_ENDIAN 1
#else
#define GRUB_ELF_ENABLE_BI_ENDIAN 0
#endif

#if defined(GRUB_CPU_WORDS_BIGENDIAN)
#define GRUB_ELF_NATIVE_ENDIANNESS ELFDATA2MSB
#define GRUB_ELF_OPPOSITE_ENDIANNESS ELFDATA2LSB
#else
#define GRUB_ELF_NATIVE_ENDIANNESS ELFDATA2LSB
#define GRUB_ELF_OPPOSITE_ENDIANNESS ELFDATA2MSB
#endif

static int grub_elf32_check_endianess_and_bswap_ehdr (grub_elf_t elf);
static int grub_elf64_check_endianess_and_bswap_ehdr (grub_elf_t elf);

50 51 52 53 54 55 56 57 58 59
/* Check if EHDR is a valid ELF header.  */
static grub_err_t
grub_elf_check_header (grub_elf_t elf)
{
  Elf32_Ehdr *e = &elf->ehdr.ehdr32;

  if (e->e_ident[EI_MAG0] != ELFMAG0
      || e->e_ident[EI_MAG1] != ELFMAG1
      || e->e_ident[EI_MAG2] != ELFMAG2
      || e->e_ident[EI_MAG3] != ELFMAG3
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
      || e->e_ident[EI_VERSION] != EV_CURRENT)
    return grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-independent ELF magic"));

  if (grub_elf_is_elf32 (elf))
    {
      if (!grub_elf32_check_endianess_and_bswap_ehdr (elf)) {
	return grub_error (GRUB_ERR_BAD_OS, "invalid ELF endianness magic");
      }
    }
  else if (grub_elf_is_elf64 (elf))
    {
      if (!grub_elf64_check_endianess_and_bswap_ehdr (elf)) {
	return grub_error (GRUB_ERR_BAD_OS, "invalid ELF endianness magic");
      }
    }
  else
    return grub_error (GRUB_ERR_BAD_OS, "unknown ELF class");

  if (e->e_version != EV_CURRENT)
79
    return grub_error (GRUB_ERR_BAD_OS, N_("invalid arch-independent ELF magic"));
80 81 82 83 84 85 86 87 88 89

  return GRUB_ERR_NONE;
}

grub_err_t
grub_elf_close (grub_elf_t elf)
{
  grub_file_t file = elf->file;

  grub_free (elf->phdrs);
90
  grub_free (elf->filename);
91 92 93 94 95 96 97 98 99
  grub_free (elf);

  if (file)
    grub_file_close (file);

  return grub_errno;
}

grub_elf_t
100
grub_elf_file (grub_file_t file, const char *filename)
101 102 103
{
  grub_elf_t elf;

104
  elf = grub_zalloc (sizeof (*elf));
105 106 107 108 109
  if (! elf)
    return 0;

  elf->file = file;

110 111 112
  if (grub_file_seek (elf->file, 0) == (grub_off_t) -1)
    goto fail;

113
  if (grub_file_read (elf->file, &elf->ehdr, sizeof (elf->ehdr))
114 115
      != sizeof (elf->ehdr))
    {
116 117 118
      if (!grub_errno)
	grub_error (GRUB_ERR_FILE_READ_ERROR, N_("premature end of file %s"),
		    filename);
119 120 121 122 123 124
      goto fail;
    }

  if (grub_elf_check_header (elf))
    goto fail;

125 126 127 128
  elf->filename = grub_strdup (filename);
  if (!elf->filename)
    goto fail;

129 130 131
  return elf;

fail:
132
  grub_free (elf->filename);
133 134
  grub_free (elf->phdrs);
  grub_free (elf);
135 136 137 138 139 140 141
  return 0;
}

grub_elf_t
grub_elf_open (const char *name)
{
  grub_file_t file;
142
  grub_elf_t elf;
143

144
  file = grub_file_open (name);
145 146 147
  if (! file)
    return 0;

148
  elf = grub_elf_file (file, name);
149 150 151 152
  if (! elf)
    grub_file_close (file);

  return elf;
153 154 155
}


156 157 158
#define grub_swap_bytes_halfXX grub_swap_bytes16
#define grub_swap_bytes_wordXX grub_swap_bytes32

159
/* 32-bit */
160 161 162 163 164 165 166 167 168
#define ehdrXX ehdr32
#define ELFCLASSXX ELFCLASS32
#define ElfXX_Addr Elf32_Addr
#define grub_elfXX_size grub_elf32_size
#define grub_elfXX_load grub_elf32_load
#define FOR_ELFXX_PHDRS FOR_ELF32_PHDRS
#define grub_elf_is_elfXX grub_elf_is_elf32
#define grub_elfXX_load_phdrs grub_elf32_load_phdrs
#define ElfXX_Phdr Elf32_Phdr
169
#define ElfXX_Ehdr Elf32_Ehdr
170
#define grub_uintXX_t grub_uint32_t
171 172 173 174
#define grub_swap_bytes_addrXX grub_swap_bytes32
#define grub_swap_bytes_offXX grub_swap_bytes32
#define grub_swap_bytes_XwordXX grub_swap_bytes32
#define grub_elfXX_check_endianess_and_bswap_ehdr grub_elf32_check_endianess_and_bswap_ehdr
175 176 177 178 179 180 181 182 183 184 185 186

#include "elfXX.c"

#undef ehdrXX
#undef ELFCLASSXX
#undef ElfXX_Addr
#undef grub_elfXX_size
#undef grub_elfXX_load
#undef FOR_ELFXX_PHDRS
#undef grub_elf_is_elfXX
#undef grub_elfXX_load_phdrs
#undef ElfXX_Phdr
187
#undef ElfXX_Ehdr
188
#undef grub_uintXX_t
189 190 191 192
#undef grub_swap_bytes_addrXX
#undef grub_swap_bytes_offXX
#undef grub_swap_bytes_XwordXX
#undef grub_elfXX_check_endianess_and_bswap_ehdr
193

194 195

/* 64-bit */
196 197 198 199 200 201 202 203 204
#define ehdrXX ehdr64
#define ELFCLASSXX ELFCLASS64
#define ElfXX_Addr Elf64_Addr
#define grub_elfXX_size grub_elf64_size
#define grub_elfXX_load grub_elf64_load
#define FOR_ELFXX_PHDRS FOR_ELF64_PHDRS
#define grub_elf_is_elfXX grub_elf_is_elf64
#define grub_elfXX_load_phdrs grub_elf64_load_phdrs
#define ElfXX_Phdr Elf64_Phdr
205
#define ElfXX_Ehdr Elf64_Ehdr
206
#define grub_uintXX_t grub_uint64_t
207 208 209 210
#define grub_swap_bytes_addrXX grub_swap_bytes64
#define grub_swap_bytes_offXX grub_swap_bytes64
#define grub_swap_bytes_XwordXX grub_swap_bytes64
#define grub_elfXX_check_endianess_and_bswap_ehdr grub_elf64_check_endianess_and_bswap_ehdr
211 212

#include "elfXX.c"