1 /* Return section header.
2    Copyright (C) 1998-2002, 2005, 2007, 2009, 2012, 2014 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 <assert.h>
35 #include <errno.h>
36 #include <stdbool.h>
37 #include <unistd.h>
38 
39 #include <system.h>
40 #include "libelfP.h"
41 #include "common.h"
42 
43 #ifndef LIBELFBITS
44 # define LIBELFBITS 32
45 #endif
46 
47 
ElfW2(LIBELFBITS,Shdr)48 static ElfW2(LIBELFBITS,Shdr) *
49 load_shdr_wrlock (Elf_Scn *scn)
50 {
51   ElfW2(LIBELFBITS,Shdr) *result;
52 
53   /* Read the section header table.  */
54   Elf *elf = scn->elf;
55   ElfW2(LIBELFBITS,Ehdr) *ehdr = elf->state.ELFW(elf,LIBELFBITS).ehdr;
56 
57   /* Try again, maybe the data is there now.  */
58   result = scn->shdr.ELFW(e,LIBELFBITS);
59   if (result != NULL)
60     goto out;
61 
62   size_t shnum;
63   if (__elf_getshdrnum_rdlock (elf, &shnum) != 0
64       || shnum > SIZE_MAX / sizeof (ElfW2(LIBELFBITS,Shdr)))
65     goto out;
66   size_t size = shnum * sizeof (ElfW2(LIBELFBITS,Shdr));
67 
68   /* Allocate memory for the section headers.  We know the number
69      of entries from the ELF header.  */
70   ElfW2(LIBELFBITS,Shdr) *shdr = elf->state.ELFW(elf,LIBELFBITS).shdr =
71     (ElfW2(LIBELFBITS,Shdr) *) malloc (size);
72   if (elf->state.ELFW(elf,LIBELFBITS).shdr == NULL)
73     {
74       __libelf_seterrno (ELF_E_NOMEM);
75       goto out;
76     }
77   elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 1;
78 
79   if (elf->map_address != NULL)
80     {
81       /* First see whether the information in the ELF header is
82 	 valid and it does not ask for too much.  */
83       if (unlikely (ehdr->e_shoff >= elf->maximum_size)
84 	  || unlikely (elf->maximum_size - ehdr->e_shoff < size))
85 	{
86 	  /* Something is wrong.  */
87 	  __libelf_seterrno (ELF_E_INVALID_SECTION_HEADER);
88 	  goto free_and_out;
89 	}
90 
91       ElfW2(LIBELFBITS,Shdr) *notcvt;
92 
93       /* All the data is already mapped.  If we could use it
94 	 directly this would already have happened.  Unless
95 	 we allocated the memory ourselves and the ELF_F_MALLOCED
96 	 flag is set.  */
97       void *file_shdr = ((char *) elf->map_address
98 			 + elf->start_offset + ehdr->e_shoff);
99 
100       assert ((elf->flags & ELF_F_MALLOCED)
101 	      || ehdr->e_ident[EI_DATA] != MY_ELFDATA
102 	      || (! ALLOW_UNALIGNED
103 		  && ((uintptr_t) file_shdr
104 		      & (__alignof__ (ElfW2(LIBELFBITS,Shdr)) - 1)) != 0));
105 
106       /* Now copy the data and at the same time convert the byte order.  */
107       if (ehdr->e_ident[EI_DATA] == MY_ELFDATA)
108 	{
109 	  assert ((elf->flags & ELF_F_MALLOCED) || ! ALLOW_UNALIGNED);
110 	  memcpy (shdr, file_shdr, size);
111 	}
112       else
113 	{
114 	  if (ALLOW_UNALIGNED
115 	      || ((uintptr_t) file_shdr
116 		  & (__alignof__ (ElfW2(LIBELFBITS,Shdr)) - 1)) == 0)
117 	    notcvt = (ElfW2(LIBELFBITS,Shdr) *)
118 	      ((char *) elf->map_address
119 	       + elf->start_offset + ehdr->e_shoff);
120 	  else
121 	    {
122 	      notcvt = (ElfW2(LIBELFBITS,Shdr) *) alloca (size);
123 	      memcpy (notcvt, ((char *) elf->map_address
124 			       + elf->start_offset + ehdr->e_shoff),
125 		      size);
126 	    }
127 
128 	  for (size_t cnt = 0; cnt < shnum; ++cnt)
129 	    {
130 	      CONVERT_TO (shdr[cnt].sh_name, notcvt[cnt].sh_name);
131 	      CONVERT_TO (shdr[cnt].sh_type, notcvt[cnt].sh_type);
132 	      CONVERT_TO (shdr[cnt].sh_flags, notcvt[cnt].sh_flags);
133 	      CONVERT_TO (shdr[cnt].sh_addr, notcvt[cnt].sh_addr);
134 	      CONVERT_TO (shdr[cnt].sh_offset, notcvt[cnt].sh_offset);
135 	      CONVERT_TO (shdr[cnt].sh_size, notcvt[cnt].sh_size);
136 	      CONVERT_TO (shdr[cnt].sh_link, notcvt[cnt].sh_link);
137 	      CONVERT_TO (shdr[cnt].sh_info, notcvt[cnt].sh_info);
138 	      CONVERT_TO (shdr[cnt].sh_addralign,
139 			  notcvt[cnt].sh_addralign);
140 	      CONVERT_TO (shdr[cnt].sh_entsize, notcvt[cnt].sh_entsize);
141 
142 	      /* If this is a section with an extended index add a
143 		 reference in the section which uses the extended
144 		 index.  */
145 	      if (shdr[cnt].sh_type == SHT_SYMTAB_SHNDX
146 		  && shdr[cnt].sh_link < shnum)
147 		elf->state.ELFW(elf,LIBELFBITS).scns.data[shdr[cnt].sh_link].shndx_index
148 		  = cnt;
149 
150 	      /* Set the own shndx_index field in case it has not yet
151 		 been set.  */
152 	      if (elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index == 0)
153 		elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shndx_index
154 		  = -1;
155 	    }
156 	}
157     }
158   else if (likely (elf->fildes != -1))
159     {
160       /* Read the header.  */
161       ssize_t n = pread_retry (elf->fildes,
162 			       elf->state.ELFW(elf,LIBELFBITS).shdr, size,
163 			       elf->start_offset + ehdr->e_shoff);
164       if (unlikely ((size_t) n != size))
165 	{
166 	  /* Severe problems.  We cannot read the data.  */
167 	  __libelf_seterrno (ELF_E_READ_ERROR);
168 	  goto free_and_out;
169 	}
170 
171       /* If the byte order of the file is not the same as the one
172 	 of the host convert the data now.  */
173       if (ehdr->e_ident[EI_DATA] != MY_ELFDATA)
174 	for (size_t cnt = 0; cnt < shnum; ++cnt)
175 	  {
176 	    CONVERT (shdr[cnt].sh_name);
177 	    CONVERT (shdr[cnt].sh_type);
178 	    CONVERT (shdr[cnt].sh_flags);
179 	    CONVERT (shdr[cnt].sh_addr);
180 	    CONVERT (shdr[cnt].sh_offset);
181 	    CONVERT (shdr[cnt].sh_size);
182 	    CONVERT (shdr[cnt].sh_link);
183 	    CONVERT (shdr[cnt].sh_info);
184 	    CONVERT (shdr[cnt].sh_addralign);
185 	    CONVERT (shdr[cnt].sh_entsize);
186 	  }
187     }
188   else
189     {
190       /* The file descriptor was already enabled and not all data was
191 	 read.  Undo the allocation.  */
192       __libelf_seterrno (ELF_E_FD_DISABLED);
193 
194     free_and_out:
195       free (shdr);
196       elf->state.ELFW(elf,LIBELFBITS).shdr = NULL;
197       elf->state.ELFW(elf,LIBELFBITS).shdr_malloced = 0;
198 
199       goto out;
200     }
201 
202   /* Set the pointers in the `scn's.  */
203   for (size_t cnt = 0; cnt < shnum; ++cnt)
204     elf->state.ELFW(elf,LIBELFBITS).scns.data[cnt].shdr.ELFW(e,LIBELFBITS)
205       = &elf->state.ELFW(elf,LIBELFBITS).shdr[cnt];
206 
207   result = scn->shdr.ELFW(e,LIBELFBITS);
208   assert (result != NULL);
209 
210 out:
211   return result;
212 }
213 
214 static bool
scn_valid(Elf_Scn * scn)215 scn_valid (Elf_Scn *scn)
216 {
217   if (scn == NULL)
218     return false;
219 
220   if (unlikely (scn->elf->state.elf.ehdr == NULL))
221     {
222       __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR);
223       return false;
224     }
225 
226   if (unlikely (scn->elf->class != ELFW(ELFCLASS,LIBELFBITS)))
227     {
228       __libelf_seterrno (ELF_E_INVALID_CLASS);
229       return false;
230     }
231 
232   return true;
233 }
234 
235 ElfW2(LIBELFBITS,Shdr) *
236 __elfw2(LIBELFBITS,getshdr_rdlock) (scn)
237      Elf_Scn *scn;
238 {
239   ElfW2(LIBELFBITS,Shdr) *result;
240 
241   if (!scn_valid (scn))
242     return NULL;
243 
244   result = scn->shdr.ELFW(e,LIBELFBITS);
245   if (result == NULL)
246     {
247       rwlock_unlock (scn->elf->lock);
248       rwlock_wrlock (scn->elf->lock);
249       result = scn->shdr.ELFW(e,LIBELFBITS);
250       if (result == NULL)
251 	result = load_shdr_wrlock (scn);
252     }
253 
254   return result;
255 }
256 
257 ElfW2(LIBELFBITS,Shdr) *
258 __elfw2(LIBELFBITS,getshdr_wrlock) (scn)
259      Elf_Scn *scn;
260 {
261   ElfW2(LIBELFBITS,Shdr) *result;
262 
263   if (!scn_valid (scn))
264     return NULL;
265 
266   result = scn->shdr.ELFW(e,LIBELFBITS);
267   if (result == NULL)
268     result = load_shdr_wrlock (scn);
269 
270   return result;
271 }
272 
273 ElfW2(LIBELFBITS,Shdr) *
274 elfw2(LIBELFBITS,getshdr) (scn)
275      Elf_Scn *scn;
276 {
277   ElfW2(LIBELFBITS,Shdr) *result;
278 
279   if (!scn_valid (scn))
280     return NULL;
281 
282   rwlock_rdlock (scn->elf->lock);
283   result = __elfw2(LIBELFBITS,getshdr_rdlock) (scn);
284   rwlock_unlock (scn->elf->lock);
285 
286   return result;
287 }
288