/[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.88 Revision 1.128
1/* 1/*
2 * Copyright 2003-2005 Gentoo Foundation 2 * Copyright 2003-2006 Gentoo Foundation
3 * Distributed under the terms of the GNU General Public License v2 3 * Distributed under the terms of the GNU General Public License v2
4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.88 2005/09/30 03:30:54 vapier Exp $ 4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.128 2006/02/17 15:36:16 solar Exp $
5 * 5 *
6 * Copyright 2003-2005 Ned Ludd - <solar@gentoo.org> 6 * Copyright 2003-2006 Ned Ludd - <solar@gentoo.org>
7 * Copyright 2004-2005 Mike Frysinger - <vapier@gentoo.org> 7 * Copyright 2004-2006 Mike Frysinger - <vapier@gentoo.org>
8 */ 8 */
9 9
10#include <stdio.h>
11#include <stdlib.h>
12#include <sys/types.h>
13#include <libgen.h>
14#include <limits.h>
15#define __USE_GNU
16#include <string.h>
17#include <errno.h>
18#include <unistd.h>
19#include <sys/stat.h>
20#include <dirent.h>
21#include <getopt.h>
22#include <assert.h>
23#include "paxelf.h" 10#include "paxinc.h"
24 11
25static const char *rcsid = "$Id: scanelf.c,v 1.88 2005/09/30 03:30:54 vapier Exp $"; 12static const char *rcsid = "$Id: scanelf.c,v 1.128 2006/02/17 15:36:16 solar Exp $";
26#define argv0 "scanelf" 13#define argv0 "scanelf"
27 14
28#define IS_MODIFIER(c) (c == '%' || c == '#') 15#define IS_MODIFIER(c) (c == '%' || c == '#')
29 16
30 17
31 18
32/* prototypes */ 19/* prototypes */
20static int scanelf_elfobj(elfobj *elf);
21static int scanelf_elf(const char *filename, int fd, size_t len);
22static int scanelf_archive(const char *filename, int fd, size_t len);
33static void scanelf_file(const char *filename); 23static void scanelf_file(const char *filename);
34static void scanelf_dir(const char *path); 24static void scanelf_dir(const char *path);
35static void scanelf_ldpath(); 25static void scanelf_ldpath(void);
36static void scanelf_envpath(); 26static void scanelf_envpath(void);
37static void usage(int status); 27static void usage(int status);
38static void parseargs(int argc, char *argv[]); 28static void parseargs(int argc, char *argv[]);
39static char *xstrdup(const char *s); 29static char *xstrdup(const char *s);
40static void *xmalloc(size_t size); 30static void *xmalloc(size_t size);
41static void xstrcat(char **dst, const char *src, size_t *curr_len); 31static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n);
32#define xstrcat(dst,src,curr_len) xstrncat(dst,src,curr_len,0)
42static inline void xchrcat(char **dst, const char append, size_t *curr_len); 33static inline void xchrcat(char **dst, const char append, size_t *curr_len);
43 34
44/* variables to control behavior */ 35/* variables to control behavior */
36static char match_etypes[126] = "";
45static char *ldpaths[256]; 37static char *ldpaths[256];
46static char scan_ldpath = 0; 38static char scan_ldpath = 0;
47static char scan_envpath = 0; 39static char scan_envpath = 0;
48static char scan_symlink = 1; 40static char scan_symlink = 1;
41static char scan_archives = 0;
49static char dir_recurse = 0; 42static char dir_recurse = 0;
50static char dir_crossmount = 1; 43static char dir_crossmount = 1;
51static char show_pax = 0; 44static char show_pax = 0;
52static char show_phdr = 0; 45static char show_phdr = 0;
53static char show_textrel = 0; 46static char show_textrel = 0;
61static char be_quiet = 0; 54static char be_quiet = 0;
62static char be_verbose = 0; 55static char be_verbose = 0;
63static char be_wewy_wewy_quiet = 0; 56static char be_wewy_wewy_quiet = 0;
64static char *find_sym = NULL, *versioned_symname = NULL; 57static char *find_sym = NULL, *versioned_symname = NULL;
65static char *find_lib = NULL; 58static char *find_lib = NULL;
59static char *find_section = NULL;
66static char *out_format = NULL; 60static char *out_format = NULL;
67static char *search_path = NULL; 61static char *search_path = NULL;
62static char fix_elf = 0;
68static char gmatch = 0; 63static char gmatch = 0;
64static char use_ldcache = 0;
69 65
66int match_bits = 0;
67caddr_t ldcache = 0;
68size_t ldcache_size = 0;
69unsigned long setpax = 0UL;
70 70
71/* sub-funcs for scanelf_file() */ 71/* sub-funcs for scanelf_file() */
72static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab) 72static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
73{ 73{
74 /* find the best SHT_DYNSYM and SHT_STRTAB sections */ 74 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
93 } \ 93 } \
94 } 94 }
95 GET_SYMTABS(32) 95 GET_SYMTABS(32)
96 GET_SYMTABS(64) 96 GET_SYMTABS(64)
97} 97}
98
98static char *scanelf_file_pax(elfobj *elf, char *found_pax) 99static char *scanelf_file_pax(elfobj *elf, char *found_pax)
99{ 100{
100 static char *paxflags;
101 static char ret[7]; 101 static char ret[7];
102 unsigned long i, shown; 102 unsigned long i, shown;
103 103
104 if (!show_pax) return NULL; 104 if (!show_pax) return NULL;
105 105
112 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 112 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
113 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 113 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
114 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 114 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
115 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \ 115 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
116 continue; \ 116 continue; \
117 if (fix_elf && setpax) { \
118 /* set the paxctl flags */ \
119 ESET(phdr[i].p_flags, setpax); \
120 } \
117 if (be_quiet && (EGET(phdr[i].p_flags) == 10240)) \ 121 if (be_quiet && (EGET(phdr[i].p_flags) == 10240)) \
118 continue; \ 122 continue; \
119 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \ 123 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
120 *found_pax = 1; \ 124 *found_pax = 1; \
121 ++shown; \ 125 ++shown; \
124 } 128 }
125 SHOW_PAX(32) 129 SHOW_PAX(32)
126 SHOW_PAX(64) 130 SHOW_PAX(64)
127 } 131 }
128 132
133
134 if (fix_elf && setpax) {
135 /* set the chpax settings */
136 if (elf->elf_class == ELFCLASS32)
137 ESET(EHDR32(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
138 else
139 ESET(EHDR64(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
140 }
141
129 /* fall back to EI_PAX if no PT_PAX was found */ 142 /* fall back to EI_PAX if no PT_PAX was found */
130 if (!*ret) { 143 if (!*ret) {
144 static char *paxflags;
131 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf)); 145 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
132 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) { 146 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
133 *found_pax = 1; 147 *found_pax = 1;
134 return paxflags; 148 return (be_wewy_wewy_quiet ? NULL : paxflags);
135 } 149 }
136 strncpy(ret, paxflags, sizeof(ret)); 150 strncpy(ret, paxflags, sizeof(ret));
137 } 151 }
138 152
139 if (be_quiet && !shown) 153 if (be_wewy_wewy_quiet || (be_quiet && !shown))
140 return NULL; 154 return NULL;
155 else
141 return ret; 156 return ret;
142
143} 157}
158
144static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load) 159static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load)
145{ 160{
146 static char ret[12]; 161 static char ret[12];
147 char *found; 162 char *found;
148 unsigned long i, off, shown, check_flags;
149 unsigned char multi_stack, multi_relro, multi_load; 163 unsigned long i, shown, multi_stack, multi_relro, multi_load;
164 int max_pt_load;
150 165
151 if (!show_phdr) return NULL; 166 if (!show_phdr) return NULL;
152 167
153 memcpy(ret, "--- --- ---\0", 12); 168 memcpy(ret, "--- --- ---\0", 12);
154 169
155 shown = 0; 170 shown = 0;
156 multi_stack = multi_relro = multi_load = 0; 171 multi_stack = multi_relro = multi_load = 0;
172 max_pt_load = elf_max_pt_load(elf);
157 173
158 if (elf->phdr) { 174#define NOTE_GNU_STACK ".note.GNU-stack"
159#define SHOW_PHDR(B) \ 175#define SHOW_PHDR(B) \
160 if (elf->elf_class == ELFCLASS ## B) { \ 176 if (elf->elf_class == ELFCLASS ## B) { \
161 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 177 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
178 Elf ## B ## _Off offset; \
179 uint32_t flags, check_flags; \
180 if (elf->phdr != NULL) { \
162 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 181 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
163 uint32_t flags; \
164 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 182 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
165 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \ 183 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
166 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \ 184 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
167 found = found_phdr; \ 185 found = found_phdr; \
168 off = 0; \ 186 offset = 0; \
169 check_flags = PF_X; \ 187 check_flags = PF_X; \
170 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \ 188 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
171 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \ 189 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
172 found = found_relro; \ 190 found = found_relro; \
173 off = 4; \ 191 offset = 4; \
174 check_flags = PF_X; \ 192 check_flags = PF_X; \
175 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \ 193 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
194 if (ehdr->e_type == ET_DYN || ehdr->e_type == ET_EXEC) \
176 if (multi_load++ > 2) warnf("%s: more than 2 PT_LOAD's !?", elf->filename); \ 195 if (multi_load++ > max_pt_load) warnf("%s: more than %i PT_LOAD's !?", elf->filename, max_pt_load); \
177 found = found_load; \ 196 found = found_load; \
178 off = 8; \ 197 offset = 8; \
179 check_flags = PF_W|PF_X; \ 198 check_flags = PF_W|PF_X; \
180 } else \ 199 } else \
181 continue; \ 200 continue; \
182 flags = EGET(phdr[i].p_flags); \ 201 flags = EGET(phdr[i].p_flags); \
183 if (be_quiet && ((flags & check_flags) != check_flags)) \ 202 if (be_quiet && ((flags & check_flags) != check_flags)) \
184 continue; \ 203 continue; \
204 if (fix_elf && ((flags & PF_X) != flags)) { \
205 ESET(phdr[i].p_flags, flags & (PF_X ^ (size_t)-1)); \
206 ret[3] = ret[7] = '!'; \
207 flags = EGET(phdr[i].p_flags); \
208 } \
185 memcpy(ret+off, gnu_short_stack_flags(flags), 3); \ 209 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
186 *found = 1; \ 210 *found = 1; \
187 ++shown; \ 211 ++shown; \
212 } \
213 } else if (elf->shdr != NULL) { \
214 /* no program headers which means this is prob an object file */ \
215 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
216 Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \
217 char *str; \
218 if ((void*)strtbl > (void*)elf->data_end) \
219 goto skip_this_shdr##B; \
220 check_flags = SHF_WRITE|SHF_EXECINSTR; \
221 for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \
222 if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \
223 offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \
224 str = elf->data + offset; \
225 if (str > elf->data + offset + sizeof(NOTE_GNU_STACK)) continue; \
226 if (!strcmp(str, NOTE_GNU_STACK)) { \
227 if (multi_stack++) warnf("%s: multiple .note.GNU-stack's !?", elf->filename); \
228 flags = EGET(shdr[i].sh_flags); \
229 if (be_quiet && ((flags & check_flags) != check_flags)) \
230 continue; \
231 ++*found_phdr; \
232 shown = 1; \
233 if (flags & SHF_WRITE) ret[0] = 'W'; \
234 if (flags & SHF_ALLOC) ret[1] = 'A'; \
235 if (flags & SHF_EXECINSTR) ret[2] = 'X'; \
236 if (flags & 0xFFFFFFF8) warn("Invalid section flags for GNU-stack"); \
237 break; \
238 } \
239 } \
240 skip_this_shdr##B: \
241 if (!multi_stack) { \
242 *found_phdr = 1; \
243 shown = 1; \
244 memcpy(ret, "!WX", 3); \
245 } \
188 } \ 246 } \
189 } 247 }
190 SHOW_PHDR(32) 248 SHOW_PHDR(32)
191 SHOW_PHDR(64) 249 SHOW_PHDR(64)
192 }
193 250
194 if (be_quiet && !shown) 251 if (be_wewy_wewy_quiet || (be_quiet && !shown))
195 return NULL; 252 return NULL;
196 else 253 else
197 return ret; 254 return ret;
198} 255}
199static char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 256static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
200{ 257{
201 static char ret[] = "TEXTREL"; 258 static const char *ret = "TEXTREL";
202 unsigned long i; 259 unsigned long i;
203 260
204 if (!show_textrel && !show_textrels) return NULL; 261 if (!show_textrel && !show_textrels) return NULL;
205 262
206 if (elf->phdr) { 263 if (elf->phdr) {
229 } 286 }
230 287
231 if (be_quiet || be_wewy_wewy_quiet) 288 if (be_quiet || be_wewy_wewy_quiet)
232 return NULL; 289 return NULL;
233 else 290 else
234 return (char *)" - "; 291 return " - ";
235} 292}
236static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel) 293static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel)
237{ 294{
238 unsigned long s, r, rmax; 295 unsigned long s, r, rmax;
239 void *symtab_void, *strtab_void, *text_void; 296 void *symtab_void, *strtab_void, *text_void;
292 if (be_verbose <= 2) continue; \ 349 if (be_verbose <= 2) continue; \
293 } else \ 350 } else \
294 *found_textrels = 1; \ 351 *found_textrels = 1; \
295 /* locate this relocation symbol name */ \ 352 /* locate this relocation symbol name */ \
296 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 353 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
354 if ((void*)sym > (void*)elf->data_end) { \
355 warn("%s: corrupt ELF symbol", elf->filename); \
356 continue; \
357 } \
297 sym_max = ELF ## B ## _R_SYM(r_info); \ 358 sym_max = ELF ## B ## _R_SYM(r_info); \
298 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \ 359 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
299 sym += sym_max; \ 360 sym += sym_max; \
300 else \ 361 else \
301 sym = NULL; \ 362 sym = NULL; \
333 warnf("ELF %s has TEXTREL markings but doesnt appear to have any real TEXTREL's !?", elf->filename); 394 warnf("ELF %s has TEXTREL markings but doesnt appear to have any real TEXTREL's !?", elf->filename);
334 395
335 return NULL; 396 return NULL;
336} 397}
337 398
338static void rpath_security_checks(elfobj *, char *); 399static void rpath_security_checks(elfobj *, char *, const char *);
339static void rpath_security_checks(elfobj *elf, char *item) { 400static void rpath_security_checks(elfobj *elf, char *item, const char *dt_type)
401{
340 struct stat st; 402 struct stat st;
341 switch (*item) { 403 switch (*item) {
342 case 0:
343 warnf("Security problem NULL RPATH in %s", elf->filename);
344 break;
345 case '/': break; 404 case '/': break;
405 case '.':
406 warnf("Security problem with relative %s '%s' in %s", dt_type, item, elf->filename);
407 break;
408 case ':':
409 case '\0':
410 warnf("Security problem NULL %s in %s", dt_type, elf->filename);
411 break;
346 case '$': 412 case '$':
347 if (fstat(elf->fd, &st) != -1) 413 if (fstat(elf->fd, &st) != -1)
348 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID)) 414 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
349 warnf("Security problem with RPATH='%s' in %s with mode set of %o", 415 warnf("Security problem with %s='%s' in %s with mode set of %o",
350 item, elf->filename, st.st_mode & 07777); 416 dt_type, item, elf->filename, st.st_mode & 07777);
351 break; 417 break;
352 default: 418 default:
353 warnf("Maybe? sec problem with RPATH='%s' in %s", item, elf->filename); 419 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename);
354 break; 420 break;
355 } 421 }
356} 422}
357static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len) 423static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
358{ 424{
394 /* Verify the memory is somewhat sane */ \ 460 /* Verify the memory is somewhat sane */ \
395 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 461 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
396 if (offset < (Elf ## B ## _Off)elf->len) { \ 462 if (offset < (Elf ## B ## _Off)elf->len) { \
397 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \ 463 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
398 *r = (char*)(elf->data + offset); \ 464 *r = (char*)(elf->data + offset); \
465 /* cache the length in case we need to nuke this section later on */ \
466 if (fix_elf) \
467 offset = strlen(*r); \
399 /* If quiet, don't output paths in ld.so.conf */ \ 468 /* If quiet, don't output paths in ld.so.conf */ \
400 if (be_quiet) { \ 469 if (be_quiet) { \
401 size_t len; \ 470 size_t len; \
402 char *start, *end; \ 471 char *start, *end; \
403 /* note that we only 'chop' off leading known paths. */ \ 472 /* note that we only 'chop' off leading known paths. */ \
404 /* since *r is read-only memory, we can only move the ptr forward. */ \ 473 /* since *r is read-only memory, we can only move the ptr forward. */ \
405 start = *r; \ 474 start = *r; \
406 /* scan each path in : delimited list */ \ 475 /* scan each path in : delimited list */ \
407 while (start) { \ 476 while (start) { \
408 rpath_security_checks(elf, start); \ 477 rpath_security_checks(elf, start, get_elfdtype(word)); \
409 end = strchr(start, ':'); \ 478 end = strchr(start, ':'); \
410 len = (end ? abs(end - start) : strlen(start)); \ 479 len = (end ? abs(end - start) : strlen(start)); \
480 if (use_ldcache) \
411 for (s = 0; ldpaths[s]; ++s) { \ 481 for (s = 0; ldpaths[s]; ++s) \
412 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \ 482 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \
413 *r = (end ? end + 1 : NULL); \ 483 *r = end; \
484 /* corner case ... if RPATH reads "/usr/lib:", we want \
485 * to show ':' rather than '' */ \
486 if (end && end[1] != '\0') \
487 (*r)++; \
414 break; \ 488 break; \
415 } \ 489 } \
416 } \
417 if (!*r || !ldpaths[s] || !end) \ 490 if (!*r || !end) \
418 start = NULL; \ 491 break; \
419 else \ 492 else \
420 start = start + len + 1; \ 493 start = start + len + 1; \
421 } \ 494 } \
422 } \ 495 } \
496 if (*r) { \
497 if (fix_elf > 2 || (fix_elf && **r == '\0')) { \
498 /* just nuke it */ \
499 nuke_it##B: \
500 memset(*r, 0x00, offset); \
501 *r = NULL; \
502 ESET(dyn->d_tag, DT_DEBUG); \
503 ESET(dyn->d_un.d_ptr, 0); \
504 } else if (fix_elf) { \
505 /* try to clean "bad" paths */ \
506 size_t len, tmpdir_len; \
507 char *start, *end; \
508 const char *tmpdir; \
509 start = *r; \
510 tmpdir = (getenv("TMPDIR") ? : "."); \
511 tmpdir_len = strlen(tmpdir); \
512 while (1) { \
513 end = strchr(start, ':'); \
514 if (start == end) { \
515 eat_this_path##B: \
516 len = strlen(end); \
517 memmove(start, end+1, len); \
518 start[len-1] = '\0'; \
519 end = start - 1; \
520 } else if (tmpdir && !strncmp(start, tmpdir, tmpdir_len)) { \
521 if (!end) { \
522 if (start == *r) \
523 goto nuke_it##B; \
524 *--start = '\0'; \
525 } else \
526 goto eat_this_path##B; \
527 } \
528 if (!end) \
529 break; \
530 start = end + 1; \
531 } \
532 if (**r == '\0') \
533 goto nuke_it##B; \
534 } \
535 if (*r) \
423 if (*r) *found_rpath = 1; \ 536 *found_rpath = 1; \
537 } \
424 } \ 538 } \
425 ++dyn; \ 539 ++dyn; \
426 } \ 540 } \
427 } } 541 } }
428 SHOW_RPATH(32) 542 SHOW_RPATH(32)
445 } else if (rpath || runpath) 559 } else if (rpath || runpath)
446 xstrcat(ret, (runpath ? runpath : rpath), ret_len); 560 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
447 else if (!be_quiet) 561 else if (!be_quiet)
448 xstrcat(ret, " - ", ret_len); 562 xstrcat(ret, " - ", ret_len);
449} 563}
564
565#define LDSO_CACHE_MAGIC "ld.so-"
566#define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1)
567#define LDSO_CACHE_VER "1.7.0"
568#define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1)
569#define FLAG_ANY -1
570#define FLAG_TYPE_MASK 0x00ff
571#define FLAG_LIBC4 0x0000
572#define FLAG_ELF 0x0001
573#define FLAG_ELF_LIBC5 0x0002
574#define FLAG_ELF_LIBC6 0x0003
575#define FLAG_REQUIRED_MASK 0xff00
576#define FLAG_SPARC_LIB64 0x0100
577#define FLAG_IA64_LIB64 0x0200
578#define FLAG_X8664_LIB64 0x0300
579#define FLAG_S390_LIB64 0x0400
580#define FLAG_POWERPC_LIB64 0x0500
581#define FLAG_MIPS64_LIBN32 0x0600
582#define FLAG_MIPS64_LIBN64 0x0700
583
584static char *lookup_cache_lib(elfobj *, char *);
585static char *lookup_cache_lib(elfobj *elf, char *fname)
586{
587 int fd = 0;
588 char *strs;
589 static char buf[__PAX_UTILS_PATH_MAX] = "";
590 const char *cachefile = "/etc/ld.so.cache";
591 struct stat st;
592
593 typedef struct {
594 char magic[LDSO_CACHE_MAGIC_LEN];
595 char version[LDSO_CACHE_VER_LEN];
596 int nlibs;
597 } header_t;
598 header_t *header;
599
600 typedef struct {
601 int flags;
602 int sooffset;
603 int liboffset;
604 } libentry_t;
605 libentry_t *libent;
606
607 if (fname == NULL)
608 return NULL;
609
610 if (ldcache == 0) {
611 if (stat(cachefile, &st) || (fd = open(cachefile, O_RDONLY)) == -1)
612 return NULL;
613
614 /* cache these values so we only map/unmap the cache file once */
615 ldcache_size = st.st_size;
616 ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0);
617
618 close(fd);
619
620 if (ldcache == (caddr_t)-1) {
621 ldcache = 0;
622 return NULL;
623 }
624
625 if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN))
626 return NULL;
627 if (memcmp (((header_t *) ldcache)->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
628 return NULL;
629 }
630
631 header = (header_t *) ldcache;
632 libent = (libentry_t *) (ldcache + sizeof(header_t));
633 strs = (char *) &libent[header->nlibs];
634
635 for (fd = 0; fd < header->nlibs; fd++) {
636 /* this should be more fine grained, but for now we assume that
637 * diff arches will not be cached together. and we ignore the
638 * the different multilib mips cases. */
639 if (elf->elf_class == ELFCLASS64 && !(libent[fd].flags & FLAG_REQUIRED_MASK))
640 continue;
641 if (elf->elf_class == ELFCLASS32 && (libent[fd].flags & FLAG_REQUIRED_MASK))
642 continue;
643
644 if (strcmp(fname, strs + libent[fd].sooffset) != 0)
645 continue;
646 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
647 }
648 return buf;
649}
650
651
450static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len) 652static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
451{ 653{
452 unsigned long i; 654 unsigned long i;
453 char *needed; 655 char *needed;
454 void *strtbl_void; 656 void *strtbl_void;
657 char *p;
455 658
456 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL; 659 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
457 660
458 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 661 strtbl_void = elf_findsecbyname(elf, ".dynstr");
459 662
479 } \ 682 } \
480 needed = (char*)(elf->data + offset); \ 683 needed = (char*)(elf->data + offset); \
481 if (op == 0) { \ 684 if (op == 0) { \
482 if (!be_wewy_wewy_quiet) { \ 685 if (!be_wewy_wewy_quiet) { \
483 if (*found_needed) xchrcat(ret, ',', ret_len); \ 686 if (*found_needed) xchrcat(ret, ',', ret_len); \
687 if (use_ldcache) \
688 if ((p = lookup_cache_lib(elf, needed)) != NULL) \
689 needed = p; \
484 xstrcat(ret, needed, ret_len); \ 690 xstrcat(ret, needed, ret_len); \
485 } \ 691 } \
486 *found_needed = 1; \ 692 *found_needed = 1; \
487 } else { \ 693 } else { \
488 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \ 694 if (!strncmp(find_lib, needed, strlen( !gmatch ? needed : find_lib))) { \
612 return NULL; 818 return NULL;
613} 819}
614static char *scanelf_file_sym(elfobj *elf, char *found_sym) 820static char *scanelf_file_sym(elfobj *elf, char *found_sym)
615{ 821{
616 unsigned long i; 822 unsigned long i;
823 char *ret;
617 void *symtab_void, *strtab_void; 824 void *symtab_void, *strtab_void;
618 825
619 if (!find_sym) return NULL; 826 if (!find_sym) return NULL;
827 ret = find_sym;
620 828
621 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void); 829 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
622 830
623 if (symtab_void && strtab_void) { 831 if (symtab_void && strtab_void) {
624#define FIND_SYM(B) \ 832#define FIND_SYM(B) \
625 if (elf->elf_class == ELFCLASS ## B) { \ 833 if (elf->elf_class == ELFCLASS ## B) { \
626 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 834 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
627 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 835 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
628 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 836 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
629 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 837 unsigned long cnt = EGET(symtab->sh_entsize); \
630 char *symname; \ 838 char *symname; \
839 if (cnt) \
840 cnt = EGET(symtab->sh_size) / cnt; \
631 for (i = 0; i < cnt; ++i) { \ 841 for (i = 0; i < cnt; ++i) { \
632 if (sym->st_name) { \ 842 if (sym->st_name) { \
633 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 843 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
844 if ((void*)symname > (void*)elf->data_end) { \
845 warnf("%s: corrupt ELF symbols", elf->filename); \
846 continue; \
847 } \
634 if (*find_sym == '*') { \ 848 if (*find_sym == '*') { \
635 printf("%s(%s) %5lX %15s %s\n", \ 849 printf("%s(%s) %5lX %15s %s\n", \
636 ((*found_sym == 0) ? "\n\t" : "\t"), \ 850 ((*found_sym == 0) ? "\n\t" : "\t"), \
637 elf->base_filename, \ 851 elf->base_filename, \
638 (long)sym->st_size, \ 852 (unsigned long)sym->st_size, \
639 (char *)get_elfstttype(sym->st_info), \ 853 get_elfstttype(sym->st_info), \
640 symname); \ 854 symname); \
641 *found_sym = 1; \ 855 *found_sym = 1; \
642 } else if ((strcmp(find_sym, symname) == 0) || \ 856 } else { \
857 char *this_sym, *next_sym; \
858 this_sym = find_sym; \
859 do { \
860 next_sym = strchr(this_sym, ','); \
861 if (next_sym == NULL) \
862 next_sym = this_sym + strlen(this_sym); \
863 if ((strncmp(this_sym, symname, (next_sym-this_sym)) == 0 && symname[next_sym-this_sym] == '\0') || \
643 (strcmp(symname, versioned_symname) == 0)) \ 864 (strcmp(symname, versioned_symname) == 0)) { \
865 ret = this_sym; \
644 (*found_sym)++; \ 866 (*found_sym)++; \
867 goto break_out; \
868 } \
869 this_sym = next_sym + 1; \
870 } while (*next_sym != '\0'); \
871 } \
645 } \ 872 } \
646 ++sym; \ 873 ++sym; \
647 } } 874 } }
648 FIND_SYM(32) 875 FIND_SYM(32)
649 FIND_SYM(64) 876 FIND_SYM(64)
650 } 877 }
651 878
879break_out:
652 if (be_wewy_wewy_quiet) return NULL; 880 if (be_wewy_wewy_quiet) return NULL;
653 881
654 if (*find_sym != '*' && *found_sym) 882 if (*find_sym != '*' && *found_sym)
655 return find_sym; 883 return ret;
656 if (be_quiet) 884 if (be_quiet)
657 return NULL; 885 return NULL;
658 else 886 else
659 return (char *)" - "; 887 return (char *)" - ";
660} 888}
889
890
891static char *scanelf_file_sections(elfobj *elf, char *found_section)
892{
893 if (!find_section)
894 return NULL;
895
896#define FIND_SECTION(B) \
897 if (elf->elf_class == ELFCLASS ## B) { \
898 Elf ## B ## _Shdr *section; \
899 section = SHDR ## B (elf_findsecbyname(elf, find_section)); \
900 if (section != NULL) \
901 *found_section = 1; \
902 }
903 FIND_SECTION(32)
904 FIND_SECTION(64)
905
906
907 if (be_wewy_wewy_quiet) return NULL;
908
909 if (*found_section)
910 return find_section;
911
912 if (be_quiet)
913 return NULL;
914 else
915 return (char *)" - ";
916}
917
661/* scan an elf file and show all the fun stuff */ 918/* scan an elf file and show all the fun stuff */
662#define prints(str) write(fileno(stdout), str, strlen(str)) 919#define prints(str) write(fileno(stdout), str, strlen(str))
663static void scanelf_file(const char *filename) 920static int scanelf_elfobj(elfobj *elf)
664{ 921{
665 unsigned long i; 922 unsigned long i;
666 char found_pax, found_phdr, found_relro, found_load, found_textrel, 923 char found_pax, found_phdr, found_relro, found_load, found_textrel,
667 found_rpath, found_needed, found_interp, found_bind, found_soname, 924 found_rpath, found_needed, found_interp, found_bind, found_soname,
668 found_sym, found_lib, found_file, found_textrels; 925 found_sym, found_lib, found_file, found_textrels, found_section;
669 elfobj *elf;
670 struct stat st;
671 static char *out_buffer = NULL; 926 static char *out_buffer = NULL;
672 static size_t out_len; 927 static size_t out_len;
673 928
674 /* make sure 'filename' exists */
675 if (lstat(filename, &st) == -1) {
676 if (be_verbose > 2) printf("%s: does not exist\n", filename);
677 return;
678 }
679 /* always handle regular files and handle symlinked files if no -y */
680 if (S_ISLNK(st.st_mode)) {
681 if (!scan_symlink) return;
682 stat(filename, &st);
683 }
684 if (!S_ISREG(st.st_mode)) {
685 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
686 return;
687 }
688
689 found_pax = found_phdr = found_relro = found_load = found_textrel = \ 929 found_pax = found_phdr = found_relro = found_load = found_textrel = \
690 found_rpath = found_needed = found_interp = found_bind = found_soname = \ 930 found_rpath = found_needed = found_interp = found_bind = found_soname = \
691 found_sym = found_lib = found_file = found_textrels = 0; 931 found_sym = found_lib = found_file = found_textrels = found_section = 0;
692 932
693 /* verify this is real ELF */
694 if ((elf = readelf(filename)) == NULL) {
695 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
696 return;
697 }
698
699 if (be_verbose > 1) 933 if (be_verbose > 2)
700 printf("%s: scanning file {%s,%s}\n", filename, 934 printf("%s: scanning file {%s,%s}\n", elf->filename,
701 get_elfeitype(EI_CLASS, elf->elf_class), 935 get_elfeitype(EI_CLASS, elf->elf_class),
702 get_elfeitype(EI_DATA, elf->data[EI_DATA])); 936 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
703 else if (be_verbose) 937 else if (be_verbose > 1)
704 printf("%s: scanning file\n", filename); 938 printf("%s: scanning file\n", elf->filename);
705 939
706 /* init output buffer */ 940 /* init output buffer */
707 if (!out_buffer) { 941 if (!out_buffer) {
708 out_len = sizeof(char) * 80; 942 out_len = sizeof(char) * 80;
709 out_buffer = (char*)xmalloc(out_len); 943 out_buffer = (char*)xmalloc(out_len);
731 case 'b': prints("BIND "); break; 965 case 'b': prints("BIND "); break;
732 case 'S': prints("SONAME "); break; 966 case 'S': prints("SONAME "); break;
733 case 's': prints("SYM "); break; 967 case 's': prints("SYM "); break;
734 case 'N': prints("LIB "); break; 968 case 'N': prints("LIB "); break;
735 case 'T': prints("TEXTRELS "); break; 969 case 'T': prints("TEXTRELS "); break;
970 case 'k': prints("SECTION "); break;
736 default: warnf("'%c' has no title ?", out_format[i]); 971 default: warnf("'%c' has no title ?", out_format[i]);
737 } 972 }
738 } 973 }
739 if (!found_file) prints("FILE "); 974 if (!found_file) prints("FILE ");
740 prints("\n"); 975 prints("\n");
744 979
745 /* dump all the good stuff */ 980 /* dump all the good stuff */
746 for (i = 0; out_format[i]; ++i) { 981 for (i = 0; out_format[i]; ++i) {
747 const char *out; 982 const char *out;
748 const char *tmp; 983 const char *tmp;
749
750 /* make sure we trim leading spaces in quiet mode */
751 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
752 *out_buffer = '\0';
753 984
754 if (!IS_MODIFIER(out_format[i])) { 985 if (!IS_MODIFIER(out_format[i])) {
755 xchrcat(&out_buffer, out_format[i], &out_len); 986 xchrcat(&out_buffer, out_format[i], &out_len);
756 continue; 987 continue;
757 } 988 }
763 case '#': 994 case '#':
764 xchrcat(&out_buffer, out_format[i], &out_len); break; 995 xchrcat(&out_buffer, out_format[i], &out_len); break;
765 case 'F': 996 case 'F':
766 found_file = 1; 997 found_file = 1;
767 if (be_wewy_wewy_quiet) break; 998 if (be_wewy_wewy_quiet) break;
768 xstrcat(&out_buffer, filename, &out_len); 999 xstrcat(&out_buffer, elf->filename, &out_len);
769 break; 1000 break;
770 case 'p': 1001 case 'p':
771 found_file = 1; 1002 found_file = 1;
772 if (be_wewy_wewy_quiet) break; 1003 if (be_wewy_wewy_quiet) break;
773 tmp = filename; 1004 tmp = elf->filename;
774 if (search_path) { 1005 if (search_path) {
775 ssize_t len_search = strlen(search_path); 1006 ssize_t len_search = strlen(search_path);
776 ssize_t len_file = strlen(filename); 1007 ssize_t len_file = strlen(elf->filename);
777 if (!strncmp(filename, search_path, len_search) && \ 1008 if (!strncmp(elf->filename, search_path, len_search) && \
778 len_file > len_search) 1009 len_file > len_search)
779 tmp += len_search; 1010 tmp += len_search;
780 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++; 1011 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
781 } 1012 }
782 xstrcat(&out_buffer, tmp, &out_len); 1013 xstrcat(&out_buffer, tmp, &out_len);
783 break; 1014 break;
784 case 'f': 1015 case 'f':
785 found_file = 1; 1016 found_file = 1;
786 if (be_wewy_wewy_quiet) break; 1017 if (be_wewy_wewy_quiet) break;
787 tmp = strrchr(filename, '/'); 1018 tmp = strrchr(elf->filename, '/');
788 tmp = (tmp == NULL ? filename : tmp+1); 1019 tmp = (tmp == NULL ? elf->filename : tmp+1);
789 xstrcat(&out_buffer, tmp, &out_len); 1020 xstrcat(&out_buffer, tmp, &out_len);
790 break; 1021 break;
791 case 'o': out = get_elfetype(elf); break; 1022 case 'o': out = get_elfetype(elf); break;
792 case 'x': out = scanelf_file_pax(elf, &found_pax); break; 1023 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
793 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break; 1024 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
798 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break; 1029 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
799 case 'i': out = scanelf_file_interp(elf, &found_interp); break; 1030 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
800 case 'b': out = scanelf_file_bind(elf, &found_bind); break; 1031 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
801 case 'S': out = scanelf_file_soname(elf, &found_soname); break; 1032 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
802 case 's': out = scanelf_file_sym(elf, &found_sym); break; 1033 case 's': out = scanelf_file_sym(elf, &found_sym); break;
1034 case 'k': out = scanelf_file_sections(elf, &found_section); break;
803 default: warnf("'%c' has no scan code?", out_format[i]); 1035 default: warnf("'%c' has no scan code?", out_format[i]);
804 } 1036 }
1037 if (out) {
1038 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
1039 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
1040 xstrncat(&out_buffer, out, &out_len, (tmp-out));
1041 else
805 if (out) xstrcat(&out_buffer, out, &out_len); 1042 xstrcat(&out_buffer, out, &out_len);
1043 }
806 } 1044 }
807 1045
808#define FOUND_SOMETHING() \ 1046#define FOUND_SOMETHING() \
809 (found_pax || found_phdr || found_relro || found_load || found_textrel || \ 1047 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
810 found_rpath || found_needed || found_interp || found_bind || \ 1048 found_rpath || found_needed || found_interp || found_bind || \
811 found_soname || found_sym || found_lib || found_textrels) 1049 found_soname || found_sym || found_lib || found_textrels || found_section )
812 1050
813 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) { 1051 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
814 xchrcat(&out_buffer, ' ', &out_len); 1052 xchrcat(&out_buffer, ' ', &out_len);
815 xstrcat(&out_buffer, filename, &out_len); 1053 xstrcat(&out_buffer, elf->filename, &out_len);
816 } 1054 }
817 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) { 1055 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
818 puts(out_buffer); 1056 puts(out_buffer);
819 fflush(stdout); 1057 fflush(stdout);
820 } 1058 }
821 1059
1060 return 0;
1061}
1062
1063/* scan a single elf */
1064static int scanelf_elf(const char *filename, int fd, size_t len)
1065{
1066 int ret = 1;
1067 elfobj *elf;
1068
1069 /* verify this is real ELF */
1070 if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) {
1071 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
1072 return ret;
1073 }
1074 switch (match_bits) {
1075 case 32:
1076 if (elf->elf_class != ELFCLASS32)
1077 goto label_done;
1078 break;
1079 case 64:
1080 if (elf->elf_class != ELFCLASS64)
1081 goto label_done;
1082 break;
1083 default: break;
1084 }
1085 if (strlen(match_etypes)) {
1086 char sbuf[126];
1087 strncpy(sbuf, match_etypes, sizeof(sbuf));
1088 if (strchr(match_etypes, ',') != NULL) {
1089 char *p;
1090 while((p = strrchr(sbuf, ',')) != NULL) {
1091 *p = 0;
1092 if (atoi(p+1) == get_etype(elf))
1093 goto label_ret;
1094 }
1095 }
1096 if (atoi(sbuf) != get_etype(elf))
1097 goto label_done;
1098 }
1099
1100label_ret:
1101 ret = scanelf_elfobj(elf);
1102
1103label_done:
822 unreadelf(elf); 1104 unreadelf(elf);
1105 return ret;
1106}
1107
1108/* scan an archive of elfs */
1109static int scanelf_archive(const char *filename, int fd, size_t len)
1110{
1111 archive_handle *ar;
1112 archive_member *m;
1113 char *ar_buffer;
1114 elfobj *elf;
1115
1116 ar = ar_open_fd(filename, fd);
1117 if (ar == NULL)
1118 return 1;
1119
1120 ar_buffer = (char*)mmap(0, len, PROT_READ | (fix_elf ? PROT_WRITE : 0), (fix_elf ? MAP_SHARED : MAP_PRIVATE), fd, 0);
1121 while ((m=ar_next(ar)) != NULL) {
1122 elf = readelf_buffer(m->name, ar_buffer+lseek(fd,0,SEEK_CUR), m->size);
1123 if (elf) {
1124 scanelf_elfobj(elf);
1125 unreadelf(elf);
1126 }
1127 }
1128 munmap(ar_buffer, len);
1129
1130 return 0;
1131}
1132/* scan a file which may be an elf or an archive or some other magical beast */
1133static void scanelf_file(const char *filename)
1134{
1135 struct stat st;
1136 int fd;
1137
1138 /* make sure 'filename' exists */
1139 if (lstat(filename, &st) == -1) {
1140 if (be_verbose > 2) printf("%s: does not exist\n", filename);
1141 return;
1142 }
1143
1144 /* always handle regular files and handle symlinked files if no -y */
1145 if (S_ISLNK(st.st_mode)) {
1146 if (!scan_symlink) return;
1147 stat(filename, &st);
1148 }
1149 if (!S_ISREG(st.st_mode)) {
1150 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
1151 return;
1152 }
1153
1154 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1)
1155 return;
1156
1157 if (scanelf_elf(filename, fd, st.st_size) == 1 && scan_archives)
1158 /* if it isn't an ELF, maybe it's an .a archive */
1159 scanelf_archive(filename, fd, st.st_size);
1160
1161 close(fd);
823} 1162}
824 1163
825/* scan a directory for ET_EXEC files and print when we find one */ 1164/* scan a directory for ET_EXEC files and print when we find one */
826static void scanelf_dir(const char *path) 1165static void scanelf_dir(const char *path)
827{ 1166{
828 register DIR *dir; 1167 register DIR *dir;
829 register struct dirent *dentry; 1168 register struct dirent *dentry;
830 struct stat st_top, st; 1169 struct stat st_top, st;
831 char buf[_POSIX_PATH_MAX]; 1170 char buf[__PAX_UTILS_PATH_MAX];
832 size_t pathlen = 0, len = 0; 1171 size_t pathlen = 0, len = 0;
833 1172
834 /* make sure path exists */ 1173 /* make sure path exists */
835 if (lstat(path, &st_top) == -1) { 1174 if (lstat(path, &st_top) == -1) {
836 if (be_verbose > 2) printf("%s: does not exist\n", path); 1175 if (be_verbose > 2) printf("%s: does not exist\n", path);
846 /* now scan the dir looking for fun stuff */ 1185 /* now scan the dir looking for fun stuff */
847 if ((dir = opendir(path)) == NULL) { 1186 if ((dir = opendir(path)) == NULL) {
848 warnf("could not opendir %s: %s", path, strerror(errno)); 1187 warnf("could not opendir %s: %s", path, strerror(errno));
849 return; 1188 return;
850 } 1189 }
851 if (be_verbose) printf("%s: scanning dir\n", path); 1190 if (be_verbose > 1) printf("%s: scanning dir\n", path);
852 1191
853 pathlen = strlen(path); 1192 pathlen = strlen(path);
854 while ((dentry = readdir(dir))) { 1193 while ((dentry = readdir(dir))) {
855 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 1194 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
856 continue; 1195 continue;
875 1214
876static int scanelf_from_file(char *filename) 1215static int scanelf_from_file(char *filename)
877{ 1216{
878 FILE *fp = NULL; 1217 FILE *fp = NULL;
879 char *p; 1218 char *p;
880 char path[_POSIX_PATH_MAX]; 1219 char path[__PAX_UTILS_PATH_MAX];
881 1220
882 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL)) 1221 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL))
883 fp = stdin; 1222 fp = stdin;
884 else if ((fp = fopen(filename, "r")) == NULL) 1223 else if ((fp = fopen(filename, "r")) == NULL)
885 return 1; 1224 return 1;
886 1225
887 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) { 1226 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
888 if ((p = strchr(path, '\n')) != NULL) 1227 if ((p = strchr(path, '\n')) != NULL)
889 *p = 0; 1228 *p = 0;
890 search_path = path; 1229 search_path = path;
891 scanelf_dir(path); 1230 scanelf_dir(path);
892 } 1231 }
893 if (fp != stdin) 1232 if (fp != stdin)
894 fclose(fp); 1233 fclose(fp);
895 return 0; 1234 return 0;
896} 1235}
897 1236
898static void load_ld_so_conf() 1237static int load_ld_so_conf(int i, const char *fname)
899{ 1238{
900 FILE *fp = NULL; 1239 FILE *fp = NULL;
901 char *p; 1240 char *p;
902 char path[_POSIX_PATH_MAX]; 1241 char path[__PAX_UTILS_PATH_MAX];
903 int i = 0;
904 1242
905 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 1243 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
906 return; 1244 return i;
907 1245
1246 if ((fp = fopen(fname, "r")) == NULL)
1247 return i;
1248
908 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) { 1249 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
909 if (*path != '/')
910 continue;
911
912 if ((p = strrchr(path, '\r')) != NULL) 1250 if ((p = strrchr(path, '\r')) != NULL)
913 *p = 0; 1251 *p = 0;
914 if ((p = strchr(path, '\n')) != NULL) 1252 if ((p = strchr(path, '\n')) != NULL)
915 *p = 0; 1253 *p = 0;
1254#ifdef HAVE_GLOB
1255 // recursive includes of the same file will make this segfault.
1256 if ((*path == 'i') && (strncmp(path, "include", 7) == 0) && isblank(path[7])) {
1257 glob64_t gl;
1258 size_t x;
1259 char gpath[__PAX_UTILS_PATH_MAX];
1260
1261 gpath[sizeof(gpath)] = 0;
1262
1263 if (path[8] != '/')
1264 snprintf(gpath, sizeof(gpath)-1, "/etc/%s", &path[8]);
1265 else
1266 strncpy(gpath, &path[8], sizeof(gpath)-1);
1267
1268 if ((glob64(gpath, 0, NULL, &gl)) == 0) {
1269 for (x = 0; x < gl.gl_pathc; ++x) {
1270 /* try to avoid direct loops */
1271 if (strcmp(gl.gl_pathv[x], fname) == 0)
1272 continue;
1273 i = load_ld_so_conf(i, gl.gl_pathv[x]);
1274 if (i + 1 >= sizeof(ldpaths) / sizeof(*ldpaths)) {
1275 globfree64(&gl);
1276 return i;
1277 }
1278 }
1279 globfree64 (&gl);
1280 continue;
1281 } else
1282 abort();
1283 }
1284#endif
1285 if (*path != '/')
1286 continue;
916 1287
917 ldpaths[i++] = xstrdup(path); 1288 ldpaths[i++] = xstrdup(path);
918 1289
919 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths)) 1290 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
920 break; 1291 break;
921 } 1292 }
922 ldpaths[i] = NULL; 1293 ldpaths[i] = NULL;
923 1294
924 fclose(fp); 1295 fclose(fp);
1296 return i;
925} 1297}
926 1298
927/* scan /etc/ld.so.conf for paths */ 1299/* scan /etc/ld.so.conf for paths */
928static void scanelf_ldpath() 1300static void scanelf_ldpath()
929{ 1301{
964 } 1336 }
965 1337
966 free(path); 1338 free(path);
967} 1339}
968 1340
969
970
971/* usage / invocation handling functions */ 1341/* usage / invocation handling functions */
972#define PARSE_FLAGS "plRmyxetrnibSs:gN:TaqvF:f:o:BhV" 1342#define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:BhV"
973#define a_argument required_argument 1343#define a_argument required_argument
974static struct option const long_opts[] = { 1344static struct option const long_opts[] = {
975 {"path", no_argument, NULL, 'p'}, 1345 {"path", no_argument, NULL, 'p'},
976 {"ldpath", no_argument, NULL, 'l'}, 1346 {"ldpath", no_argument, NULL, 'l'},
977 {"recursive", no_argument, NULL, 'R'}, 1347 {"recursive", no_argument, NULL, 'R'},
978 {"mount", no_argument, NULL, 'm'}, 1348 {"mount", no_argument, NULL, 'm'},
979 {"symlink", no_argument, NULL, 'y'}, 1349 {"symlink", no_argument, NULL, 'y'},
1350 {"archives", no_argument, NULL, 'A'},
1351 {"ldcache", no_argument, NULL, 'L'},
1352 {"fix", no_argument, NULL, 'X'},
1353 {"setpax", a_argument, NULL, 'z'},
980 {"pax", no_argument, NULL, 'x'}, 1354 {"pax", no_argument, NULL, 'x'},
981 {"header", no_argument, NULL, 'e'}, 1355 {"header", no_argument, NULL, 'e'},
982 {"textrel", no_argument, NULL, 't'}, 1356 {"textrel", no_argument, NULL, 't'},
983 {"rpath", no_argument, NULL, 'r'}, 1357 {"rpath", no_argument, NULL, 'r'},
984 {"needed", no_argument, NULL, 'n'}, 1358 {"needed", no_argument, NULL, 'n'},
985 {"interp", no_argument, NULL, 'i'}, 1359 {"interp", no_argument, NULL, 'i'},
986 {"bind", no_argument, NULL, 'b'}, 1360 {"bind", no_argument, NULL, 'b'},
987 {"soname", no_argument, NULL, 'S'}, 1361 {"soname", no_argument, NULL, 'S'},
988 {"symbol", a_argument, NULL, 's'}, 1362 {"symbol", a_argument, NULL, 's'},
1363 {"section", a_argument, NULL, 'k'},
989 {"lib", a_argument, NULL, 'N'}, 1364 {"lib", a_argument, NULL, 'N'},
990 {"gmatch", no_argument, NULL, 'g'}, 1365 {"gmatch", no_argument, NULL, 'g'},
991 {"textrels", no_argument, NULL, 'T'}, 1366 {"textrels", no_argument, NULL, 'T'},
1367 {"etype", a_argument, NULL, 'E'},
1368 {"bits", a_argument, NULL, 'M'},
992 {"all", no_argument, NULL, 'a'}, 1369 {"all", no_argument, NULL, 'a'},
993 {"quiet", no_argument, NULL, 'q'}, 1370 {"quiet", no_argument, NULL, 'q'},
994 {"verbose", no_argument, NULL, 'v'}, 1371 {"verbose", no_argument, NULL, 'v'},
995 {"format", a_argument, NULL, 'F'}, 1372 {"format", a_argument, NULL, 'F'},
996 {"from", a_argument, NULL, 'f'}, 1373 {"from", a_argument, NULL, 'f'},
1004static const char *opts_help[] = { 1381static const char *opts_help[] = {
1005 "Scan all directories in PATH environment", 1382 "Scan all directories in PATH environment",
1006 "Scan all directories in /etc/ld.so.conf", 1383 "Scan all directories in /etc/ld.so.conf",
1007 "Scan directories recursively", 1384 "Scan directories recursively",
1008 "Don't recursively cross mount points", 1385 "Don't recursively cross mount points",
1009 "Don't scan symlinks\n", 1386 "Don't scan symlinks",
1387 "Scan archives (.a files)",
1388 "Utilize ld.so.cache information (use with -r/-n)",
1389 "Try and 'fix' bad things (use with -r/-e)",
1390 "Sets EI_PAX/PT_PAX_FLAGS to <arg> (use with -Xx)\n",
1010 "Print PaX markings", 1391 "Print PaX markings",
1011 "Print GNU_STACK/PT_LOAD markings", 1392 "Print GNU_STACK/PT_LOAD markings",
1012 "Print TEXTREL information", 1393 "Print TEXTREL information",
1013 "Print RPATH information", 1394 "Print RPATH information",
1014 "Print NEEDED information", 1395 "Print NEEDED information",
1015 "Print INTERP information", 1396 "Print INTERP information",
1016 "Print BIND information", 1397 "Print BIND information",
1017 "Print SONAME information", 1398 "Print SONAME information",
1018 "Find a specified symbol", 1399 "Find a specified symbol",
1400 "Find a specified section",
1019 "Find a specified library", 1401 "Find a specified library",
1020 "Use strncmp to match libraries. (use with -N)", 1402 "Use strncmp to match libraries. (use with -N)",
1021 "Locate cause of TEXTREL", 1403 "Locate cause of TEXTREL",
1404 "Print only ELF files matching numeric constant type",
1405 "Print only ELF files matching numeric bits",
1022 "Print all scanned info (-x -e -t -r -b)\n", 1406 "Print all scanned info (-x -e -t -r -b)\n",
1023 "Only output 'bad' things", 1407 "Only output 'bad' things",
1024 "Be verbose (can be specified more than once)", 1408 "Be verbose (can be specified more than once)",
1025 "Use specified format for output", 1409 "Use specified format for output",
1026 "Read input stream from a filename", 1410 "Read input stream from a filename",
1034/* display usage and exit */ 1418/* display usage and exit */
1035static void usage(int status) 1419static void usage(int status)
1036{ 1420{
1037 unsigned long i; 1421 unsigned long i;
1038 printf("* Scan ELF binaries for stuff\n\n" 1422 printf("* Scan ELF binaries for stuff\n\n"
1039 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); 1423 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
1040 printf("Options: -[%s]\n", PARSE_FLAGS); 1424 printf("Options: -[%s]\n", PARSE_FLAGS);
1041 for (i = 0; long_opts[i].name; ++i) 1425 for (i = 0; long_opts[i].name; ++i)
1042 if (long_opts[i].has_arg == no_argument) 1426 if (long_opts[i].has_arg == no_argument)
1043 printf(" -%c, --%-13s* %s\n", long_opts[i].val, 1427 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
1044 long_opts[i].name, opts_help[i]); 1428 long_opts[i].name, opts_help[i]);
1045 else 1429 else
1046 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val, 1430 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
1047 long_opts[i].name, opts_help[i]); 1431 long_opts[i].name, opts_help[i]);
1048 1432
1049 if (status != EXIT_SUCCESS) 1433 if (status != EXIT_SUCCESS)
1050 exit(status); 1434 exit(status);
1051 1435
1052 puts("\nThe format modifiers for the -F option are:"); 1436 puts("\nThe format modifiers for the -F option are:");
1053 puts(" F Filename \tx PaX Flags \te STACK/RELRO"); 1437 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
1054 puts(" t TEXTREL \tr RPATH \tn NEEDED"); 1438 puts(" t TEXTREL \tr RPATH \tn NEEDED");
1055 puts(" i INTERP \tb BIND \ts symbol"); 1439 puts(" i INTERP \tb BIND \ts symbol");
1056 puts(" N library \to Type \tT TEXTRELs"); 1440 puts(" N library \to Type \tT TEXTRELs");
1057 puts(" S SONAME"); 1441 puts(" S SONAME \tk section");
1058 puts(" p filename (with search path removed)"); 1442 puts(" p filename (with search path removed)");
1059 puts(" f filename (short name/basename)"); 1443 puts(" f filename (short name/basename)");
1060 puts("Prefix each modifier with '%' (verbose) or '#' (silent)"); 1444 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1445
1446 puts("\nELF Etypes:");
1447 print_etypes(stdout);
1061 1448
1062 exit(status); 1449 exit(status);
1063} 1450}
1064 1451
1065/* parse command line arguments and preform needed actions */ 1452/* parse command line arguments and preform needed actions */
1078 VERSION, __FILE__, __DATE__, rcsid, argv0); 1465 VERSION, __FILE__, __DATE__, rcsid, argv0);
1079 exit(EXIT_SUCCESS); 1466 exit(EXIT_SUCCESS);
1080 break; 1467 break;
1081 case 'h': usage(EXIT_SUCCESS); break; 1468 case 'h': usage(EXIT_SUCCESS); break;
1082 case 'f': 1469 case 'f':
1083 if (from_file) err("Don't specify -f twice"); 1470 if (from_file) warn("You prob don't want to specify -f twice");
1084 from_file = xstrdup(optarg); 1471 from_file = optarg;
1472 break;
1473 case 'E':
1474 strncpy(match_etypes, optarg, sizeof(match_etypes));
1475 break;
1476 case 'M':
1477 match_bits = atoi(optarg);
1085 break; 1478 break;
1086 case 'o': { 1479 case 'o': {
1087 FILE *fp = NULL; 1480 FILE *fp = NULL;
1088 if ((fp = freopen(optarg, "w", stdout)) == NULL) 1481 if ((fp = freopen(optarg, "w", stdout)) == NULL)
1089 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1482 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1090 SET_STDOUT(fp); 1483 SET_STDOUT(fp);
1091 break; 1484 break;
1092 } 1485 }
1093 1486 case 'k':
1487 if (find_section) warn("You prob don't want to specify -k twice");
1488 find_section = optarg;
1489 break;
1094 case 's': { 1490 case 's': {
1095 size_t len;
1096 if (find_sym) err("Don't specify -s twice"); 1491 if (find_sym) warn("You prob don't want to specify -s twice");
1097 find_sym = xstrdup(optarg); 1492 find_sym = optarg;
1098 len = strlen(find_sym) + 1;
1099 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1)); 1493 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1100 sprintf(versioned_symname, "%s@", find_sym); 1494 sprintf(versioned_symname, "%s@", find_sym);
1101 break; 1495 break;
1102 } 1496 }
1103 case 'N': { 1497 case 'N': {
1104 if (find_lib) err("Don't specify -N twice"); 1498 if (find_lib) warn("You prob don't want to specify -N twice");
1105 find_lib = xstrdup(optarg); 1499 find_lib = optarg;
1106 break; 1500 break;
1107 } 1501 }
1108 1502
1109 case 'F': { 1503 case 'F': {
1110 if (out_format) err("Don't specify -F twice"); 1504 if (out_format) warn("You prob don't want to specify -F twice");
1111 out_format = xstrdup(optarg); 1505 out_format = optarg;
1112 break; 1506 break;
1507 }
1508 case 'z': {
1509 unsigned long flags = 10240;
1510 size_t x;
1511
1512#define do_state(option, flag) \
1513 if (islower(option)) { \
1514 flags &= ~PF_##flag; \
1515 flags |= PF_NO##flag; \
1516 } else { \
1517 flags &= ~PF_NO##flag; \
1518 flags |= PF_##flag; \
1113 } 1519 }
1114 1520
1521 for (x = 0 ; x < strlen(optarg); x++) {
1522 switch(optarg[x]) {
1523 case 'p':
1524 case 'P':
1525 do_state(optarg[x], PAGEEXEC);
1526 break;
1527 case 's':
1528 case 'S':
1529 do_state(optarg[x], SEGMEXEC);
1530 break;
1531 case 'm':
1532 case 'M':
1533 do_state(optarg[x], MPROTECT);
1534 break;
1535 case 'e':
1536 case 'E':
1537 do_state(optarg[x], EMUTRAMP);
1538 break;
1539 case 'r':
1540 case 'R':
1541 do_state(optarg[x], RANDMMAP);
1542 break;
1543 case 'x':
1544 case 'X':
1545 do_state(optarg[x], RANDEXEC);
1546 break;
1547 default:
1548 break;
1549 }
1550 }
1551 if (!(((flags & PF_PAGEEXEC) && (flags & PF_NOPAGEEXEC)) ||
1552 ((flags & PF_SEGMEXEC) && (flags & PF_NOSEGMEXEC)) ||
1553 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP)) ||
1554 ((flags & PF_RANDEXEC) && (flags & PF_NORANDEXEC)) ||
1555 ((flags & PF_EMUTRAMP) && (flags & PF_NOEMUTRAMP)) ||
1556 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP))))
1557 setpax = flags;
1558 break;
1559 }
1115 case 'g': gmatch = 1; 1560 case 'g': gmatch = 1; break;
1561 case 'L': use_ldcache = 1; break;
1116 case 'y': scan_symlink = 0; break; 1562 case 'y': scan_symlink = 0; break;
1563 case 'A': scan_archives = 1; break;
1117 case 'B': show_banner = 0; break; 1564 case 'B': show_banner = 0; break;
1118 case 'l': scan_ldpath = 1; break; 1565 case 'l': scan_ldpath = 1; break;
1119 case 'p': scan_envpath = 1; break; 1566 case 'p': scan_envpath = 1; break;
1120 case 'R': dir_recurse = 1; break; 1567 case 'R': dir_recurse = 1; break;
1121 case 'm': dir_crossmount = 0; break; 1568 case 'm': dir_crossmount = 0; break;
1569 case 'X': ++fix_elf; break;
1122 case 'x': show_pax = 1; break; 1570 case 'x': show_pax = 1; break;
1123 case 'e': show_phdr = 1; break; 1571 case 'e': show_phdr = 1; break;
1124 case 't': show_textrel = 1; break; 1572 case 't': show_textrel = 1; break;
1125 case 'r': show_rpath = 1; break; 1573 case 'r': show_rpath = 1; break;
1126 case 'n': show_needed = 1; break; 1574 case 'n': show_needed = 1; break;
1131 case 'q': be_quiet = 1; break; 1579 case 'q': be_quiet = 1; break;
1132 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1580 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1133 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break; 1581 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break;
1134 1582
1135 case ':': 1583 case ':':
1136 err("Option missing parameter\n"); 1584 err("Option '%c' is missing parameter", optopt);
1137 case '?': 1585 case '?':
1138 err("Unknown option\n"); 1586 err("Unknown option '%c' or argument missing", optopt);
1139 default: 1587 default:
1140 err("Unhandled option '%c'", i); 1588 err("Unhandled option '%c'; please report this", i);
1141 } 1589 }
1142 } 1590 }
1143 1591
1144 /* let the format option override all other options */ 1592 /* let the format option override all other options */
1145 if (out_format) { 1593 if (out_format) {
1153 case '%': break; 1601 case '%': break;
1154 case '#': break; 1602 case '#': break;
1155 case 'F': break; 1603 case 'F': break;
1156 case 'p': break; 1604 case 'p': break;
1157 case 'f': break; 1605 case 'f': break;
1606 case 'k': break;
1158 case 's': break; 1607 case 's': break;
1159 case 'N': break; 1608 case 'N': break;
1160 case 'o': break; 1609 case 'o': break;
1161 case 'x': show_pax = 1; break; 1610 case 'x': show_pax = 1; break;
1162 case 'e': show_phdr = 1; break; 1611 case 'e': show_phdr = 1; break;
1186 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 1635 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1187 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len); 1636 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1188 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len); 1637 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1189 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len); 1638 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1190 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len); 1639 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1640 if (find_section) xstrcat(&out_format, "%k ", &fmt_len);
1191 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len); 1641 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1192 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 1642 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1193 } 1643 }
1194 if (be_verbose > 2) printf("Format: %s\n", out_format); 1644 if (be_verbose > 2) printf("Format: %s\n", out_format);
1195 1645
1196 /* now lets actually do the scanning */ 1646 /* now lets actually do the scanning */
1197 if (scan_ldpath || (show_rpath && be_quiet)) 1647 if (scan_ldpath || use_ldcache)
1198 load_ld_so_conf(); 1648 load_ld_so_conf(0, "/etc/ld.so.conf");
1199 if (scan_ldpath) scanelf_ldpath(); 1649 if (scan_ldpath) scanelf_ldpath();
1200 if (scan_envpath) scanelf_envpath(); 1650 if (scan_envpath) scanelf_envpath();
1201 if (from_file) { 1651 if (from_file) {
1202 scanelf_from_file(from_file); 1652 scanelf_from_file(from_file);
1203 free(from_file);
1204 from_file = *argv; 1653 from_file = *argv;
1205 } 1654 }
1206 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file) 1655 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1207 err("Nothing to scan !?"); 1656 err("Nothing to scan !?");
1208 while (optind < argc) { 1657 while (optind < argc) {
1209 search_path = argv[optind++]; 1658 search_path = argv[optind++];
1210 scanelf_dir(search_path); 1659 scanelf_dir(search_path);
1211 } 1660 }
1212 1661
1213 /* clean up */ 1662 /* clean up */
1214 if (find_sym) { 1663 if (versioned_symname) free(versioned_symname);
1215 free(find_sym);
1216 free(versioned_symname);
1217 }
1218 if (find_lib) free(find_lib);
1219 if (out_format) free(out_format);
1220 for (i = 0; ldpaths[i]; ++i) 1664 for (i = 0; ldpaths[i]; ++i)
1221 free(ldpaths[i]); 1665 free(ldpaths[i]);
1666
1667 if (ldcache != 0)
1668 munmap(ldcache, ldcache_size);
1222} 1669}
1223 1670
1224 1671
1225 1672
1226/* utility funcs */ 1673/* utility funcs */
1228{ 1675{
1229 char *ret = strdup(s); 1676 char *ret = strdup(s);
1230 if (!ret) err("Could not strdup(): %s", strerror(errno)); 1677 if (!ret) err("Could not strdup(): %s", strerror(errno));
1231 return ret; 1678 return ret;
1232} 1679}
1233
1234static void *xmalloc(size_t size) 1680static void *xmalloc(size_t size)
1235{ 1681{
1236 void *ret = malloc(size); 1682 void *ret = malloc(size);
1237 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size); 1683 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1238 return ret; 1684 return ret;
1239} 1685}
1240
1241static void xstrcat(char **dst, const char *src, size_t *curr_len) 1686static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
1242{ 1687{
1243 size_t new_len; 1688 size_t new_len;
1244 1689
1245 new_len = strlen(*dst) + strlen(src); 1690 new_len = strlen(*dst) + strlen(src);
1246 if (*curr_len <= new_len) { 1691 if (*curr_len <= new_len) {
1247 *curr_len = new_len + (*curr_len / 2); 1692 *curr_len = new_len + (*curr_len / 2);
1248 *dst = realloc(*dst, *curr_len); 1693 *dst = realloc(*dst, *curr_len);
1249 if (!*dst) 1694 if (!*dst)
1250 err("could not realloc %li bytes", (unsigned long)*curr_len); 1695 err("could not realloc() %li bytes", (unsigned long)*curr_len);
1251 } 1696 }
1252 1697
1698 if (n)
1699 strncat(*dst, src, n);
1700 else
1253 strcat(*dst, src); 1701 strcat(*dst, src);
1254} 1702}
1255
1256static inline void xchrcat(char **dst, const char append, size_t *curr_len) 1703static inline void xchrcat(char **dst, const char append, size_t *curr_len)
1257{ 1704{
1258 static char my_app[2]; 1705 static char my_app[2];
1259 my_app[0] = append; 1706 my_app[0] = append;
1260 my_app[1] = '\0'; 1707 my_app[1] = '\0';

Legend:
Removed from v.1.88  
changed lines
  Added in v.1.128

  ViewVC Help
Powered by ViewVC 1.1.20