/src/libbpf/elfutils/libelf/elf_getphdrnum.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Return number of program headers in the ELF file. |
2 | | Copyright (C) 2010, 2014, 2015, 2016 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 |
41 | | internal_function |
42 | | __elf_getphdrnum_rdlock (Elf *elf, size_t *dst) |
43 | 0 | { |
44 | 0 | if (unlikely (elf->state.elf64.ehdr == NULL)) |
45 | 0 | { |
46 | | /* Maybe no ELF header was created yet. */ |
47 | 0 | *dst = 0; |
48 | 0 | __libelf_seterrno (ELF_E_WRONG_ORDER_EHDR); |
49 | 0 | return -1; |
50 | 0 | } |
51 | | |
52 | 0 | *dst = (elf->class == ELFCLASS32 |
53 | 0 | ? elf->state.elf32.ehdr->e_phnum |
54 | 0 | : elf->state.elf64.ehdr->e_phnum); |
55 | |
|
56 | 0 | if (*dst == PN_XNUM) |
57 | 0 | { |
58 | 0 | const Elf_ScnList *const scns = (elf->class == ELFCLASS32 |
59 | 0 | ? &elf->state.elf32.scns |
60 | 0 | : &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 | 0 | if (elf->class == ELFCLASS32) |
66 | 0 | { |
67 | 0 | if (likely (scns->cnt > 0)) |
68 | 0 | { |
69 | 0 | Elf_Scn *scn = &elf->state.elf32.scns.data[0]; |
70 | 0 | Elf32_Shdr *shdr = scn->shdr.e32 ?: __elf32_getshdr_rdlock (scn); |
71 | 0 | if (shdr) |
72 | 0 | *dst = shdr->sh_info; |
73 | 0 | } |
74 | 0 | } |
75 | 0 | else |
76 | 0 | { |
77 | 0 | if (likely (scns->cnt > 0)) |
78 | 0 | { |
79 | 0 | Elf_Scn *scn = &elf->state.elf64.scns.data[0]; |
80 | 0 | Elf64_Shdr *shdr = scn->shdr.e64 ?: __elf64_getshdr_rdlock (scn); |
81 | 0 | if (shdr) |
82 | 0 | *dst = shdr->sh_info; |
83 | 0 | } |
84 | 0 | } |
85 | 0 | } |
86 | |
|
87 | 0 | return 0; |
88 | 0 | } |
89 | | |
90 | | int |
91 | | internal_function |
92 | | __elf_getphdrnum_chk_rdlock (Elf *elf, size_t *dst) |
93 | 0 | { |
94 | 0 | int result = __elf_getphdrnum_rdlock (elf, dst); |
95 | | |
96 | | /* If the phdrs haven't been created or read in yet then do some |
97 | | sanity checking to make sure phnum and phoff are consistent. */ |
98 | 0 | if (elf->state.elf.phdr == NULL) |
99 | 0 | { |
100 | 0 | Elf64_Off off = (elf->class == ELFCLASS32 |
101 | 0 | ? elf->state.elf32.ehdr->e_phoff |
102 | 0 | : elf->state.elf64.ehdr->e_phoff); |
103 | 0 | if (unlikely (off == 0)) |
104 | 0 | { |
105 | 0 | *dst = 0; |
106 | 0 | return result; |
107 | 0 | } |
108 | | |
109 | 0 | if (unlikely (off >= elf->maximum_size)) |
110 | 0 | { |
111 | 0 | __libelf_seterrno (ELF_E_INVALID_DATA); |
112 | 0 | return -1; |
113 | 0 | } |
114 | | |
115 | | /* Check for too many sections. */ |
116 | 0 | size_t phdr_size = (elf->class == ELFCLASS32 |
117 | 0 | ? sizeof (Elf32_Phdr) : sizeof (Elf64_Phdr)); |
118 | 0 | if (unlikely (*dst > SIZE_MAX / phdr_size)) |
119 | 0 | { |
120 | 0 | __libelf_seterrno (ELF_E_INVALID_DATA); |
121 | 0 | return -1; |
122 | 0 | } |
123 | | |
124 | | /* Truncated file? Don't return more than can be indexed. */ |
125 | 0 | if (unlikely (elf->maximum_size - off < *dst * phdr_size)) |
126 | 0 | *dst = (elf->maximum_size - off) / phdr_size; |
127 | 0 | } |
128 | | |
129 | 0 | return result; |
130 | 0 | } |
131 | | |
132 | | int |
133 | | elf_getphdrnum (Elf *elf, size_t *dst) |
134 | 0 | { |
135 | 0 | int result; |
136 | |
|
137 | 0 | if (elf == NULL) |
138 | 0 | return -1; |
139 | | |
140 | 0 | if (unlikely (elf->kind != ELF_K_ELF)) |
141 | 0 | { |
142 | 0 | __libelf_seterrno (ELF_E_INVALID_HANDLE); |
143 | 0 | return -1; |
144 | 0 | } |
145 | | |
146 | 0 | rwlock_rdlock (elf->lock); |
147 | 0 | result = __elf_getphdrnum_chk_rdlock (elf, dst); |
148 | 0 | rwlock_unlock (elf->lock); |
149 | |
|
150 | 0 | return result; |
151 | 0 | } |