1 /* Return number of program headers in the ELF file.
2    Copyright (C) 2010, 2014 Red Hat, Inc.
3    This file is part of elfutils.
4 
5    This file is free software; you can redistribute it and/or modify
6    it under the terms of either
7 
8      * the GNU Lesser General Public License as published by the Free
9        Software Foundation; either version 3 of the License, or (at
10        your option) any later version
11 
12    or
13 
14      * the GNU General Public License as published by the Free
15        Software Foundation; either version 2 of the License, or (at
16        your option) any later version
17 
18    or both in parallel, as here.
19 
20    elfutils is distributed in the hope that it will be useful, but
21    WITHOUT ANY WARRANTY; without even the implied warranty of
22    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23    General Public License for more details.
24 
25    You should have received copies of the GNU General Public License and
26    the GNU Lesser General Public License along with this program.  If
27    not, see <http://www.gnu.org/licenses/>.  */
28 
29 #ifdef HAVE_CONFIG_H
30 # include <config.h>
31 #endif
32 
33 #include <assert.h>
34 #include <gelf.h>
35 #include <stddef.h>
36 
37 #include "libelfP.h"
38 
39 
40 int
__elf_getphdrnum_rdlock(elf,dst)41 __elf_getphdrnum_rdlock (elf, dst)
42      Elf *elf;
43      size_t *dst;
44 {
45  if (unlikely (elf->state.elf64.ehdr == NULL))
46    {
47      /* Maybe no ELF header was created yet.  */
48      __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR);
49      return -1;
50    }
51 
52  *dst = (elf->class == ELFCLASS32
53 	 ? elf->state.elf32.ehdr->e_phnum
54 	 : elf->state.elf64.ehdr->e_phnum);
55 
56  if (*dst == PN_XNUM)
57    {
58      const Elf_ScnList *const scns = (elf->class == ELFCLASS32
59 				      ? &elf->state.elf32.scns
60 				      : &elf->state.elf64.scns);
61 
62      /* If there are no section headers, perhaps this is really just 65536
63 	written without PN_XNUM support.  Either that or it's bad data.  */
64 
65      if (elf->class == ELFCLASS32)
66        {
67 	 if (likely (scns->cnt > 0
68 		     && elf->state.elf32.scns.data[0].shdr.e32 != NULL))
69 	   *dst = scns->data[0].shdr.e32->sh_info;
70        }
71      else
72        {
73 	 if (likely (scns->cnt > 0
74 		     && elf->state.elf64.scns.data[0].shdr.e64 != NULL))
75 	   *dst = scns->data[0].shdr.e64->sh_info;
76        }
77    }
78 
79  return 0;
80 }
81 
82 int
elf_getphdrnum(elf,dst)83 elf_getphdrnum (elf, dst)
84      Elf *elf;
85      size_t *dst;
86 {
87   int result;
88 
89   if (elf == NULL)
90     return -1;
91 
92   if (unlikely (elf->kind != ELF_K_ELF))
93     {
94       __libelf_seterrno (ELF_E_INVALID_HANDLE);
95       return -1;
96     }
97 
98   rwlock_rdlock (elf->lock);
99   result = __elf_getphdrnum_rdlock (elf, dst);
100 
101   /* Do some sanity checking to make sure phnum and phoff are consistent.  */
102   Elf64_Off off = (elf->class == ELFCLASS32
103 		   ? elf->state.elf32.ehdr->e_phoff
104 		   : elf->state.elf64.ehdr->e_phoff);
105   if (unlikely (off == 0))
106     {
107       *dst = 0;
108       goto out;
109     }
110 
111   if (unlikely (off >= elf->maximum_size))
112     {
113       __libelf_seterrno (ELF_E_INVALID_DATA);
114       result = -1;
115       goto out;
116     }
117 
118   /* Check for too many sections.  */
119   size_t phdr_size = (elf->class == ELFCLASS32
120 		      ? sizeof (Elf32_Phdr) : sizeof (Elf64_Phdr));
121   if (unlikely (*dst > SIZE_MAX / phdr_size))
122     {
123       __libelf_seterrno (ELF_E_INVALID_DATA);
124       result = -1;
125       goto out;
126     }
127 
128   /* Truncated file?  Don't return more than can be indexed.  */
129   if (unlikely (elf->maximum_size - off < *dst * phdr_size))
130     *dst = (elf->maximum_size - off) / phdr_size;
131 
132 out:
133   rwlock_unlock (elf->lock);
134 
135   return result;
136 }
137