/[gentoo-projects]/pax-utils/scanelf.c
Gentoo

Diff of /pax-utils/scanelf.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

Revision 1.35 Revision 1.164
1/* 1/*
2 * Copyright 2003 Ned Ludd <solar@gentoo.org>
3 * Copyright 1999-2005 Gentoo Foundation 2 * Copyright 2003-2006 Gentoo Foundation
4 * Distributed under the terms of the GNU General Public License v2 3 * Distributed under the terms of the GNU General Public License v2
5 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.35 2005/04/14 00:17:30 solar Exp $ 4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.164 2006/12/03 00:17:18 solar Exp $
6 * 5 *
7 ******************************************************************** 6 * Copyright 2003-2006 Ned Ludd - <solar@gentoo.org>
8 * This program is free software; you can redistribute it and/or 7 * Copyright 2004-2006 Mike Frysinger - <vapier@gentoo.org>
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the
11 * License, or (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
21 * MA 02111-1307, USA.
22 */ 8 */
23 9
24#include <stdio.h>
25#include <stdlib.h>
26#include <sys/types.h>
27#define __USE_GNU
28#include <string.h>
29#include <errno.h>
30#include <unistd.h>
31#include <sys/stat.h>
32#include <dirent.h>
33#include <getopt.h>
34#include <assert.h>
35
36#include "paxelf.h" 10#include "paxinc.h"
37 11
38static const char *rcsid = "$Id: scanelf.c,v 1.35 2005/04/14 00:17:30 solar Exp $"; 12static const char *rcsid = "$Id: scanelf.c,v 1.164 2006/12/03 00:17:18 solar Exp $";
13#define argv0 "scanelf"
39 14
15#define IS_MODIFIER(c) (c == '%' || c == '#' || c == '+')
40 16
41/* helper functions for showing errors */ 17#define do_state(option, flag) \
42#define argv0 "scanelf" /*((*argv != NULL) ? argv[0] : __FILE__ "\b\b")*/ 18 if (islower(option)) { \
43#define warn(fmt, args...) \ 19 flags &= ~PF_##flag; \
44 fprintf(stderr, "%s: " fmt "\n", argv0, ## args) 20 flags |= PF_NO##flag; \
45#define warnf(fmt, args...) warn("%s(): " fmt, __FUNCTION__, ## args) 21 } else { \
46#define err(fmt, args...) \ 22 flags &= ~PF_NO##flag; \
47 do { \ 23 flags |= PF_##flag; \
48 warn(fmt, ## args); \ 24 }
49 exit(EXIT_FAILURE); \
50 } while (0)
51
52 25
53 26
54/* prototypes */ 27/* prototypes */
55static void scanelf_file(const char *filename); 28static int file_matches_list(const char *filename, char **matchlist);
29static int scanelf_elfobj(elfobj *elf);
30static int scanelf_elf(const char *filename, int fd, size_t len);
31static int scanelf_archive(const char *filename, int fd, size_t len);
32static int scanelf_file(const char *filename, const struct stat *st_cache);
56static void scanelf_dir(const char *path); 33static int scanelf_dir(const char *path);
57static void scanelf_ldpath(); 34static void scanelf_ldpath(void);
58static void scanelf_envpath(); 35static void scanelf_envpath(void);
59static void usage(int status); 36static void usage(int status);
37static char **get_split_env(const char *envvar);
38static void parseenv(void);
60static void parseargs(int argc, char *argv[]); 39static int parseargs(int argc, char *argv[]);
40static char *xstrdup(const char *s);
41static void *xmalloc(size_t size);
42static void *xrealloc(void *ptr, size_t size);
43static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n);
44#define xstrcat(dst,src,curr_len) xstrncat(dst,src,curr_len,0)
45static inline void xchrcat(char **dst, const char append, size_t *curr_len);
61 46
62/* variables to control behavior */ 47/* variables to control behavior */
48static char match_etypes[126] = "";
49static char *ldpaths[256];
63static char scan_ldpath = 0; 50static char scan_ldpath = 0;
64static char scan_envpath = 0; 51static char scan_envpath = 0;
52static char scan_symlink = 1;
53static char scan_archives = 0;
65static char dir_recurse = 0; 54static char dir_recurse = 0;
66static char dir_crossmount = 1; 55static char dir_crossmount = 1;
67static char show_pax = 0; 56static char show_pax = 0;
68static char show_stack = 0; 57static char show_phdr = 0;
69static char show_textrel = 0; 58static char show_textrel = 0;
70static char show_rpath = 0; 59static char show_rpath = 0;
71static char show_needed = 0; 60static char show_needed = 0;
61static char show_interp = 0;
62static char show_bind = 0;
63static char show_soname = 0;
64static char show_textrels = 0;
72static char show_banner = 1; 65static char show_banner = 1;
73static char be_quiet = 0; 66static char be_quiet = 0;
74static char be_verbose = 0; 67static char be_verbose = 0;
68static char be_wewy_wewy_quiet = 0;
69static char be_semi_verbose = 0;
70static char *find_sym = NULL, *versioned_symname = NULL;
75static char *find_sym = NULL; 71static char *find_lib = NULL;
72static char *find_section = NULL;
73static char *out_format = NULL;
74static char *search_path = NULL;
75static char fix_elf = 0;
76static char gmatch = 0;
77static char use_ldcache = 0;
76 78
79static char **qa_textrels = NULL;
80static char **qa_execstack = NULL;
81static char **qa_wx_load = NULL;
77 82
83int match_bits = 0;
84caddr_t ldcache = 0;
85size_t ldcache_size = 0;
86unsigned long setpax = 0UL;
78 87
79/* scan an elf file and show all the fun stuff */ 88
80static void scanelf_file(const char *filename) 89
90/* sub-funcs for scanelf_file() */
91static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
81{ 92{
82 int i; 93 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
83 char found_pax, found_stack, found_relro, found_textrel, 94#define GET_SYMTABS(B) \
84 found_rpath, found_needed, found_sym; 95 if (elf->elf_class == ELFCLASS ## B) { \
85 elfobj *elf; 96 Elf ## B ## _Shdr *symtab, *strtab, *dynsym, *dynstr; \
97 /* debug sections */ \
98 symtab = SHDR ## B (elf_findsecbyname(elf, ".symtab")); \
99 strtab = SHDR ## B (elf_findsecbyname(elf, ".strtab")); \
100 /* runtime sections */ \
101 dynsym = SHDR ## B (elf_findsecbyname(elf, ".dynsym")); \
102 dynstr = SHDR ## B (elf_findsecbyname(elf, ".dynstr")); \
103 if (symtab && dynsym) { \
104 *sym = (void*)((EGET(symtab->sh_size) > EGET(dynsym->sh_size)) ? symtab : dynsym); \
105 } else { \
106 *sym = (void*)(symtab ? symtab : dynsym); \
107 } \
108 if (strtab && dynstr) { \
109 *tab = (void*)((EGET(strtab->sh_size) > EGET(dynstr->sh_size)) ? strtab : dynstr); \
110 } else { \
111 *tab = (void*)(strtab ? strtab : dynstr); \
112 } \
113 }
114 GET_SYMTABS(32)
115 GET_SYMTABS(64)
116}
117
118static char *scanelf_file_pax(elfobj *elf, char *found_pax)
119{
120 static char ret[7];
121 unsigned long i, shown;
122
123 if (!show_pax) return NULL;
124
125 shown = 0;
126 memset(&ret, 0, sizeof(ret));
127
128 if (elf->phdr) {
129#define SHOW_PAX(B) \
130 if (elf->elf_class == ELFCLASS ## B) { \
131 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
132 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
133 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
134 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
135 continue; \
136 if (fix_elf && setpax) { \
137 /* set the paxctl flags */ \
138 ESET(phdr[i].p_flags, setpax); \
139 } \
140 if (be_quiet && (EGET(phdr[i].p_flags) == (PF_NOEMUTRAMP | PF_NORANDEXEC))) \
141 continue; \
142 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
143 *found_pax = 1; \
144 ++shown; \
145 break; \
146 } \
147 }
148 SHOW_PAX(32)
149 SHOW_PAX(64)
150 }
151
152
153 if (fix_elf && setpax) {
154 /* set the chpax settings */
155 if (elf->elf_class == ELFCLASS32) {
156 if (EHDR32(elf->ehdr)->e_type == ET_DYN || EHDR32(elf->ehdr)->e_type == ET_EXEC)
157 ESET(EHDR32(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
158 } else {
159 if (EHDR64(elf->ehdr)->e_type == ET_DYN || EHDR64(elf->ehdr)->e_type == ET_EXEC)
160 ESET(EHDR64(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
161 }
162 }
163
164 /* fall back to EI_PAX if no PT_PAX was found */
165 if (!*ret) {
166 static char *paxflags;
167 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
168 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
169 *found_pax = 1;
170 return (be_wewy_wewy_quiet ? NULL : paxflags);
171 }
172 strncpy(ret, paxflags, sizeof(ret));
173 }
174
175 if (be_wewy_wewy_quiet || (be_quiet && !shown))
176 return NULL;
177 else
178 return ret;
179}
180
181static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load)
182{
183 static char ret[12];
184 char *found;
185 unsigned long i, shown, multi_stack, multi_relro, multi_load;
186 int max_pt_load;
187
188 if (!show_phdr) return NULL;
189
190 memcpy(ret, "--- --- ---\0", 12);
191
192 shown = 0;
193 multi_stack = multi_relro = multi_load = 0;
194 max_pt_load = elf_max_pt_load(elf);
195
196#define NOTE_GNU_STACK ".note.GNU-stack"
197#define SHOW_PHDR(B) \
198 if (elf->elf_class == ELFCLASS ## B) { \
199 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
200 Elf ## B ## _Off offset; \
201 uint32_t flags, check_flags; \
202 if (elf->phdr != NULL) { \
203 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
204 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
205 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
206 if (multi_stack++) \
207 warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
208 if (file_matches_list(elf->filename, qa_execstack)) \
209 continue; \
210 found = found_phdr; \
211 offset = 0; \
212 check_flags = PF_X; \
213 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
214 if (multi_relro++) \
215 warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
216 found = found_relro; \
217 offset = 4; \
218 check_flags = PF_X; \
219 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
220 if (ehdr->e_type == ET_DYN || ehdr->e_type == ET_EXEC) \
221 if (multi_load++ > max_pt_load) \
222 warnf("%s: more than %i PT_LOAD's !?", elf->filename, max_pt_load); \
223 if (file_matches_list(elf->filename, qa_wx_load)) \
224 continue; \
225 found = found_load; \
226 offset = 8; \
227 check_flags = PF_W|PF_X; \
228 } else \
229 continue; \
230 flags = EGET(phdr[i].p_flags); \
231 if (be_quiet && ((flags & check_flags) != check_flags)) \
232 continue; \
233 if ((EGET(phdr[i].p_type) != PT_LOAD) && (fix_elf && ((flags & PF_X) != flags))) { \
234 ESET(phdr[i].p_flags, flags & (PF_X ^ (size_t)-1)); \
235 ret[3] = ret[7] = '!'; \
236 flags = EGET(phdr[i].p_flags); \
237 } \
238 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
239 *found = 1; \
240 ++shown; \
241 } \
242 } else if (elf->shdr != NULL) { \
243 /* no program headers which means this is prob an object file */ \
244 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
245 Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \
246 char *str; \
247 if ((void*)strtbl > (void*)elf->data_end) \
248 goto skip_this_shdr##B; \
249 check_flags = SHF_WRITE|SHF_EXECINSTR; \
250 for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \
251 if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \
252 offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \
253 str = elf->data + offset; \
254 if (str > elf->data + offset + sizeof(NOTE_GNU_STACK)) continue; \
255 if (!strcmp(str, NOTE_GNU_STACK)) { \
256 if (multi_stack++) warnf("%s: multiple .note.GNU-stack's !?", elf->filename); \
257 flags = EGET(shdr[i].sh_flags); \
258 if (be_quiet && ((flags & check_flags) != check_flags)) \
259 continue; \
260 ++*found_phdr; \
261 shown = 1; \
262 if (flags & SHF_WRITE) ret[0] = 'W'; \
263 if (flags & SHF_ALLOC) ret[1] = 'A'; \
264 if (flags & SHF_EXECINSTR) ret[2] = 'X'; \
265 if (flags & 0xFFFFFFF8) warn("Invalid section flags for GNU-stack"); \
266 break; \
267 } \
268 } \
269 skip_this_shdr##B: \
270 if (!multi_stack) { \
271 if (file_matches_list(elf->filename, qa_execstack)) \
272 return NULL; \
273 *found_phdr = 1; \
274 shown = 1; \
275 memcpy(ret, "!WX", 3); \
276 } \
277 } \
278 }
279 SHOW_PHDR(32)
280 SHOW_PHDR(64)
281
282 if (be_wewy_wewy_quiet || (be_quiet && !shown))
283 return NULL;
284 else
285 return ret;
286}
287
288static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
289{
290 static const char *ret = "TEXTREL";
291 unsigned long i;
292
293 if (!show_textrel && !show_textrels) return NULL;
294
295 if (file_matches_list(elf->filename, qa_textrels)) return NULL;
296
297 if (elf->phdr) {
298#define SHOW_TEXTREL(B) \
299 if (elf->elf_class == ELFCLASS ## B) { \
300 Elf ## B ## _Dyn *dyn; \
301 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
302 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
303 Elf ## B ## _Off offset; \
304 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
305 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
306 offset = EGET(phdr[i].p_offset); \
307 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
308 dyn = DYN ## B (elf->data + offset); \
309 while (EGET(dyn->d_tag) != DT_NULL) { \
310 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
311 *found_textrel = 1; \
312 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
313 return (be_wewy_wewy_quiet ? NULL : ret); \
314 } \
315 ++dyn; \
316 } \
317 } }
318 SHOW_TEXTREL(32)
319 SHOW_TEXTREL(64)
320 }
321
322 if (be_quiet || be_wewy_wewy_quiet)
323 return NULL;
324 else
325 return " - ";
326}
327static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel)
328{
329 unsigned long s, r, rmax;
330 void *symtab_void, *strtab_void, *text_void;
331
332 if (!show_textrels) return NULL;
333
334 /* don't search for TEXTREL's if the ELF doesn't have any */
335 if (!*found_textrel) scanelf_file_textrel(elf, found_textrel);
336 if (!*found_textrel) return NULL;
337
338 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
339 text_void = elf_findsecbyname(elf, ".text");
340
341 if (symtab_void && strtab_void && text_void && elf->shdr) {
342#define SHOW_TEXTRELS(B) \
343 if (elf->elf_class == ELFCLASS ## B) { \
344 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
345 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
346 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
347 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
348 Elf ## B ## _Shdr *text = SHDR ## B (text_void); \
349 Elf ## B ## _Addr vaddr = EGET(text->sh_addr); \
350 uint ## B ## _t memsz = EGET(text->sh_size); \
351 Elf ## B ## _Rel *rel; \
352 Elf ## B ## _Rela *rela; \
353 /* search the section headers for relocations */ \
354 for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \
355 uint32_t sh_type = EGET(shdr[s].sh_type); \
356 if (sh_type == SHT_REL) { \
357 rel = REL ## B (elf->data + EGET(shdr[s].sh_offset)); \
358 rela = NULL; \
359 rmax = EGET(shdr[s].sh_size) / sizeof(*rel); \
360 } else if (sh_type == SHT_RELA) { \
361 rel = NULL; \
362 rela = RELA ## B (elf->data + EGET(shdr[s].sh_offset)); \
363 rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \
364 } else \
365 continue; \
366 /* now see if any of the relocs are in the .text */ \
367 for (r = 0; r < rmax; ++r) { \
368 unsigned long sym_max; \
369 Elf ## B ## _Addr offset_tmp; \
370 Elf ## B ## _Sym *func; \
371 Elf ## B ## _Sym *sym; \
372 Elf ## B ## _Addr r_offset; \
373 uint ## B ## _t r_info; \
374 if (sh_type == SHT_REL) { \
375 r_offset = EGET(rel[r].r_offset); \
376 r_info = EGET(rel[r].r_info); \
377 } else { \
378 r_offset = EGET(rela[r].r_offset); \
379 r_info = EGET(rela[r].r_info); \
380 } \
381 /* make sure this relocation is inside of the .text */ \
382 if (r_offset < vaddr || r_offset >= vaddr + memsz) { \
383 if (be_verbose <= 2) continue; \
384 } else \
385 *found_textrels = 1; \
386 /* locate this relocation symbol name */ \
387 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
388 if ((void*)sym > (void*)elf->data_end) { \
389 warn("%s: corrupt ELF symbol", elf->filename); \
390 continue; \
391 } \
392 sym_max = ELF ## B ## _R_SYM(r_info); \
393 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
394 sym += sym_max; \
395 else \
396 sym = NULL; \
397 sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
398 /* show the raw details about this reloc */ \
399 printf(" %s: ", elf->base_filename); \
400 if (sym && sym->st_name) \
401 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
402 else \
403 printf("(memory/fake?)"); \
404 printf(" [0x%lX]", (unsigned long)r_offset); \
405 /* now try to find the closest symbol that this rel is probably in */ \
406 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
407 func = NULL; \
408 offset_tmp = 0; \
409 while (sym_max--) { \
410 if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \
411 func = sym; \
412 offset_tmp = EGET(sym->st_value); \
413 } \
414 ++sym; \
415 } \
416 printf(" in "); \
417 if (func && func->st_name) \
418 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(func->st_name))); \
419 else \
420 printf("(NULL: fake?)"); \
421 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
422 } \
423 } }
424 SHOW_TEXTRELS(32)
425 SHOW_TEXTRELS(64)
426 }
427 if (!*found_textrels)
428 warnf("ELF %s has TEXTREL markings but doesnt appear to have any real TEXTREL's !?", elf->filename);
429
430 return NULL;
431}
432
433static void rpath_security_checks(elfobj *, char *, const char *);
434static void rpath_security_checks(elfobj *elf, char *item, const char *dt_type)
435{
86 struct stat st; 436 struct stat st;
87 437 switch (*item) {
88 /* make sure path exists */ 438 case '/': break;
89 if (lstat(filename, &st) == -1) 439 case '.':
90 return; 440 warnf("Security problem with relative %s '%s' in %s", dt_type, item, elf->filename);
91 if (!S_ISREG(st.st_mode)) 441 break;
92 return; 442 case ':':
93 found_pax = found_stack = found_relro = found_textrel = \ 443 case '\0':
94 found_rpath = found_needed = found_sym = 0; 444 warnf("Security problem NULL %s in %s", dt_type, elf->filename);
95 445 break;
96 /* verify this is real ELF */ 446 case '$':
97 if ((elf = readelf(filename)) == NULL) { 447 if (fstat(elf->fd, &st) != -1)
98 if (be_verbose > 2) printf("%s: not an ELF\n", filename); 448 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
99 return; 449 warnf("Security problem with %s='%s' in %s with mode set of %o",
100 } 450 dt_type, item, elf->filename, st.st_mode & 07777);
101 451 break;
102 if (be_verbose > 1) 452 default:
103 printf("%s: {%s,%s} scanning file\n", filename, 453 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename);
104 get_elfeitype(elf, EI_CLASS, elf->elf_class), 454 break;
105 get_elfeitype(elf, EI_DATA, elf->data[EI_DATA]));
106 else if (be_verbose)
107 printf("%s: scanning file\n", filename);
108
109 /* show the header */
110 if (!be_quiet && show_banner) {
111 printf(" TYPE ");
112 if (show_pax) printf(" PAX ");
113 if (show_stack) printf("STK/REL ");
114 if (show_textrel) printf("TEXTREL ");
115 if (show_rpath) printf("RPATH ");
116 if (show_needed) printf("NEEDED ");
117 printf(" FILE\n");
118 show_banner = 0;
119 }
120
121 /* dump all the good stuff */
122 if (!be_quiet)
123 printf("%-7s ", get_elfetype(elf));
124
125 if (show_pax) {
126 char *paxflags = pax_short_hf_flags(PAX_FLAGS(elf));
127 if (!be_quiet || (be_quiet && strncmp(paxflags, "PeMRxS", 6))) {
128 found_pax = 1;
129 printf("%s ", pax_short_hf_flags(PAX_FLAGS(elf)));
130 } 455 }
131 } 456}
132 457static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
133 /* stack fun */ 458{
134 if (show_stack) { 459 unsigned long i, s;
135#define SHOW_STACK(B) \
136 if (elf->elf_class == ELFCLASS ## B) { \
137 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
138 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
139 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
140 if (EGET(phdr[i].p_type) != PT_GNU_STACK && \
141 EGET(phdr[i].p_type) != PT_GNU_RELRO) continue; \
142 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \
143 continue; \
144 if (EGET(phdr[i].p_type) == PT_GNU_STACK) \
145 found_stack = 1; \
146 if (EGET(phdr[i].p_type) == PT_GNU_RELRO) \
147 found_relro = 1; \
148 printf("%s ", gnu_short_stack_flags(EGET(phdr[i].p_flags))); \
149 } \
150 }
151 SHOW_STACK(32)
152 SHOW_STACK(64)
153 if (!be_quiet && !found_stack) printf("--- ");
154 if (!be_quiet && !found_relro) printf("--- ");
155 }
156
157 /* textrel fun */
158 if (show_textrel) {
159#define SHOW_TEXTREL(B) \
160 if (elf->elf_class == ELFCLASS ## B) { \
161 Elf ## B ## _Dyn *dyn; \
162 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
163 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
164 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
165 if (phdr[i].p_type != PT_DYNAMIC) continue; \
166 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \
167 while (EGET(dyn->d_tag) != DT_NULL) { \
168 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
169 found_textrel = 1; \
170 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
171 fputs("TEXTREL ", stdout); \
172 } \
173 ++dyn; \
174 } \
175 } }
176 SHOW_TEXTREL(32)
177 SHOW_TEXTREL(64)
178 if (!be_quiet && !found_textrel) fputs("------- ", stdout);
179 }
180
181 /* rpath fun */
182 /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */
183 if (show_rpath) {
184 char *rpath, *runpath; 460 char *rpath, *runpath, **r;
461 void *strtbl_void;
462
463 if (!show_rpath) return;
464
185 void *strtbl_void = elf_findsecbyname(elf, ".dynstr"); 465 strtbl_void = elf_findsecbyname(elf, ".dynstr");
186 rpath = runpath = NULL; 466 rpath = runpath = NULL;
187 467
188 if (strtbl_void) { 468 if (elf->phdr && strtbl_void) {
189#define SHOW_RPATH(B) \ 469#define SHOW_RPATH(B) \
190 if (elf->elf_class == ELFCLASS ## B) { \ 470 if (elf->elf_class == ELFCLASS ## B) { \
191 Elf ## B ## _Dyn *dyn; \ 471 Elf ## B ## _Dyn *dyn; \
192 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 472 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
193 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 473 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
194 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 474 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
475 Elf ## B ## _Off offset; \
476 Elf ## B ## _Xword word; \
477 /* Scan all the program headers */ \
195 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 478 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
479 /* Just scan dynamic headers */ \
196 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 480 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
481 offset = EGET(phdr[i].p_offset); \
482 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
483 /* Just scan dynamic RPATH/RUNPATH headers */ \
197 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 484 dyn = DYN ## B (elf->data + offset); \
198 while (EGET(dyn->d_tag) != DT_NULL) { \ 485 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
199 if (EGET(dyn->d_tag) == DT_RPATH) { \ 486 if (word == DT_RPATH) { \
487 r = &rpath; \
488 } else if (word == DT_RUNPATH) { \
489 r = &runpath; \
490 } else { \
491 ++dyn; \
492 continue; \
493 } \
494 /* Verify the memory is somewhat sane */ \
200 rpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 495 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
496 if (offset < (Elf ## B ## _Off)elf->len) { \
497 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
498 *r = (char*)(elf->data + offset); \
499 /* cache the length in case we need to nuke this section later on */ \
500 if (fix_elf) \
501 offset = strlen(*r); \
502 /* If quiet, don't output paths in ld.so.conf */ \
503 if (be_quiet) { \
504 size_t len; \
505 char *start, *end; \
506 /* note that we only 'chop' off leading known paths. */ \
507 /* since *r is read-only memory, we can only move the ptr forward. */ \
508 start = *r; \
509 /* scan each path in : delimited list */ \
510 while (start) { \
511 rpath_security_checks(elf, start, get_elfdtype(word)); \
512 end = strchr(start, ':'); \
513 len = (end ? abs(end - start) : strlen(start)); \
514 if (use_ldcache) \
515 for (s = 0; ldpaths[s]; ++s) \
516 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \
517 *r = end; \
518 /* corner case ... if RPATH reads "/usr/lib:", we want \
519 * to show ':' rather than '' */ \
520 if (end && end[1] != '\0') \
521 (*r)++; \
522 break; \
523 } \
524 if (!*r || !end) \
525 break; \
526 else \
527 start = start + len + 1; \
528 } \
529 } \
530 if (*r) { \
531 if (fix_elf > 2 || (fix_elf && **r == '\0')) { \
532 /* just nuke it */ \
533 nuke_it##B: \
534 memset(*r, 0x00, offset); \
535 *r = NULL; \
536 ESET(dyn->d_tag, DT_DEBUG); \
537 ESET(dyn->d_un.d_ptr, 0); \
538 } else if (fix_elf) { \
539 /* try to clean "bad" paths */ \
540 size_t len, tmpdir_len; \
541 char *start, *end; \
542 const char *tmpdir; \
543 start = *r; \
544 tmpdir = (getenv("TMPDIR") ? : "."); \
545 tmpdir_len = strlen(tmpdir); \
546 while (1) { \
547 end = strchr(start, ':'); \
548 if (start == end) { \
549 eat_this_path##B: \
550 len = strlen(end); \
551 memmove(start, end+1, len); \
552 start[len-1] = '\0'; \
553 end = start - 1; \
554 } else if (tmpdir && !strncmp(start, tmpdir, tmpdir_len)) { \
555 if (!end) { \
556 if (start == *r) \
557 goto nuke_it##B; \
558 *--start = '\0'; \
559 } else \
560 goto eat_this_path##B; \
561 } \
562 if (!end) \
563 break; \
564 start = end + 1; \
565 } \
566 if (**r == '\0') \
567 goto nuke_it##B; \
568 } \
569 if (*r) \
201 found_rpath = 1; \ 570 *found_rpath = 1; \
202 } else if (EGET(dyn->d_tag) == DT_RUNPATH) { \ 571 } \
203 runpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
204 found_rpath = 1; \
205 } \ 572 } \
206 ++dyn; \ 573 ++dyn; \
207 } \ 574 } \
208 } } 575 } }
209 SHOW_RPATH(32) 576 SHOW_RPATH(32)
210 SHOW_RPATH(64) 577 SHOW_RPATH(64)
211 } 578 }
579
580 if (be_wewy_wewy_quiet) return;
581
212 if (rpath && runpath) { 582 if (rpath && runpath) {
213 if (!strcmp(rpath, runpath)) 583 if (!strcmp(rpath, runpath)) {
214 printf("%-5s ", runpath); 584 xstrcat(ret, runpath, ret_len);
215 else { 585 } else {
216 fprintf(stderr, "%s's RPATH [%s] != RUNPATH [%s]\n", filename, rpath, runpath); 586 fprintf(stderr, "RPATH [%s] != RUNPATH [%s]\n", rpath, runpath);
217 printf("{%s,%s} ", rpath, runpath); 587 xchrcat(ret, '{', ret_len);
588 xstrcat(ret, rpath, ret_len);
589 xchrcat(ret, ',', ret_len);
590 xstrcat(ret, runpath, ret_len);
591 xchrcat(ret, '}', ret_len);
218 } 592 }
219 } else if (rpath || runpath) 593 } else if (rpath || runpath)
220 printf("%-5s ", (runpath ? runpath : rpath)); 594 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
221 else if (!be_quiet && !found_rpath) 595 else if (!be_quiet)
222 printf(" - "); 596 xstrcat(ret, " - ", ret_len);
597}
598
599#define LDSO_CACHE_MAGIC "ld.so-"
600#define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1)
601#define LDSO_CACHE_VER "1.7.0"
602#define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1)
603#define FLAG_ANY -1
604#define FLAG_TYPE_MASK 0x00ff
605#define FLAG_LIBC4 0x0000
606#define FLAG_ELF 0x0001
607#define FLAG_ELF_LIBC5 0x0002
608#define FLAG_ELF_LIBC6 0x0003
609#define FLAG_REQUIRED_MASK 0xff00
610#define FLAG_SPARC_LIB64 0x0100
611#define FLAG_IA64_LIB64 0x0200
612#define FLAG_X8664_LIB64 0x0300
613#define FLAG_S390_LIB64 0x0400
614#define FLAG_POWERPC_LIB64 0x0500
615#define FLAG_MIPS64_LIBN32 0x0600
616#define FLAG_MIPS64_LIBN64 0x0700
617
618static char *lookup_cache_lib(elfobj *, char *);
619
620#if defined(__GLIBC__) || defined(__UCLIBC__)
621
622static char *lookup_cache_lib(elfobj *elf, char *fname)
623{
624 int fd = 0;
625 char *strs;
626 static char buf[__PAX_UTILS_PATH_MAX] = "";
627 const char *cachefile = "/etc/ld.so.cache";
628 struct stat st;
629
630 typedef struct {
631 char magic[LDSO_CACHE_MAGIC_LEN];
632 char version[LDSO_CACHE_VER_LEN];
633 int nlibs;
634 } header_t;
635 header_t *header;
636
637 typedef struct {
638 int flags;
639 int sooffset;
640 int liboffset;
641 } libentry_t;
642 libentry_t *libent;
643
644 if (fname == NULL)
645 return NULL;
646
647 if (ldcache == 0) {
648 if (stat(cachefile, &st) || (fd = open(cachefile, O_RDONLY)) == -1)
649 return NULL;
650
651 /* cache these values so we only map/unmap the cache file once */
652 ldcache_size = st.st_size;
653 ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0);
654
655 close(fd);
656
657 if (ldcache == (caddr_t)-1) {
658 ldcache = 0;
659 return NULL;
223 } 660 }
224 661
225 /* print out all the NEEDED entries */ 662 if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN))
226 if (show_needed) { 663 return NULL;
664 if (memcmp (((header_t *) ldcache)->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
665 return NULL;
666 }
667
668 header = (header_t *) ldcache;
669 libent = (libentry_t *) (ldcache + sizeof(header_t));
670 strs = (char *) &libent[header->nlibs];
671
672 for (fd = 0; fd < header->nlibs; fd++) {
673 /* this should be more fine grained, but for now we assume that
674 * diff arches will not be cached together. and we ignore the
675 * the different multilib mips cases. */
676 if (elf->elf_class == ELFCLASS64 && !(libent[fd].flags & FLAG_REQUIRED_MASK))
677 continue;
678 if (elf->elf_class == ELFCLASS32 && (libent[fd].flags & FLAG_REQUIRED_MASK))
679 continue;
680
681 if (strcmp(fname, strs + libent[fd].sooffset) != 0)
682 continue;
683 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
684 }
685 return buf;
686}
687#elif defined(__NetBSD__)
688static char *lookup_cache_lib(elfobj *elf, char *fname)
689{
690 static char buf[__PAX_UTILS_PATH_MAX] = "";
691 static struct stat st;
692
693 char **ldpath;
694 for (ldpath = ldpaths; *ldpath != NULL; ldpath++) {
695 if ((unsigned) snprintf(buf, sizeof(buf), "%s/%s", *ldpath, fname) >= sizeof(buf))
696 continue; /* if the pathname is too long, or something went wrong, ignore */
697
698 if (stat(buf, &st) != 0)
699 continue; /* if the lib doesn't exist in *ldpath, look further */
700
701 /* NetBSD doesn't actually do sanity checks, it just loads the file
702 * and if that doesn't work, continues looking in other directories.
703 * This cannot easily be safely emulated, unfortunately. For now,
704 * just assume that if it exists, it's a valid library. */
705
706 return buf;
707 }
708
709 /* not found in any path */
710 return NULL;
711}
712#else
713#warning Cache support not implemented for your target
714static char *lookup_cache_lib(elfobj *elf, char *fname)
715{
716 return NULL;
717}
718#endif
719
720static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
721{
722 unsigned long i;
227 char *needed; 723 char *needed;
724 void *strtbl_void;
725 char *p;
726
727 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
728
228 void *strtbl_void = elf_findsecbyname(elf, ".dynstr"); 729 strtbl_void = elf_findsecbyname(elf, ".dynstr");
229 730
230 if (strtbl_void) { 731 if (elf->phdr && strtbl_void) {
231#define SHOW_NEEDED(B) \ 732#define SHOW_NEEDED(B) \
232 if (elf->elf_class == ELFCLASS ## B) { \ 733 if (elf->elf_class == ELFCLASS ## B) { \
233 Elf ## B ## _Dyn *dyn; \ 734 Elf ## B ## _Dyn *dyn; \
234 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 735 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
235 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 736 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
236 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 737 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
738 Elf ## B ## _Off offset; \
237 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 739 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
238 if (be_verbose && EGET(phdr[i].p_type) == PT_INTERP) { \
239 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \
240 printf("%s\n", elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr)); \
241 exit(0); \
242 } \
243 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 740 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
741 offset = EGET(phdr[i].p_offset); \
742 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
244 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 743 dyn = DYN ## B (elf->data + offset); \
245 while (EGET(dyn->d_tag) != DT_NULL) { \ 744 while (EGET(dyn->d_tag) != DT_NULL) { \
246 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 745 if (EGET(dyn->d_tag) == DT_NEEDED) { \
247 needed = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 746 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
248 if (found_needed) printf(","); \ 747 if (offset >= (Elf ## B ## _Off)elf->len) { \
249 printf("%s", needed); \ 748 ++dyn; \
749 continue; \
750 } \
751 needed = (char*)(elf->data + offset); \
752 if (op == 0) { \
753 if (!be_wewy_wewy_quiet) { \
754 if (*found_needed) xchrcat(ret, ',', ret_len); \
755 if (use_ldcache) \
756 if ((p = lookup_cache_lib(elf, needed)) != NULL) \
757 needed = p; \
758 xstrcat(ret, needed, ret_len); \
759 } \
250 found_needed = 1; \ 760 *found_needed = 1; \
761 } else { \
762 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \
763 *found_lib = 1; \
764 return (be_wewy_wewy_quiet ? NULL : needed); \
765 } \
766 } \
251 } \ 767 } \
252 ++dyn; \ 768 ++dyn; \
253 } \ 769 } \
254 } } 770 } }
255 SHOW_NEEDED(32) 771 SHOW_NEEDED(32)
256 SHOW_NEEDED(64) 772 SHOW_NEEDED(64)
773 if (op == 0 && !*found_needed && be_verbose)
774 warn("ELF lacks DT_NEEDED sections: %s", elf->filename);
257 } 775 }
258 if (!be_quiet && !found_needed) 776
259 printf(" - "); 777 return NULL;
260 else if (found_needed) 778}
261 printf(" "); 779static char *scanelf_file_interp(elfobj *elf, char *found_interp)
780{
781 void *strtbl_void;
782
783 if (!show_interp) return NULL;
784
785 strtbl_void = elf_findsecbyname(elf, ".interp");
786
787 if (strtbl_void) {
788#define SHOW_INTERP(B) \
789 if (elf->elf_class == ELFCLASS ## B) { \
790 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
791 *found_interp = 1; \
792 return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(strtbl->sh_offset)); \
262 } 793 }
794 SHOW_INTERP(32)
795 SHOW_INTERP(64)
796 }
797 return NULL;
798}
799static char *scanelf_file_bind(elfobj *elf, char *found_bind)
800{
801 unsigned long i;
802 struct stat s;
803 char dynamic = 0;
263 804
264 /* search the symbol table for a specified symbol */ 805 if (!show_bind) return NULL;
265 if (find_sym) { 806 if (!elf->phdr) return NULL;
807
808#define SHOW_BIND(B) \
809 if (elf->elf_class == ELFCLASS ## B) { \
810 Elf ## B ## _Dyn *dyn; \
811 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
812 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
813 Elf ## B ## _Off offset; \
814 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
815 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
816 dynamic = 1; \
817 offset = EGET(phdr[i].p_offset); \
818 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
819 dyn = DYN ## B (elf->data + offset); \
820 while (EGET(dyn->d_tag) != DT_NULL) { \
821 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
822 (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
823 { \
824 if (be_quiet) return NULL; \
825 *found_bind = 1; \
826 return (char *)(be_wewy_wewy_quiet ? NULL : "NOW"); \
827 } \
828 ++dyn; \
829 } \
830 } \
831 }
832 SHOW_BIND(32)
833 SHOW_BIND(64)
834
835 if (be_wewy_wewy_quiet) return NULL;
836
837 /* don't output anything if quiet mode and the ELF is static or not setuid */
838 if (be_quiet && (!dynamic || (!fstat(elf->fd, &s) && !(s.st_mode & (S_ISUID|S_ISGID))))) {
839 return NULL;
840 } else {
841 *found_bind = 1;
842 return (char *) (dynamic ? "LAZY" : "STATIC");
843 }
844}
845static char *scanelf_file_soname(elfobj *elf, char *found_soname)
846{
847 unsigned long i;
848 char *soname;
849 void *strtbl_void;
850
851 if (!show_soname) return NULL;
852
853 strtbl_void = elf_findsecbyname(elf, ".dynstr");
854
855 if (elf->phdr && strtbl_void) {
856#define SHOW_SONAME(B) \
857 if (elf->elf_class == ELFCLASS ## B) { \
858 Elf ## B ## _Dyn *dyn; \
859 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
860 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
861 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
862 Elf ## B ## _Off offset; \
863 /* only look for soname in shared objects */ \
864 if (ehdr->e_type != ET_DYN) \
865 return NULL; \
866 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
867 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
868 offset = EGET(phdr[i].p_offset); \
869 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
870 dyn = DYN ## B (elf->data + offset); \
871 while (EGET(dyn->d_tag) != DT_NULL) { \
872 if (EGET(dyn->d_tag) == DT_SONAME) { \
873 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
874 if (offset >= (Elf ## B ## _Off)elf->len) { \
875 ++dyn; \
876 continue; \
877 } \
878 soname = (char*)(elf->data + offset); \
879 *found_soname = 1; \
880 return (be_wewy_wewy_quiet ? NULL : soname); \
881 } \
882 ++dyn; \
883 } \
884 } }
885 SHOW_SONAME(32)
886 SHOW_SONAME(64)
887 }
888
889 return NULL;
890}
891static char *scanelf_file_sym(elfobj *elf, char *found_sym)
892{
893 unsigned long i;
894 char *ret;
266 void *symtab_void, *strtab_void; 895 void *symtab_void, *strtab_void;
267 char *versioned_symname;
268 size_t len;
269 896
270 len = strlen(find_sym) + 1; 897 if (!find_sym) return NULL;
271 versioned_symname = (char *)malloc(sizeof(char) * (len+1)); 898 ret = find_sym;
272 if (!versioned_symname) {
273 warnf("Could not malloc() mem for sym scan");
274 return;
275 }
276 sprintf(versioned_symname, "%s@", find_sym);
277 899
278 symtab_void = elf_findsecbyname(elf, ".symtab"); 900 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
279 strtab_void = elf_findsecbyname(elf, ".strtab");
280 901
281 if (symtab_void && strtab_void) { 902 if (symtab_void && strtab_void) {
282#define FIND_SYM(B) \ 903#define FIND_SYM(B) \
283 if (elf->elf_class == ELFCLASS ## B) { \ 904 if (elf->elf_class == ELFCLASS ## B) { \
284 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 905 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
285 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 906 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
286 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 907 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
287 int cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 908 unsigned long cnt = EGET(symtab->sh_entsize); \
288 char *symname; \ 909 char *symname; \
910 if (cnt) \
911 cnt = EGET(symtab->sh_size) / cnt; \
289 for (i = 0; i < cnt; ++i) { \ 912 for (i = 0; i < cnt; ++i) { \
290 if (sym->st_name) { \ 913 if (sym->st_name) { \
914 /* make sure the symbol name is in acceptable memory range */ \
291 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 915 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
916 if ((void*)symname > (void*)elf->data_end) { \
917 warnf("%s: corrupt ELF symbols", elf->filename); \
918 ++sym; \
919 continue; \
920 } \
921 /* debug display ... show all symbols and some extra info */ \
292 if (*find_sym == '*') { \ 922 if (*ret == '*') { \
293 printf("%s(%s) %5lX %15s %s\n", \ 923 printf("%s(%s) %5lX %15s %s\n", \
294 ((found_sym == 0) ? "\n\t" : "\t"), \ 924 ((*found_sym == 0) ? "\n\t" : "\t"), \
295 (char *)basename(filename), \ 925 elf->base_filename, \
296 (long)sym->st_size, \ 926 (unsigned long)sym->st_size, \
297 (char *)get_elfstttype(sym->st_info), \ 927 get_elfstttype(sym->st_info), \
298 symname); \ 928 symname); \
299 found_sym = 1; \ 929 *found_sym = 1; \
300 } else if ((strcmp(find_sym, symname) == 0) || \ 930 } else { \
301 (strncmp(symname, versioned_symname, len) == 0)) \ 931 /* allow the user to specify a comma delimited list of symbols to search for */ \
932 char *this_sym, *this_sym_ver, *next_sym; \
933 this_sym = ret; \
934 this_sym_ver = versioned_symname; \
935 do { \
936 next_sym = strchr(this_sym, ','); \
937 if (next_sym == NULL) \
938 next_sym = this_sym + strlen(this_sym); \
939 /* do we want a defined symbol ? */ \
940 if (*this_sym == '+') { \
941 if (sym->st_shndx == SHN_UNDEF) \
942 goto skip_this_sym##B; \
943 ++this_sym; \
944 ++this_sym_ver; \
945 /* do we want an undefined symbol ? */ \
946 } else if (*this_sym == '-') { \
947 if (sym->st_shndx != SHN_UNDEF) \
948 goto skip_this_sym##B; \
949 ++this_sym; \
950 ++this_sym_ver; \
951 } \
952 /* ok, lets compare the name now */ \
953 if ((strncmp(this_sym, symname, (next_sym-this_sym)) == 0 && symname[next_sym-this_sym] == '\0') || \
954 (strncmp(this_sym_ver, symname, strlen(this_sym_ver)) == 0)) { \
955 if (be_semi_verbose) { \
956 char buf[126]; \
957 snprintf(buf, sizeof(buf), "%lX %s %s", \
958 (unsigned long)sym->st_size, get_elfstttype(sym->st_info), this_sym); \
959 ret = buf; \
960 } else \
961 ret = this_sym; \
302 found_sym++; \ 962 (*found_sym)++; \
963 goto break_out; \
964 } \
965 skip_this_sym##B: this_sym = next_sym + 1; \
966 } while (*next_sym != '\0'); \
967 } \
303 } \ 968 } \
304 ++sym; \ 969 ++sym; \
305 } } 970 } }
306 FIND_SYM(32) 971 FIND_SYM(32)
307 FIND_SYM(64) 972 FIND_SYM(64)
973 }
974
975break_out:
976 if (be_wewy_wewy_quiet) return NULL;
977
978 if (*find_sym != '*' && *found_sym)
979 return ret;
980 if (be_quiet)
981 return NULL;
982 else
983 return (char *)" - ";
984}
985
986
987static char *scanelf_file_sections(elfobj *elf, char *found_section)
988{
989 if (!find_section)
990 return NULL;
991
992#define FIND_SECTION(B) \
993 if (elf->elf_class == ELFCLASS ## B) { \
994 int invert; \
995 Elf ## B ## _Shdr *section; \
996 invert = (*find_section == '!' ? 1 : 0); \
997 section = SHDR ## B (elf_findsecbyname(elf, find_section+invert)); \
998 if ((section == NULL && invert) || (section != NULL && !invert)) \
999 *found_section = 1; \
1000 }
1001 FIND_SECTION(32)
1002 FIND_SECTION(64)
1003
1004 if (be_wewy_wewy_quiet)
1005 return NULL;
1006
1007 if (*found_section)
1008 return find_section;
1009
1010 if (be_quiet)
1011 return NULL;
1012 else
1013 return (char *)" - ";
1014}
1015
1016/* scan an elf file and show all the fun stuff */
1017#define prints(str) write(fileno(stdout), str, strlen(str))
1018static int scanelf_elfobj(elfobj *elf)
1019{
1020 unsigned long i;
1021 char found_pax, found_phdr, found_relro, found_load, found_textrel,
1022 found_rpath, found_needed, found_interp, found_bind, found_soname,
1023 found_sym, found_lib, found_file, found_textrels, found_section;
1024 static char *out_buffer = NULL;
1025 static size_t out_len;
1026
1027 found_pax = found_phdr = found_relro = found_load = found_textrel = \
1028 found_rpath = found_needed = found_interp = found_bind = found_soname = \
1029 found_sym = found_lib = found_file = found_textrels = found_section = 0;
1030
1031 if (be_verbose > 2)
1032 printf("%s: scanning file {%s,%s}\n", elf->filename,
1033 get_elfeitype(EI_CLASS, elf->elf_class),
1034 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
1035 else if (be_verbose > 1)
1036 printf("%s: scanning file\n", elf->filename);
1037
1038 /* init output buffer */
1039 if (!out_buffer) {
1040 out_len = sizeof(char) * 80;
1041 out_buffer = (char*)xmalloc(out_len);
1042 }
1043 *out_buffer = '\0';
1044
1045 /* show the header */
1046 if (!be_quiet && show_banner) {
1047 for (i = 0; out_format[i]; ++i) {
1048 if (!IS_MODIFIER(out_format[i])) continue;
1049
1050 switch (out_format[++i]) {
1051 case '+': break;
1052 case '%': break;
1053 case '#': break;
1054 case 'F':
1055 case 'p':
1056 case 'f': prints("FILE "); found_file = 1; break;
1057 case 'o': prints(" TYPE "); break;
1058 case 'x': prints(" PAX "); break;
1059 case 'e': prints("STK/REL/PTL "); break;
1060 case 't': prints("TEXTREL "); break;
1061 case 'r': prints("RPATH "); break;
1062 case 'n': prints("NEEDED "); break;
1063 case 'i': prints("INTERP "); break;
1064 case 'b': prints("BIND "); break;
1065 case 'S': prints("SONAME "); break;
1066 case 's': prints("SYM "); break;
1067 case 'N': prints("LIB "); break;
1068 case 'T': prints("TEXTRELS "); break;
1069 case 'k': prints("SECTION "); break;
1070 default: warnf("'%c' has no title ?", out_format[i]);
308 } 1071 }
309 free(versioned_symname); 1072 }
310 if (*find_sym != '*') { 1073 if (!found_file) prints("FILE ");
311 if (found_sym) 1074 prints("\n");
312 printf(" %s ", find_sym); 1075 found_file = 0;
313 else if (!be_quiet) 1076 show_banner = 0;
314 fputs(" - ", stdout); 1077 }
1078
1079 /* dump all the good stuff */
1080 for (i = 0; out_format[i]; ++i) {
1081 const char *out;
1082 const char *tmp;
1083
1084 if (!IS_MODIFIER(out_format[i])) {
1085 xchrcat(&out_buffer, out_format[i], &out_len);
1086 continue;
1087 }
1088
1089 out = NULL;
1090 be_wewy_wewy_quiet = (out_format[i] == '#');
1091 be_semi_verbose = (out_format[i] == '+');
1092 switch (out_format[++i]) {
1093 case '+':
1094 case '%':
1095 case '#':
1096 xchrcat(&out_buffer, out_format[i], &out_len); break;
1097 case 'F':
1098 found_file = 1;
1099 if (be_wewy_wewy_quiet) break;
1100 xstrcat(&out_buffer, elf->filename, &out_len);
1101 break;
1102 case 'p':
1103 found_file = 1;
1104 if (be_wewy_wewy_quiet) break;
1105 tmp = elf->filename;
1106 if (search_path) {
1107 ssize_t len_search = strlen(search_path);
1108 ssize_t len_file = strlen(elf->filename);
1109 if (!strncmp(elf->filename, search_path, len_search) && \
1110 len_file > len_search)
1111 tmp += len_search;
1112 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
315 } 1113 }
1114 xstrcat(&out_buffer, tmp, &out_len);
1115 break;
1116 case 'f':
1117 found_file = 1;
1118 if (be_wewy_wewy_quiet) break;
1119 tmp = strrchr(elf->filename, '/');
1120 tmp = (tmp == NULL ? elf->filename : tmp+1);
1121 xstrcat(&out_buffer, tmp, &out_len);
1122 break;
1123 case 'o': out = get_elfetype(elf); break;
1124 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
1125 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
1126 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
1127 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break;
1128 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
1129 case 'n':
1130 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
1131 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
1132 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
1133 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
1134 case 's': out = scanelf_file_sym(elf, &found_sym); break;
1135 case 'k': out = scanelf_file_sections(elf, &found_section); break;
1136 default: warnf("'%c' has no scan code?", out_format[i]);
316 } 1137 }
1138 if (out) {
1139 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
1140 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
1141 xstrncat(&out_buffer, out, &out_len, (tmp-out));
1142 else
1143 xstrcat(&out_buffer, out, &out_len);
1144 }
1145 }
317 1146
318 if (!be_quiet || found_pax || found_stack || found_textrel || \ 1147#define FOUND_SOMETHING() \
319 found_rpath || found_needed || found_sym) 1148 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
320 puts(filename); 1149 found_rpath || found_needed || found_interp || found_bind || \
1150 found_soname || found_sym || found_lib || found_textrels || found_section )
321 1151
1152 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
1153 xchrcat(&out_buffer, ' ', &out_len);
1154 xstrcat(&out_buffer, elf->filename, &out_len);
1155 }
1156 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
1157 puts(out_buffer);
1158 fflush(stdout);
1159 }
1160
1161 return 0;
1162}
1163
1164/* scan a single elf */
1165static int scanelf_elf(const char *filename, int fd, size_t len)
1166{
1167 int ret = 1;
1168 elfobj *elf;
1169
1170 /* verify this is real ELF */
1171 if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) {
1172 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
1173 return ret;
1174 }
1175 switch (match_bits) {
1176 case 32:
1177 if (elf->elf_class != ELFCLASS32)
1178 goto label_done;
1179 break;
1180 case 64:
1181 if (elf->elf_class != ELFCLASS64)
1182 goto label_done;
1183 break;
1184 default: break;
1185 }
1186 if (strlen(match_etypes)) {
1187 char sbuf[126];
1188 strncpy(sbuf, match_etypes, sizeof(sbuf));
1189 if (strchr(match_etypes, ',') != NULL) {
1190 char *p;
1191 while((p = strrchr(sbuf, ',')) != NULL) {
1192 *p = 0;
1193 if (etype_lookup(p+1) == get_etype(elf))
1194 goto label_ret;
1195 }
1196 }
1197 if (etype_lookup(sbuf) != get_etype(elf))
1198 goto label_done;
1199 }
1200
1201label_ret:
1202 ret = scanelf_elfobj(elf);
1203
1204label_done:
322 unreadelf(elf); 1205 unreadelf(elf);
1206 return ret;
1207}
1208
1209/* scan an archive of elfs */
1210static int scanelf_archive(const char *filename, int fd, size_t len)
1211{
1212 archive_handle *ar;
1213 archive_member *m;
1214 char *ar_buffer;
1215 elfobj *elf;
1216
1217 ar = ar_open_fd(filename, fd);
1218 if (ar == NULL)
1219 return 1;
1220
1221 ar_buffer = (char*)mmap(0, len, PROT_READ | (fix_elf ? PROT_WRITE : 0), (fix_elf ? MAP_SHARED : MAP_PRIVATE), fd, 0);
1222 while ((m=ar_next(ar)) != NULL) {
1223 elf = readelf_buffer(m->name, ar_buffer+lseek(fd,0,SEEK_CUR), m->size);
1224 if (elf) {
1225 scanelf_elfobj(elf);
1226 unreadelf(elf);
1227 }
1228 }
1229 munmap(ar_buffer, len);
1230
1231 return 0;
1232}
1233/* scan a file which may be an elf or an archive or some other magical beast */
1234static int scanelf_file(const char *filename, const struct stat *st_cache)
1235{
1236 const struct stat *st = st_cache;
1237 struct stat symlink_st;
1238 int fd;
1239
1240 /* always handle regular files and handle symlinked files if no -y */
1241 if (S_ISLNK(st->st_mode)) {
1242 if (!scan_symlink) return 1;
1243 stat(filename, &symlink_st);
1244 st = &symlink_st;
1245 }
1246
1247 if (!S_ISREG(st->st_mode)) {
1248 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
1249 return 1;
1250 }
1251
1252 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1)
1253 return 1;
1254
1255 if (scanelf_elf(filename, fd, st->st_size) == 1 && scan_archives)
1256 /* if it isn't an ELF, maybe it's an .a archive */
1257 scanelf_archive(filename, fd, st->st_size);
1258
1259 close(fd);
1260 return 0;
323} 1261}
324 1262
325/* scan a directory for ET_EXEC files and print when we find one */ 1263/* scan a directory for ET_EXEC files and print when we find one */
326static void scanelf_dir(const char *path) 1264static int scanelf_dir(const char *path)
327{ 1265{
328 register DIR *dir; 1266 register DIR *dir;
329 register struct dirent *dentry; 1267 register struct dirent *dentry;
330 struct stat st_top, st; 1268 struct stat st_top, st;
331 char buf[_POSIX_PATH_MAX]; 1269 char buf[__PAX_UTILS_PATH_MAX];
332 size_t pathlen = 0, len = 0; 1270 size_t pathlen = 0, len = 0;
1271 int ret = 0;
333 1272
334 /* make sure path exists */ 1273 /* make sure path exists */
335 if (lstat(path, &st_top) == -1) 1274 if (lstat(path, &st_top) == -1) {
1275 if (be_verbose > 2) printf("%s: does not exist\n", path);
336 return; 1276 return 1;
1277 }
337 1278
338 /* ok, if it isn't a directory, assume we can open it */ 1279 /* ok, if it isn't a directory, assume we can open it */
339 if (!S_ISDIR(st_top.st_mode)) { 1280 if (!S_ISDIR(st_top.st_mode)) {
340 scanelf_file(path); 1281 return scanelf_file(path, &st_top);
341 return;
342 } 1282 }
343 1283
344 /* now scan the dir looking for fun stuff */ 1284 /* now scan the dir looking for fun stuff */
345 if ((dir = opendir(path)) == NULL) { 1285 if ((dir = opendir(path)) == NULL) {
346 warnf("could not opendir %s: %s", path, strerror(errno)); 1286 warnf("could not opendir %s: %s", path, strerror(errno));
347 return; 1287 return 1;
348 } 1288 }
349 if (be_verbose) printf("%s: scanning dir\n", path); 1289 if (be_verbose > 1) printf("%s: scanning dir\n", path);
350 1290
351 pathlen = strlen(path); 1291 pathlen = strlen(path);
352 while ((dentry = readdir(dir))) { 1292 while ((dentry = readdir(dir))) {
353 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 1293 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
354 continue; 1294 continue;
355 len = (pathlen + 1 + strlen(dentry->d_name) + 1); 1295 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
356 if (len >= sizeof(buf)) { 1296 if (len >= sizeof(buf)) {
357 warnf("Skipping '%s': len > sizeof(buf); %d > %d\n", path, (int)len, (int)sizeof(buf)); 1297 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
1298 (unsigned long)len, (unsigned long)sizeof(buf));
358 continue; 1299 continue;
359 } 1300 }
360 sprintf(buf, "%s/%s", path, dentry->d_name); 1301 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name);
361 if (lstat(buf, &st) != -1) { 1302 if (lstat(buf, &st) != -1) {
362 if (S_ISREG(st.st_mode)) 1303 if (S_ISREG(st.st_mode))
363 scanelf_file(buf); 1304 ret = scanelf_file(buf, &st);
364 else if (dir_recurse && S_ISDIR(st.st_mode)) { 1305 else if (dir_recurse && S_ISDIR(st.st_mode)) {
365 if (dir_crossmount || (st_top.st_dev == st.st_dev)) 1306 if (dir_crossmount || (st_top.st_dev == st.st_dev))
366 scanelf_dir(buf); 1307 ret = scanelf_dir(buf);
367 } 1308 }
368 } 1309 }
369 } 1310 }
370 closedir(dir); 1311 closedir(dir);
1312 return ret;
371} 1313}
1314
1315static int scanelf_from_file(const char *filename)
1316{
1317 FILE *fp = NULL;
1318 char *p;
1319 char path[__PAX_UTILS_PATH_MAX];
1320 int ret = 0;
1321
1322 if (strcmp(filename, "-") == 0)
1323 fp = stdin;
1324 else if ((fp = fopen(filename, "r")) == NULL)
1325 return 1;
1326
1327 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1328 if ((p = strchr(path, '\n')) != NULL)
1329 *p = 0;
1330 search_path = path;
1331 ret = scanelf_dir(path);
1332 }
1333 if (fp != stdin)
1334 fclose(fp);
1335 return ret;
1336}
1337
1338#if defined(__GLIBC__) || defined(__UCLIBC__) || defined(__NetBSD__)
1339
1340static int load_ld_cache_config(int i, const char *fname)
1341{
1342 FILE *fp = NULL;
1343 char *p;
1344 char path[__PAX_UTILS_PATH_MAX];
1345
1346 if (i + 1 == ARRAY_SIZE(ldpaths))
1347 return i;
1348
1349 if ((fp = fopen(fname, "r")) == NULL)
1350 return i;
1351
1352 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1353 if ((p = strrchr(path, '\r')) != NULL)
1354 *p = 0;
1355 if ((p = strchr(path, '\n')) != NULL)
1356 *p = 0;
1357#ifdef __linux__
1358 // recursive includes of the same file will make this segfault.
1359 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) {
1360 glob64_t gl;
1361 size_t x;
1362 char gpath[__PAX_UTILS_PATH_MAX];
1363
1364 memset(gpath, 0, sizeof(gpath));
1365
1366 if (path[8] != '/')
1367 snprintf(gpath, sizeof(gpath), "/etc/%s", &path[8]);
1368 else
1369 strncpy(gpath, &path[8], sizeof(gpath));
1370
1371 if ((glob64(gpath, 0, NULL, &gl)) == 0) {
1372 for (x = 0; x < gl.gl_pathc; ++x) {
1373 /* try to avoid direct loops */
1374 if (strcmp(gl.gl_pathv[x], fname) == 0)
1375 continue;
1376 i = load_ld_cache_config(i, gl.gl_pathv[x]);
1377 if (i + 1 >= ARRAY_SIZE(ldpaths)) {
1378 globfree64(&gl);
1379 return i;
1380 }
1381 }
1382 globfree64 (&gl);
1383 continue;
1384 }
1385 }
1386#endif
1387 if (*path != '/')
1388 continue;
1389
1390 ldpaths[i++] = xstrdup(path);
1391
1392 if (i + 1 == ARRAY_SIZE(ldpaths))
1393 break;
1394 }
1395 ldpaths[i] = NULL;
1396
1397 fclose(fp);
1398 return i;
1399}
1400
1401#elif defined(__FreeBSD__) || (__DragonFly__)
1402
1403static int load_ld_cache_config(int i, const char *fname)
1404{
1405 FILE *fp = NULL;
1406 char *b = NULL, *p;
1407 struct elfhints_hdr hdr;
1408
1409 if (i + 1 == ARRAY_SIZE(ldpaths))
1410 return i;
1411
1412 if ((fp = fopen(fname, "r")) == NULL)
1413 return i;
1414
1415 if (fread(&hdr, 1, sizeof(hdr), fp) != sizeof(hdr) ||
1416 hdr.magic != ELFHINTS_MAGIC || hdr.version != 1 ||
1417 fseek(fp, hdr.strtab + hdr.dirlist, SEEK_SET) == -1)
1418 {
1419 fclose(fp);
1420 return i;
1421 }
1422
1423 b = (char*)malloc(hdr.dirlistlen+1);
1424 if (fread(b, 1, hdr.dirlistlen+1, fp) != hdr.dirlistlen+1) {
1425 fclose(fp);
1426 free(b);
1427 return i;
1428 }
1429
1430 while ((p = strsep(&b, ":"))) {
1431 if (*p == '\0') continue;
1432 ldpaths[i++] = xstrdup(p);
1433
1434 if (i + 1 == ARRAY_SIZE(ldpaths))
1435 break;
1436 }
1437 ldpaths[i] = NULL;
1438
1439 free(b);
1440 fclose(fp);
1441 return i;
1442}
1443
1444#else
1445
1446#warning Cache config support not implemented for your target
1447static int load_ld_cache_config(int i, const char *fname)
1448{
1449 memset(ldpaths, 0x00, sizeof(ldpaths));
1450}
1451
1452#endif
372 1453
373/* scan /etc/ld.so.conf for paths */ 1454/* scan /etc/ld.so.conf for paths */
374static void scanelf_ldpath() 1455static void scanelf_ldpath()
375{ 1456{
376 char scan_l, scan_ul, scan_ull; 1457 char scan_l, scan_ul, scan_ull;
377 char *path, *p; 1458 int i = 0;
378 FILE *fp;
379 1459
380 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 1460 if (!ldpaths[0])
381 err("Unable to open ld.so.conf: %s", strerror(errno)); 1461 err("Unable to load any paths from ld.so.conf");
382 1462
383 scan_l = scan_ul = scan_ull = 0; 1463 scan_l = scan_ul = scan_ull = 0;
384 1464
385 if ((path = malloc(_POSIX_PATH_MAX)) == NULL) { 1465 while (ldpaths[i]) {
386 warn("Can not malloc() memory for ldpath scanning");
387 return;
388 }
389 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL)
390 if (*path == '/') {
391 if ((p = strrchr(path, '\r')) != NULL)
392 *p = 0;
393 if ((p = strrchr(path, '\n')) != NULL)
394 *p = 0;
395 if (!scan_l && !strcmp(path, "/lib")) scan_l = 1; 1466 if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
396 if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1; 1467 if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
397 if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1; 1468 if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
398 scanelf_dir(path); 1469 scanelf_dir(ldpaths[i]);
1470 ++i;
399 } 1471 }
400 free(path);
401 fclose(fp);
402 1472
403 if (!scan_l) scanelf_dir("/lib"); 1473 if (!scan_l) scanelf_dir("/lib");
404 if (!scan_ul) scanelf_dir("/usr/lib"); 1474 if (!scan_ul) scanelf_dir("/usr/lib");
405 if (!scan_ull) scanelf_dir("/usr/local/lib"); 1475 if (!scan_ull) scanelf_dir("/usr/local/lib");
406} 1476}
411 char *path, *p; 1481 char *path, *p;
412 1482
413 path = getenv("PATH"); 1483 path = getenv("PATH");
414 if (!path) 1484 if (!path)
415 err("PATH is not set in your env !"); 1485 err("PATH is not set in your env !");
416 1486 path = xstrdup(path);
417 if ((path = strdup(path)) == NULL)
418 err("strdup failed: %s", strerror(errno));
419 1487
420 while ((p = strrchr(path, ':')) != NULL) { 1488 while ((p = strrchr(path, ':')) != NULL) {
421 scanelf_dir(p + 1); 1489 scanelf_dir(p + 1);
422 *p = 0; 1490 *p = 0;
423 } 1491 }
424 1492
425 free(path); 1493 free(path);
426} 1494}
427 1495
428
429
430/* usage / invocation handling functions */ 1496/* usage / invocation handling functions */
431#define PARSE_FLAGS "plRmxetrns:aqvo:BhV" 1497#define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:BhV"
432#define a_argument required_argument 1498#define a_argument required_argument
433static struct option const long_opts[] = { 1499static struct option const long_opts[] = {
434 {"path", no_argument, NULL, 'p'}, 1500 {"path", no_argument, NULL, 'p'},
435 {"ldpath", no_argument, NULL, 'l'}, 1501 {"ldpath", no_argument, NULL, 'l'},
436 {"recursive", no_argument, NULL, 'R'}, 1502 {"recursive", no_argument, NULL, 'R'},
437 {"mount", no_argument, NULL, 'm'}, 1503 {"mount", no_argument, NULL, 'm'},
1504 {"symlink", no_argument, NULL, 'y'},
1505 {"archives", no_argument, NULL, 'A'},
1506 {"ldcache", no_argument, NULL, 'L'},
1507 {"fix", no_argument, NULL, 'X'},
1508 {"setpax", a_argument, NULL, 'z'},
438 {"pax", no_argument, NULL, 'x'}, 1509 {"pax", no_argument, NULL, 'x'},
439 {"header", no_argument, NULL, 'e'}, 1510 {"header", no_argument, NULL, 'e'},
440 {"textrel", no_argument, NULL, 't'}, 1511 {"textrel", no_argument, NULL, 't'},
441 {"rpath", no_argument, NULL, 'r'}, 1512 {"rpath", no_argument, NULL, 'r'},
442 {"needed", no_argument, NULL, 'n'}, 1513 {"needed", no_argument, NULL, 'n'},
1514 {"interp", no_argument, NULL, 'i'},
1515 {"bind", no_argument, NULL, 'b'},
1516 {"soname", no_argument, NULL, 'S'},
443 {"symbol", a_argument, NULL, 's'}, 1517 {"symbol", a_argument, NULL, 's'},
1518 {"section", a_argument, NULL, 'k'},
1519 {"lib", a_argument, NULL, 'N'},
1520 {"gmatch", no_argument, NULL, 'g'},
1521 {"textrels", no_argument, NULL, 'T'},
1522 {"etype", a_argument, NULL, 'E'},
1523 {"bits", a_argument, NULL, 'M'},
444 {"all", no_argument, NULL, 'a'}, 1524 {"all", no_argument, NULL, 'a'},
445 {"quiet", no_argument, NULL, 'q'}, 1525 {"quiet", no_argument, NULL, 'q'},
446 {"verbose", no_argument, NULL, 'v'}, 1526 {"verbose", no_argument, NULL, 'v'},
1527 {"format", a_argument, NULL, 'F'},
1528 {"from", a_argument, NULL, 'f'},
447 {"file", a_argument, NULL, 'o'}, 1529 {"file", a_argument, NULL, 'o'},
448 {"nobanner", no_argument, NULL, 'B'}, 1530 {"nobanner", no_argument, NULL, 'B'},
449 {"help", no_argument, NULL, 'h'}, 1531 {"help", no_argument, NULL, 'h'},
450 {"version", no_argument, NULL, 'V'}, 1532 {"version", no_argument, NULL, 'V'},
451 {NULL, no_argument, NULL, 0x0} 1533 {NULL, no_argument, NULL, 0x0}
452}; 1534};
1535
453static char *opts_help[] = { 1536static const char *opts_help[] = {
454 "Scan all directories in PATH environment", 1537 "Scan all directories in PATH environment",
455 "Scan all directories in /etc/ld.so.conf", 1538 "Scan all directories in /etc/ld.so.conf",
456 "Scan directories recursively", 1539 "Scan directories recursively",
457 "Don't recursively cross mount points\n", 1540 "Don't recursively cross mount points",
1541 "Don't scan symlinks",
1542 "Scan archives (.a files)",
1543 "Utilize ld.so.cache information (use with -r/-n)",
1544 "Try and 'fix' bad things (use with -r/-e)",
1545 "Sets EI_PAX/PT_PAX_FLAGS to <arg> (use with -Xx)\n",
458 "Print PaX markings", 1546 "Print PaX markings",
459 "Print GNU_STACK markings", 1547 "Print GNU_STACK/PT_LOAD markings",
460 "Print TEXTREL information", 1548 "Print TEXTREL information",
461 "Print RPATH information", 1549 "Print RPATH information",
462 "Print NEEDED information", 1550 "Print NEEDED information",
1551 "Print INTERP information",
1552 "Print BIND information",
1553 "Print SONAME information",
463 "Find a specified symbol", 1554 "Find a specified symbol",
1555 "Find a specified section",
1556 "Find a specified library",
1557 "Use strncmp to match libraries. (use with -N)",
1558 "Locate cause of TEXTREL",
1559 "Print only ELF files matching etype ET_DYN,ET_EXEC ...",
1560 "Print only ELF files matching numeric bits",
464 "Print all scanned info (-x -e -t -r)\n", 1561 "Print all scanned info (-x -e -t -r -b)\n",
465 "Only output 'bad' things", 1562 "Only output 'bad' things",
466 "Be verbose (can be specified more than once)", 1563 "Be verbose (can be specified more than once)",
1564 "Use specified format for output",
1565 "Read input stream from a filename",
467 "Write output stream to a filename", 1566 "Write output stream to a filename",
468 "Don't display the header", 1567 "Don't display the header",
469 "Print this help and exit", 1568 "Print this help and exit",
470 "Print version and exit", 1569 "Print version and exit",
471 NULL 1570 NULL
472}; 1571};
473 1572
474/* display usage and exit */ 1573/* display usage and exit */
475static void usage(int status) 1574static void usage(int status)
476{ 1575{
477 int i; 1576 unsigned long i;
478 printf(" Scan ELF binaries for stuff\n" 1577 printf("* Scan ELF binaries for stuff\n\n"
479 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); 1578 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
480 printf("Options: -[%s]\n", PARSE_FLAGS); 1579 printf("Options: -[%s]\n", PARSE_FLAGS);
481 for (i = 0; long_opts[i].name; ++i) 1580 for (i = 0; long_opts[i].name; ++i)
482 if (long_opts[i].has_arg == no_argument) 1581 if (long_opts[i].has_arg == no_argument)
483 printf(" -%c, --%-13s %s\n", long_opts[i].val, 1582 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
484 long_opts[i].name, opts_help[i]); 1583 long_opts[i].name, opts_help[i]);
485 else 1584 else
486 printf(" -%c, --%-6s <arg> %s\n", long_opts[i].val, 1585 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
487 long_opts[i].name, opts_help[i]); 1586 long_opts[i].name, opts_help[i]);
1587
1588 if (status != EXIT_SUCCESS)
1589 exit(status);
1590
1591 puts("\nThe format modifiers for the -F option are:");
1592 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
1593 puts(" t TEXTREL \tr RPATH \tn NEEDED");
1594 puts(" i INTERP \tb BIND \ts symbol");
1595 puts(" N library \to Type \tT TEXTRELs");
1596 puts(" S SONAME \tk section");
1597 puts(" p filename (with search path removed)");
1598 puts(" f filename (short name/basename)");
1599 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1600
1601 puts("\nELF Etypes:");
1602 print_etypes(stdout);
1603
488 exit(status); 1604 exit(status);
489} 1605}
490 1606
491/* parse command line arguments and preform needed actions */ 1607/* parse command line arguments and preform needed actions */
492static void parseargs(int argc, char *argv[]) 1608static int parseargs(int argc, char *argv[])
493{ 1609{
494 int flag; 1610 int i;
1611 const char *from_file = NULL;
1612 int ret = 0;
495 1613
496 opterr = 0; 1614 opterr = 0;
497 while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 1615 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
498 switch (flag) { 1616 switch (i) {
499 1617
500 case 'V': /* version info */ 1618 case 'V':
501 printf("%s compiled %s\n%s\n" 1619 printf("pax-utils-%s: %s compiled %s\n%s\n"
502 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n", 1620 "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
503 __FILE__, __DATE__, rcsid, argv0); 1621 VERSION, __FILE__, __DATE__, rcsid, argv0);
504 exit(EXIT_SUCCESS); 1622 exit(EXIT_SUCCESS);
505 break; 1623 break;
506 case 'h': usage(EXIT_SUCCESS); break; 1624 case 'h': usage(EXIT_SUCCESS); break;
507 1625 case 'f':
1626 if (from_file) warn("You prob don't want to specify -f twice");
1627 from_file = optarg;
1628 break;
1629 case 'E':
1630 strncpy(match_etypes, optarg, sizeof(match_etypes));
1631 break;
1632 case 'M':
1633 match_bits = atoi(optarg);
1634 break;
508 case 'o': { 1635 case 'o': {
509 FILE *fp = NULL;
510 fp = freopen(optarg, "w", stdout); 1636 if (freopen(optarg, "w", stdout) == NULL)
511 if (fp == NULL)
512 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1637 err("Could not open output stream '%s': %s", optarg, strerror(errno));
513 stdout = fp; 1638 break;
1639 }
1640 case 'k':
1641 if (find_section) warn("You prob don't want to specify -k twice");
1642 find_section = optarg;
1643 break;
1644 case 's': {
1645 if (find_sym) warn("You prob don't want to specify -s twice");
1646 find_sym = optarg;
1647 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1648 sprintf(versioned_symname, "%s@", find_sym);
1649 break;
1650 }
1651 case 'N': {
1652 if (find_lib) warn("You prob don't want to specify -N twice");
1653 find_lib = optarg;
1654 break;
1655 }
1656
1657 case 'F': {
1658 if (out_format) warn("You prob don't want to specify -F twice");
1659 out_format = optarg;
1660 break;
1661 }
1662 case 'z': {
1663 unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC);
1664 size_t x;
1665
1666 for (x = 0 ; x < strlen(optarg); x++) {
1667 switch(optarg[x]) {
1668 case 'p':
1669 case 'P':
1670 do_state(optarg[x], PAGEEXEC);
514 break; 1671 break;
1672 case 's':
1673 case 'S':
1674 do_state(optarg[x], SEGMEXEC);
1675 break;
1676 case 'm':
1677 case 'M':
1678 do_state(optarg[x], MPROTECT);
1679 break;
1680 case 'e':
1681 case 'E':
1682 do_state(optarg[x], EMUTRAMP);
1683 break;
1684 case 'r':
1685 case 'R':
1686 do_state(optarg[x], RANDMMAP);
1687 break;
1688 case 'x':
1689 case 'X':
1690 do_state(optarg[x], RANDEXEC);
1691 break;
1692 default:
1693 break;
1694 }
515 } 1695 }
516 1696 if (!(((flags & PF_PAGEEXEC) && (flags & PF_NOPAGEEXEC)) ||
517 case 's': find_sym = strdup(optarg); break; 1697 ((flags & PF_SEGMEXEC) && (flags & PF_NOSEGMEXEC)) ||
518 1698 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP)) ||
1699 ((flags & PF_RANDEXEC) && (flags & PF_NORANDEXEC)) ||
1700 ((flags & PF_EMUTRAMP) && (flags & PF_NOEMUTRAMP)) ||
1701 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP))))
1702 setpax = flags;
1703 break;
1704 }
1705 case 'g': gmatch = 1; break;
1706 case 'L': use_ldcache = 1; break;
1707 case 'y': scan_symlink = 0; break;
1708 case 'A': scan_archives = 1; break;
519 case 'B': show_banner = 0; break; 1709 case 'B': show_banner = 0; break;
520 case 'l': scan_ldpath = 1; break; 1710 case 'l': scan_ldpath = 1; break;
521 case 'p': scan_envpath = 1; break; 1711 case 'p': scan_envpath = 1; break;
522 case 'R': dir_recurse = 1; break; 1712 case 'R': dir_recurse = 1; break;
523 case 'm': dir_crossmount = 0; break; 1713 case 'm': dir_crossmount = 0; break;
1714 case 'X': ++fix_elf; break;
524 case 'x': show_pax = 1; break; 1715 case 'x': show_pax = 1; break;
525 case 'e': show_stack = 1; break; 1716 case 'e': show_phdr = 1; break;
526 case 't': show_textrel = 1; break; 1717 case 't': show_textrel = 1; break;
527 case 'r': show_rpath = 1; break; 1718 case 'r': show_rpath = 1; break;
528 case 'n': show_needed = 1; break; 1719 case 'n': show_needed = 1; break;
1720 case 'i': show_interp = 1; break;
1721 case 'b': show_bind = 1; break;
1722 case 'S': show_soname = 1; break;
1723 case 'T': show_textrels = 1; break;
529 case 'q': be_quiet = 1; break; 1724 case 'q': be_quiet = 1; break;
530 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1725 case 'v': be_verbose = (be_verbose % 20) + 1; break;
531 case 'a': show_pax = show_stack = show_textrel = show_needed = show_rpath = 1; break; 1726 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break;
532 1727
533 case ':': 1728 case ':':
534 warn("Option missing parameter"); 1729 err("Option '%c' is missing parameter", optopt);
535 usage(EXIT_FAILURE);
536 break;
537 case '?': 1730 case '?':
538 warn("Unknown option"); 1731 err("Unknown option '%c' or argument missing", optopt);
539 usage(EXIT_FAILURE);
540 break;
541 default: 1732 default:
542 err("Unhandled option '%c'", flag); 1733 err("Unhandled option '%c'; please report this", i);
543 break; 1734 }
1735 }
1736
1737 /* let the format option override all other options */
1738 if (out_format) {
1739 show_pax = show_phdr = show_textrel = show_rpath = \
1740 show_needed = show_interp = show_bind = show_soname = \
1741 show_textrels = 0;
1742 for (i = 0; out_format[i]; ++i) {
1743 if (!IS_MODIFIER(out_format[i])) continue;
1744
1745 switch (out_format[++i]) {
1746 case '+': break;
1747 case '%': break;
1748 case '#': break;
1749 case 'F': break;
1750 case 'p': break;
1751 case 'f': break;
1752 case 'k': break;
1753 case 's': break;
1754 case 'N': break;
1755 case 'o': break;
1756 case 'x': show_pax = 1; break;
1757 case 'e': show_phdr = 1; break;
1758 case 't': show_textrel = 1; break;
1759 case 'r': show_rpath = 1; break;
1760 case 'n': show_needed = 1; break;
1761 case 'i': show_interp = 1; break;
1762 case 'b': show_bind = 1; break;
1763 case 'S': show_soname = 1; break;
1764 case 'T': show_textrels = 1; break;
1765 default:
1766 err("Invalid format specifier '%c' (byte %i)",
1767 out_format[i], i+1);
544 } 1768 }
545 } 1769 }
546 1770
547 if (be_quiet && be_verbose) 1771 /* construct our default format */
548 err("You can be quiet or you can be verbose, not both, stupid"); 1772 } else {
1773 size_t fmt_len = 30;
1774 out_format = (char*)xmalloc(sizeof(char) * fmt_len);
1775 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
1776 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
1777 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
1778 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1779 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1780 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1781 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1782 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1783 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1784 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1785 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1786 if (find_section) xstrcat(&out_format, "%k ", &fmt_len);
1787 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1788 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1789 }
1790 if (be_verbose > 2) printf("Format: %s\n", out_format);
549 1791
1792 /* now lets actually do the scanning */
1793 if (scan_ldpath || use_ldcache)
1794 load_ld_cache_config(0, __PAX_UTILS_DEFAULT_LD_CACHE_CONFIG);
550 if (scan_ldpath) scanelf_ldpath(); 1795 if (scan_ldpath) scanelf_ldpath();
551 if (scan_envpath) scanelf_envpath(); 1796 if (scan_envpath) scanelf_envpath();
1797 if (!from_file && optind == argc && ttyname(0) == NULL && !scan_ldpath && !scan_envpath)
1798 from_file = "-";
1799 if (from_file) {
1800 scanelf_from_file(from_file);
1801 from_file = *argv;
1802 }
552 if (optind == argc && !scan_ldpath && !scan_envpath) 1803 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
553 err("Nothing to scan !?"); 1804 err("Nothing to scan !?");
554 while (optind < argc) 1805 while (optind < argc) {
555 scanelf_dir(argv[optind++]); 1806 search_path = argv[optind++];
1807 ret = scanelf_dir(search_path);
1808 }
556 1809
557 if (find_sym) free(find_sym); 1810 /* clean up */
558} 1811 free(versioned_symname);
1812 for (i = 0; ldpaths[i]; ++i)
1813 free(ldpaths[i]);
559 1814
1815 if (ldcache != 0)
1816 munmap(ldcache, ldcache_size);
1817 return ret;
1818}
1819
1820static char **get_split_env(const char *envvar)
1821{
1822 const char *delims = " \t\n";
1823 char **envvals = NULL;
1824 char *env, *s;
1825 int nentry;
1826
1827 if ((env = getenv(envvar)) == NULL)
1828 return NULL;
1829
1830 env = xstrdup(env);
1831 if (env == NULL)
1832 return NULL;
1833
1834 s = strtok(env, delims);
1835 if (s == NULL) {
1836 free(env);
1837 return NULL;
1838 }
1839
1840 nentry = 0;
1841 while (s != NULL) {
1842 ++nentry;
1843 envvals = xrealloc(envvals, sizeof(*envvals) * (nentry+1));
1844 envvals[nentry-1] = s;
1845 s = strtok(NULL, delims);
1846 }
1847 envvals[nentry] = NULL;
1848
1849 /* don't want to free(env) as it contains the memory that backs
1850 * the envvals array of strings */
1851 return envvals;
1852}
1853static void parseenv()
1854{
1855 qa_textrels = get_split_env("QA_TEXTRELS");
1856 qa_execstack = get_split_env("QA_EXECSTACK");
1857 qa_wx_load = get_split_env("QA_WX_LOAD");
1858}
1859
1860#ifdef __PAX_UTILS_CLEANUP
1861static void cleanup()
1862{
1863 free(out_format);
1864 free(qa_textrels);
1865 free(qa_execstack);
1866 free(qa_wx_load);
1867}
1868#endif
560 1869
561 1870
562int main(int argc, char *argv[]) 1871int main(int argc, char *argv[])
563{ 1872{
1873 int ret;
564 if (argc < 2) 1874 if (argc < 2)
565 usage(EXIT_FAILURE); 1875 usage(EXIT_FAILURE);
1876 parseenv();
566 parseargs(argc, argv); 1877 ret = parseargs(argc, argv);
567 fclose(stdout); 1878 fclose(stdout);
568 return EXIT_SUCCESS; 1879#ifdef __PAX_UTILS_CLEANUP
1880 cleanup();
1881 warn("The calls to add/delete heap should be off:\n"
1882 "\t- 1 due to the out_buffer not being freed in scanelf_file()\n"
1883 "\t- 1 per QA_TEXTRELS/QA_EXECSTACK/QA_WX_LOAD");
1884#endif
1885 return ret;
569} 1886}
1887
1888
1889
1890/* utility funcs */
1891static char *xstrdup(const char *s)
1892{
1893 char *ret = strdup(s);
1894 if (!ret) err("Could not strdup(): %s", strerror(errno));
1895 return ret;
1896}
1897static void *xmalloc(size_t size)
1898{
1899 void *ret = malloc(size);
1900 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1901 return ret;
1902}
1903static void *xrealloc(void *ptr, size_t size)
1904{
1905 void *ret = realloc(ptr, size);
1906 if (!ret) err("Could not realloc() %li bytes", (unsigned long)size);
1907 return ret;
1908}
1909static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
1910{
1911 size_t new_len;
1912
1913 new_len = strlen(*dst) + strlen(src);
1914 if (*curr_len <= new_len) {
1915 *curr_len = new_len + (*curr_len / 2);
1916 *dst = realloc(*dst, *curr_len);
1917 if (!*dst)
1918 err("could not realloc() %li bytes", (unsigned long)*curr_len);
1919 }
1920
1921 if (n)
1922 strncat(*dst, src, n);
1923 else
1924 strcat(*dst, src);
1925}
1926static inline void xchrcat(char **dst, const char append, size_t *curr_len)
1927{
1928 static char my_app[2];
1929 my_app[0] = append;
1930 my_app[1] = '\0';
1931 xstrcat(dst, my_app, curr_len);
1932}
1933
1934/* Match filename against entries in matchlist, return TRUE
1935 * if the file is listed */
1936static int file_matches_list(const char *filename, char **matchlist)
1937{
1938 char **file;
1939 char *match;
1940 char buf[__PAX_UTILS_PATH_MAX];
1941
1942 if (matchlist == NULL)
1943 return 0;
1944
1945 for (file = matchlist; *file != NULL; file++) {
1946 if (search_path) {
1947 snprintf(buf, sizeof(buf), "%s%s", search_path, *file);
1948 match = buf;
1949 } else {
1950 match = *file;
1951 }
1952 if (fnmatch(match, filename, 0) == 0)
1953 return 1;
1954 }
1955 return 0;
1956}

Legend:
Removed from v.1.35  
changed lines
  Added in v.1.164

  ViewVC Help
Powered by ViewVC 1.1.20