1/* Get ELF program header table.
2   Copyright (C) 1998-2010, 2014, 2015 Red Hat, Inc.
3   This file is part of elfutils.
4   Written by Ulrich Drepper <drepper@redhat.com>, 1998.
5
6   This file is free software; you can redistribute it and/or modify
7   it under the terms of either
8
9     * the GNU Lesser General Public License as published by the Free
10       Software Foundation; either version 3 of the License, or (at
11       your option) any later version
12
13   or
14
15     * the GNU General Public License as published by the Free
16       Software Foundation; either version 2 of the License, or (at
17       your option) any later version
18
19   or both in parallel, as here.
20
21   elfutils is distributed in the hope that it will be useful, but
22   WITHOUT ANY WARRANTY; without even the implied warranty of
23   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
24   General Public License for more details.
25
26   You should have received copies of the GNU General Public License and
27   the GNU Lesser General Public License along with this program.  If
28   not, see <http://www.gnu.org/licenses/>.  */
29
30#ifdef HAVE_CONFIG_H
31# include <config.h>
32#endif
33
34#include <errno.h>
35#include <stdbool.h>
36#include <stdlib.h>
37#include <unistd.h>
38#include <assert.h>
39
40#include <system.h>
41#include "libelfP.h"
42#include "common.h"
43
44#ifndef LIBELFBITS
45# define LIBELFBITS 32
46#endif
47
48ElfW2(LIBELFBITS,Phdr) *
49__elfw2(LIBELFBITS,getphdr_wrlock) (Elf *elf)
50{
51  ElfW2(LIBELFBITS,Phdr) *result;
52
53  /* If the program header entry has already been filled in the code
54     below must already have been run.  So the class is set, too.  No
55     need to waste any more time here.  */
56  result = elf->state.ELFW(elf,LIBELFBITS).phdr;
57  if (likely (result != NULL))
58    return result;
59
60  if (elf->class == 0)
61    elf->class = ELFW(ELFCLASS,LIBELFBITS);
62  else if (elf->class != ELFW(ELFCLASS,LIBELFBITS))
63    {
64      __libelf_seterrno (ELF_E_INVALID_CLASS);
65      result = NULL;
66      goto out;
67    }
68
69  if (likely (result == NULL))
70    {
71      /* Read the section header table.  */
72      ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
73
74      /* If no program header exists return NULL.  */
75      size_t phnum;
76      if (__elf_getphdrnum_rdlock (elf, &phnum) != 0)
77	goto out;
78      if (phnum == 0 || ehdr->e_phoff == 0)
79	{
80	  __libelf_seterrno (ELF_E_NO_PHDR);
81	  goto out;
82	}
83
84      /* Check this doesn't overflow.  */
85      size_t size = phnum * sizeof (ElfW2(LIBELFBITS,Phdr));
86
87      if (phnum > SIZE_MAX / sizeof (ElfW2(LIBELFBITS,Phdr))
88	  || ehdr->e_phoff > elf->maximum_size
89	  || elf->maximum_size - ehdr->e_phoff < size)
90	{
91	  __libelf_seterrno (ELF_E_INVALID_DATA);
92	  goto out;
93	}
94
95      if (elf->map_address != NULL)
96	{
97	  /* First see whether the information in the ELF header is
98	     valid and it does not ask for too much.  */
99	  if (unlikely (ehdr->e_phoff >= elf->maximum_size)
100	      || unlikely (elf->maximum_size - ehdr->e_phoff < size))
101	    {
102	      /* Something is wrong.  */
103	      __libelf_seterrno (ELF_E_INVALID_PHDR);
104	      goto out;
105	    }
106
107	  /* All the data is already mapped.  Use it.  */
108	  void *file_phdr = ((char *) elf->map_address
109			     + elf->start_offset + ehdr->e_phoff);
110	  if (ehdr->e_ident[EI_DATA] == MY_ELFDATA
111	      && (ALLOW_UNALIGNED
112		  || ((uintptr_t) file_phdr
113		      & (__alignof__ (ElfW2(LIBELFBITS,Phdr)) - 1)) == 0))
114	    /* Simply use the mapped data.  */
115	    elf->state.ELFW(elf,LIBELFBITS).phdr = file_phdr;
116	  else
117	    {
118	      ElfW2(LIBELFBITS,Phdr) *notcvt;
119	      ElfW2(LIBELFBITS,Phdr) *phdr;
120
121	      /* Allocate memory for the program headers.  We know the number
122		 of entries from the ELF header.  */
123	      phdr = elf->state.ELFW(elf,LIBELFBITS).phdr =
124		(ElfW2(LIBELFBITS,Phdr) *) malloc (size);
125	      if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
126		{
127		  __libelf_seterrno (ELF_E_NOMEM);
128		  goto out;
129		}
130	      elf->state.ELFW(elf,LIBELFBITS).phdr_flags |=
131		ELF_F_MALLOCED | ELF_F_DIRTY;
132
133	      /* Now copy the data and at the same time convert the
134		 byte order.  */
135
136	      if (ehdr->e_ident[EI_DATA] == MY_ELFDATA)
137		{
138		  assert (! ALLOW_UNALIGNED);
139		  memcpy (phdr, file_phdr, size);
140		}
141	      else
142		{
143		  bool copy = ! (ALLOW_UNALIGNED
144				 || ((uintptr_t) file_phdr
145				     & (__alignof__ (ElfW2(LIBELFBITS,Phdr))
146					- 1)) == 0);
147		  if (! copy)
148		    notcvt = file_phdr;
149		  else
150		    {
151		      notcvt = (ElfW2(LIBELFBITS,Phdr) *) malloc (size);
152		      if (unlikely (notcvt == NULL))
153			{
154			  __libelf_seterrno (ELF_E_NOMEM);
155			  goto out;
156			}
157		      memcpy (notcvt, file_phdr, size);
158		    }
159
160		  for (size_t cnt = 0; cnt < phnum; ++cnt)
161		    {
162		      CONVERT_TO (phdr[cnt].p_type, notcvt[cnt].p_type);
163		      CONVERT_TO (phdr[cnt].p_offset, notcvt[cnt].p_offset);
164		      CONVERT_TO (phdr[cnt].p_vaddr, notcvt[cnt].p_vaddr);
165		      CONVERT_TO (phdr[cnt].p_paddr, notcvt[cnt].p_paddr);
166		      CONVERT_TO (phdr[cnt].p_filesz, notcvt[cnt].p_filesz);
167		      CONVERT_TO (phdr[cnt].p_memsz, notcvt[cnt].p_memsz);
168		      CONVERT_TO (phdr[cnt].p_flags, notcvt[cnt].p_flags);
169		      CONVERT_TO (phdr[cnt].p_align, notcvt[cnt].p_align);
170		    }
171
172		  if (copy)
173		    free (notcvt);
174		}
175	    }
176	}
177      else if (likely (elf->fildes != -1))
178	{
179	  /* Allocate memory for the program headers.  We know the number
180	     of entries from the ELF header.  */
181	  elf->state.ELFW(elf,LIBELFBITS).phdr =
182	    (ElfW2(LIBELFBITS,Phdr) *) malloc (size);
183	  if (elf->state.ELFW(elf,LIBELFBITS).phdr == NULL)
184	    {
185	      __libelf_seterrno (ELF_E_NOMEM);
186	      goto out;
187	    }
188	  elf->state.ELFW(elf,LIBELFBITS).phdr_flags |= ELF_F_MALLOCED;
189
190	  /* Read the header.  */
191	  ssize_t n = pread_retry (elf->fildes,
192				   elf->state.ELFW(elf,LIBELFBITS).phdr, size,
193				   elf->start_offset + ehdr->e_phoff);
194	  if (unlikely ((size_t) n != size))
195	    {
196	      /* Severe problems.  We cannot read the data.  */
197	      __libelf_seterrno (ELF_E_READ_ERROR);
198	      free (elf->state.ELFW(elf,LIBELFBITS).phdr);
199	      elf->state.ELFW(elf,LIBELFBITS).phdr = NULL;
200	      goto out;
201	    }
202
203	  /* If the byte order of the file is not the same as the one
204	     of the host convert the data now.  */
205	  if (ehdr->e_ident[EI_DATA] != MY_ELFDATA)
206	    {
207	      ElfW2(LIBELFBITS,Phdr) *phdr
208		= elf->state.ELFW(elf,LIBELFBITS).phdr;
209
210	      for (size_t cnt = 0; cnt < phnum; ++cnt)
211		{
212		  CONVERT (phdr[cnt].p_type);
213		  CONVERT (phdr[cnt].p_offset);
214		  CONVERT (phdr[cnt].p_vaddr);
215		  CONVERT (phdr[cnt].p_paddr);
216		  CONVERT (phdr[cnt].p_filesz);
217		  CONVERT (phdr[cnt].p_memsz);
218		  CONVERT (phdr[cnt].p_flags);
219		  CONVERT (phdr[cnt].p_align);
220		}
221	    }
222	}
223      else
224	{
225	  /* The file descriptor was already enabled and not all data was
226	     read.  */
227	  __libelf_seterrno (ELF_E_FD_DISABLED);
228	  goto out;
229	}
230
231      result = elf->state.ELFW(elf,LIBELFBITS).phdr;
232    }
233
234 out:
235  return result;
236}
237
238ElfW2(LIBELFBITS,Phdr) *
239elfw2(LIBELFBITS,getphdr) (Elf *elf)
240{
241  ElfW2(LIBELFBITS,Phdr) *result;
242
243  if (elf == NULL)
244    return NULL;
245
246  if (unlikely (elf->kind != ELF_K_ELF))
247    {
248      __libelf_seterrno (ELF_E_INVALID_HANDLE);
249      return NULL;
250    }
251
252  /* If the program header entry has already been filled in the code
253   * in getphdr_wrlock must already have been run.  So the class is
254   * set, too.  No need to waste any more time here.  */
255  result = elf->state.ELFW(elf,LIBELFBITS).phdr;
256  if (likely (result != NULL))
257    return result;
258
259  rwlock_wrlock (elf->lock);
260  result = __elfw2(LIBELFBITS,getphdr_wrlock) (elf);
261  rwlock_unlock (elf->lock);
262
263  return result;
264}
265INTDEF(elfw2(LIBELFBITS,getphdr))
266