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

Diff of /pax-utils/scanelf.c

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

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

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

  ViewVC Help
Powered by ViewVC 1.1.20