/[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.43 Revision 1.80
1/* 1/*
2 * Copyright 2003 Ned Ludd <solar@gentoo.org>
3 * Copyright 1999-2005 Gentoo Foundation 2 * Copyright 2003-2005 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.43 2005/05/06 02:55:27 vapier Exp $ 4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.80 2005/06/13 03:09:51 vapier Exp $
6 * 5 *
7 ******************************************************************** 6 ********************************************************************
8 * This program is free software; you can redistribute it and/or 7 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as 8 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation; either version 2 of the 9 * published by the Free Software Foundation; either version 2 of the
22 */ 21 */
23 22
24#include <stdio.h> 23#include <stdio.h>
25#include <stdlib.h> 24#include <stdlib.h>
26#include <sys/types.h> 25#include <sys/types.h>
26#include <libgen.h>
27#include <limits.h>
27#define __USE_GNU 28#define __USE_GNU
28#include <string.h> 29#include <string.h>
29#include <errno.h> 30#include <errno.h>
30#include <unistd.h> 31#include <unistd.h>
31#include <sys/stat.h> 32#include <sys/stat.h>
32#include <dirent.h> 33#include <dirent.h>
33#include <getopt.h> 34#include <getopt.h>
34#include <assert.h> 35#include <assert.h>
35
36#include "paxelf.h" 36#include "paxelf.h"
37 37
38static const char *rcsid = "$Id: scanelf.c,v 1.43 2005/05/06 02:55:27 vapier Exp $"; 38static const char *rcsid = "$Id: scanelf.c,v 1.80 2005/06/13 03:09:51 vapier Exp $";
39#define argv0 "scanelf" 39#define argv0 "scanelf"
40
41#define IS_MODIFIER(c) (c == '%' || c == '#')
40 42
41 43
42 44
43/* prototypes */ 45/* prototypes */
44static void scanelf_file(const char *filename); 46static void scanelf_file(const char *filename);
45static void scanelf_dir(const char *path); 47static void scanelf_dir(const char *path);
46static void scanelf_ldpath(); 48static void scanelf_ldpath();
47static void scanelf_envpath(); 49static void scanelf_envpath();
48static void usage(int status); 50static void usage(int status);
49static void parseargs(int argc, char *argv[]); 51static void parseargs(int argc, char *argv[]);
50static char *xstrdup(char *s); 52static char *xstrdup(const char *s);
51static void *xmalloc(size_t size); 53static void *xmalloc(size_t size);
52static void xstrcat(char **dst, const char *src, size_t *curr_len); 54static void xstrcat(char **dst, const char *src, size_t *curr_len);
53static inline void xchrcat(char **dst, const char append, size_t *curr_len); 55static inline void xchrcat(char **dst, const char append, size_t *curr_len);
54static int xemptybuffer(const char *buff);
55 56
56/* variables to control behavior */ 57/* variables to control behavior */
58static char *ldpaths[256];
57static char scan_ldpath = 0; 59static char scan_ldpath = 0;
58static char scan_envpath = 0; 60static char scan_envpath = 0;
59static char scan_symlink = 1; 61static char scan_symlink = 1;
60static char dir_recurse = 0; 62static char dir_recurse = 0;
61static char dir_crossmount = 1; 63static char dir_crossmount = 1;
62static char show_pax = 0; 64static char show_pax = 0;
63static char show_stack = 0; 65static char show_phdr = 0;
64static char show_textrel = 0; 66static char show_textrel = 0;
65static char show_rpath = 0; 67static char show_rpath = 0;
66static char show_needed = 0; 68static char show_needed = 0;
67static char show_interp = 0; 69static char show_interp = 0;
70static char show_bind = 0;
71static char show_textrels = 0;
68static char show_banner = 1; 72static char show_banner = 1;
69static char be_quiet = 0; 73static char be_quiet = 0;
70static char be_verbose = 0; 74static char be_verbose = 0;
75static char be_wewy_wewy_quiet = 0;
71static char *find_sym = NULL, *versioned_symname = NULL; 76static char *find_sym = NULL, *versioned_symname = NULL;
77static char *find_lib = NULL;
72static char *out_format = NULL; 78static char *out_format = NULL;
79static char *search_path = NULL;
73 80
74 81
75 82
76/* sub-funcs for scanelf_file() */ 83/* sub-funcs for scanelf_file() */
84static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
85{
86 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
87#define GET_SYMTABS(B) \
88 if (elf->elf_class == ELFCLASS ## B) { \
89 Elf ## B ## _Shdr *symtab, *strtab, *dynsym, *dynstr; \
90 /* debug sections */ \
91 symtab = SHDR ## B (elf_findsecbyname(elf, ".symtab")); \
92 strtab = SHDR ## B (elf_findsecbyname(elf, ".strtab")); \
93 /* runtime sections */ \
94 dynsym = SHDR ## B (elf_findsecbyname(elf, ".dynsym")); \
95 dynstr = SHDR ## B (elf_findsecbyname(elf, ".dynstr")); \
96 if (symtab && dynsym) { \
97 *sym = (void*)((EGET(symtab->sh_size) > EGET(dynsym->sh_size)) ? symtab : dynsym); \
98 } else { \
99 *sym = (void*)(symtab ? symtab : dynsym); \
100 } \
101 if (strtab && dynstr) { \
102 *tab = (void*)((EGET(strtab->sh_size) > EGET(dynstr->sh_size)) ? strtab : dynstr); \
103 } else { \
104 *tab = (void*)(strtab ? strtab : dynstr); \
105 } \
106 }
107 GET_SYMTABS(32)
108 GET_SYMTABS(64)
109}
77static char *scanelf_file_pax(elfobj *elf, char *found_pax) 110static char *scanelf_file_pax(elfobj *elf, char *found_pax)
78{ 111{
79 static char *paxflags; 112 static char *paxflags;
113 static char ret[7];
114 unsigned long i, shown;
115
80 116
81 if (!show_pax) return NULL; 117 if (!show_pax) return NULL;
82 118
83 paxflags = pax_short_hf_flags(PAX_FLAGS(elf));
84 if (!be_quiet || (be_quiet && strncmp(paxflags, "PeMRxS", 6))) {
85 *found_pax = 1;
86 return paxflags;
87 }
88
89 return NULL;
90}
91static char *scanelf_file_stack(elfobj *elf, char *found_stack, char *found_relro)
92{
93 static char ret[8];
94 char *found;
95 int i, off, shown;
96
97 if (!show_stack) return NULL;
98
99 shown = 0; 119 shown = 0;
100 strcpy(ret, "--- ---"); 120 memset(&ret, 0, sizeof(ret));
121
122 if (elf->phdr) {
101#define SHOW_STACK(B) \ 123#define SHOW_PAX(B) \
102 if (elf->elf_class == ELFCLASS ## B) { \ 124 if (elf->elf_class == ELFCLASS ## B) { \
103 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 125 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
104 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 126 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
105 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 127 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
128 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
129 continue; \
130 if (be_quiet && (EGET(phdr[i].p_flags) == 10240)) \
131 continue; \
132 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
133 *found_pax = 1; \
134 ++shown; \
135 break; \
136 } \
137 }
138 SHOW_PAX(32)
139 SHOW_PAX(64)
140 }
141
142 /* fall back to EI_PAX if no PT_PAX was found */
143 if (!*ret) {
144 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
145 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
146 *found_pax = 1;
147 return paxflags;
148 }
149 strncpy(ret, paxflags, sizeof(ret));
150 // ++shown;
151 }
152
153 if (be_quiet && !shown)
154 return NULL;
155 return ret;
156
157}
158static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load)
159{
160 static char ret[12];
161 char *found;
162 unsigned long i, off, shown, check_flags;
163 unsigned char multi_stack, multi_relro, multi_load;
164
165 if (!show_phdr) return NULL;
166
167 memcpy(ret, "--- --- ---\0", 12);
168
169 shown = 0;
170 multi_stack = multi_relro = multi_load = 0;
171
172 if (elf->phdr) {
173#define SHOW_PHDR(B) \
174 if (elf->elf_class == ELFCLASS ## B) { \
175 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
176 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
177 uint32_t flags; \
178 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
106 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \ 179 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
180 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
107 found = found_stack; \ 181 found = found_phdr; \
108 off = 0; \ 182 off = 0; \
183 check_flags = PF_X; \
109 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \ 184 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
185 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
110 found = found_relro; \ 186 found = found_relro; \
111 off = 3; \ 187 off = 4; \
188 check_flags = PF_X; \
189 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
190 if (multi_load++ > 2) warnf("%s: more than 2 PT_LOAD's !?", elf->filename); \
191 found = found_load; \
192 off = 8; \
193 check_flags = PF_W|PF_X; \
112 } else \ 194 } else \
113 continue; \ 195 continue; \
114 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \ 196 flags = EGET(phdr[i].p_flags); \
197 if (be_quiet && ((flags & check_flags) != check_flags)) \
115 continue; \ 198 continue; \
116 memcpy(ret+off, gnu_short_stack_flags(EGET(phdr[i].p_flags)), 3); \ 199 memcpy(ret+off, gnu_short_stack_flags(flags), 3); \
117 *found = 1; \ 200 *found = 1; \
118 ++shown; \ 201 ++shown; \
119 } \ 202 } \
120 } 203 }
121 SHOW_STACK(32) 204 SHOW_PHDR(32)
122 SHOW_STACK(64) 205 SHOW_PHDR(64)
206 }
207
123 if (be_quiet && !shown) 208 if (be_quiet && !shown)
124 return NULL; 209 return NULL;
125 else 210 else
126 return ret; 211 return ret;
127} 212}
128static char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 213static char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
129{ 214{
130 static char *ret = "TEXTREL"; 215 static char ret[] = "TEXTREL";
131 int i; 216 unsigned long i;
132 217
133 if (!show_textrel) return NULL; 218 if (!show_textrel && !show_textrels) return NULL;
134 219
220 if (elf->phdr) {
135#define SHOW_TEXTREL(B) \ 221#define SHOW_TEXTREL(B) \
136 if (elf->elf_class == ELFCLASS ## B) { \ 222 if (elf->elf_class == ELFCLASS ## B) { \
137 Elf ## B ## _Dyn *dyn; \ 223 Elf ## B ## _Dyn *dyn; \
138 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 224 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
139 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 225 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
226 Elf ## B ## _Off offset; \
140 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 227 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
141 if (phdr[i].p_type != PT_DYNAMIC) continue; \ 228 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
229 offset = EGET(phdr[i].p_offset); \
230 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
142 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 231 dyn = DYN ## B (elf->data + offset); \
143 while (EGET(dyn->d_tag) != DT_NULL) { \ 232 while (EGET(dyn->d_tag) != DT_NULL) { \
144 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \ 233 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
145 *found_textrel = 1; \ 234 *found_textrel = 1; \
146 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \ 235 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
147 return ret; \ 236 return (be_wewy_wewy_quiet ? NULL : ret); \
148 } \ 237 } \
149 ++dyn; \ 238 ++dyn; \
150 } \ 239 } \
151 } } 240 } }
152 SHOW_TEXTREL(32) 241 SHOW_TEXTREL(32)
153 SHOW_TEXTREL(64) 242 SHOW_TEXTREL(64)
154 if (be_quiet) 243 }
244
245 if (be_quiet || be_wewy_wewy_quiet)
155 return NULL; 246 return NULL;
156 else 247 else
157 return " - "; 248 return (char *)" - ";
249}
250static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel)
251{
252 unsigned long p, s, r, rmax;
253 void *symtab_void, *strtab_void;
254
255 if (!show_textrels) return NULL;
256
257 /* don't search for TEXTREL's if the ELF doesn't have any */
258 if (!*found_textrel) scanelf_file_textrel(elf, found_textrel);
259 if (!*found_textrel) return NULL;
260
261 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
262
263 if (symtab_void && strtab_void && elf->phdr && elf->shdr) {
264#define SHOW_TEXTRELS(B) \
265 if (elf->elf_class == ELFCLASS ## B) { \
266 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
267 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
268 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
269 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
270 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
271 Elf ## B ## _Rel *rel; \
272 Elf ## B ## _Rela *rela; \
273 /* search the section headers for relocations */ \
274 for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \
275 uint32_t sh_type = EGET(shdr[s].sh_type); \
276 if (sh_type == SHT_REL) { \
277 rel = REL ## B (elf->data + EGET(shdr[s].sh_offset)); \
278 rela = NULL; \
279 rmax = EGET(shdr[s].sh_size) / sizeof(*rel); \
280 } else if (sh_type == SHT_RELA) { \
281 rel = NULL; \
282 rela = RELA ## B (elf->data + EGET(shdr[s].sh_offset)); \
283 rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \
284 } else \
285 continue; \
286 /* search the program headers for PT_LOAD headers */ \
287 for (p = 0; p < EGET(ehdr->e_phnum); ++p) { \
288 Elf ## B ## _Addr vaddr; \
289 uint ## B ## _t memsz; \
290 if (EGET(phdr[p].p_type) != PT_LOAD) continue; \
291 if (EGET(phdr[p].p_flags) & PF_W) continue; \
292 vaddr = EGET(phdr[p].p_vaddr); \
293 memsz = EGET(phdr[p].p_memsz); \
294 /* now see if any of the relocs are in the PT_LOAD */ \
295 for (r = 0; r < rmax; ++r) { \
296 unsigned long sym_max; \
297 Elf ## B ## _Addr offset_tmp; \
298 Elf ## B ## _Sym *func; \
299 Elf ## B ## _Sym *sym; \
300 Elf ## B ## _Addr r_offset; \
301 uint ## B ## _t r_info; \
302 if (sh_type == SHT_REL) { \
303 r_offset = EGET(rel[r].r_offset); \
304 r_info = EGET(rel[r].r_info); \
305 } else { \
306 r_offset = EGET(rela[r].r_offset); \
307 r_info = EGET(rela[r].r_info); \
308 } \
309 /* make sure this relocation is inside of the .text */ \
310 if (r_offset < vaddr || r_offset >= vaddr + memsz) continue; \
311 *found_textrels = 1; \
312 /* locate this relocation symbol name */ \
313 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
314 sym_max = ELF ## B ## _R_SYM(r_info); \
315 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
316 sym += sym_max; \
317 else \
318 sym = NULL; \
319 sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
320 /* show the raw details about this reloc */ \
321 printf("\tTEXTREL %s: ", elf->base_filename); \
322 if (sym && sym->st_name) \
323 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
324 else \
325 printf("(NULL: fake?)"); \
326 printf(" [0x%lX]", (unsigned long)r_offset); \
327 /* now try to find the closest symbol that this rel is probably in */ \
328 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
329 func = NULL; \
330 offset_tmp = 0; \
331 while (sym_max--) { \
332 if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \
333 func = sym; \
334 offset_tmp = EGET(sym->st_value); \
335 } \
336 ++sym; \
337 } \
338 printf(" in "); \
339 if (func && func->st_name) \
340 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(func->st_name))); \
341 else \
342 printf("(NULL: fake?)"); \
343 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
344 } \
345 } \
346 } }
347 SHOW_TEXTRELS(32)
348 SHOW_TEXTRELS(64)
349 }
350
351 return NULL;
158} 352}
159static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len) 353static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
160{ 354{
161 /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */ 355 unsigned long i, s;
162 int i;
163 char *rpath, *runpath; 356 char *rpath, *runpath, **r;
164 void *strtbl_void; 357 void *strtbl_void;
165 358
166 if (!show_rpath) return; 359 if (!show_rpath) return;
167 360
168 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 361 strtbl_void = elf_findsecbyname(elf, ".dynstr");
169 rpath = runpath = NULL; 362 rpath = runpath = NULL;
170 363
171 if (strtbl_void) { 364 if (elf->phdr && strtbl_void) {
172#define SHOW_RPATH(B) \ 365#define SHOW_RPATH(B) \
173 if (elf->elf_class == ELFCLASS ## B) { \ 366 if (elf->elf_class == ELFCLASS ## B) { \
174 Elf ## B ## _Dyn *dyn; \ 367 Elf ## B ## _Dyn *dyn; \
175 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 368 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
176 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 369 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
177 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 370 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
371 Elf ## B ## _Off offset; \
372 Elf ## B ## _Xword word; \
373 /* Scan all the program headers */ \
178 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 374 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
375 /* Just scan dynamic headers */ \
179 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 376 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
377 offset = EGET(phdr[i].p_offset); \
378 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
379 /* Just scan dynamic RPATH/RUNPATH headers */ \
180 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 380 dyn = DYN ## B (elf->data + offset); \
181 while (EGET(dyn->d_tag) != DT_NULL) { \ 381 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
182 if (EGET(dyn->d_tag) == DT_RPATH) { \ 382 if (word == DT_RPATH) { \
183 if (rpath) warn("ELF has multiple DT_RPATH's !?"); \ 383 r = &rpath; \
384 } else if (word == DT_RUNPATH) { \
385 r = &runpath; \
386 } else { \
387 ++dyn; \
388 continue; \
389 } \
390 /* Verify the memory is somewhat sane */ \
184 rpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 391 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
392 if (offset < (Elf ## B ## _Off)elf->len) { \
393 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
394 *r = (char*)(elf->data + offset); \
395 /* If quiet, don't output paths in ld.so.conf */ \
396 if (be_quiet) { \
397 size_t len; \
398 char *start, *end; \
399 /* note that we only 'chop' off leading known paths. */ \
400 /* since *r is read-only memory, we can only move the ptr forward. */ \
401 start = *r; \
402 /* scan each path in : delimited list */ \
403 while (start) { \
404 end = strchr(start, ':'); \
405 len = (end ? abs(end - start) : strlen(start)); \
406 for (s = 0; ldpaths[s]; ++s) { \
407 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \
408 *r = (end ? end + 1 : NULL); \
409 break; \
410 } \
411 } \
412 if (!*r || !ldpaths[s] || !end) \
413 start = NULL; \
414 else \
415 start = start + len + 1; \
416 } \
417 } \
185 *found_rpath = 1; \ 418 if (*r) *found_rpath = 1; \
186 } else if (EGET(dyn->d_tag) == DT_RUNPATH) { \
187 if (runpath) warn("ELF has multiple DT_RUNPATH's !?"); \
188 runpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
189 *found_rpath = 1; \
190 } \ 419 } \
191 ++dyn; \ 420 ++dyn; \
192 } \ 421 } \
193 } } 422 } }
194 SHOW_RPATH(32) 423 SHOW_RPATH(32)
195 SHOW_RPATH(64) 424 SHOW_RPATH(64)
196 } 425 }
426
427 if (be_wewy_wewy_quiet) return;
197 428
198 if (rpath && runpath) { 429 if (rpath && runpath) {
199 if (!strcmp(rpath, runpath)) { 430 if (!strcmp(rpath, runpath)) {
200 xstrcat(ret, runpath, ret_len); 431 xstrcat(ret, runpath, ret_len);
201 } else { 432 } else {
209 } else if (rpath || runpath) 440 } else if (rpath || runpath)
210 xstrcat(ret, (runpath ? runpath : rpath), ret_len); 441 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
211 else if (!be_quiet) 442 else if (!be_quiet)
212 xstrcat(ret, " - ", ret_len); 443 xstrcat(ret, " - ", ret_len);
213} 444}
214static void scanelf_file_needed(elfobj *elf, char *found_needed, char **ret, size_t *ret_len) 445static char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
215{ 446{
216 int i; 447 unsigned long i;
217 char *needed; 448 char *needed;
218 void *strtbl_void; 449 void *strtbl_void;
219 450
220 if (!show_needed) return; 451 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
221 452
222 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 453 strtbl_void = elf_findsecbyname(elf, ".dynstr");
223 454
224 if (strtbl_void) { 455 if (elf->phdr && strtbl_void) {
225#define SHOW_NEEDED(B) \ 456#define SHOW_NEEDED(B) \
226 if (elf->elf_class == ELFCLASS ## B) { \ 457 if (elf->elf_class == ELFCLASS ## B) { \
227 Elf ## B ## _Dyn *dyn; \ 458 Elf ## B ## _Dyn *dyn; \
228 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 459 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
229 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 460 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
230 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 461 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
462 Elf ## B ## _Off offset; \
231 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 463 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
232 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 464 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
465 offset = EGET(phdr[i].p_offset); \
466 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
233 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 467 dyn = DYN ## B (elf->data + offset); \
234 while (EGET(dyn->d_tag) != DT_NULL) { \ 468 while (EGET(dyn->d_tag) != DT_NULL) { \
235 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 469 if (EGET(dyn->d_tag) == DT_NEEDED) { \
236 needed = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 470 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
471 if (offset >= (Elf ## B ## _Off)elf->len) { \
472 ++dyn; \
473 continue; \
474 } \
475 needed = (char*)(elf->data + offset); \
476 if (op == 0) { \
477 if (!be_wewy_wewy_quiet) { \
237 if (*found_needed) xchrcat(ret, ',', ret_len); \ 478 if (*found_needed) xchrcat(ret, ',', ret_len); \
238 xstrcat(ret, needed, ret_len); \ 479 xstrcat(ret, needed, ret_len); \
480 } \
239 *found_needed = 1; \ 481 *found_needed = 1; \
482 } else { \
483 if (strcmp(find_lib, needed)) return NULL; \
484 *found_lib = 1; \
485 return (be_wewy_wewy_quiet ? NULL : find_lib); \
486 } \
240 } \ 487 } \
241 ++dyn; \ 488 ++dyn; \
242 } \ 489 } \
243 } } 490 } }
244 SHOW_NEEDED(32) 491 SHOW_NEEDED(32)
245 SHOW_NEEDED(64) 492 SHOW_NEEDED(64)
246 } 493 }
494
495 return NULL;
247} 496}
248static char *scanelf_file_interp(elfobj *elf, char *found_interp) 497static char *scanelf_file_interp(elfobj *elf, char *found_interp)
249{ 498{
250 void *strtbl_void; 499 void *strtbl_void;
251 500
256 if (strtbl_void) { 505 if (strtbl_void) {
257#define SHOW_INTERP(B) \ 506#define SHOW_INTERP(B) \
258 if (elf->elf_class == ELFCLASS ## B) { \ 507 if (elf->elf_class == ELFCLASS ## B) { \
259 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 508 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
260 *found_interp = 1; \ 509 *found_interp = 1; \
261 return elf->data + EGET(strtbl->sh_offset); \ 510 return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(strtbl->sh_offset)); \
262 } 511 }
263 SHOW_INTERP(32) 512 SHOW_INTERP(32)
264 SHOW_INTERP(64) 513 SHOW_INTERP(64)
265 } 514 }
266 return NULL; 515 return NULL;
267} 516}
517static char *scanelf_file_bind(elfobj *elf, char *found_bind)
518{
519 unsigned long i;
520 struct stat s;
521
522 if (!show_bind) return NULL;
523 if (!elf->phdr) return NULL;
524
525#define SHOW_BIND(B) \
526 if (elf->elf_class == ELFCLASS ## B) { \
527 Elf ## B ## _Dyn *dyn; \
528 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
529 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
530 Elf ## B ## _Off offset; \
531 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
532 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
533 offset = EGET(phdr[i].p_offset); \
534 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
535 dyn = DYN ## B (elf->data + offset); \
536 while (EGET(dyn->d_tag) != DT_NULL) { \
537 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
538 (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
539 { \
540 if (be_quiet) return NULL; \
541 *found_bind = 1; \
542 return (char *)(be_wewy_wewy_quiet ? NULL : "NOW"); \
543 } \
544 ++dyn; \
545 } \
546 } \
547 }
548 SHOW_BIND(32)
549 SHOW_BIND(64)
550
551 if (be_wewy_wewy_quiet) return NULL;
552
553 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) {
554 return NULL;
555 } else {
556 *found_bind = 1;
557 return (char *) "LAZY";
558 }
559}
268static char *scanelf_file_sym(elfobj *elf, char *found_sym, const char *filename) 560static char *scanelf_file_sym(elfobj *elf, char *found_sym)
269{ 561{
270 int i; 562 unsigned long i;
271 void *symtab_void, *strtab_void; 563 void *symtab_void, *strtab_void;
272 564
273 if (!find_sym) return NULL; 565 if (!find_sym) return NULL;
274 566
275 symtab_void = elf_findsecbyname(elf, ".symtab"); 567 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
276 strtab_void = elf_findsecbyname(elf, ".strtab");
277 568
278 if (symtab_void && strtab_void) { 569 if (symtab_void && strtab_void) {
279#define FIND_SYM(B) \ 570#define FIND_SYM(B) \
280 if (elf->elf_class == ELFCLASS ## B) { \ 571 if (elf->elf_class == ELFCLASS ## B) { \
281 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 572 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
282 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 573 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
283 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 574 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
284 int cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 575 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
285 char *symname; \ 576 char *symname; \
286 for (i = 0; i < cnt; ++i) { \ 577 for (i = 0; i < cnt; ++i) { \
287 if (sym->st_name) { \ 578 if (sym->st_name) { \
288 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 579 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
289 if (*find_sym == '*') { \ 580 if (*find_sym == '*') { \
290 printf("%s(%s) %5lX %15s %s\n", \ 581 printf("%s(%s) %5lX %15s %s\n", \
291 ((*found_sym == 0) ? "\n\t" : "\t"), \ 582 ((*found_sym == 0) ? "\n\t" : "\t"), \
292 (char *)basename(filename), \ 583 elf->base_filename, \
293 (long)sym->st_size, \ 584 (long)sym->st_size, \
294 (char *)get_elfstttype(sym->st_info), \ 585 (char *)get_elfstttype(sym->st_info), \
295 symname); \ 586 symname); \
296 *found_sym = 1; \ 587 *found_sym = 1; \
297 } else if ((strcmp(find_sym, symname) == 0) || \ 588 } else if ((strcmp(find_sym, symname) == 0) || \
301 ++sym; \ 592 ++sym; \
302 } } 593 } }
303 FIND_SYM(32) 594 FIND_SYM(32)
304 FIND_SYM(64) 595 FIND_SYM(64)
305 } 596 }
597
598 if (be_wewy_wewy_quiet) return NULL;
599
306 if (*find_sym != '*' && *found_sym) 600 if (*find_sym != '*' && *found_sym)
307 return find_sym; 601 return find_sym;
308 if (be_quiet) 602 if (be_quiet)
309 return NULL; 603 return NULL;
310 else 604 else
311 return " - "; 605 return (char *)" - ";
312} 606}
313/* scan an elf file and show all the fun stuff */ 607/* scan an elf file and show all the fun stuff */
314#define prints(str) fputs(str, stdout) 608#define prints(str) write(fileno(stdout), str, strlen(str))
315static void scanelf_file(const char *filename) 609static void scanelf_file(const char *filename)
316{ 610{
317 int i; 611 unsigned long i;
318 char found_pax, found_stack, found_relro, found_textrel, 612 char found_pax, found_phdr, found_relro, found_load, found_textrel,
319 found_rpath, found_needed, found_interp, found_sym, 613 found_rpath, found_needed, found_interp, found_bind,
320 found_file; 614 found_sym, found_lib, found_file, found_textrels;
321 elfobj *elf; 615 elfobj *elf;
322 struct stat st; 616 struct stat st;
323 static char *out_buffer = NULL; 617 static char *out_buffer = NULL;
324 static size_t out_len; 618 static size_t out_len;
325 619
327 if (lstat(filename, &st) == -1) { 621 if (lstat(filename, &st) == -1) {
328 if (be_verbose > 2) printf("%s: does not exist\n", filename); 622 if (be_verbose > 2) printf("%s: does not exist\n", filename);
329 return; 623 return;
330 } 624 }
331 /* always handle regular files and handle symlinked files if no -y */ 625 /* always handle regular files and handle symlinked files if no -y */
332 if (!(S_ISREG(st.st_mode) || (S_ISLNK(st.st_mode) && scan_symlink))) { 626 if (S_ISLNK(st.st_mode)) {
627 if (!scan_symlink) return;
628 stat(filename, &st);
629 }
630 if (!S_ISREG(st.st_mode)) {
333 if (be_verbose > 2) printf("%s: skipping non-file\n", filename); 631 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
334 return; 632 return;
335 } 633 }
336 634
337 found_pax = found_stack = found_relro = found_textrel = \ 635 found_pax = found_phdr = found_relro = found_load = found_textrel = \
338 found_rpath = found_needed = found_interp = found_sym = \ 636 found_rpath = found_needed = found_interp = found_bind = \
339 found_file = 0; 637 found_sym = found_lib = found_file = found_textrels = 0;
340 638
341 /* verify this is real ELF */ 639 /* verify this is real ELF */
342 if ((elf = readelf(filename)) == NULL) { 640 if ((elf = readelf(filename)) == NULL) {
343 if (be_verbose > 2) printf("%s: not an ELF\n", filename); 641 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
344 return; 642 return;
345 } 643 }
346 644
347 if (be_verbose > 1) 645 if (be_verbose > 1)
348 printf("%s: scanning file {%s,%s}\n", filename, 646 printf("%s: scanning file {%s,%s}\n", filename,
349 get_elfeitype(elf, EI_CLASS, elf->elf_class), 647 get_elfeitype(EI_CLASS, elf->elf_class),
350 get_elfeitype(elf, EI_DATA, elf->data[EI_DATA])); 648 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
351 else if (be_verbose) 649 else if (be_verbose)
352 printf("%s: scanning file\n", filename); 650 printf("%s: scanning file\n", filename);
353 651
354 /* init output buffer */ 652 /* init output buffer */
355 if (!out_buffer) { 653 if (!out_buffer) {
358 } 656 }
359 *out_buffer = '\0'; 657 *out_buffer = '\0';
360 658
361 /* show the header */ 659 /* show the header */
362 if (!be_quiet && show_banner) { 660 if (!be_quiet && show_banner) {
363 for (i=0; out_format[i]; ++i) { 661 for (i = 0; out_format[i]; ++i) {
364 if (out_format[i] != '%') continue; 662 if (!IS_MODIFIER(out_format[i])) continue;
365 663
366 switch (out_format[++i]) { 664 switch (out_format[++i]) {
367 case '%': break; 665 case '%': break;
666 case '#': break;
667 case 'F':
668 case 'p':
368 case 'F': prints("FILE "); break; 669 case 'f': prints("FILE "); found_file = 1; break;
369 case 'o': prints(" TYPE "); break; 670 case 'o': prints(" TYPE "); break;
370 case 'x': prints(" PAX "); break; 671 case 'x': prints(" PAX "); break;
371 case 'e': prints("STK/REL "); break; 672 case 'e': prints("STK/REL/PTL "); break;
372 case 't': prints("TEXTREL "); break; 673 case 't': prints("TEXTREL "); break;
373 case 'r': prints("RPATH "); break; 674 case 'r': prints("RPATH "); break;
374 case 'n': prints("NEEDED "); break; 675 case 'n': prints("NEEDED "); break;
375 case 'i': prints("INTERP "); break; 676 case 'i': prints("INTERP "); break;
677 case 'b': prints("BIND "); break;
376 case 's': prints("SYM "); break; 678 case 's': prints("SYM "); break;
679 case 'N': prints("LIB "); break;
680 case 'T': prints("TEXTRELS "); break;
681 default: warnf("'%c' has no title ?", out_format[i]);
377 } 682 }
378 } 683 }
684 if (!found_file) prints("FILE ");
379 prints("\n"); 685 prints("\n");
686 found_file = 0;
380 show_banner = 0; 687 show_banner = 0;
381 } 688 }
382 689
383 /* dump all the good stuff */ 690 /* dump all the good stuff */
384 for (i=0; out_format[i]; ++i) { 691 for (i = 0; out_format[i]; ++i) {
385 const char *out; 692 const char *out;
693 const char *tmp;
386 694
387 /* make sure we trim leading spaces in quiet mode */ 695 /* make sure we trim leading spaces in quiet mode */
388 if (be_quiet && *out_buffer == ' ' && !out_buffer[1]) 696 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
389 *out_buffer = '\0'; 697 *out_buffer = '\0';
390 698
391 if (out_format[i] != '%') { 699 if (!IS_MODIFIER(out_format[i])) {
392 xchrcat(&out_buffer, out_format[i], &out_len); 700 xchrcat(&out_buffer, out_format[i], &out_len);
393 continue; 701 continue;
394 } 702 }
395 703
396 out = NULL; 704 out = NULL;
705 be_wewy_wewy_quiet = (out_format[i] == '#');
397 switch (out_format[++i]) { 706 switch (out_format[++i]) {
707 case '%':
708 case '#':
398 case '%': xchrcat(&out_buffer, '%', &out_len); break; 709 xchrcat(&out_buffer, out_format[i], &out_len); break;
399 case 'F': found_file = 1; xstrcat(&out_buffer, filename, &out_len); break; 710 case 'F':
711 found_file = 1;
712 if (be_wewy_wewy_quiet) break;
713 xstrcat(&out_buffer, filename, &out_len);
714 break;
715 case 'p':
716 found_file = 1;
717 if (be_wewy_wewy_quiet) break;
718 tmp = filename;
719 if (search_path) {
720 ssize_t len_search = strlen(search_path);
721 ssize_t len_file = strlen(filename);
722 if (!strncmp(filename, search_path, len_search) && \
723 len_file > len_search)
724 tmp += len_search;
725 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
726 }
727 xstrcat(&out_buffer, tmp, &out_len);
728 break;
729 case 'f':
730 found_file = 1;
731 if (be_wewy_wewy_quiet) break;
732 tmp = strrchr(filename, '/');
733 tmp = (tmp == NULL ? filename : tmp+1);
734 xstrcat(&out_buffer, tmp, &out_len);
735 break;
400 case 'o': out = get_elfetype(elf); break; 736 case 'o': out = get_elfetype(elf); break;
401 case 'x': out = scanelf_file_pax(elf, &found_pax); break; 737 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
402 case 'e': out = scanelf_file_stack(elf, &found_stack, &found_relro); break; 738 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
403 case 't': out = scanelf_file_textrel(elf, &found_textrel); break; 739 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
740 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break;
404 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break; 741 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
742 case 'n':
405 case 'n': scanelf_file_needed(elf, &found_needed, &out_buffer, &out_len); break; 743 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
406 case 'i': out = scanelf_file_interp(elf, &found_interp); break; 744 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
745 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
407 case 's': out = scanelf_file_sym(elf, &found_sym, filename); break; 746 case 's': out = scanelf_file_sym(elf, &found_sym); break;
747 default: warnf("'%c' has no scan code?", out_format[i]);
408 } 748 }
409 if (out) xstrcat(&out_buffer, out, &out_len); 749 if (out) xstrcat(&out_buffer, out, &out_len);
410 } 750 }
411 751
412 if (!found_file) { 752#define FOUND_SOMETHING() \
413 if (!be_quiet || found_pax || found_stack || found_textrel || \ 753 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
414 found_rpath || found_needed || found_interp || found_sym) 754 found_rpath || found_needed || found_interp || found_bind || \
755 found_sym || found_lib || found_textrels)
756
757 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
758 xchrcat(&out_buffer, ' ', &out_len);
415 xstrcat(&out_buffer, filename, &out_len); 759 xstrcat(&out_buffer, filename, &out_len);
416 } 760 }
417 if (!(be_quiet && xemptybuffer(out_buffer))) 761 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
418 puts(out_buffer); 762 puts(out_buffer);
763 fflush(stdout);
764 }
419 765
420 unreadelf(elf); 766 unreadelf(elf);
421} 767}
422 768
423/* scan a directory for ET_EXEC files and print when we find one */ 769/* scan a directory for ET_EXEC files and print when we find one */
452 while ((dentry = readdir(dir))) { 798 while ((dentry = readdir(dir))) {
453 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 799 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
454 continue; 800 continue;
455 len = (pathlen + 1 + strlen(dentry->d_name) + 1); 801 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
456 if (len >= sizeof(buf)) { 802 if (len >= sizeof(buf)) {
457 warnf("Skipping '%s': len > sizeof(buf); %d > %d\n", path, (int)len, (int)sizeof(buf)); 803 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
804 (unsigned long)len, (unsigned long)sizeof(buf));
458 continue; 805 continue;
459 } 806 }
460 sprintf(buf, "%s/%s", path, dentry->d_name); 807 sprintf(buf, "%s/%s", path, dentry->d_name);
461 if (lstat(buf, &st) != -1) { 808 if (lstat(buf, &st) != -1) {
462 if (S_ISREG(st.st_mode)) 809 if (S_ISREG(st.st_mode))
468 } 815 }
469 } 816 }
470 closedir(dir); 817 closedir(dir);
471} 818}
472 819
820static int scanelf_from_file(char *filename)
821{
822 FILE *fp = NULL;
823 char *p;
824 char path[_POSIX_PATH_MAX];
825
826 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL))
827 fp = stdin;
828 else if ((fp = fopen(filename, "r")) == NULL)
829 return 1;
830
831 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
832 if ((p = strchr(path, '\n')) != NULL)
833 *p = 0;
834 search_path = path;
835 scanelf_dir(path);
836 }
837 if (fp != stdin)
838 fclose(fp);
839 return 0;
840}
841
842static void load_ld_so_conf()
843{
844 FILE *fp = NULL;
845 char *p;
846 char path[_POSIX_PATH_MAX];
847 int i = 0;
848
849 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
850 return;
851
852 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
853 if (*path != '/')
854 continue;
855
856 if ((p = strrchr(path, '\r')) != NULL)
857 *p = 0;
858 if ((p = strchr(path, '\n')) != NULL)
859 *p = 0;
860
861 ldpaths[i++] = xstrdup(path);
862
863 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
864 break;
865 }
866 ldpaths[i] = NULL;
867
868 fclose(fp);
869}
870
473/* scan /etc/ld.so.conf for paths */ 871/* scan /etc/ld.so.conf for paths */
474static void scanelf_ldpath() 872static void scanelf_ldpath()
475{ 873{
476 char scan_l, scan_ul, scan_ull; 874 char scan_l, scan_ul, scan_ull;
477 char *path, *p; 875 int i = 0;
478 FILE *fp;
479 876
480 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 877 if (!ldpaths[0])
481 err("Unable to open ld.so.conf: %s", strerror(errno)); 878 err("Unable to load any paths from ld.so.conf");
482 879
483 scan_l = scan_ul = scan_ull = 0; 880 scan_l = scan_ul = scan_ull = 0;
484 881
485 path = (char*)xmalloc(_POSIX_PATH_MAX); 882 while (ldpaths[i]) {
486 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL)
487 if (*path == '/') {
488 if ((p = strrchr(path, '\r')) != NULL)
489 *p = 0;
490 if ((p = strrchr(path, '\n')) != NULL)
491 *p = 0;
492 if (!scan_l && !strcmp(path, "/lib")) scan_l = 1; 883 if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
493 if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1; 884 if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
494 if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1; 885 if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
495 scanelf_dir(path); 886 scanelf_dir(ldpaths[i]);
887 ++i;
496 } 888 }
497 free(path);
498 fclose(fp);
499 889
500 if (!scan_l) scanelf_dir("/lib"); 890 if (!scan_l) scanelf_dir("/lib");
501 if (!scan_ul) scanelf_dir("/usr/lib"); 891 if (!scan_ul) scanelf_dir("/usr/lib");
502 if (!scan_ull) scanelf_dir("/usr/local/lib"); 892 if (!scan_ull) scanelf_dir("/usr/local/lib");
503} 893}
521} 911}
522 912
523 913
524 914
525/* usage / invocation handling functions */ 915/* usage / invocation handling functions */
526#define PARSE_FLAGS "plRmyxetrnis:aqvF:o:BhV" 916#define PARSE_FLAGS "plRmyxetrnibs:N:TaqvF:f:o:BhV"
527#define a_argument required_argument 917#define a_argument required_argument
528static struct option const long_opts[] = { 918static struct option const long_opts[] = {
529 {"path", no_argument, NULL, 'p'}, 919 {"path", no_argument, NULL, 'p'},
530 {"ldpath", no_argument, NULL, 'l'}, 920 {"ldpath", no_argument, NULL, 'l'},
531 {"recursive", no_argument, NULL, 'R'}, 921 {"recursive", no_argument, NULL, 'R'},
535 {"header", no_argument, NULL, 'e'}, 925 {"header", no_argument, NULL, 'e'},
536 {"textrel", no_argument, NULL, 't'}, 926 {"textrel", no_argument, NULL, 't'},
537 {"rpath", no_argument, NULL, 'r'}, 927 {"rpath", no_argument, NULL, 'r'},
538 {"needed", no_argument, NULL, 'n'}, 928 {"needed", no_argument, NULL, 'n'},
539 {"interp", no_argument, NULL, 'i'}, 929 {"interp", no_argument, NULL, 'i'},
930 {"bind", no_argument, NULL, 'b'},
540 {"symbol", a_argument, NULL, 's'}, 931 {"symbol", a_argument, NULL, 's'},
932 {"lib", a_argument, NULL, 'N'},
933 {"textrels", no_argument, NULL, 'T'},
541 {"all", no_argument, NULL, 'a'}, 934 {"all", no_argument, NULL, 'a'},
542 {"quiet", no_argument, NULL, 'q'}, 935 {"quiet", no_argument, NULL, 'q'},
543 {"verbose", no_argument, NULL, 'v'}, 936 {"verbose", no_argument, NULL, 'v'},
544 {"format", a_argument, NULL, 'F'}, 937 {"format", a_argument, NULL, 'F'},
938 {"from", a_argument, NULL, 'f'},
545 {"file", a_argument, NULL, 'o'}, 939 {"file", a_argument, NULL, 'o'},
546 {"nobanner", no_argument, NULL, 'B'}, 940 {"nobanner", no_argument, NULL, 'B'},
547 {"help", no_argument, NULL, 'h'}, 941 {"help", no_argument, NULL, 'h'},
548 {"version", no_argument, NULL, 'V'}, 942 {"version", no_argument, NULL, 'V'},
549 {NULL, no_argument, NULL, 0x0} 943 {NULL, no_argument, NULL, 0x0}
550}; 944};
945
551static char *opts_help[] = { 946static const char *opts_help[] = {
552 "Scan all directories in PATH environment", 947 "Scan all directories in PATH environment",
553 "Scan all directories in /etc/ld.so.conf", 948 "Scan all directories in /etc/ld.so.conf",
554 "Scan directories recursively", 949 "Scan directories recursively",
555 "Don't recursively cross mount points", 950 "Don't recursively cross mount points",
556 "Don't scan symlinks\n", 951 "Don't scan symlinks\n",
557 "Print PaX markings", 952 "Print PaX markings",
558 "Print GNU_STACK markings", 953 "Print GNU_STACK/PT_LOAD markings",
559 "Print TEXTREL information", 954 "Print TEXTREL information",
560 "Print RPATH information", 955 "Print RPATH information",
561 "Print NEEDED information", 956 "Print NEEDED information",
562 "Print INTERP information", 957 "Print INTERP information",
958 "Print BIND information",
563 "Find a specified symbol", 959 "Find a specified symbol",
960 "Find a specified library",
961 "Locate cause of TEXTREL",
564 "Print all scanned info (-x -e -t -r)\n", 962 "Print all scanned info (-x -e -t -r -n -i -b)\n",
565 "Only output 'bad' things", 963 "Only output 'bad' things",
566 "Be verbose (can be specified more than once)", 964 "Be verbose (can be specified more than once)",
567 "Use specified format for output", 965 "Use specified format for output",
966 "Read input stream from a filename",
568 "Write output stream to a filename", 967 "Write output stream to a filename",
569 "Don't display the header", 968 "Don't display the header",
570 "Print this help and exit", 969 "Print this help and exit",
571 "Print version and exit", 970 "Print version and exit",
572 NULL 971 NULL
573}; 972};
574 973
575/* display usage and exit */ 974/* display usage and exit */
576static void usage(int status) 975static void usage(int status)
577{ 976{
578 int i; 977 unsigned long i;
579 printf(" Scan ELF binaries for stuff\n\n" 978 printf("* Scan ELF binaries for stuff\n\n"
580 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); 979 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
581 printf("Options: -[%s]\n", PARSE_FLAGS); 980 printf("Options: -[%s]\n", PARSE_FLAGS);
582 for (i = 0; long_opts[i].name; ++i) 981 for (i = 0; long_opts[i].name; ++i)
583 if (long_opts[i].has_arg == no_argument) 982 if (long_opts[i].has_arg == no_argument)
584 printf(" -%c, --%-13s %s\n", long_opts[i].val, 983 printf(" -%c, --%-13s* %s\n", long_opts[i].val,
585 long_opts[i].name, opts_help[i]); 984 long_opts[i].name, opts_help[i]);
586 else 985 else
587 printf(" -%c, --%-6s <arg> %s\n", long_opts[i].val, 986 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val,
588 long_opts[i].name, opts_help[i]); 987 long_opts[i].name, opts_help[i]);
988
989 if (status != EXIT_SUCCESS)
990 exit(status);
991
992 puts("\nThe format modifiers for the -F option are:");
993 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
994 puts(" t TEXTREL \tr RPATH \tn NEEDED");
995 puts(" i INTERP \tb BIND \ts symbol");
996 puts(" N library \to Type \tT TEXTRELs");
997 puts(" p filename (with search path removed)");
998 puts(" f base filename");
999 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1000
589 exit(status); 1001 exit(status);
590} 1002}
591 1003
592/* parse command line arguments and preform needed actions */ 1004/* parse command line arguments and preform needed actions */
593static void parseargs(int argc, char *argv[]) 1005static void parseargs(int argc, char *argv[])
594{ 1006{
595 int flag; 1007 int i;
1008 char *from_file = NULL;
596 1009
597 opterr = 0; 1010 opterr = 0;
598 while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 1011 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
599 switch (flag) { 1012 switch (i) {
600 1013
601 case 'V': 1014 case 'V':
602 printf("%s compiled %s\n%s\n" 1015 printf("pax-utils-%s: %s compiled %s\n%s\n"
603 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n", 1016 "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
604 __FILE__, __DATE__, rcsid, argv0); 1017 VERSION, __FILE__, __DATE__, rcsid, argv0);
605 exit(EXIT_SUCCESS); 1018 exit(EXIT_SUCCESS);
606 break; 1019 break;
607 case 'h': usage(EXIT_SUCCESS); break; 1020 case 'h': usage(EXIT_SUCCESS); break;
608 1021 case 'f':
1022 if (from_file) err("Don't specify -f twice");
1023 from_file = xstrdup(optarg);
1024 break;
609 case 'o': { 1025 case 'o': {
610 FILE *fp = NULL; 1026 FILE *fp = NULL;
611 fp = freopen(optarg, "w", stdout); 1027 if ((fp = freopen(optarg, "w", stdout)) == NULL)
612 if (fp == NULL)
613 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1028 err("Could not open output stream '%s': %s", optarg, strerror(errno));
614 stdout = fp; 1029 SET_STDOUT(fp);
615 break; 1030 break;
616 } 1031 }
617 1032
618 case 's': { 1033 case 's': {
619 size_t len; 1034 size_t len;
1035 if (find_sym) err("Don't specify -s twice");
620 find_sym = xstrdup(optarg); 1036 find_sym = xstrdup(optarg);
621 len = strlen(find_sym) + 1; 1037 len = strlen(find_sym) + 1;
622 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1)); 1038 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1));
623 sprintf(versioned_symname, "%s@", find_sym); 1039 sprintf(versioned_symname, "%s@", find_sym);
624 break; 1040 break;
625 } 1041 }
1042 case 'N': {
1043 if (find_lib) err("Don't specify -N twice");
1044 find_lib = xstrdup(optarg);
1045 break;
1046 }
626 1047
627 case 'F': { 1048 case 'F': {
1049 if (out_format) err("Don't specify -F twice");
628 out_format = strdup(optarg); 1050 out_format = xstrdup(optarg);
629 break; 1051 break;
630 } 1052 }
631 1053
632 case 'y': scan_symlink = 0; break; 1054 case 'y': scan_symlink = 0; break;
633 case 'B': show_banner = 0; break; 1055 case 'B': show_banner = 0; break;
634 case 'l': scan_ldpath = 1; break; 1056 case 'l': scan_ldpath = 1; break;
635 case 'p': scan_envpath = 1; break; 1057 case 'p': scan_envpath = 1; break;
636 case 'R': dir_recurse = 1; break; 1058 case 'R': dir_recurse = 1; break;
637 case 'm': dir_crossmount = 0; break; 1059 case 'm': dir_crossmount = 0; break;
638 case 'x': show_pax = 1; break; 1060 case 'x': show_pax = 1; break;
639 case 'e': show_stack = 1; break; 1061 case 'e': show_phdr = 1; break;
640 case 't': show_textrel = 1; break; 1062 case 't': show_textrel = 1; break;
641 case 'r': show_rpath = 1; break; 1063 case 'r': show_rpath = 1; break;
642 case 'n': show_needed = 1; break; 1064 case 'n': show_needed = 1; break;
643 case 'i': show_interp = 1; break; 1065 case 'i': show_interp = 1; break;
1066 case 'b': show_bind = 1; break;
1067 case 'T': show_textrels = 1; break;
644 case 'q': be_quiet = 1; break; 1068 case 'q': be_quiet = 1; break;
645 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1069 case 'v': be_verbose = (be_verbose % 20) + 1; break;
646 case 'a': show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 1; break; 1070 case 'a': show_pax = show_phdr = show_textrel = show_rpath = \
1071 show_needed = show_interp = show_bind = 1; break;
647 1072
648 case ':': 1073 case ':':
649 warn("Option missing parameter\n"); 1074 err("Option missing parameter\n");
650 usage(EXIT_FAILURE);
651 break;
652 case '?': 1075 case '?':
653 warn("Unknown option\n"); 1076 err("Unknown option\n");
654 usage(EXIT_FAILURE);
655 break;
656 default: 1077 default:
657 err("Unhandled option '%c'", flag); 1078 err("Unhandled option '%c'", i);
658 break;
659 }
660 } 1079 }
661 1080 }
662 if (be_quiet && be_verbose)
663 err("You can be quiet or you can be verbose, not both, stupid");
664 1081
665 /* let the format option override all other options */ 1082 /* let the format option override all other options */
666 if (out_format) { 1083 if (out_format) {
667 show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 0; 1084 show_pax = show_phdr = show_textrel = show_rpath = \
1085 show_needed = show_interp = show_bind = show_textrels = 0;
668 for (flag=0; out_format[flag]; ++flag) { 1086 for (i = 0; out_format[i]; ++i) {
669 if (out_format[flag] != '%') continue; 1087 if (!IS_MODIFIER(out_format[i])) continue;
670 1088
671 switch (out_format[++flag]) { 1089 switch (out_format[++i]) {
672 case '%': break; 1090 case '%': break;
1091 case '#': break;
673 case 'F': break; 1092 case 'F': break;
1093 case 'p': break;
1094 case 'f': break;
674 case 's': break; 1095 case 's': break;
1096 case 'N': break;
675 case 'o': break; 1097 case 'o': break;
676 case 'x': show_pax = 1; break; 1098 case 'x': show_pax = 1; break;
677 case 'e': show_stack = 1; break; 1099 case 'e': show_phdr = 1; break;
678 case 't': show_textrel = 1; break; 1100 case 't': show_textrel = 1; break;
679 case 'r': show_rpath = 1; break; 1101 case 'r': show_rpath = 1; break;
680 case 'n': show_needed = 1; break; 1102 case 'n': show_needed = 1; break;
681 case 'i': show_interp = 1; break; 1103 case 'i': show_interp = 1; break;
1104 case 'b': show_bind = 1; break;
1105 case 'T': show_textrels = 1; break;
682 default: 1106 default:
683 err("Invalid format specifier '%c' (byte %i)", 1107 err("Invalid format specifier '%c' (byte %i)",
684 out_format[flag], flag+1); 1108 out_format[i], i+1);
685 } 1109 }
686 } 1110 }
687 1111
688 /* construct our default format */ 1112 /* construct our default format */
689 } else { 1113 } else {
690 size_t fmt_len = 30; 1114 size_t fmt_len = 30;
691 out_format = (char*)xmalloc(sizeof(char) * fmt_len); 1115 out_format = (char*)xmalloc(sizeof(char) * fmt_len);
692 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len); 1116 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
693 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len); 1117 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
694 if (show_stack) xstrcat(&out_format, "%e ", &fmt_len); 1118 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
695 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); 1119 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
696 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); 1120 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
697 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); 1121 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
698 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 1122 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1123 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1124 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
699 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len); 1125 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1126 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
700 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 1127 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
701 } 1128 }
702 if (be_verbose > 2) printf("Format: %s\n", out_format); 1129 if (be_verbose > 2) printf("Format: %s\n", out_format);
703 1130
704 /* now lets actually do the scanning */ 1131 /* now lets actually do the scanning */
1132 if (scan_ldpath || (show_rpath && be_quiet))
1133 load_ld_so_conf();
705 if (scan_ldpath) scanelf_ldpath(); 1134 if (scan_ldpath) scanelf_ldpath();
706 if (scan_envpath) scanelf_envpath(); 1135 if (scan_envpath) scanelf_envpath();
1136 if (from_file) {
1137 scanelf_from_file(from_file);
1138 free(from_file);
1139 from_file = *argv;
1140 }
707 if (optind == argc && !scan_ldpath && !scan_envpath) 1141 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
708 err("Nothing to scan !?"); 1142 err("Nothing to scan !?");
709 while (optind < argc) 1143 while (optind < argc) {
710 scanelf_dir(argv[optind++]); 1144 search_path = argv[optind++];
1145 scanelf_dir(search_path);
1146 }
711 1147
712 /* clean up */ 1148 /* clean up */
713 if (find_sym) { 1149 if (find_sym) {
714 free(find_sym); 1150 free(find_sym);
715 free(versioned_symname); 1151 free(versioned_symname);
716 } 1152 }
1153 if (find_lib) free(find_lib);
717 if (out_format) free(out_format); 1154 if (out_format) free(out_format);
1155 for (i = 0; ldpaths[i]; ++i)
1156 free(ldpaths[i]);
718} 1157}
719 1158
720 1159
721 1160
722/* utility funcs */ 1161/* utility funcs */
723static char *xstrdup(char *s) 1162static char *xstrdup(const char *s)
724{ 1163{
725 char *ret = strdup(s); 1164 char *ret = strdup(s);
726 if (!ret) err("Could not strdup(): %s", strerror(errno)); 1165 if (!ret) err("Could not strdup(): %s", strerror(errno));
727 return ret; 1166 return ret;
728} 1167}
1168
729static void *xmalloc(size_t size) 1169static void *xmalloc(size_t size)
730{ 1170{
731 void *ret = malloc(size); 1171 void *ret = malloc(size);
732 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size); 1172 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
733 return ret; 1173 return ret;
734} 1174}
1175
735static void xstrcat(char **dst, const char *src, size_t *curr_len) 1176static void xstrcat(char **dst, const char *src, size_t *curr_len)
736{ 1177{
737 long new_len; 1178 size_t new_len;
738 1179
739 new_len = strlen(*dst) + strlen(src); 1180 new_len = strlen(*dst) + strlen(src);
740 if (*curr_len <= new_len) { 1181 if (*curr_len <= new_len) {
741 *curr_len = new_len + (*curr_len / 2); 1182 *curr_len = new_len + (*curr_len / 2);
742 *dst = realloc(*dst, *curr_len); 1183 *dst = realloc(*dst, *curr_len);
744 err("could not realloc %li bytes", (unsigned long)*curr_len); 1185 err("could not realloc %li bytes", (unsigned long)*curr_len);
745 } 1186 }
746 1187
747 strcat(*dst, src); 1188 strcat(*dst, src);
748} 1189}
1190
749static inline void xchrcat(char **dst, const char append, size_t *curr_len) 1191static inline void xchrcat(char **dst, const char append, size_t *curr_len)
750{ 1192{
751 static char my_app[2]; 1193 static char my_app[2];
752 my_app[0] = append; 1194 my_app[0] = append;
753 my_app[1] = '\0'; 1195 my_app[1] = '\0';
754 xstrcat(dst, my_app, curr_len); 1196 xstrcat(dst, my_app, curr_len);
755} 1197}
756static int xemptybuffer(const char *buff)
757{
758 long i;
759 for (i=0; buff[i]; ++i)
760 if (buff[i] != ' ')
761 return 0;
762 return 1;
763}
764 1198
765 1199
766 1200
767int main(int argc, char *argv[]) 1201int main(int argc, char *argv[])
768{ 1202{
769 if (argc < 2) 1203 if (argc < 2)
770 usage(EXIT_FAILURE); 1204 usage(EXIT_FAILURE);
771 parseargs(argc, argv); 1205 parseargs(argc, argv);
772 fclose(stdout); 1206 fclose(stdout);
1207#ifdef __BOUNDS_CHECKING_ON
1208 warn("The calls to add/delete heap should be off by 1 due to the out_buffer not being freed in scanelf_file()");
1209#endif
773 return EXIT_SUCCESS; 1210 return EXIT_SUCCESS;
774} 1211}

Legend:
Removed from v.1.43  
changed lines
  Added in v.1.80

  ViewVC Help
Powered by ViewVC 1.1.20