]> git.ipfire.org Git - thirdparty/glibc.git/blame - elf/readelflib.c
libio: Convert __vswprintf_internal to buffers (bug 27857)
[thirdparty/glibc.git] / elf / readelflib.c
CommitLineData
581c785b 1/* Copyright (C) 1999-2022 Free Software Foundation, Inc.
591e1ffb 2 This file is part of the GNU C Library.
591e1ffb
UD
3
4 The GNU C Library is free software; you can redistribute it and/or
41bdb6e2
AJ
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
591e1ffb
UD
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
41bdb6e2 12 Lesser General Public License for more details.
591e1ffb 13
41bdb6e2 14 You should have received a copy of the GNU Lesser General Public
59ba27a6 15 License along with the GNU C Library; if not, see
5a82c748 16 <https://www.gnu.org/licenses/>. */
591e1ffb 17
efbbd9c3
L
18#include <elf-read-prop.h>
19
591e1ffb
UD
20/* This code is a heavily simplified version of the readelf program
21 that's part of the current binutils development version. For architectures
22 which need to handle both 32bit and 64bit ELF libraries, this file is
23 included twice for each arch size. */
24
dc95d158
AJ
25/* check_ptr checks that a pointer is in the mmaped file and doesn't
26 point outside it. */
a0f5c800 27#undef check_ptr
dc95d158
AJ
28#define check_ptr(ptr) \
29do \
30 { \
31 if ((void *)(ptr) < file_contents \
32 || (void *)(ptr) > (file_contents+file_length)) \
33 { \
34 error (0, 0, _("file %s is truncated\n"), file_name); \
35 return 1; \
36 } \
37 } \
38 while (0);
c98d82db 39
591e1ffb
UD
40/* Returns 0 if everything is ok, != 0 in case of error. */
41int
dc95d158 42process_elf_file (const char *file_name, const char *lib, int *flag,
c628c229
AZ
43 unsigned int *isa_level, char **soname, void *file_contents,
44 size_t file_length)
591e1ffb
UD
45{
46 int i;
591e1ffb
UD
47 unsigned int dynamic_addr;
48 size_t dynamic_size;
49 char *program_interpreter;
c98d82db 50
591e1ffb
UD
51 ElfW(Ehdr) *elf_header;
52 ElfW(Phdr) *elf_pheader, *segment;
53 ElfW(Dyn) *dynamic_segment, *dyn_entry;
c98d82db 54 char *dynamic_strings;
591e1ffb
UD
55
56 elf_header = (ElfW(Ehdr) *) file_contents;
57
58 if (elf_header->e_ident [EI_CLASS] != ElfW (CLASS))
59 {
60 if (opt_verbose)
61 {
63fb40b3 62 if (elf_header->e_ident [EI_CLASS] == ELFCLASS32)
591e1ffb 63 error (0, 0, _("%s is a 32 bit ELF file.\n"), file_name);
63fb40b3 64 else if (elf_header->e_ident [EI_CLASS] == ELFCLASS64)
591e1ffb
UD
65 error (0, 0, _("%s is a 64 bit ELF file.\n"), file_name);
66 else
67 error (0, 0, _("Unknown ELFCLASS in file %s.\n"), file_name);
68 }
69 return 1;
70 }
71
72 if (elf_header->e_type != ET_DYN)
73 {
74 error (0, 0, _("%s is not a shared object file (Type: %d).\n"), file_name,
75 elf_header->e_type);
76 return 1;
77 }
c98d82db 78
591e1ffb
UD
79 /* Get information from elf program header. */
80 elf_pheader = (ElfW(Phdr) *) (elf_header->e_phoff + file_contents);
dc95d158 81 check_ptr (elf_pheader);
591e1ffb 82
8ee87859
LM
83 /* The library is an elf library. */
84 *flag = FLAG_ELF_LIBC6;
c98d82db 85
efbbd9c3
L
86 /* The default ISA level is 0. */
87 *isa_level = 0;
88
591e1ffb
UD
89 dynamic_addr = 0;
90 dynamic_size = 0;
91 program_interpreter = NULL;
92 for (i = 0, segment = elf_pheader;
93 i < elf_header->e_phnum; i++, segment++)
94 {
dc95d158
AJ
95 check_ptr (segment);
96
591e1ffb
UD
97 switch (segment->p_type)
98 {
591e1ffb
UD
99 case PT_DYNAMIC:
100 if (dynamic_addr)
101 error (0, 0, _("more than one dynamic segment\n"));
102
103 dynamic_addr = segment->p_offset;
104 dynamic_size = segment->p_filesz;
105 break;
a986484f 106
591e1ffb
UD
107 case PT_INTERP:
108 program_interpreter = (char *) (file_contents + segment->p_offset);
dc95d158 109 check_ptr (program_interpreter);
591e1ffb 110
efbbd9c3
L
111 case PT_GNU_PROPERTY:
112 /* The NT_GNU_PROPERTY_TYPE_0 note must be aligned to 4 bytes
113 in 32-bit objects and to 8 bytes in 64-bit objects. Skip
114 notes with incorrect alignment. */
115 if (segment->p_align == (__ELF_NATIVE_CLASS / 8))
116 {
117 const ElfW(Nhdr) *note = (const void *) (file_contents
118 + segment->p_offset);
119 const ElfW(Addr) size = segment->p_filesz;
120 const ElfW(Addr) align = segment->p_align;
121
122 const ElfW(Addr) start = (ElfW(Addr)) (uintptr_t) note;
123 unsigned int last_type = 0;
124
125 while ((ElfW(Addr)) (uintptr_t) (note + 1) - start < size)
126 {
127 /* Find the NT_GNU_PROPERTY_TYPE_0 note. */
128 if (note->n_namesz == 4
129 && note->n_type == NT_GNU_PROPERTY_TYPE_0
130 && memcmp (note + 1, "GNU", 4) == 0)
131 {
132 /* Check for invalid property. */
133 if (note->n_descsz < 8
134 || (note->n_descsz % sizeof (ElfW(Addr))) != 0)
135 goto done;
136
137 /* Start and end of property array. */
138 unsigned char *ptr = (unsigned char *) (note + 1) + 4;
139 unsigned char *ptr_end = ptr + note->n_descsz;
140
141 do
142 {
143 unsigned int type = *(unsigned int *) ptr;
144 unsigned int datasz = *(unsigned int *) (ptr + 4);
145
146 /* Property type must be in ascending order. */
147 if (type < last_type)
148 goto done;
149
150 ptr += 8;
151 if ((ptr + datasz) > ptr_end)
152 goto done;
153
154 last_type = type;
155
156 /* Target specific property processing.
157 Return value:
158 false: Continue processing the properties.
159 true : Stop processing the properties.
160 */
161 if (read_gnu_property (isa_level, type,
162 datasz, ptr))
163 goto done;
164
165 /* Check the next property item. */
166 ptr += ALIGN_UP (datasz, sizeof (ElfW(Addr)));
167 }
168 while ((ptr_end - ptr) >= 8);
169
170 /* Only handle one NT_GNU_PROPERTY_TYPE_0. */
171 goto done;
172 }
173
174 note = ((const void *) note
175 + ELF_NOTE_NEXT_OFFSET (note->n_namesz,
176 note->n_descsz,
177 align));
178 }
179 }
180done:
181 break;
182
591e1ffb
UD
183 default:
184 break;
185 }
c98d82db 186
591e1ffb 187 }
591e1ffb
UD
188
189 /* Now we can read the dynamic sections. */
190 if (dynamic_size == 0)
191 return 1;
c98d82db 192
591e1ffb 193 dynamic_segment = (ElfW(Dyn) *) (file_contents + dynamic_addr);
dc95d158 194 check_ptr (dynamic_segment);
591e1ffb
UD
195
196 /* Find the string table. */
197 dynamic_strings = NULL;
198 for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL;
199 ++dyn_entry)
200 {
dc95d158 201 check_ptr (dyn_entry);
591e1ffb
UD
202 if (dyn_entry->d_tag == DT_STRTAB)
203 {
58e8f5fd
AS
204 /* Find the file offset of the segment containing the dynamic
205 string table. */
206 ElfW(Off) loadoff = -1;
207 for (i = 0, segment = elf_pheader;
208 i < elf_header->e_phnum; i++, segment++)
209 {
210 if (segment->p_type == PT_LOAD
211 && dyn_entry->d_un.d_val >= segment->p_vaddr
212 && (dyn_entry->d_un.d_val - segment->p_vaddr
213 < segment->p_filesz))
214 {
215 loadoff = segment->p_vaddr - segment->p_offset;
216 break;
217 }
218 }
219 if (loadoff == (ElfW(Off)) -1)
220 {
221 /* Very strange. */
222 loadoff = 0;
223 }
224
225 dynamic_strings = (char *) (file_contents + dyn_entry->d_un.d_val
226 - loadoff);
dc95d158 227 check_ptr (dynamic_strings);
591e1ffb
UD
228 break;
229 }
230 }
231
232 if (dynamic_strings == NULL)
233 return 1;
234
8ee87859 235 /* Now read the DT_SONAME entries. */
591e1ffb
UD
236 for (dyn_entry = dynamic_segment; dyn_entry->d_tag != DT_NULL;
237 ++dyn_entry)
238 {
8ee87859 239 if (dyn_entry->d_tag == DT_SONAME)
591e1ffb
UD
240 {
241 char *name = dynamic_strings + dyn_entry->d_un.d_val;
dc95d158 242 check_ptr (name);
8ee87859
LM
243 *soname = xstrdup (name);
244 return 0;
591e1ffb
UD
245 }
246 }
247
591e1ffb
UD
248 return 0;
249}