/[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.73
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.73 2005/06/04 13:52:54 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.73 2005/06/04 13:52:54 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;
72static char show_banner = 1; 71static char show_banner = 1;
73static char be_quiet = 0; 72static char be_quiet = 0;
74static char be_verbose = 0; 73static char be_verbose = 0;
74static char be_wewy_wewy_quiet = 0;
75static char *find_sym = NULL, *versioned_symname = NULL;
75static char *find_sym = NULL; 76static char *find_lib = NULL;
77static char *out_format = NULL;
78static char *search_path = NULL;
76 79
77 80
78 81
79/* scan an elf file and show all the fun stuff */ 82/* sub-funcs for scanelf_file() */
80static void scanelf_file(const char *filename) 83static char *scanelf_file_pax(elfobj *elf, char *found_pax)
81{ 84{
82 int i; 85 static char *paxflags;
83 char found_pax, found_stack, found_relro, found_textrel, 86 static char ret[7];
84 found_rpath, found_needed, found_sym; 87 unsigned long i, shown;
85 elfobj *elf;
86 struct stat st;
87 88
88 /* make sure path exists */
89 if (lstat(filename, &st) == -1)
90 return;
91 if (!S_ISREG(st.st_mode))
92 return;
93 found_pax = found_stack = found_relro = found_textrel = \
94 found_rpath = found_needed = found_sym = 0;
95 89
96 /* verify this is real ELF */ 90 if (!show_pax) return NULL;
97 if ((elf = readelf(filename)) == NULL) {
98 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
99 return;
100 }
101 91
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; 92 shown = 0;
119 } 93 memset(&ret, 0, sizeof(ret));
120 94
121 /* dump all the good stuff */ 95 if (elf->phdr) {
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 }
131 }
132
133 /* stack fun */
134 if (show_stack) {
135#define SHOW_STACK(B) \ 96#define SHOW_PAX(B) \
136 if (elf->elf_class == ELFCLASS ## B) { \ 97 if (elf->elf_class == ELFCLASS ## B) { \
137 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 98 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
138 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 99 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
139 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 100 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
140 if (EGET(phdr[i].p_type) != PT_GNU_STACK && \ 101 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
141 EGET(phdr[i].p_type) != PT_GNU_RELRO) continue; \
142 if (be_quiet && !(EGET(phdr[i].p_flags) & PF_X)) \
143 continue; \ 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) {
117 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
118 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
119 *found_pax = 1;
120 return paxflags;
121 }
122 strncpy(ret, paxflags, sizeof(ret));
123 // ++shown;
124 }
125
126 if (be_quiet && !shown)
127 return NULL;
128 return ret;
129
130}
131static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load)
132{
133 static char ret[12];
134 char *found;
135 unsigned long i, off, shown, check_flags;
136 unsigned char multi_stack, multi_relro, multi_load;
137
138 if (!show_phdr) return NULL;
139
140 memcpy(ret, "--- --- ---\0", 12);
141
142 shown = 0;
143 multi_stack = multi_relro = multi_load = 0;
144
145 if (elf->phdr) {
146#define SHOW_PHDR(B) \
147 if (elf->elf_class == ELFCLASS ## B) { \
148 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
149 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
150 uint32_t flags; \
151 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
144 if (EGET(phdr[i].p_type) == PT_GNU_STACK) \ 152 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
145 found_stack = 1; \ 153 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
154 found = found_phdr; \
155 off = 0; \
156 check_flags = PF_X; \
146 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); \
159 found = found_relro; \
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; \
167 } else \
168 continue; \
169 flags = EGET(phdr[i].p_flags); \
170 if (be_quiet && ((flags & check_flags) != check_flags)) \
171 continue; \
172 memcpy(ret+off, gnu_short_stack_flags(flags), 3); \
173 *found = 1; \
174 ++shown; \
175 } \
176 }
177 SHOW_PHDR(32)
178 SHOW_PHDR(64)
179 }
180
181 if (be_quiet && !shown)
182 return NULL;
183 else
184 return ret;
185}
186static char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
187{
188 static char ret[] = "TEXTREL";
189 unsigned long i;
190
191 if (!show_textrel) return NULL;
192
193 if (elf->phdr) {
194#define SHOW_TEXTREL(B) \
195 if (elf->elf_class == ELFCLASS ## B) { \
196 Elf ## B ## _Dyn *dyn; \
197 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
198 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
199 Elf ## B ## _Off offset; \
200 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
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; \
204 dyn = DYN ## B (elf->data + offset); \
205 while (EGET(dyn->d_tag) != DT_NULL) { \
206 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
147 found_relro = 1; \ 207 *found_textrel = 1; \
148 printf("%s ", gnu_short_stack_flags(EGET(phdr[i].p_flags))); \ 208 /*if (dyn->d_un.d_val & DF_TEXTREL)*/ \
209 return (be_wewy_wewy_quiet ? NULL : ret); \
210 } \
211 ++dyn; \
149 } \ 212 } \
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 } } 213 } }
176 SHOW_TEXTREL(32) 214 SHOW_TEXTREL(32)
177 SHOW_TEXTREL(64) 215 SHOW_TEXTREL(64)
178 if (!be_quiet && !found_textrel) fputs("------- ", stdout);
179 } 216 }
180 217
181 /* rpath fun */ 218 if (be_quiet || be_wewy_wewy_quiet)
182 /* TODO: if be_quiet, only output RPATH's which aren't in /etc/ld.so.conf */ 219 return NULL;
183 if (show_rpath) { 220 else
221 return (char *)" - ";
222}
223static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
224{
225 unsigned long i, s;
184 char *rpath, *runpath; 226 char *rpath, *runpath, **r;
227 void *strtbl_void;
228
229 if (!show_rpath) return;
230
185 void *strtbl_void = elf_findsecbyname(elf, ".dynstr"); 231 strtbl_void = elf_findsecbyname(elf, ".dynstr");
186 rpath = runpath = NULL; 232 rpath = runpath = NULL;
187 233
188 if (strtbl_void) { 234 if (elf->phdr && strtbl_void) {
189#define SHOW_RPATH(B) \ 235#define SHOW_RPATH(B) \
190 if (elf->elf_class == ELFCLASS ## B) { \ 236 if (elf->elf_class == ELFCLASS ## B) { \
191 Elf ## B ## _Dyn *dyn; \ 237 Elf ## B ## _Dyn *dyn; \
192 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 238 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
193 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 239 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
194 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 */ \
195 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 244 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
245 /* Just scan dynamic headers */ \
196 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 */ \
197 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 250 dyn = DYN ## B (elf->data + offset); \
198 while (EGET(dyn->d_tag) != DT_NULL) { \ 251 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
199 if (EGET(dyn->d_tag) == DT_RPATH) { \ 252 if (word == DT_RPATH) { \
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 */ \
200 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 } \
201 found_rpath = 1; \ 283 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 } \ 284 } \
206 ++dyn; \ 285 ++dyn; \
207 } \ 286 } \
208 } } 287 } }
209 SHOW_RPATH(32) 288 SHOW_RPATH(32)
210 SHOW_RPATH(64) 289 SHOW_RPATH(64)
211 } 290 }
291
292 if (be_wewy_wewy_quiet) return;
293
212 if (rpath && runpath) { 294 if (rpath && runpath) {
213 if (!strcmp(rpath, runpath)) 295 if (!strcmp(rpath, runpath)) {
214 printf("%-5s ", runpath); 296 xstrcat(ret, runpath, ret_len);
215 else { 297 } else {
216 fprintf(stderr, "%s's RPATH [%s] != RUNPATH [%s]\n", filename, rpath, runpath); 298 fprintf(stderr, "RPATH [%s] != RUNPATH [%s]\n", rpath, runpath);
217 printf("{%s,%s} ", rpath, runpath); 299 xchrcat(ret, '{', ret_len);
300 xstrcat(ret, rpath, ret_len);
301 xchrcat(ret, ',', ret_len);
302 xstrcat(ret, runpath, ret_len);
303 xchrcat(ret, '}', ret_len);
218 } 304 }
219 } else if (rpath || runpath) 305 } else if (rpath || runpath)
220 printf("%-5s ", (runpath ? runpath : rpath)); 306 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
221 else if (!be_quiet && !found_rpath) 307 else if (!be_quiet)
222 printf(" - "); 308 xstrcat(ret, " - ", ret_len);
223 } 309}
224 310static 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 */ 311{
226 if (show_needed) { 312 unsigned long i;
227 char *needed; 313 char *needed;
314 void *strtbl_void;
315
316 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
317
228 void *strtbl_void = elf_findsecbyname(elf, ".dynstr"); 318 strtbl_void = elf_findsecbyname(elf, ".dynstr");
229 319
230 if (strtbl_void) { 320 if (elf->phdr && strtbl_void) {
231#define SHOW_NEEDED(B) \ 321#define SHOW_NEEDED(B) \
232 if (elf->elf_class == ELFCLASS ## B) { \ 322 if (elf->elf_class == ELFCLASS ## B) { \
233 Elf ## B ## _Dyn *dyn; \ 323 Elf ## B ## _Dyn *dyn; \
234 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 324 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
235 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 325 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
236 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 326 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
327 Elf ## B ## _Off offset; \
237 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 328 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; \ 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; \
244 dyn = DYN ## B (elf->data + EGET(phdr[i].p_offset)); \ 332 dyn = DYN ## B (elf->data + offset); \
245 while (EGET(dyn->d_tag) != DT_NULL) { \ 333 while (EGET(dyn->d_tag) != DT_NULL) { \
246 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 334 if (EGET(dyn->d_tag) == DT_NEEDED) { \
247 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); \
248 if (found_needed) printf(","); \ 336 if (offset >= (Elf ## B ## _Off)elf->len) { \
249 printf("%s", needed); \ 337 ++dyn; \
338 continue; \
339 } \
340 needed = (char*)(elf->data + offset); \
341 if (op == 0) { \
342 if (!be_wewy_wewy_quiet) { \
343 if (*found_needed) xchrcat(ret, ',', ret_len); \
344 xstrcat(ret, needed, ret_len); \
345 } \
250 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 } \
251 } \ 352 } \
252 ++dyn; \ 353 ++dyn; \
253 } \ 354 } \
254 } } 355 } }
255 SHOW_NEEDED(32) 356 SHOW_NEEDED(32)
256 SHOW_NEEDED(64) 357 SHOW_NEEDED(64)
257 } 358 }
258 if (!be_quiet && !found_needed) 359
259 printf(" - "); 360 return NULL;
260 else if (found_needed) 361}
261 printf(" "); 362static char *scanelf_file_interp(elfobj *elf, char *found_interp)
363{
364 void *strtbl_void;
365
366 if (!show_interp) return NULL;
367
368 strtbl_void = elf_findsecbyname(elf, ".interp");
369
370 if (strtbl_void) {
371#define SHOW_INTERP(B) \
372 if (elf->elf_class == ELFCLASS ## B) { \
373 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
374 *found_interp = 1; \
375 return (be_wewy_wewy_quiet ? NULL : elf->data + EGET(strtbl->sh_offset)); \
262 } 376 }
377 SHOW_INTERP(32)
378 SHOW_INTERP(64)
379 }
380 return NULL;
381}
382static char *scanelf_file_bind(elfobj *elf, char *found_bind)
383{
384 unsigned long i;
385 struct stat s;
263 386
264 /* search the symbol table for a specified symbol */ 387 if (!show_bind) return NULL;
265 if (find_sym) { 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}
425static char *scanelf_file_sym(elfobj *elf, char *found_sym)
426{
427 unsigned long i;
266 void *symtab_void, *strtab_void; 428 void *symtab_void, *strtab_void;
267 char *versioned_symname;
268 size_t len;
269 429
270 len = strlen(find_sym) + 1; 430 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 431
432 /* debug sections */
278 symtab_void = elf_findsecbyname(elf, ".symtab"); 433 symtab_void = elf_findsecbyname(elf, ".symtab");
279 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 }
280 440
281 if (symtab_void && strtab_void) { 441 if (symtab_void && strtab_void) {
442 char *base, *basemem;
443 basemem = xstrdup(elf->filename);
444 base = basename(basemem);
282#define FIND_SYM(B) \ 445#define FIND_SYM(B) \
283 if (elf->elf_class == ELFCLASS ## B) { \ 446 if (elf->elf_class == ELFCLASS ## B) { \
284 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 447 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
285 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 448 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
286 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)); \
287 int cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 450 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
288 char *symname; \ 451 char *symname; \
289 for (i = 0; i < cnt; ++i) { \ 452 for (i = 0; i < cnt; ++i) { \
290 if (sym->st_name) { \ 453 if (sym->st_name) { \
291 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)); \
292 if (*find_sym == '*') { \ 455 if (*find_sym == '*') { \
293 printf("%s(%s) %5lX %15s %s\n", \ 456 printf("%s(%s) %5lX %15s %s\n", \
294 ((found_sym == 0) ? "\n\t" : "\t"), \ 457 ((*found_sym == 0) ? "\n\t" : "\t"), \
295 (char *)basename(filename), \ 458 base, \
296 (long)sym->st_size, \ 459 (long)sym->st_size, \
297 (char *)get_elfstttype(sym->st_info), \ 460 (char *)get_elfstttype(sym->st_info), \
298 symname); \ 461 symname); \
299 found_sym = 1; \ 462 *found_sym = 1; \
300 } else if ((strcmp(find_sym, symname) == 0) || \ 463 } else if ((strcmp(find_sym, symname) == 0) || \
301 (strncmp(symname, versioned_symname, len) == 0)) \ 464 (strcmp(symname, versioned_symname) == 0)) \
302 found_sym++; \ 465 (*found_sym)++; \
303 } \ 466 } \
304 ++sym; \ 467 ++sym; \
305 } } 468 } }
306 FIND_SYM(32) 469 FIND_SYM(32)
307 FIND_SYM(64) 470 FIND_SYM(64)
471 free(basemem);
472 }
473
474 if (be_wewy_wewy_quiet) return NULL;
475
476 if (*find_sym != '*' && *found_sym)
477 return find_sym;
478 if (be_quiet)
479 return NULL;
480 else
481 return (char *)" - ";
482}
483/* scan an elf file and show all the fun stuff */
484#define prints(str) write(fileno(stdout), str, strlen(str))
485static void scanelf_file(const char *filename)
486{
487 unsigned long i;
488 char found_pax, found_phdr, found_relro, found_load, found_textrel,
489 found_rpath, found_needed, found_interp, found_bind,
490 found_sym, found_lib, found_file;
491 elfobj *elf;
492 struct stat st;
493 static char *out_buffer = NULL;
494 static size_t out_len;
495
496 /* make sure 'filename' exists */
497 if (lstat(filename, &st) == -1) {
498 if (be_verbose > 2) printf("%s: does not exist\n", filename);
499 return;
500 }
501 /* always handle regular files and handle symlinked files if no -y */
502 if (S_ISLNK(st.st_mode)) {
503 if (!scan_symlink) return;
504 stat(filename, &st);
505 }
506 if (!S_ISREG(st.st_mode)) {
507 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
508 return;
509 }
510
511 found_pax = found_phdr = found_relro = found_load = \
512 found_textrel = found_rpath = found_needed = found_interp = \
513 found_bind = found_sym = found_lib = found_file = 0;
514
515 /* verify this is real ELF */
516 if ((elf = readelf(filename)) == NULL) {
517 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
518 return;
519 }
520
521 if (be_verbose > 1)
522 printf("%s: scanning file {%s,%s}\n", filename,
523 get_elfeitype(EI_CLASS, elf->elf_class),
524 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
525 else if (be_verbose)
526 printf("%s: scanning file\n", filename);
527
528 /* init output buffer */
529 if (!out_buffer) {
530 out_len = sizeof(char) * 80;
531 out_buffer = (char*)xmalloc(out_len);
532 }
533 *out_buffer = '\0';
534
535 /* show the header */
536 if (!be_quiet && show_banner) {
537 for (i = 0; out_format[i]; ++i) {
538 if (!IS_MODIFIER(out_format[i])) continue;
539
540 switch (out_format[++i]) {
541 case '%': break;
542 case '#': break;
543 case 'F':
544 case 'p':
545 case 'f': prints("FILE "); found_file = 1; break;
546 case 'o': prints(" TYPE "); break;
547 case 'x': prints(" PAX "); break;
548 case 'e': prints("STK/REL/PTL "); break;
549 case 't': prints("TEXTREL "); break;
550 case 'r': prints("RPATH "); break;
551 case 'n': prints("NEEDED "); break;
552 case 'i': prints("INTERP "); break;
553 case 'b': prints("BIND "); break;
554 case 's': prints("SYM "); break;
555 case 'N': prints("LIB "); break;
308 } 556 }
309 free(versioned_symname); 557 }
310 if (*find_sym != '*') { 558 if (!found_file) prints("FILE ");
311 if (found_sym) 559 prints("\n");
312 printf(" %s ", find_sym); 560 found_file = 0;
313 else if (!be_quiet) 561 show_banner = 0;
314 fputs(" - ", stdout); 562 }
563
564 /* dump all the good stuff */
565 for (i = 0; out_format[i]; ++i) {
566 const char *out;
567 const char *tmp;
568
569 /* make sure we trim leading spaces in quiet mode */
570 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
571 *out_buffer = '\0';
572
573 if (!IS_MODIFIER(out_format[i])) {
574 xchrcat(&out_buffer, out_format[i], &out_len);
575 continue;
576 }
577
578 out = NULL;
579 be_wewy_wewy_quiet = (out_format[i] == '#');
580 switch (out_format[++i]) {
581 case '%':
582 case '#':
583 xchrcat(&out_buffer, out_format[i], &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++;
315 } 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;
610 case 'o': out = get_elfetype(elf); break;
611 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
612 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
613 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
614 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
615 case 'n':
616 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
617 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
618 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
619 case 's': out = scanelf_file_sym(elf, &found_sym); break;
316 } 620 }
621 if (out) xstrcat(&out_buffer, out, &out_len);
622 }
317 623
318 if (!be_quiet || found_pax || found_stack || found_textrel || \ 624#define FOUND_SOMETHING() \
319 found_rpath || found_needed || found_sym) 625 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
320 puts(filename); 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);
630 xstrcat(&out_buffer, filename, &out_len);
631 }
632 if (!be_quiet || (be_quiet && FOUND_SOMETHING()))
633 puts(out_buffer);
321 634
322 unreadelf(elf); 635 unreadelf(elf);
323} 636}
324 637
325/* scan a directory for ET_EXEC files and print when we find one */ 638/* scan a directory for ET_EXEC files and print when we find one */
330 struct stat st_top, st; 643 struct stat st_top, st;
331 char buf[_POSIX_PATH_MAX]; 644 char buf[_POSIX_PATH_MAX];
332 size_t pathlen = 0, len = 0; 645 size_t pathlen = 0, len = 0;
333 646
334 /* make sure path exists */ 647 /* make sure path exists */
335 if (lstat(path, &st_top) == -1) 648 if (lstat(path, &st_top) == -1) {
649 if (be_verbose > 2) printf("%s: does not exist\n", path);
336 return; 650 return;
651 }
337 652
338 /* ok, if it isn't a directory, assume we can open it */ 653 /* ok, if it isn't a directory, assume we can open it */
339 if (!S_ISDIR(st_top.st_mode)) { 654 if (!S_ISDIR(st_top.st_mode)) {
340 scanelf_file(path); 655 scanelf_file(path);
341 return; 656 return;
352 while ((dentry = readdir(dir))) { 667 while ((dentry = readdir(dir))) {
353 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 668 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
354 continue; 669 continue;
355 len = (pathlen + 1 + strlen(dentry->d_name) + 1); 670 len = (pathlen + 1 + strlen(dentry->d_name) + 1);
356 if (len >= sizeof(buf)) { 671 if (len >= sizeof(buf)) {
357 warnf("Skipping '%s': len > sizeof(buf); %d > %d\n", path, (int)len, (int)sizeof(buf)); 672 warnf("Skipping '%s': len > sizeof(buf); %u > %u\n", path, len, sizeof(buf));
358 continue; 673 continue;
359 } 674 }
360 sprintf(buf, "%s/%s", path, dentry->d_name); 675 sprintf(buf, "%s/%s", path, dentry->d_name);
361 if (lstat(buf, &st) != -1) { 676 if (lstat(buf, &st) != -1) {
362 if (S_ISREG(st.st_mode)) 677 if (S_ISREG(st.st_mode))
368 } 683 }
369 } 684 }
370 closedir(dir); 685 closedir(dir);
371} 686}
372 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
373/* scan /etc/ld.so.conf for paths */ 739/* scan /etc/ld.so.conf for paths */
374static void scanelf_ldpath() 740static void scanelf_ldpath()
375{ 741{
376 char scan_l, scan_ul, scan_ull; 742 char scan_l, scan_ul, scan_ull;
377 char *path, *p; 743 int i = 0;
378 FILE *fp;
379 744
380 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 745 if (!ldpaths[0])
381 err("Unable to open ld.so.conf: %s", strerror(errno)); 746 err("Unable to load any paths from ld.so.conf");
382 747
383 scan_l = scan_ul = scan_ull = 0; 748 scan_l = scan_ul = scan_ull = 0;
384 749
385 if ((path = malloc(_POSIX_PATH_MAX)) == NULL) { 750 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; 751 if (!scan_l && !strcmp(ldpaths[i], "/lib")) scan_l = 1;
396 if (!scan_ul && !strcmp(path, "/usr/lib")) scan_ul = 1; 752 if (!scan_ul && !strcmp(ldpaths[i], "/usr/lib")) scan_ul = 1;
397 if (!scan_ull && !strcmp(path, "/usr/local/lib")) scan_ull = 1; 753 if (!scan_ull && !strcmp(ldpaths[i], "/usr/local/lib")) scan_ull = 1;
398 scanelf_dir(path); 754 scanelf_dir(ldpaths[i]);
755 ++i;
399 } 756 }
400 free(path);
401 fclose(fp);
402 757
403 if (!scan_l) scanelf_dir("/lib"); 758 if (!scan_l) scanelf_dir("/lib");
404 if (!scan_ul) scanelf_dir("/usr/lib"); 759 if (!scan_ul) scanelf_dir("/usr/lib");
405 if (!scan_ull) scanelf_dir("/usr/local/lib"); 760 if (!scan_ull) scanelf_dir("/usr/local/lib");
406} 761}
411 char *path, *p; 766 char *path, *p;
412 767
413 path = getenv("PATH"); 768 path = getenv("PATH");
414 if (!path) 769 if (!path)
415 err("PATH is not set in your env !"); 770 err("PATH is not set in your env !");
416 771 path = xstrdup(path);
417 if ((path = strdup(path)) == NULL)
418 err("strdup failed: %s", strerror(errno));
419 772
420 while ((p = strrchr(path, ':')) != NULL) { 773 while ((p = strrchr(path, ':')) != NULL) {
421 scanelf_dir(p + 1); 774 scanelf_dir(p + 1);
422 *p = 0; 775 *p = 0;
423 } 776 }
426} 779}
427 780
428 781
429 782
430/* usage / invocation handling functions */ 783/* usage / invocation handling functions */
431#define PARSE_FLAGS "plRmxetrns:aqvo:BhV" 784#define PARSE_FLAGS "plRmyxetrnibs:N:aqvF:f:o:BhV"
432#define a_argument required_argument 785#define a_argument required_argument
433static struct option const long_opts[] = { 786static struct option const long_opts[] = {
434 {"path", no_argument, NULL, 'p'}, 787 {"path", no_argument, NULL, 'p'},
435 {"ldpath", no_argument, NULL, 'l'}, 788 {"ldpath", no_argument, NULL, 'l'},
436 {"recursive", no_argument, NULL, 'R'}, 789 {"recursive", no_argument, NULL, 'R'},
437 {"mount", no_argument, NULL, 'm'}, 790 {"mount", no_argument, NULL, 'm'},
791 {"symlink", no_argument, NULL, 'y'},
438 {"pax", no_argument, NULL, 'x'}, 792 {"pax", no_argument, NULL, 'x'},
439 {"header", no_argument, NULL, 'e'}, 793 {"header", no_argument, NULL, 'e'},
440 {"textrel", no_argument, NULL, 't'}, 794 {"textrel", no_argument, NULL, 't'},
441 {"rpath", no_argument, NULL, 'r'}, 795 {"rpath", no_argument, NULL, 'r'},
442 {"needed", no_argument, NULL, 'n'}, 796 {"needed", no_argument, NULL, 'n'},
797 {"interp", no_argument, NULL, 'i'},
798 {"bind", no_argument, NULL, 'b'},
443 {"symbol", a_argument, NULL, 's'}, 799 {"symbol", a_argument, NULL, 's'},
800 {"lib", a_argument, NULL, 'N'},
444 {"all", no_argument, NULL, 'a'}, 801 {"all", no_argument, NULL, 'a'},
445 {"quiet", no_argument, NULL, 'q'}, 802 {"quiet", no_argument, NULL, 'q'},
446 {"verbose", no_argument, NULL, 'v'}, 803 {"verbose", no_argument, NULL, 'v'},
804 {"format", a_argument, NULL, 'F'},
805 {"from", a_argument, NULL, 'f'},
447 {"file", a_argument, NULL, 'o'}, 806 {"file", a_argument, NULL, 'o'},
448 {"nobanner", no_argument, NULL, 'B'}, 807 {"nobanner", no_argument, NULL, 'B'},
449 {"help", no_argument, NULL, 'h'}, 808 {"help", no_argument, NULL, 'h'},
450 {"version", no_argument, NULL, 'V'}, 809 {"version", no_argument, NULL, 'V'},
451 {NULL, no_argument, NULL, 0x0} 810 {NULL, no_argument, NULL, 0x0}
452}; 811};
812
453static char *opts_help[] = { 813static const char *opts_help[] = {
454 "Scan all directories in PATH environment", 814 "Scan all directories in PATH environment",
455 "Scan all directories in /etc/ld.so.conf", 815 "Scan all directories in /etc/ld.so.conf",
456 "Scan directories recursively", 816 "Scan directories recursively",
457 "Don't recursively cross mount points\n", 817 "Don't recursively cross mount points",
818 "Don't scan symlinks\n",
458 "Print PaX markings", 819 "Print PaX markings",
459 "Print GNU_STACK markings", 820 "Print GNU_STACK/PT_LOAD markings",
460 "Print TEXTREL information", 821 "Print TEXTREL information",
461 "Print RPATH information", 822 "Print RPATH information",
462 "Print NEEDED information", 823 "Print NEEDED information",
824 "Print INTERP information",
825 "Print BIND information",
463 "Find a specified symbol", 826 "Find a specified symbol",
827 "Find a specified library",
464 "Print all scanned info (-x -e -t -r)\n", 828 "Print all scanned info (-x -e -t -r -n -i -b)\n",
465 "Only output 'bad' things", 829 "Only output 'bad' things",
466 "Be verbose (can be specified more than once)", 830 "Be verbose (can be specified more than once)",
831 "Use specified format for output",
832 "Read input stream from a filename",
467 "Write output stream to a filename", 833 "Write output stream to a filename",
468 "Don't display the header", 834 "Don't display the header",
469 "Print this help and exit", 835 "Print this help and exit",
470 "Print version and exit", 836 "Print version and exit",
471 NULL 837 NULL
472}; 838};
473 839
474/* display usage and exit */ 840/* display usage and exit */
475static void usage(int status) 841static void usage(int status)
476{ 842{
477 int i; 843 unsigned long i;
478 printf(" Scan ELF binaries for stuff\n" 844 printf("* Scan ELF binaries for stuff\n\n"
479 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); 845 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0);
480 printf("Options: -[%s]\n", PARSE_FLAGS); 846 printf("Options: -[%s]\n", PARSE_FLAGS);
481 for (i = 0; long_opts[i].name; ++i) 847 for (i = 0; long_opts[i].name; ++i)
482 if (long_opts[i].has_arg == no_argument) 848 if (long_opts[i].has_arg == no_argument)
483 printf(" -%c, --%-13s %s\n", long_opts[i].val, 849 printf(" -%c, --%-13s* %s\n", long_opts[i].val,
484 long_opts[i].name, opts_help[i]); 850 long_opts[i].name, opts_help[i]);
485 else 851 else
486 printf(" -%c, --%-6s <arg> %s\n", long_opts[i].val, 852 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val,
487 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
488 exit(status); 867 exit(status);
489} 868}
490 869
491/* parse command line arguments and preform needed actions */ 870/* parse command line arguments and preform needed actions */
492static void parseargs(int argc, char *argv[]) 871static void parseargs(int argc, char *argv[])
493{ 872{
494 int flag; 873 int i;
874 char *from_file = NULL;
495 875
496 opterr = 0; 876 opterr = 0;
497 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) {
498 switch (flag) { 878 switch (i) {
499 879
500 case 'V': /* version info */ 880 case 'V':
501 printf("%s compiled %s\n%s\n" 881 printf("%s compiled %s\n%s\n"
502 "%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",
503 __FILE__, __DATE__, rcsid, argv0); 883 __FILE__, __DATE__, rcsid, argv0);
504 exit(EXIT_SUCCESS); 884 exit(EXIT_SUCCESS);
505 break; 885 break;
506 case 'h': usage(EXIT_SUCCESS); break; 886 case 'h': usage(EXIT_SUCCESS); break;
507 887 case 'f':
888 if (from_file) err("Don't specify -f twice");
889 from_file = xstrdup(optarg);
890 break;
508 case 'o': { 891 case 'o': {
509 FILE *fp = NULL; 892 FILE *fp = NULL;
510 fp = freopen(optarg, "w", stdout); 893 if ((fp = freopen(optarg, "w", stdout)) == NULL)
511 if (fp == NULL)
512 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 894 err("Could not open output stream '%s': %s", optarg, strerror(errno));
513 stdout = fp; 895 SET_STDOUT(fp);
514 break; 896 break;
515 } 897 }
516 898
517 case 's': find_sym = strdup(optarg); break; 899 case 's': {
900 size_t len;
901 if (find_sym) err("Don't specify -s twice");
902 find_sym = xstrdup(optarg);
903 len = strlen(find_sym) + 1;
904 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1));
905 sprintf(versioned_symname, "%s@", find_sym);
906 break;
907 }
908 case 'N': {
909 if (find_lib) err("Don't specify -N twice");
910 find_lib = xstrdup(optarg);
911 break;
912 }
518 913
914 case 'F': {
915 if (out_format) err("Don't specify -F twice");
916 out_format = xstrdup(optarg);
917 break;
918 }
919
920 case 'y': scan_symlink = 0; break;
519 case 'B': show_banner = 0; break; 921 case 'B': show_banner = 0; break;
520 case 'l': scan_ldpath = 1; break; 922 case 'l': scan_ldpath = 1; break;
521 case 'p': scan_envpath = 1; break; 923 case 'p': scan_envpath = 1; break;
522 case 'R': dir_recurse = 1; break; 924 case 'R': dir_recurse = 1; break;
523 case 'm': dir_crossmount = 0; break; 925 case 'm': dir_crossmount = 0; break;
524 case 'x': show_pax = 1; break; 926 case 'x': show_pax = 1; break;
525 case 'e': show_stack = 1; break; 927 case 'e': show_phdr = 1; break;
526 case 't': show_textrel = 1; break; 928 case 't': show_textrel = 1; break;
527 case 'r': show_rpath = 1; break; 929 case 'r': show_rpath = 1; break;
528 case 'n': show_needed = 1; break; 930 case 'n': show_needed = 1; break;
931 case 'i': show_interp = 1; break;
932 case 'b': show_bind = 1; break;
529 case 'q': be_quiet = 1; break; 933 case 'q': be_quiet = 1; break;
530 case 'v': be_verbose = (be_verbose % 20) + 1; break; 934 case 'v': be_verbose = (be_verbose % 20) + 1; break;
531 case 'a': show_pax = show_stack = show_textrel = show_needed = show_rpath = 1; break; 935 case 'a': show_pax = show_phdr = show_textrel = show_rpath = \
936 show_needed = show_interp = show_bind = 1; break;
532 937
533 case ':': 938 case ':':
534 warn("Option missing parameter"); 939 err("Option missing parameter\n");
535 usage(EXIT_FAILURE);
536 break;
537 case '?': 940 case '?':
538 warn("Unknown option"); 941 err("Unknown option\n");
539 usage(EXIT_FAILURE);
540 break;
541 default: 942 default:
542 err("Unhandled option '%c'", flag); 943 err("Unhandled option '%c'", i);
543 break; 944 }
945 }
946
947 /* let the format option override all other options */
948 if (out_format) {
949 show_pax = show_phdr = show_textrel = show_rpath = \
950 show_needed = show_interp = show_bind = 0;
951 for (i = 0; out_format[i]; ++i) {
952 if (!IS_MODIFIER(out_format[i])) continue;
953
954 switch (out_format[++i]) {
955 case '%': break;
956 case '#': break;
957 case 'F': break;
958 case 'p': break;
959 case 'f': break;
960 case 's': break;
961 case 'N': break;
962 case 'o': break;
963 case 'x': show_pax = 1; break;
964 case 'e': show_phdr = 1; break;
965 case 't': show_textrel = 1; break;
966 case 'r': show_rpath = 1; break;
967 case 'n': show_needed = 1; break;
968 case 'i': show_interp = 1; break;
969 case 'b': show_bind = 1; break;
970 default:
971 err("Invalid format specifier '%c' (byte %i)",
972 out_format[i], i+1);
544 } 973 }
545 } 974 }
546 975
547 if (be_quiet && be_verbose) 976 /* construct our default format */
548 err("You can be quiet or you can be verbose, not both, stupid"); 977 } else {
978 size_t fmt_len = 30;
979 out_format = (char*)xmalloc(sizeof(char) * fmt_len);
980 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
981 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
982 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
983 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
984 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
985 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
986 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
987 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
988 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
989 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
990 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
991 }
992 if (be_verbose > 2) printf("Format: %s\n", out_format);
549 993
994 /* now lets actually do the scanning */
995 if (scan_ldpath || (show_rpath && be_quiet))
996 load_ld_so_conf();
550 if (scan_ldpath) scanelf_ldpath(); 997 if (scan_ldpath) scanelf_ldpath();
551 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 }
552 if (optind == argc && !scan_ldpath && !scan_envpath) 1004 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
553 err("Nothing to scan !?"); 1005 err("Nothing to scan !?");
554 while (optind < argc) 1006 while (optind < argc) {
555 scanelf_dir(argv[optind++]); 1007 search_path = argv[optind++];
1008 scanelf_dir(search_path);
1009 }
556 1010
1011 /* clean up */
1012 if (find_sym) {
1013 free(find_sym);
1014 free(versioned_symname);
1015 }
557 if (find_sym) free(find_sym); 1016 if (find_lib) free(find_lib);
1017 if (out_format) free(out_format);
1018 for (i = 0; ldpaths[i]; ++i)
1019 free(ldpaths[i]);
1020}
1021
1022
1023
1024/* utility funcs */
1025static char *xstrdup(const char *s)
1026{
1027 char *ret = strdup(s);
1028 if (!ret) err("Could not strdup(): %s", strerror(errno));
1029 return ret;
1030}
1031
1032static void *xmalloc(size_t size)
1033{
1034 void *ret = malloc(size);
1035 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1036 return ret;
1037}
1038
1039static void xstrcat(char **dst, const char *src, size_t *curr_len)
1040{
1041 size_t new_len;
1042
1043 new_len = strlen(*dst) + strlen(src);
1044 if (*curr_len <= new_len) {
1045 *curr_len = new_len + (*curr_len / 2);
1046 *dst = realloc(*dst, *curr_len);
1047 if (!*dst)
1048 err("could not realloc %li bytes", (unsigned long)*curr_len);
1049 }
1050
1051 strcat(*dst, src);
1052}
1053
1054static inline void xchrcat(char **dst, const char append, size_t *curr_len)
1055{
1056 static char my_app[2];
1057 my_app[0] = append;
1058 my_app[1] = '\0';
1059 xstrcat(dst, my_app, curr_len);
558} 1060}
559 1061
560 1062
561 1063
562int main(int argc, char *argv[]) 1064int main(int argc, char *argv[])
563{ 1065{
564 if (argc < 2) 1066 if (argc < 2)
565 usage(EXIT_FAILURE); 1067 usage(EXIT_FAILURE);
566 parseargs(argc, argv); 1068 parseargs(argc, argv);
567 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
568 return EXIT_SUCCESS; 1073 return EXIT_SUCCESS;
569} 1074}

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

  ViewVC Help
Powered by ViewVC 1.1.20