/[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.72
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.72 2005/06/04 06:23:06 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.72 2005/06/04 06:23:06 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;
63static char show_stack = 0; 65static char show_stack = 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;
68static char show_banner = 1; 71static char show_banner = 1;
69static char be_quiet = 0; 72static char be_quiet = 0;
70static char be_verbose = 0; 73static char be_verbose = 0;
74static char be_wewy_wewy_quiet = 0;
71static char *find_sym = NULL, *versioned_symname = NULL; 75static char *find_sym = NULL, *versioned_symname = NULL;
76static char *find_lib = NULL;
72static char *out_format = NULL; 77static char *out_format = NULL;
78static char *search_path = NULL;
73 79
74 80
75 81
76/* sub-funcs for scanelf_file() */ 82/* sub-funcs for scanelf_file() */
77static char *scanelf_file_pax(elfobj *elf, char *found_pax) 83static char *scanelf_file_pax(elfobj *elf, char *found_pax)
78{ 84{
79 static char *paxflags; 85 static char *paxflags;
86 static char ret[7];
87 unsigned long i, shown;
88
80 89
81 if (!show_pax) return NULL; 90 if (!show_pax) return NULL;
82 91
92 shown = 0;
93 memset(&ret, 0, sizeof(ret));
94
95 if (elf->phdr) {
96#define SHOW_PAX(B) \
97 if (elf->elf_class == ELFCLASS ## B) { \
98 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
99 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
100 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
101 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
102 continue; \
103 if (be_quiet && (EGET(phdr[i].p_flags) == 10240)) \
104 continue; \
105 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
106 *found_pax = 1; \
107 ++shown; \
108 break; \
109 } \
110 }
111 SHOW_PAX(32)
112 SHOW_PAX(64)
113 }
114
115 /* fall back to EI_PAX if no PT_PAX was found */
116 if (!*ret) {
83 paxflags = pax_short_hf_flags(PAX_FLAGS(elf)); 117 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
84 if (!be_quiet || (be_quiet && strncmp(paxflags, "PeMRxS", 6))) { 118 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
85 *found_pax = 1; 119 *found_pax = 1;
86 return paxflags; 120 return paxflags;
87 } 121 }
122 strncpy(ret, paxflags, sizeof(ret));
123 // ++shown;
124 }
88 125
126 if (be_quiet && !shown)
89 return NULL; 127 return NULL;
128 return ret;
129
90} 130}
91static char *scanelf_file_stack(elfobj *elf, char *found_stack, char *found_relro) 131static char *scanelf_file_stack(elfobj *elf, char *found_stack, char *found_relro, char *found_load)
92{ 132{
93 static char ret[8]; 133 static char ret[12];
94 char *found; 134 char *found;
95 int i, off, shown; 135 unsigned long i, off, shown, check_flags;
136 unsigned char multi_stack, multi_relro, multi_load;
96 137
97 if (!show_stack) return NULL; 138 if (!show_stack) return NULL;
98 139
140 memcpy(ret, "--- --- ---\0", 12);
141
99 shown = 0; 142 shown = 0;
100 strcpy(ret, "--- ---"); 143 multi_stack = multi_relro = multi_load = 0;
144
145 if (elf->phdr) {
101#define SHOW_STACK(B) \ 146#define SHOW_STACK(B) \
102 if (elf->elf_class == ELFCLASS ## B) { \ 147 if (elf->elf_class == ELFCLASS ## B) { \
103 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 148 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
104 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 149 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
150 uint32_t flags; \
105 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 151 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
106 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \ 152 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
153 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
107 found = found_stack; \ 154 found = found_stack; \
108 off = 0; \ 155 off = 0; \
156 check_flags = PF_X; \
109 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \ 157 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
158 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
110 found = found_relro; \ 159 found = found_relro; \
111 off = 3; \ 160 off = 4; \
161 check_flags = PF_X; \
162 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
163 if (multi_load++ > 2) warnf("%s: more than 2 PT_LOAD's !?", elf->filename); \
164 found = found_load; \
165 off = 8; \
166 check_flags = PF_W|PF_X; \
112 } else \ 167 } else \
113 continue; \ 168 continue; \
114 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \ 169 flags = EGET(phdr[i].p_flags); \
170 if (be_quiet && ((flags & check_flags) != check_flags)) \
115 continue; \ 171 continue; \
116 memcpy(ret+off, gnu_short_stack_flags(EGET(phdr[i].p_flags)), 3); \ 172 memcpy(ret+off, gnu_short_stack_flags(flags), 3); \
117 *found = 1; \ 173 *found = 1; \
118 ++shown; \ 174 ++shown; \
119 } \ 175 } \
120 } 176 }
121 SHOW_STACK(32) 177 SHOW_STACK(32)
122 SHOW_STACK(64) 178 SHOW_STACK(64)
179 }
180
123 if (be_quiet && !shown) 181 if (be_quiet && !shown)
124 return NULL; 182 return NULL;
125 else 183 else
126 return ret; 184 return ret;
127} 185}
128static char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 186static char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
129{ 187{
130 static char *ret = "TEXTREL"; 188 static char ret[] = "TEXTREL";
131 int i; 189 unsigned long i;
132 190
133 if (!show_textrel) return NULL; 191 if (!show_textrel) return NULL;
134 192
193 if (elf->phdr) {
135#define SHOW_TEXTREL(B) \ 194#define SHOW_TEXTREL(B) \
136 if (elf->elf_class == ELFCLASS ## B) { \ 195 if (elf->elf_class == ELFCLASS ## B) { \
137 Elf ## B ## _Dyn *dyn; \ 196 Elf ## B ## _Dyn *dyn; \
138 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 197 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
139 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 198 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
199 Elf ## B ## _Off offset; \
140 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 200 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
141 if (phdr[i].p_type != PT_DYNAMIC) continue; \ 201 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
202 offset = EGET(phdr[i].p_offset); \
203 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
142 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 204 dyn = DYN ## B (elf->data + offset); \
143 while (EGET(dyn->d_tag) != DT_NULL) { \ 205 while (EGET(dyn->d_tag) != DT_NULL) { \
144 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \ 206 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
145 *found_textrel = 1; \ 207 *found_textrel = 1; \
146 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \ 208 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
147 return ret; \ 209 return (be_wewy_wewy_quiet ? NULL : ret); \
148 } \ 210 } \
149 ++dyn; \ 211 ++dyn; \
150 } \ 212 } \
151 } } 213 } }
152 SHOW_TEXTREL(32) 214 SHOW_TEXTREL(32)
153 SHOW_TEXTREL(64) 215 SHOW_TEXTREL(64)
154 if (be_quiet) 216 }
217
218 if (be_quiet || be_wewy_wewy_quiet)
155 return NULL; 219 return NULL;
156 else 220 else
157 return " - "; 221 return (char *)" - ";
158} 222}
159static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len) 223static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
160{ 224{
161 /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */ 225 unsigned long i, s;
162 int i;
163 char *rpath, *runpath; 226 char *rpath, *runpath, **r;
164 void *strtbl_void; 227 void *strtbl_void;
165 228
166 if (!show_rpath) return; 229 if (!show_rpath) return;
167 230
168 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 231 strtbl_void = elf_findsecbyname(elf, ".dynstr");
169 rpath = runpath = NULL; 232 rpath = runpath = NULL;
170 233
171 if (strtbl_void) { 234 if (elf->phdr && strtbl_void) {
172#define SHOW_RPATH(B) \ 235#define SHOW_RPATH(B) \
173 if (elf->elf_class == ELFCLASS ## B) { \ 236 if (elf->elf_class == ELFCLASS ## B) { \
174 Elf ## B ## _Dyn *dyn; \ 237 Elf ## B ## _Dyn *dyn; \
175 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 238 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
176 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 239 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
177 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 240 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
241 Elf ## B ## _Off offset; \
242 Elf ## B ## _Xword word; \
243 /* Scan all the program headers */ \
178 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 244 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
245 /* Just scan dynamic headers */ \
179 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 246 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
247 offset = EGET(phdr[i].p_offset); \
248 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
249 /* Just scan dynamic RPATH/RUNPATH headers */ \
180 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 250 dyn = DYN ## B (elf->data + offset); \
181 while (EGET(dyn->d_tag) != DT_NULL) { \ 251 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
182 if (EGET(dyn->d_tag) == DT_RPATH) { \ 252 if (word == DT_RPATH) { \
183 if (rpath) warn("ELF has multiple DT_RPATH's !?"); \ 253 r = &rpath; \
254 } else if (word == DT_RUNPATH) { \
255 r = &runpath; \
256 } else { \
257 ++dyn; \
258 continue; \
259 } \
260 /* Verify the memory is somewhat sane */ \
184 rpath = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 261 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
262 if (offset < (Elf ## B ## _Off)elf->len) { \
263 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
264 *r = (char*)(elf->data + offset); \
265 /* If quiet, don't output paths in ld.so.conf */ \
266 if (be_quiet) { \
267 size_t len; \
268 char *start, *end; \
269 for (s = 0; *r && ldpaths[s]; ++s) { \
270 /* scan each path in : delimited list */ \
271 start = *r; \
272 end = strchr(start, ':'); \
273 while ((start && ((end = strchr(start, ':')) != NULL)) || start) { \
274 len = (end ? abs(end - start) : strlen(start)); \
275 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \
276 *r = (end ? end + 1 : NULL); \
277 break; \
278 } \
279 start = (end ? start + len + 1 : NULL); \
280 } \
281 } \
282 } \
185 *found_rpath = 1; \ 283 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 } \ 284 } \
191 ++dyn; \ 285 ++dyn; \
192 } \ 286 } \
193 } } 287 } }
194 SHOW_RPATH(32) 288 SHOW_RPATH(32)
195 SHOW_RPATH(64) 289 SHOW_RPATH(64)
196 } 290 }
291
292 if (be_wewy_wewy_quiet) return;
197 293
198 if (rpath && runpath) { 294 if (rpath && runpath) {
199 if (!strcmp(rpath, runpath)) { 295 if (!strcmp(rpath, runpath)) {
200 xstrcat(ret, runpath, ret_len); 296 xstrcat(ret, runpath, ret_len);
201 } else { 297 } else {
209 } else if (rpath || runpath) 305 } else if (rpath || runpath)
210 xstrcat(ret, (runpath ? runpath : rpath), ret_len); 306 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
211 else if (!be_quiet) 307 else if (!be_quiet)
212 xstrcat(ret, " - ", ret_len); 308 xstrcat(ret, " - ", ret_len);
213} 309}
214static void scanelf_file_needed(elfobj *elf, char *found_needed, char **ret, size_t *ret_len) 310static char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
215{ 311{
216 int i; 312 unsigned long i;
217 char *needed; 313 char *needed;
218 void *strtbl_void; 314 void *strtbl_void;
219 315
220 if (!show_needed) return; 316 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
221 317
222 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 318 strtbl_void = elf_findsecbyname(elf, ".dynstr");
223 319
224 if (strtbl_void) { 320 if (elf->phdr && strtbl_void) {
225#define SHOW_NEEDED(B) \ 321#define SHOW_NEEDED(B) \
226 if (elf->elf_class == ELFCLASS ## B) { \ 322 if (elf->elf_class == ELFCLASS ## B) { \
227 Elf ## B ## _Dyn *dyn; \ 323 Elf ## B ## _Dyn *dyn; \
228 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 324 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
229 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 325 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
230 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 326 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
327 Elf ## B ## _Off offset; \
231 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 328 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
232 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 329 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
330 offset = EGET(phdr[i].p_offset); \
331 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
233 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 332 dyn = DYN ## B (elf->data + offset); \
234 while (EGET(dyn->d_tag) != DT_NULL) { \ 333 while (EGET(dyn->d_tag) != DT_NULL) { \
235 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 334 if (EGET(dyn->d_tag) == DT_NEEDED) { \
236 needed = elf->data + EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 335 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
336 if (offset >= (Elf ## B ## _Off)elf->len) { \
337 ++dyn; \
338 continue; \
339 } \
340 needed = (char*)(elf->data + offset); \
341 if (op == 0) { \
342 if (!be_wewy_wewy_quiet) { \
237 if (*found_needed) xchrcat(ret, ',', ret_len); \ 343 if (*found_needed) xchrcat(ret, ',', ret_len); \
238 xstrcat(ret, needed, ret_len); \ 344 xstrcat(ret, needed, ret_len); \
345 } \
239 *found_needed = 1; \ 346 *found_needed = 1; \
347 } else { \
348 if (strcmp(find_lib, needed)) return NULL; \
349 *found_lib = 1; \
350 return (be_wewy_wewy_quiet ? NULL : find_lib); \
351 } \
240 } \ 352 } \
241 ++dyn; \ 353 ++dyn; \
242 } \ 354 } \
243 } } 355 } }
244 SHOW_NEEDED(32) 356 SHOW_NEEDED(32)
245 SHOW_NEEDED(64) 357 SHOW_NEEDED(64)
246 } 358 }
359
360 return NULL;
247} 361}
248static char *scanelf_file_interp(elfobj *elf, char *found_interp) 362static char *scanelf_file_interp(elfobj *elf, char *found_interp)
249{ 363{
250 void *strtbl_void; 364 void *strtbl_void;
251 365
256 if (strtbl_void) { 370 if (strtbl_void) {
257#define SHOW_INTERP(B) \ 371#define SHOW_INTERP(B) \
258 if (elf->elf_class == ELFCLASS ## B) { \ 372 if (elf->elf_class == ELFCLASS ## B) { \
259 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 373 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
260 *found_interp = 1; \ 374 *found_interp = 1; \
261 return elf->data + EGET(strtbl->sh_offset); \ 375 return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(strtbl->sh_offset)); \
262 } 376 }
263 SHOW_INTERP(32) 377 SHOW_INTERP(32)
264 SHOW_INTERP(64) 378 SHOW_INTERP(64)
265 } 379 }
266 return NULL; 380 return NULL;
267} 381}
382static char *scanelf_file_bind(elfobj *elf, char *found_bind)
383{
384 unsigned long i;
385 struct stat s;
386
387 if (!show_bind) return NULL;
388 if (!elf->phdr) return NULL;
389
390#define SHOW_BIND(B) \
391 if (elf->elf_class == ELFCLASS ## B) { \
392 Elf ## B ## _Dyn *dyn; \
393 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
394 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
395 Elf ## B ## _Off offset; \
396 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
397 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
398 offset = EGET(phdr[i].p_offset); \
399 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
400 dyn = DYN ## B (elf->data + offset); \
401 while (EGET(dyn->d_tag) != DT_NULL) { \
402 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
403 (EGET(dyn->d_tag) == DT_FLAGS && EGET(dyn->d_un.d_val) & DF_BIND_NOW)) \
404 { \
405 if (be_quiet) return NULL; \
406 *found_bind = 1; \
407 return (char *)(be_wewy_wewy_quiet ? NULL : "NOW"); \
408 } \
409 ++dyn; \
410 } \
411 } \
412 }
413 SHOW_BIND(32)
414 SHOW_BIND(64)
415
416 if (be_wewy_wewy_quiet) return NULL;
417
418 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) {
419 return NULL;
420 } else {
421 *found_bind = 1;
422 return (char *) "LAZY";
423 }
424}
268static char *scanelf_file_sym(elfobj *elf, char *found_sym, const char *filename) 425static char *scanelf_file_sym(elfobj *elf, char *found_sym)
269{ 426{
270 int i; 427 unsigned long i;
271 void *symtab_void, *strtab_void; 428 void *symtab_void, *strtab_void;
272 429
273 if (!find_sym) return NULL; 430 if (!find_sym) return NULL;
274 431
432 /* debug sections */
275 symtab_void = elf_findsecbyname(elf, ".symtab"); 433 symtab_void = elf_findsecbyname(elf, ".symtab");
276 strtab_void = elf_findsecbyname(elf, ".strtab"); 434 strtab_void = elf_findsecbyname(elf, ".strtab");
435 /* fall back to runtime sections */
436 if (!symtab_void || !strtab_void) {
437 symtab_void = elf_findsecbyname(elf, ".dynsym");
438 strtab_void = elf_findsecbyname(elf, ".dynstr");
439 }
277 440
278 if (symtab_void && strtab_void) { 441 if (symtab_void && strtab_void) {
442 char *base, *basemem;
443 basemem = xstrdup(elf->filename);
444 base = basename(basemem);
279#define FIND_SYM(B) \ 445#define FIND_SYM(B) \
280 if (elf->elf_class == ELFCLASS ## B) { \ 446 if (elf->elf_class == ELFCLASS ## B) { \
281 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 447 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
282 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 448 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
283 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 449 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
284 int cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 450 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
285 char *symname; \ 451 char *symname; \
286 for (i = 0; i < cnt; ++i) { \ 452 for (i = 0; i < cnt; ++i) { \
287 if (sym->st_name) { \ 453 if (sym->st_name) { \
288 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 454 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
289 if (*find_sym == '*') { \ 455 if (*find_sym == '*') { \
290 printf("%s(%s) %5lX %15s %s\n", \ 456 printf("%s(%s) %5lX %15s %s\n", \
291 ((*found_sym == 0) ? "\n\t" : "\t"), \ 457 ((*found_sym == 0) ? "\n\t" : "\t"), \
292 (char *)basename(filename), \ 458 base, \
293 (long)sym->st_size, \ 459 (long)sym->st_size, \
294 (char *)get_elfstttype(sym->st_info), \ 460 (char *)get_elfstttype(sym->st_info), \
295 symname); \ 461 symname); \
296 *found_sym = 1; \ 462 *found_sym = 1; \
297 } else if ((strcmp(find_sym, symname) == 0) || \ 463 } else if ((strcmp(find_sym, symname) == 0) || \
300 } \ 466 } \
301 ++sym; \ 467 ++sym; \
302 } } 468 } }
303 FIND_SYM(32) 469 FIND_SYM(32)
304 FIND_SYM(64) 470 FIND_SYM(64)
471 free(basemem);
305 } 472 }
473
474 if (be_wewy_wewy_quiet) return NULL;
475
306 if (*find_sym != '*' && *found_sym) 476 if (*find_sym != '*' && *found_sym)
307 return find_sym; 477 return find_sym;
308 if (be_quiet) 478 if (be_quiet)
309 return NULL; 479 return NULL;
310 else 480 else
311 return " - "; 481 return (char *)" - ";
312} 482}
313/* scan an elf file and show all the fun stuff */ 483/* scan an elf file and show all the fun stuff */
314#define prints(str) fputs(str, stdout) 484#define prints(str) write(fileno(stdout), str, strlen(str))
315static void scanelf_file(const char *filename) 485static void scanelf_file(const char *filename)
316{ 486{
317 int i; 487 unsigned long i;
318 char found_pax, found_stack, found_relro, found_textrel, 488 char found_pax, found_stack, found_relro, found_load, found_textrel,
319 found_rpath, found_needed, found_interp, found_sym, 489 found_rpath, found_needed, found_interp, found_bind,
320 found_file; 490 found_sym, found_lib, found_file;
321 elfobj *elf; 491 elfobj *elf;
322 struct stat st; 492 struct stat st;
323 static char *out_buffer = NULL; 493 static char *out_buffer = NULL;
324 static size_t out_len; 494 static size_t out_len;
325 495
327 if (lstat(filename, &st) == -1) { 497 if (lstat(filename, &st) == -1) {
328 if (be_verbose > 2) printf("%s: does not exist\n", filename); 498 if (be_verbose > 2) printf("%s: does not exist\n", filename);
329 return; 499 return;
330 } 500 }
331 /* always handle regular files and handle symlinked files if no -y */ 501 /* 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))) { 502 if (S_ISLNK(st.st_mode)) {
503 if (!scan_symlink) return;
504 stat(filename, &st);
505 }
506 if (!S_ISREG(st.st_mode)) {
333 if (be_verbose > 2) printf("%s: skipping non-file\n", filename); 507 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
334 return; 508 return;
335 } 509 }
336 510
337 found_pax = found_stack = found_relro = found_textrel = \ 511 found_pax = found_stack = found_relro = found_load = \
338 found_rpath = found_needed = found_interp = found_sym = \ 512 found_textrel = found_rpath = found_needed = found_interp = \
339 found_file = 0; 513 found_bind = found_sym = found_lib = found_file = 0;
340 514
341 /* verify this is real ELF */ 515 /* verify this is real ELF */
342 if ((elf = readelf(filename)) == NULL) { 516 if ((elf = readelf(filename)) == NULL) {
343 if (be_verbose > 2) printf("%s: not an ELF\n", filename); 517 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
344 return; 518 return;
345 } 519 }
346 520
347 if (be_verbose > 1) 521 if (be_verbose > 1)
348 printf("%s: scanning file {%s,%s}\n", filename, 522 printf("%s: scanning file {%s,%s}\n", filename,
349 get_elfeitype(elf, EI_CLASS, elf->elf_class), 523 get_elfeitype(EI_CLASS, elf->elf_class),
350 get_elfeitype(elf, EI_DATA, elf->data[EI_DATA])); 524 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
351 else if (be_verbose) 525 else if (be_verbose)
352 printf("%s: scanning file\n", filename); 526 printf("%s: scanning file\n", filename);
353 527
354 /* init output buffer */ 528 /* init output buffer */
355 if (!out_buffer) { 529 if (!out_buffer) {
358 } 532 }
359 *out_buffer = '\0'; 533 *out_buffer = '\0';
360 534
361 /* show the header */ 535 /* show the header */
362 if (!be_quiet && show_banner) { 536 if (!be_quiet && show_banner) {
363 for (i=0; out_format[i]; ++i) { 537 for (i = 0; out_format[i]; ++i) {
364 if (out_format[i] != '%') continue; 538 if (!IS_MODIFIER(out_format[i])) continue;
365 539
366 switch (out_format[++i]) { 540 switch (out_format[++i]) {
367 case '%': break; 541 case '%': break;
542 case '#': break;
543 case 'F':
544 case 'p':
368 case 'F': prints("FILE "); break; 545 case 'f': prints("FILE "); found_file = 1; break;
369 case 'o': prints(" TYPE "); break; 546 case 'o': prints(" TYPE "); break;
370 case 'x': prints(" PAX "); break; 547 case 'x': prints(" PAX "); break;
371 case 'e': prints("STK/REL "); break; 548 case 'e': prints("STK/REL/PTL "); break;
372 case 't': prints("TEXTREL "); break; 549 case 't': prints("TEXTREL "); break;
373 case 'r': prints("RPATH "); break; 550 case 'r': prints("RPATH "); break;
374 case 'n': prints("NEEDED "); break; 551 case 'n': prints("NEEDED "); break;
375 case 'i': prints("INTERP "); break; 552 case 'i': prints("INTERP "); break;
553 case 'b': prints("BIND "); break;
376 case 's': prints("SYM "); break; 554 case 's': prints("SYM "); break;
555 case 'N': prints("LIB "); break;
377 } 556 }
378 } 557 }
558 if (!found_file) prints("FILE ");
379 prints("\n"); 559 prints("\n");
560 found_file = 0;
380 show_banner = 0; 561 show_banner = 0;
381 } 562 }
382 563
383 /* dump all the good stuff */ 564 /* dump all the good stuff */
384 for (i=0; out_format[i]; ++i) { 565 for (i = 0; out_format[i]; ++i) {
385 const char *out; 566 const char *out;
567 const char *tmp;
386 568
387 /* make sure we trim leading spaces in quiet mode */ 569 /* make sure we trim leading spaces in quiet mode */
388 if (be_quiet && *out_buffer == ' ' && !out_buffer[1]) 570 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
389 *out_buffer = '\0'; 571 *out_buffer = '\0';
390 572
391 if (out_format[i] != '%') { 573 if (!IS_MODIFIER(out_format[i])) {
392 xchrcat(&out_buffer, out_format[i], &out_len); 574 xchrcat(&out_buffer, out_format[i], &out_len);
393 continue; 575 continue;
394 } 576 }
395 577
396 out = NULL; 578 out = NULL;
579 be_wewy_wewy_quiet = (out_format[i] == '#');
397 switch (out_format[++i]) { 580 switch (out_format[++i]) {
581 case '%':
582 case '#':
398 case '%': xchrcat(&out_buffer, '%', &out_len); break; 583 xchrcat(&out_buffer, out_format[i], &out_len); break;
399 case 'F': found_file = 1; xstrcat(&out_buffer, filename, &out_len); break; 584 case 'F':
585 if (be_wewy_wewy_quiet) break;
586 found_file = 1;
587 xstrcat(&out_buffer, filename, &out_len);
588 break;
589 case 'p':
590 if (be_wewy_wewy_quiet) break;
591 found_file = 1;
592 tmp = filename;
593 if (search_path) {
594 ssize_t len_search = strlen(search_path);
595 ssize_t len_file = strlen(filename);
596 if (!strncmp(filename, search_path, len_search) && \
597 len_file > len_search)
598 tmp += len_search;
599 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
600 }
601 xstrcat(&out_buffer, tmp, &out_len);
602 break;
603 case 'f':
604 if (be_wewy_wewy_quiet) break;
605 found_file = 1;
606 tmp = strrchr(filename, '/');
607 tmp = (tmp == NULL ? filename : tmp+1);
608 xstrcat(&out_buffer, tmp, &out_len);
609 break;
400 case 'o': out = get_elfetype(elf); break; 610 case 'o': out = get_elfetype(elf); break;
401 case 'x': out = scanelf_file_pax(elf, &found_pax); break; 611 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
402 case 'e': out = scanelf_file_stack(elf, &found_stack, &found_relro); break; 612 case 'e': out = scanelf_file_stack(elf, &found_stack, &found_relro, &found_load); break;
403 case 't': out = scanelf_file_textrel(elf, &found_textrel); break; 613 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
404 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break; 614 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
615 case 'n':
405 case 'n': scanelf_file_needed(elf, &found_needed, &out_buffer, &out_len); break; 616 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; 617 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
618 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
407 case 's': out = scanelf_file_sym(elf, &found_sym, filename); break; 619 case 's': out = scanelf_file_sym(elf, &found_sym); break;
408 } 620 }
409 if (out) xstrcat(&out_buffer, out, &out_len); 621 if (out) xstrcat(&out_buffer, out, &out_len);
410 } 622 }
411 623
412 if (!found_file) { 624#define FOUND_SOMETHING() \
413 if (!be_quiet || found_pax || found_stack || found_textrel || \ 625 (found_pax || found_stack || found_relro || found_load || found_textrel || \
414 found_rpath || found_needed || found_interp || found_sym) 626 found_rpath || found_needed || found_interp || found_bind || found_sym || found_lib)
627
628 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
629 xchrcat(&out_buffer, ' ', &out_len);
415 xstrcat(&out_buffer, filename, &out_len); 630 xstrcat(&out_buffer, filename, &out_len);
416 } 631 }
417 if (!(be_quiet && xemptybuffer(out_buffer))) 632 if (!be_quiet || (be_quiet && FOUND_SOMETHING()))
418 puts(out_buffer); 633 puts(out_buffer);
419 634
420 unreadelf(elf); 635 unreadelf(elf);
421} 636}
422 637
468 } 683 }
469 } 684 }
470 closedir(dir); 685 closedir(dir);
471} 686}
472 687
688static int scanelf_from_file(char *filename)
689{
690 FILE *fp = NULL;
691 char *p;
692 char path[_POSIX_PATH_MAX];
693
694 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL))
695 fp = stdin;
696 else if ((fp = fopen(filename, "r")) == NULL)
697 return 1;
698
699 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
700 if ((p = strchr(path, '\n')) != NULL)
701 *p = 0;
702 search_path = path;
703 scanelf_dir(path);
704 }
705 if (fp != stdin)
706 fclose(fp);
707 return 0;
708}
709
710static void load_ld_so_conf()
711{
712 FILE *fp = NULL;
713 char *p;
714 char path[_POSIX_PATH_MAX];
715 int i = 0;
716
717 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL)
718 return;
719
720 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) {
721 if (*path != '/')
722 continue;
723
724 if ((p = strrchr(path, '\r')) != NULL)
725 *p = 0;
726 if ((p = strchr(path, '\n')) != NULL)
727 *p = 0;
728
729 ldpaths[i++] = xstrdup(path);
730
731 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
732 break;
733 }
734 ldpaths[i] = NULL;
735
736 fclose(fp);
737}
738
473/* scan /etc/ld.so.conf for paths */ 739/* scan /etc/ld.so.conf for paths */
474static void scanelf_ldpath() 740static void scanelf_ldpath()
475{ 741{
476 char scan_l, scan_ul, scan_ull; 742 char scan_l, scan_ul, scan_ull;
477 char *path, *p; 743 int i = 0;
478 FILE *fp;
479 744
480 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 745 if (!ldpaths[0])
481 err("Unable to open ld.so.conf: %s", strerror(errno)); 746 err("Unable to load any paths from ld.so.conf");
482 747
483 scan_l = scan_ul = scan_ull = 0; 748 scan_l = scan_ul = scan_ull = 0;
484 749
485 path = (char*)xmalloc(_POSIX_PATH_MAX); 750 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; 751 if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
493 if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1; 752 if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
494 if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1; 753 if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
495 scanelf_dir(path); 754 scanelf_dir(ldpaths[i]);
755 ++i;
496 } 756 }
497 free(path);
498 fclose(fp);
499 757
500 if (!scan_l) scanelf_dir("/lib"); 758 if (!scan_l) scanelf_dir("/lib");
501 if (!scan_ul) scanelf_dir("/usr/lib"); 759 if (!scan_ul) scanelf_dir("/usr/lib");
502 if (!scan_ull) scanelf_dir("/usr/local/lib"); 760 if (!scan_ull) scanelf_dir("/usr/local/lib");
503} 761}
521} 779}
522 780
523 781
524 782
525/* usage / invocation handling functions */ 783/* usage / invocation handling functions */
526#define PARSE_FLAGS "plRmyxetrnis:aqvF:o:BhV" 784#define PARSE_FLAGS "plRmyxetrnibs:N:aqvF:f:o:BhV"
527#define a_argument required_argument 785#define a_argument required_argument
528static struct option const long_opts[] = { 786static struct option const long_opts[] = {
529 {"path", no_argument, NULL, 'p'}, 787 {"path", no_argument, NULL, 'p'},
530 {"ldpath", no_argument, NULL, 'l'}, 788 {"ldpath", no_argument, NULL, 'l'},
531 {"recursive", no_argument, NULL, 'R'}, 789 {"recursive", no_argument, NULL, 'R'},
535 {"header", no_argument, NULL, 'e'}, 793 {"header", no_argument, NULL, 'e'},
536 {"textrel", no_argument, NULL, 't'}, 794 {"textrel", no_argument, NULL, 't'},
537 {"rpath", no_argument, NULL, 'r'}, 795 {"rpath", no_argument, NULL, 'r'},
538 {"needed", no_argument, NULL, 'n'}, 796 {"needed", no_argument, NULL, 'n'},
539 {"interp", no_argument, NULL, 'i'}, 797 {"interp", no_argument, NULL, 'i'},
798 {"bind", no_argument, NULL, 'b'},
540 {"symbol", a_argument, NULL, 's'}, 799 {"symbol", a_argument, NULL, 's'},
800 {"lib", a_argument, NULL, 'N'},
541 {"all", no_argument, NULL, 'a'}, 801 {"all", no_argument, NULL, 'a'},
542 {"quiet", no_argument, NULL, 'q'}, 802 {"quiet", no_argument, NULL, 'q'},
543 {"verbose", no_argument, NULL, 'v'}, 803 {"verbose", no_argument, NULL, 'v'},
544 {"format", a_argument, NULL, 'F'}, 804 {"format", a_argument, NULL, 'F'},
805 {"from", a_argument, NULL, 'f'},
545 {"file", a_argument, NULL, 'o'}, 806 {"file", a_argument, NULL, 'o'},
546 {"nobanner", no_argument, NULL, 'B'}, 807 {"nobanner", no_argument, NULL, 'B'},
547 {"help", no_argument, NULL, 'h'}, 808 {"help", no_argument, NULL, 'h'},
548 {"version", no_argument, NULL, 'V'}, 809 {"version", no_argument, NULL, 'V'},
549 {NULL, no_argument, NULL, 0x0} 810 {NULL, no_argument, NULL, 0x0}
550}; 811};
812
551static char *opts_help[] = { 813static const char *opts_help[] = {
552 "Scan all directories in PATH environment", 814 "Scan all directories in PATH environment",
553 "Scan all directories in /etc/ld.so.conf", 815 "Scan all directories in /etc/ld.so.conf",
554 "Scan directories recursively", 816 "Scan directories recursively",
555 "Don't recursively cross mount points", 817 "Don't recursively cross mount points",
556 "Don't scan symlinks\n", 818 "Don't scan symlinks\n",
557 "Print PaX markings", 819 "Print PaX markings",
558 "Print GNU_STACK markings", 820 "Print GNU_STACK/PT_LOAD markings",
559 "Print TEXTREL information", 821 "Print TEXTREL information",
560 "Print RPATH information", 822 "Print RPATH information",
561 "Print NEEDED information", 823 "Print NEEDED information",
562 "Print INTERP information", 824 "Print INTERP information",
825 "Print BIND information",
563 "Find a specified symbol", 826 "Find a specified symbol",
827 "Find a specified library",
564 "Print all scanned info (-x -e -t -r)\n", 828 "Print all scanned info (-x -e -t -r -n -i -b)\n",
565 "Only output 'bad' things", 829 "Only output 'bad' things",
566 "Be verbose (can be specified more than once)", 830 "Be verbose (can be specified more than once)",
567 "Use specified format for output", 831 "Use specified format for output",
832 "Read input stream from a filename",
568 "Write output stream to a filename", 833 "Write output stream to a filename",
569 "Don't display the header", 834 "Don't display the header",
570 "Print this help and exit", 835 "Print this help and exit",
571 "Print version and exit", 836 "Print version and exit",
572 NULL 837 NULL
573}; 838};
574 839
575/* display usage and exit */ 840/* display usage and exit */
576static void usage(int status) 841static void usage(int status)
577{ 842{
578 int i; 843 unsigned long i;
579 printf(" Scan ELF binaries for stuff\n\n" 844 printf("* Scan ELF binaries for stuff\n\n"
580 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); 845 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
581 printf("Options: -[%s]\n", PARSE_FLAGS); 846 printf("Options: -[%s]\n", PARSE_FLAGS);
582 for (i = 0; long_opts[i].name; ++i) 847 for (i = 0; long_opts[i].name; ++i)
583 if (long_opts[i].has_arg == no_argument) 848 if (long_opts[i].has_arg == no_argument)
584 printf(" -%c, --%-13s %s\n", long_opts[i].val, 849 printf(" -%c, --%-13s* %s\n", long_opts[i].val,
585 long_opts[i].name, opts_help[i]); 850 long_opts[i].name, opts_help[i]);
586 else 851 else
587 printf(" -%c, --%-6s <arg> %s\n", long_opts[i].val, 852 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val,
588 long_opts[i].name, opts_help[i]); 853 long_opts[i].name, opts_help[i]);
854
855 if (status != EXIT_SUCCESS)
856 exit(status);
857
858 puts("\nThe format modifiers for the -F option are:");
859 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
860 puts(" t TEXTREL \tr RPATH \tn NEEDED");
861 puts(" i INTERP \tb BIND \ts symbol");
862 puts(" N library \to Type");
863 puts(" p filename (with search path removed)");
864 puts(" f base filename");
865 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
866
589 exit(status); 867 exit(status);
590} 868}
591 869
592/* parse command line arguments and preform needed actions */ 870/* parse command line arguments and preform needed actions */
593static void parseargs(int argc, char *argv[]) 871static void parseargs(int argc, char *argv[])
594{ 872{
595 int flag; 873 int i;
874 char *from_file = NULL;
596 875
597 opterr = 0; 876 opterr = 0;
598 while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 877 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
599 switch (flag) { 878 switch (i) {
600 879
601 case 'V': 880 case 'V':
602 printf("%s compiled %s\n%s\n" 881 printf("%s compiled %s\n%s\n"
603 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n", 882 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n",
604 __FILE__, __DATE__, rcsid, argv0); 883 __FILE__, __DATE__, rcsid, argv0);
605 exit(EXIT_SUCCESS); 884 exit(EXIT_SUCCESS);
606 break; 885 break;
607 case 'h': usage(EXIT_SUCCESS); break; 886 case 'h': usage(EXIT_SUCCESS); break;
608 887 case 'f':
888 if (from_file) err("Don't specify -f twice");
889 from_file = xstrdup(optarg);
890 break;
609 case 'o': { 891 case 'o': {
610 FILE *fp = NULL; 892 FILE *fp = NULL;
611 fp = freopen(optarg, "w", stdout); 893 if ((fp = freopen(optarg, "w", stdout)) == NULL)
612 if (fp == NULL)
613 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 894 err("Could not open output stream '%s': %s", optarg, strerror(errno));
614 stdout = fp; 895 SET_STDOUT(fp);
615 break; 896 break;
616 } 897 }
617 898
618 case 's': { 899 case 's': {
619 size_t len; 900 size_t len;
901 if (find_sym) err("Don't specify -s twice");
620 find_sym = xstrdup(optarg); 902 find_sym = xstrdup(optarg);
621 len = strlen(find_sym) + 1; 903 len = strlen(find_sym) + 1;
622 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1)); 904 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1));
623 sprintf(versioned_symname, "%s@", find_sym); 905 sprintf(versioned_symname, "%s@", find_sym);
624 break; 906 break;
625 } 907 }
908 case 'N': {
909 if (find_lib) err("Don't specify -N twice");
910 find_lib = xstrdup(optarg);
911 break;
912 }
626 913
627 case 'F': { 914 case 'F': {
915 if (out_format) err("Don't specify -F twice");
628 out_format = strdup(optarg); 916 out_format = xstrdup(optarg);
629 break; 917 break;
630 } 918 }
631 919
632 case 'y': scan_symlink = 0; break; 920 case 'y': scan_symlink = 0; break;
633 case 'B': show_banner = 0; break; 921 case 'B': show_banner = 0; break;
639 case 'e': show_stack = 1; break; 927 case 'e': show_stack = 1; break;
640 case 't': show_textrel = 1; break; 928 case 't': show_textrel = 1; break;
641 case 'r': show_rpath = 1; break; 929 case 'r': show_rpath = 1; break;
642 case 'n': show_needed = 1; break; 930 case 'n': show_needed = 1; break;
643 case 'i': show_interp = 1; break; 931 case 'i': show_interp = 1; break;
932 case 'b': show_bind = 1; break;
644 case 'q': be_quiet = 1; break; 933 case 'q': be_quiet = 1; break;
645 case 'v': be_verbose = (be_verbose % 20) + 1; break; 934 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; 935 case 'a': show_pax = show_stack = show_textrel = show_rpath = \
936 show_needed = show_interp = show_bind = 1; break;
647 937
648 case ':': 938 case ':':
649 warn("Option missing parameter\n"); 939 err("Option missing parameter\n");
650 usage(EXIT_FAILURE);
651 break;
652 case '?': 940 case '?':
653 warn("Unknown option\n"); 941 err("Unknown option\n");
654 usage(EXIT_FAILURE);
655 break;
656 default: 942 default:
657 err("Unhandled option '%c'", flag); 943 err("Unhandled option '%c'", i);
658 break;
659 }
660 } 944 }
661 945 }
662 if (be_quiet && be_verbose)
663 err("You can be quiet or you can be verbose, not both, stupid");
664 946
665 /* let the format option override all other options */ 947 /* let the format option override all other options */
666 if (out_format) { 948 if (out_format) {
667 show_pax = show_stack = show_textrel = show_rpath = show_needed = show_interp = 0; 949 show_pax = show_stack = show_textrel = show_rpath = \
950 show_needed = show_interp = show_bind = 0;
668 for (flag=0; out_format[flag]; ++flag) { 951 for (i = 0; out_format[i]; ++i) {
669 if (out_format[flag] != '%') continue; 952 if (!IS_MODIFIER(out_format[i])) continue;
670 953
671 switch (out_format[++flag]) { 954 switch (out_format[++i]) {
672 case '%': break; 955 case '%': break;
956 case '#': break;
673 case 'F': break; 957 case 'F': break;
958 case 'p': break;
959 case 'f': break;
674 case 's': break; 960 case 's': break;
961 case 'N': break;
675 case 'o': break; 962 case 'o': break;
676 case 'x': show_pax = 1; break; 963 case 'x': show_pax = 1; break;
677 case 'e': show_stack = 1; break; 964 case 'e': show_stack = 1; break;
678 case 't': show_textrel = 1; break; 965 case 't': show_textrel = 1; break;
679 case 'r': show_rpath = 1; break; 966 case 'r': show_rpath = 1; break;
680 case 'n': show_needed = 1; break; 967 case 'n': show_needed = 1; break;
681 case 'i': show_interp = 1; break; 968 case 'i': show_interp = 1; break;
969 case 'b': show_bind = 1; break;
682 default: 970 default:
683 err("Invalid format specifier '%c' (byte %i)", 971 err("Invalid format specifier '%c' (byte %i)",
684 out_format[flag], flag+1); 972 out_format[i], i+1);
685 } 973 }
686 } 974 }
687 975
688 /* construct our default format */ 976 /* construct our default format */
689 } else { 977 } else {
694 if (show_stack) xstrcat(&out_format, "%e ", &fmt_len); 982 if (show_stack) xstrcat(&out_format, "%e ", &fmt_len);
695 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); 983 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
696 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); 984 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
697 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); 985 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
698 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 986 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
987 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
699 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len); 988 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
989 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
700 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 990 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
701 } 991 }
702 if (be_verbose > 2) printf("Format: %s\n", out_format); 992 if (be_verbose > 2) printf("Format: %s\n", out_format);
703 993
704 /* now lets actually do the scanning */ 994 /* now lets actually do the scanning */
995 if (scan_ldpath || (show_rpath && be_quiet))
996 load_ld_so_conf();
705 if (scan_ldpath) scanelf_ldpath(); 997 if (scan_ldpath) scanelf_ldpath();
706 if (scan_envpath) scanelf_envpath(); 998 if (scan_envpath) scanelf_envpath();
999 if (from_file) {
1000 scanelf_from_file(from_file);
1001 free(from_file);
1002 from_file = *argv;
1003 }
707 if (optind == argc && !scan_ldpath && !scan_envpath) 1004 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
708 err("Nothing to scan !?"); 1005 err("Nothing to scan !?");
709 while (optind < argc) 1006 while (optind < argc) {
710 scanelf_dir(argv[optind++]); 1007 search_path = argv[optind++];
1008 scanelf_dir(search_path);
1009 }
711 1010
712 /* clean up */ 1011 /* clean up */
713 if (find_sym) { 1012 if (find_sym) {
714 free(find_sym); 1013 free(find_sym);
715 free(versioned_symname); 1014 free(versioned_symname);
716 } 1015 }
1016 if (find_lib) free(find_lib);
717 if (out_format) free(out_format); 1017 if (out_format) free(out_format);
1018 for (i = 0; ldpaths[i]; ++i)
1019 free(ldpaths[i]);
718} 1020}
719 1021
720 1022
721 1023
722/* utility funcs */ 1024/* utility funcs */
723static char *xstrdup(char *s) 1025static char *xstrdup(const char *s)
724{ 1026{
725 char *ret = strdup(s); 1027 char *ret = strdup(s);
726 if (!ret) err("Could not strdup(): %s", strerror(errno)); 1028 if (!ret) err("Could not strdup(): %s", strerror(errno));
727 return ret; 1029 return ret;
728} 1030}
1031
729static void *xmalloc(size_t size) 1032static void *xmalloc(size_t size)
730{ 1033{
731 void *ret = malloc(size); 1034 void *ret = malloc(size);
732 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size); 1035 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
733 return ret; 1036 return ret;
734} 1037}
1038
735static void xstrcat(char **dst, const char *src, size_t *curr_len) 1039static void xstrcat(char **dst, const char *src, size_t *curr_len)
736{ 1040{
737 long new_len; 1041 size_t new_len;
738 1042
739 new_len = strlen(*dst) + strlen(src); 1043 new_len = strlen(*dst) + strlen(src);
740 if (*curr_len <= new_len) { 1044 if (*curr_len <= new_len) {
741 *curr_len = new_len + (*curr_len / 2); 1045 *curr_len = new_len + (*curr_len / 2);
742 *dst = realloc(*dst, *curr_len); 1046 *dst = realloc(*dst, *curr_len);
744 err("could not realloc %li bytes", (unsigned long)*curr_len); 1048 err("could not realloc %li bytes", (unsigned long)*curr_len);
745 } 1049 }
746 1050
747 strcat(*dst, src); 1051 strcat(*dst, src);
748} 1052}
1053
749static inline void xchrcat(char **dst, const char append, size_t *curr_len) 1054static inline void xchrcat(char **dst, const char append, size_t *curr_len)
750{ 1055{
751 static char my_app[2]; 1056 static char my_app[2];
752 my_app[0] = append; 1057 my_app[0] = append;
753 my_app[1] = '\0'; 1058 my_app[1] = '\0';
754 xstrcat(dst, my_app, curr_len); 1059 xstrcat(dst, my_app, curr_len);
755} 1060}
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 1061
765 1062
766 1063
767int main(int argc, char *argv[]) 1064int main(int argc, char *argv[])
768{ 1065{
769 if (argc < 2) 1066 if (argc < 2)
770 usage(EXIT_FAILURE); 1067 usage(EXIT_FAILURE);
771 parseargs(argc, argv); 1068 parseargs(argc, argv);
772 fclose(stdout); 1069 fclose(stdout);
1070#ifdef __BOUNDS_CHECKING_ON
1071 warn("The calls to add/delete heap should be off by 1 due to the out_buffer not being freed in scanelf_file()");
1072#endif
773 return EXIT_SUCCESS; 1073 return EXIT_SUCCESS;
774} 1074}

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

  ViewVC Help
Powered by ViewVC 1.1.20