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

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

  ViewVC Help
Powered by ViewVC 1.1.20