/[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.78 Revision 1.188
1/* 1/*
2 * Copyright 2003-2005 Gentoo Foundation 2 * Copyright 2003-2007 Gentoo Foundation
3 * Distributed under the terms of the GNU General Public License v2 3 * Distributed under the terms of the GNU General Public License v2
4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.78 2005/06/08 22:23:16 vapier Exp $ 4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.188 2007/08/31 17:45:24 solar Exp $
5 * 5 *
6 ******************************************************************** 6 * Copyright 2003-2007 Ned Ludd - <solar@gentoo.org>
7 * This program is free software; you can redistribute it and/or 7 * Copyright 2004-2007 Mike Frysinger - <vapier@gentoo.org>
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 2 of the
10 * License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place - Suite 330, Boston,
20 * MA 02111-1307, USA.
21 */ 8 */
22 9
23#include <stdio.h> 10static const char *rcsid = "$Id: scanelf.c,v 1.188 2007/08/31 17:45:24 solar Exp $";
24#include <stdlib.h> 11const char * const argv0 = "scanelf";
25#include <sys/types.h> 12
26#include <libgen.h>
27#include <limits.h>
28#define __USE_GNU
29#include <string.h>
30#include <errno.h>
31#include <unistd.h>
32#include <sys/stat.h>
33#include <dirent.h>
34#include <getopt.h>
35#include <assert.h>
36#include "paxelf.h" 13#include "paxinc.h"
37 14
38static const char *rcsid = "$Id: scanelf.c,v 1.78 2005/06/08 22:23:16 vapier Exp $";
39#define argv0 "scanelf"
40
41#define IS_MODIFIER(c) (c == '%' || c == '#') 15#define IS_MODIFIER(c) (c == '%' || c == '#' || c == '+')
42
43
44 16
45/* prototypes */ 17/* prototypes */
46static void scanelf_file(const char *filename); 18static int file_matches_list(const char *filename, char **matchlist);
19static int scanelf_elfobj(elfobj *elf);
20static int scanelf_elf(const char *filename, int fd, size_t len);
21static int scanelf_archive(const char *filename, int fd, size_t len);
22static int scanelf_file(const char *filename, const struct stat *st_cache);
47static void scanelf_dir(const char *path); 23static int scanelf_dir(const char *path);
48static void scanelf_ldpath(); 24static void scanelf_ldpath(void);
49static void scanelf_envpath(); 25static void scanelf_envpath(void);
50static void usage(int status); 26static void usage(int status);
27static char **get_split_env(const char *envvar);
28static void parseenv(void);
51static void parseargs(int argc, char *argv[]); 29static int parseargs(int argc, char *argv[]);
52static char *xstrdup(const char *s); 30static int rematch(const char *regex, const char *match, int cflags);
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);
56 31
57/* variables to control behavior */ 32/* variables to control behavior */
33static char match_etypes[126] = "";
58static char *ldpaths[256]; 34static char *ldpaths[256];
59static char scan_ldpath = 0; 35static char scan_ldpath = 0;
60static char scan_envpath = 0; 36static char scan_envpath = 0;
61static char scan_symlink = 1; 37static char scan_symlink = 1;
38static char scan_archives = 0;
62static char dir_recurse = 0; 39static char dir_recurse = 0;
63static char dir_crossmount = 1; 40static char dir_crossmount = 1;
64static char show_pax = 0; 41static char show_pax = 0;
42static char show_perms = 0;
65static char show_phdr = 0; 43static char show_phdr = 0;
66static char show_textrel = 0; 44static char show_textrel = 0;
67static char show_rpath = 0; 45static char show_rpath = 0;
68static char show_needed = 0; 46static char show_needed = 0;
69static char show_interp = 0; 47static char show_interp = 0;
70static char show_bind = 0; 48static char show_bind = 0;
49static char show_soname = 0;
71static char show_textrels = 0; 50static char show_textrels = 0;
72static char show_banner = 1; 51static char show_banner = 1;
52static char show_endian = 0;
73static char be_quiet = 0; 53static char be_quiet = 0;
74static char be_verbose = 0; 54static char be_verbose = 0;
75static char be_wewy_wewy_quiet = 0; 55static char be_wewy_wewy_quiet = 0;
56static char be_semi_verbose = 0;
76static char *find_sym = NULL, *versioned_symname = NULL; 57static char *find_sym = NULL, *versioned_symname = NULL;
77static char *find_lib = NULL; 58static char *find_lib = NULL;
59static char *find_section = NULL;
78static char *out_format = NULL; 60static char *out_format = NULL;
79static char *search_path = NULL; 61static char *search_path = NULL;
62static char fix_elf = 0;
63static char g_match = 0;
64static char use_ldcache = 0;
80 65
66static char **qa_textrels = NULL;
67static char **qa_execstack = NULL;
68static char **qa_wx_load = NULL;
81 69
70int match_bits = 0;
71unsigned int match_perms = 0;
72caddr_t ldcache = 0;
73size_t ldcache_size = 0;
74unsigned long setpax = 0UL;
75
76int has_objdump = 0;
77
78static char *getstr_perms(const char *fname);
79static char *getstr_perms(const char *fname)
80{
81 struct stat st;
82 static char buf[8];
83
84 if ((stat(fname, &st)) == (-1))
85 return (char *) "";
86
87 snprintf(buf, sizeof(buf), "%o", st.st_mode);
88
89 return (char *) buf + 2;
90}
91
92/* find the path to a file by name */
93static char *which(const char *fname)
94{
95 static char fullpath[BUFSIZ];
96 char *path, *p;
97
98 path = getenv("PATH");
99 if (!path)
100 return NULL;
101
102 path = xstrdup(path);
103 while ((p = strrchr(path, ':')) != NULL) {
104 snprintf(fullpath, sizeof(fullpath), "%s/%s", p + 1, fname);
105 *p = 0;
106 if (access(fullpath, R_OK) != (-1)) {
107 free(path);
108 return (char *) fullpath;
109 }
110 }
111 free(path);
112 return NULL;
113}
114
115/* 1 on failure. 0 otherwise */
116static int rematch(const char *regex, const char *match, int cflags)
117{
118 regex_t preg;
119 int ret;
120
121 if ((match == NULL) || (regex == NULL))
122 return EXIT_FAILURE;
123
124
125 if ((ret = regcomp(&preg, regex, cflags))) {
126 char err[256];
127
128 if (regerror(ret, &preg, err, sizeof(err)))
129 fprintf(stderr, "regcomp failed: %s", err);
130 else
131 fprintf(stderr, "regcomp failed");
132
133 return EXIT_FAILURE;
134 }
135 ret = regexec(&preg, match, 0, NULL, 0);
136 regfree(&preg);
137
138 return ret;
139}
82 140
83/* sub-funcs for scanelf_file() */ 141/* sub-funcs for scanelf_file() */
84static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab) 142static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
85{ 143{
86 /* find the best SHT_DYNSYM and SHT_STRTAB sections */ 144 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
105 } \ 163 } \
106 } 164 }
107 GET_SYMTABS(32) 165 GET_SYMTABS(32)
108 GET_SYMTABS(64) 166 GET_SYMTABS(64)
109} 167}
168
110static char *scanelf_file_pax(elfobj *elf, char *found_pax) 169static char *scanelf_file_pax(elfobj *elf, char *found_pax)
111{ 170{
112 static char *paxflags;
113 static char ret[7]; 171 static char ret[7];
114 unsigned long i, shown; 172 unsigned long i, shown;
115
116 173
117 if (!show_pax) return NULL; 174 if (!show_pax) return NULL;
118 175
119 shown = 0; 176 shown = 0;
120 memset(&ret, 0, sizeof(ret)); 177 memset(&ret, 0, sizeof(ret));
125 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 182 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
126 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 183 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
127 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 184 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
128 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \ 185 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
129 continue; \ 186 continue; \
130 if (be_quiet && (EGET(phdr[i].p_flags) == 10240)) \ 187 if (fix_elf && setpax) { \
188 /* set the paxctl flags */ \
189 ESET(phdr[i].p_flags, setpax); \
190 } \
191 if (be_quiet && (EGET(phdr[i].p_flags) == (PF_NOEMUTRAMP | PF_NORANDEXEC))) \
131 continue; \ 192 continue; \
132 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \ 193 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
133 *found_pax = 1; \ 194 *found_pax = 1; \
134 ++shown; \ 195 ++shown; \
135 break; \ 196 break; \
137 } 198 }
138 SHOW_PAX(32) 199 SHOW_PAX(32)
139 SHOW_PAX(64) 200 SHOW_PAX(64)
140 } 201 }
141 202
203
204 if (fix_elf && setpax) {
205 /* set the chpax settings */
206 if (elf->elf_class == ELFCLASS32) {
207 if (EHDR32(elf->ehdr)->e_type == ET_DYN || EHDR32(elf->ehdr)->e_type == ET_EXEC)
208 ESET(EHDR32(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
209 } else {
210 if (EHDR64(elf->ehdr)->e_type == ET_DYN || EHDR64(elf->ehdr)->e_type == ET_EXEC)
211 ESET(EHDR64(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
212 }
213 }
214
142 /* fall back to EI_PAX if no PT_PAX was found */ 215 /* fall back to EI_PAX if no PT_PAX was found */
143 if (!*ret) { 216 if (!*ret) {
217 static char *paxflags;
144 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf)); 218 paxflags = pax_short_hf_flags(EI_PAX_FLAGS(elf));
145 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) { 219 if (!be_quiet || (be_quiet && EI_PAX_FLAGS(elf))) {
146 *found_pax = 1; 220 *found_pax = 1;
147 return paxflags; 221 return (be_wewy_wewy_quiet ? NULL : paxflags);
148 } 222 }
149 strncpy(ret, paxflags, sizeof(ret)); 223 strncpy(ret, paxflags, sizeof(ret));
150 // ++shown;
151 } 224 }
152 225
153 if (be_quiet && !shown) 226 if (be_wewy_wewy_quiet || (be_quiet && !shown))
154 return NULL; 227 return NULL;
228 else
155 return ret; 229 return ret;
156
157} 230}
231
158static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load) 232static char *scanelf_file_phdr(elfobj *elf, char *found_phdr, char *found_relro, char *found_load)
159{ 233{
160 static char ret[12]; 234 static char ret[12];
161 char *found; 235 char *found;
162 unsigned long i, off, shown, check_flags;
163 unsigned char multi_stack, multi_relro, multi_load; 236 unsigned long i, shown, multi_stack, multi_relro, multi_load;
237 int max_pt_load;
164 238
165 if (!show_phdr) return NULL; 239 if (!show_phdr) return NULL;
166 240
167 memcpy(ret, "--- --- ---\0", 12); 241 memcpy(ret, "--- --- ---\0", 12);
168 242
169 shown = 0; 243 shown = 0;
170 multi_stack = multi_relro = multi_load = 0; 244 multi_stack = multi_relro = multi_load = 0;
245 max_pt_load = elf_max_pt_load(elf);
171 246
172 if (elf->phdr) { 247#define NOTE_GNU_STACK ".note.GNU-stack"
173#define SHOW_PHDR(B) \ 248#define SHOW_PHDR(B) \
174 if (elf->elf_class == ELFCLASS ## B) { \ 249 if (elf->elf_class == ELFCLASS ## B) { \
175 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 250 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
251 Elf ## B ## _Off offset; \
252 uint32_t flags, check_flags; \
253 if (elf->phdr != NULL) { \
176 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 254 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
177 uint32_t flags; \
178 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 255 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
179 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \ 256 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
257 if (multi_stack++) \
180 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \ 258 warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
259 if (file_matches_list(elf->filename, qa_execstack)) \
260 continue; \
181 found = found_phdr; \ 261 found = found_phdr; \
182 off = 0; \ 262 offset = 0; \
183 check_flags = PF_X; \ 263 check_flags = PF_X; \
184 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \ 264 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
265 if (multi_relro++) \
185 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \ 266 warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
186 found = found_relro; \ 267 found = found_relro; \
187 off = 4; \ 268 offset = 4; \
188 check_flags = PF_X; \ 269 check_flags = PF_X; \
189 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \ 270 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
190 if (multi_load++ > 2) warnf("%s: more than 2 PT_LOAD's !?", elf->filename); \ 271 if (EGET(ehdr->e_type) == ET_DYN || EGET(ehdr->e_type) == ET_EXEC) \
272 if (multi_load++ > max_pt_load) \
273 warnf("%s: more than %i PT_LOAD's !?", elf->filename, max_pt_load); \
274 if (file_matches_list(elf->filename, qa_wx_load)) \
275 continue; \
191 found = found_load; \ 276 found = found_load; \
192 off = 8; \ 277 offset = 8; \
193 check_flags = PF_W|PF_X; \ 278 check_flags = PF_W|PF_X; \
194 } else \ 279 } else \
195 continue; \ 280 continue; \
196 flags = EGET(phdr[i].p_flags); \ 281 flags = EGET(phdr[i].p_flags); \
197 if (be_quiet && ((flags & check_flags) != check_flags)) \ 282 if (be_quiet && ((flags & check_flags) != check_flags)) \
198 continue; \ 283 continue; \
284 if ((EGET(phdr[i].p_type) != PT_LOAD) && (fix_elf && ((flags & PF_X) != flags))) { \
285 ESET(phdr[i].p_flags, flags & (PF_X ^ (size_t)-1)); \
286 ret[3] = ret[7] = '!'; \
287 flags = EGET(phdr[i].p_flags); \
288 } \
199 memcpy(ret+off, gnu_short_stack_flags(flags), 3); \ 289 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
200 *found = 1; \ 290 *found = 1; \
201 ++shown; \ 291 ++shown; \
292 } \
293 } else if (elf->shdr != NULL) { \
294 /* no program headers which means this is prob an object file */ \
295 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
296 Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \
297 char *str; \
298 if ((void*)strtbl > (void*)elf->data_end) \
299 goto skip_this_shdr##B; \
300 check_flags = SHF_WRITE|SHF_EXECINSTR; \
301 for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \
302 if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \
303 offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \
304 str = elf->data + offset; \
305 if (str > elf->data + offset + sizeof(NOTE_GNU_STACK)) continue; \
306 if (!strcmp(str, NOTE_GNU_STACK)) { \
307 if (multi_stack++) warnf("%s: multiple .note.GNU-stack's !?", elf->filename); \
308 flags = EGET(shdr[i].sh_flags); \
309 if (be_quiet && ((flags & check_flags) != check_flags)) \
310 continue; \
311 ++*found_phdr; \
312 shown = 1; \
313 if (flags & SHF_WRITE) ret[0] = 'W'; \
314 if (flags & SHF_ALLOC) ret[1] = 'A'; \
315 if (flags & SHF_EXECINSTR) ret[2] = 'X'; \
316 if (flags & 0xFFFFFFF8) warn("Invalid section flags for GNU-stack"); \
317 break; \
318 } \
319 } \
320 skip_this_shdr##B: \
321 if (!multi_stack) { \
322 if (file_matches_list(elf->filename, qa_execstack)) \
323 return NULL; \
324 *found_phdr = 1; \
325 shown = 1; \
326 memcpy(ret, "!WX", 3); \
327 } \
202 } \ 328 } \
203 } 329 }
204 SHOW_PHDR(32) 330 SHOW_PHDR(32)
205 SHOW_PHDR(64) 331 SHOW_PHDR(64)
206 }
207 332
208 if (be_quiet && !shown) 333 if (be_wewy_wewy_quiet || (be_quiet && !shown))
209 return NULL; 334 return NULL;
210 else 335 else
211 return ret; 336 return ret;
212} 337}
338
339/*
340 * See if this ELF contains a DT_TEXTREL tag in any of its
341 * PT_DYNAMIC sections.
342 */
213static char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 343static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
214{ 344{
215 static char ret[] = "TEXTREL"; 345 static const char *ret = "TEXTREL";
216 unsigned long i; 346 unsigned long i;
217 347
218 if (!show_textrel) return NULL; 348 if (!show_textrel && !show_textrels) return NULL;
349
350 if (file_matches_list(elf->filename, qa_textrels)) return NULL;
219 351
220 if (elf->phdr) { 352 if (elf->phdr) {
221#define SHOW_TEXTREL(B) \ 353#define SHOW_TEXTREL(B) \
222 if (elf->elf_class == ELFCLASS ## B) { \ 354 if (elf->elf_class == ELFCLASS ## B) { \
223 Elf ## B ## _Dyn *dyn; \ 355 Elf ## B ## _Dyn *dyn; \
224 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 356 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
225 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 357 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
226 Elf ## B ## _Off offset; \ 358 Elf ## B ## _Off offset; \
227 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 359 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
228 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 360 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
229 offset = EGET(phdr[i].p_offset); \ 361 offset = EGET(phdr[i].p_offset); \
230 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 362 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
231 dyn = DYN ## B (elf->data + offset); \ 363 dyn = DYN ## B (elf->data + offset); \
232 while (EGET(dyn->d_tag) != DT_NULL) { \ 364 while (EGET(dyn->d_tag) != DT_NULL) { \
233 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \ 365 if (EGET(dyn->d_tag) == DT_TEXTREL) { /*dyn->d_tag != DT_FLAGS)*/ \
243 } 375 }
244 376
245 if (be_quiet || be_wewy_wewy_quiet) 377 if (be_quiet || be_wewy_wewy_quiet)
246 return NULL; 378 return NULL;
247 else 379 else
248 return (char *)" - "; 380 return " - ";
249} 381}
382
383/*
384 * Scan the .text section to see if there are any relocations in it.
385 * Should rewrite this to check PT_LOAD sections that are marked
386 * Executable rather than the section named '.text'.
387 */
250static char *scanelf_file_textrels(elfobj *elf, char *found_textrels) 388static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel)
251{ 389{
252 unsigned long p, s, r, rmax; 390 unsigned long s, r, rmax;
253 void *symtab_void, *strtab_void; 391 void *symtab_void, *strtab_void, *text_void;
254 392
255 if (!show_textrels) return NULL; 393 if (!show_textrels) return NULL;
256 394
395 /* don't search for TEXTREL's if the ELF doesn't have any */
396 if (!*found_textrel) scanelf_file_textrel(elf, found_textrel);
397 if (!*found_textrel) return NULL;
398
257 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void); 399 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
400 text_void = elf_findsecbyname(elf, ".text");
258 401
259 if (symtab_void && strtab_void && elf->phdr && elf->shdr) { 402 if (symtab_void && strtab_void && text_void && elf->shdr) {
260#define SHOW_TEXTRELS(B) \ 403#define SHOW_TEXTRELS(B) \
261 if (elf->elf_class == ELFCLASS ## B) { \ 404 if (elf->elf_class == ELFCLASS ## B) { \
262 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 405 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
263 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
264 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \ 406 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
265 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 407 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
266 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 408 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
409 Elf ## B ## _Shdr *text = SHDR ## B (text_void); \
410 Elf ## B ## _Addr vaddr = EGET(text->sh_addr); \
411 uint ## B ## _t memsz = EGET(text->sh_size); \
267 Elf ## B ## _Rel *rel; \ 412 Elf ## B ## _Rel *rel; \
268 Elf ## B ## _Rela *rela; \ 413 Elf ## B ## _Rela *rela; \
269 /* search the section headers for relocations */ \ 414 /* search the section headers for relocations */ \
270 for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \ 415 for (s = 0; s < EGET(ehdr->e_shnum); ++s) { \
271 uint32_t sh_type = EGET(shdr[s].sh_type); \ 416 uint32_t sh_type = EGET(shdr[s].sh_type); \
277 rel = NULL; \ 422 rel = NULL; \
278 rela = RELA ## B (elf->data + EGET(shdr[s].sh_offset)); \ 423 rela = RELA ## B (elf->data + EGET(shdr[s].sh_offset)); \
279 rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \ 424 rmax = EGET(shdr[s].sh_size) / sizeof(*rela); \
280 } else \ 425 } else \
281 continue; \ 426 continue; \
282 /* search the program headers for PT_LOAD headers */ \
283 for (p = 0; p < EGET(ehdr->e_phnum); ++p) { \
284 Elf ## B ## _Addr vaddr; \
285 uint ## B ## _t memsz; \
286 if (EGET(phdr[p].p_type) != PT_LOAD) continue; \
287 if (EGET(phdr[p].p_flags) & PF_W) continue; \
288 vaddr = EGET(phdr[p].p_vaddr); \
289 memsz = EGET(phdr[p].p_memsz); \
290 /* now see if any of the relocs are in the PT_LOAD */ \ 427 /* now see if any of the relocs are in the .text */ \
291 for (r = 0; r < rmax; ++r) { \ 428 for (r = 0; r < rmax; ++r) { \
292 unsigned long sym_max; \ 429 unsigned long sym_max; \
293 Elf ## B ## _Addr offset_tmp; \ 430 Elf ## B ## _Addr offset_tmp; \
294 Elf ## B ## _Sym *func; \ 431 Elf ## B ## _Sym *func; \
295 Elf ## B ## _Sym *sym; \ 432 Elf ## B ## _Sym *sym; \
296 Elf ## B ## _Addr r_offset; \ 433 Elf ## B ## _Addr r_offset; \
297 uint ## B ## _t r_info; \ 434 uint ## B ## _t r_info; \
298 if (sh_type == SHT_REL) { \ 435 if (sh_type == SHT_REL) { \
299 r_offset = EGET(rel[r].r_offset); \ 436 r_offset = EGET(rel[r].r_offset); \
300 r_info = EGET(rel[r].r_info); \ 437 r_info = EGET(rel[r].r_info); \
301 } else { \ 438 } else { \
302 r_offset = EGET(rela[r].r_offset); \ 439 r_offset = EGET(rela[r].r_offset); \
303 r_info = EGET(rela[r].r_info); \ 440 r_info = EGET(rela[r].r_info); \
441 } \
442 /* make sure this relocation is inside of the .text */ \
443 if (r_offset < vaddr || r_offset >= vaddr + memsz) { \
444 if (be_verbose <= 2) continue; \
445 } else \
446 *found_textrels = 1; \
447 /* locate this relocation symbol name */ \
448 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
449 if ((void*)sym > (void*)elf->data_end) { \
450 warn("%s: corrupt ELF symbol", elf->filename); \
451 continue; \
452 } \
453 sym_max = ELF ## B ## _R_SYM(r_info); \
454 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
455 sym += sym_max; \
456 else \
457 sym = NULL; \
458 sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
459 /* show the raw details about this reloc */ \
460 printf(" %s: ", elf->base_filename); \
461 if (sym && sym->st_name) \
462 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
463 else \
464 printf("(memory/data?)"); \
465 printf(" [0x%lX]", (unsigned long)r_offset); \
466 /* now try to find the closest symbol that this rel is probably in */ \
467 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
468 func = NULL; \
469 offset_tmp = 0; \
470 while (sym_max--) { \
471 if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \
472 func = sym; \
473 offset_tmp = EGET(sym->st_value); \
304 } \ 474 } \
305 /* make sure this relocation is inside of the .text */ \ 475 ++sym; \
306 if (r_offset < vaddr || r_offset >= vaddr + memsz) continue; \ 476 } \
307 *found_textrels = 1; \ 477 printf(" in "); \
308 /* locate this relocation symbol name */ \ 478 if (func && func->st_name) { \
309 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 479 const char *func_name = elf->data + EGET(strtab->sh_offset) + EGET(func->st_name); \
310 sym_max = ELF ## B ## _R_SYM(r_info); \ 480 if (r_offset > EGET(func->st_size)) \
311 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \ 481 printf("(optimized out: previous %s)", func_name); \
312 sym += sym_max; \
313 else \ 482 else \
314 sym = NULL; \ 483 printf("%s", func_name); \
315 sym_max = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \
316 /* show the raw details about this reloc */ \
317 printf("\tTEXTREL %s: ", elf->base_filename); \
318 if (sym && sym->st_name) \
319 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name))); \
320 else \ 484 } else \
321 printf("(NULL: fake?)"); \ 485 printf("(optimized out)"); \
322 printf(" [0x%lX]", (unsigned long)r_offset); \
323 /* now try to find the closest symbol that this rel is probably in */ \
324 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
325 func = NULL; \
326 offset_tmp = 0; \
327 while (sym_max--) { \
328 if (EGET(sym->st_value) < r_offset && EGET(sym->st_value) > offset_tmp) { \
329 func = sym; \
330 offset_tmp = EGET(sym->st_value); \
331 } \
332 ++sym; \
333 } \
334 printf(" in "); \
335 if (func && func->st_name) \
336 printf("%s", (char*)(elf->data + EGET(strtab->sh_offset) + EGET(func->st_name))); \
337 else \
338 printf("(NULL: fake?)"); \
339 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \ 486 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
487 if (be_verbose && has_objdump) { \
488 Elf ## B ## _Addr end_addr = offset_tmp + EGET(func->st_size); \
489 char *sysbuf; \
490 size_t syslen; \
491 const char sysfmt[] = "objdump -r -R -d -w -l --start-address=0x%lX --stop-address=0x%lX %s | grep --color -i -C 3 '.*[[:space:]]%lX:[[:space:]]*R_.*'\n"; \
492 syslen = sizeof(sysfmt) + strlen(elf->filename) + 3 * sizeof(unsigned long) + 1; \
493 sysbuf = xmalloc(syslen); \
494 if (end_addr < r_offset) \
495 /* not uncommon when things are optimized out */ \
496 end_addr = r_offset + 0x100; \
497 snprintf(sysbuf, syslen, sysfmt, \
498 (unsigned long)offset_tmp, \
499 (unsigned long)end_addr, \
500 elf->filename, \
501 (unsigned long)r_offset); \
502 fflush(stdout); \
503 system(sysbuf); \
504 fflush(stdout); \
505 free(sysbuf); \
340 } \ 506 } \
341 } \ 507 } \
342 } } 508 } }
343 SHOW_TEXTRELS(32) 509 SHOW_TEXTRELS(32)
344 SHOW_TEXTRELS(64) 510 SHOW_TEXTRELS(64)
345 } 511 }
512 if (!*found_textrels)
513 warnf("ELF %s has TEXTREL markings but doesnt appear to have any real TEXTREL's !?", elf->filename);
346 514
347 return NULL; 515 return NULL;
516}
517
518static void rpath_security_checks(elfobj *, char *, const char *);
519static void rpath_security_checks(elfobj *elf, char *item, const char *dt_type)
520{
521 struct stat st;
522 switch (*item) {
523 case '/': break;
524 case '.':
525 warnf("Security problem with relative %s '%s' in %s", dt_type, item, elf->filename);
526 break;
527 case ':':
528 case '\0':
529 warnf("Security problem NULL %s in %s", dt_type, elf->filename);
530 break;
531 case '$':
532 if (fstat(elf->fd, &st) != -1)
533 if ((st.st_mode & S_ISUID) || (st.st_mode & S_ISGID))
534 warnf("Security problem with %s='%s' in %s with mode set of %o",
535 dt_type, item, elf->filename, (unsigned int) st.st_mode & 07777);
536 break;
537 default:
538 warnf("Maybe? sec problem with %s='%s' in %s", dt_type, item, elf->filename);
539 break;
540 }
348} 541}
349static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len) 542static void scanelf_file_rpath(elfobj *elf, char *found_rpath, char **ret, size_t *ret_len)
350{ 543{
351 unsigned long i, s; 544 unsigned long i, s;
352 char *rpath, *runpath, **r; 545 char *rpath, *runpath, **r;
367 Elf ## B ## _Off offset; \ 560 Elf ## B ## _Off offset; \
368 Elf ## B ## _Xword word; \ 561 Elf ## B ## _Xword word; \
369 /* Scan all the program headers */ \ 562 /* Scan all the program headers */ \
370 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 563 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
371 /* Just scan dynamic headers */ \ 564 /* Just scan dynamic headers */ \
372 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 565 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
373 offset = EGET(phdr[i].p_offset); \ 566 offset = EGET(phdr[i].p_offset); \
374 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 567 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
375 /* Just scan dynamic RPATH/RUNPATH headers */ \ 568 /* Just scan dynamic RPATH/RUNPATH headers */ \
376 dyn = DYN ## B (elf->data + offset); \ 569 dyn = DYN ## B (elf->data + offset); \
377 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \ 570 while ((word=EGET(dyn->d_tag)) != DT_NULL) { \
386 /* Verify the memory is somewhat sane */ \ 579 /* Verify the memory is somewhat sane */ \
387 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \ 580 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
388 if (offset < (Elf ## B ## _Off)elf->len) { \ 581 if (offset < (Elf ## B ## _Off)elf->len) { \
389 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \ 582 if (*r) warn("ELF has multiple %s's !?", get_elfdtype(word)); \
390 *r = (char*)(elf->data + offset); \ 583 *r = (char*)(elf->data + offset); \
584 /* cache the length in case we need to nuke this section later on */ \
585 if (fix_elf) \
586 offset = strlen(*r); \
391 /* If quiet, don't output paths in ld.so.conf */ \ 587 /* If quiet, don't output paths in ld.so.conf */ \
392 if (be_quiet) { \ 588 if (be_quiet) { \
393 size_t len; \ 589 size_t len; \
394 char *start, *end; \ 590 char *start, *end; \
395 /* note that we only 'chop' off leading known paths. */ \ 591 /* note that we only 'chop' off leading known paths. */ \
396 /* since *r is read-only memory, we can only move the ptr forward. */ \ 592 /* since *r is read-only memory, we can only move the ptr forward. */ \
397 start = *r; \ 593 start = *r; \
398 /* scan each path in : delimited list */ \ 594 /* scan each path in : delimited list */ \
399 while (start) { \ 595 while (start) { \
596 rpath_security_checks(elf, start, get_elfdtype(word)); \
400 end = strchr(start, ':'); \ 597 end = strchr(start, ':'); \
401 len = (end ? abs(end - start) : strlen(start)); \ 598 len = (end ? abs(end - start) : strlen(start)); \
599 if (use_ldcache) \
402 for (s = 0; ldpaths[s]; ++s) { \ 600 for (s = 0; ldpaths[s]; ++s) \
403 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \ 601 if (!strncmp(ldpaths[s], start, len) && !ldpaths[s][len]) { \
404 *r = (end ? end + 1 : NULL); \ 602 *r = end; \
603 /* corner case ... if RPATH reads "/usr/lib:", we want \
604 * to show ':' rather than '' */ \
605 if (end && end[1] != '\0') \
606 (*r)++; \
405 break; \ 607 break; \
406 } \ 608 } \
407 } \
408 if (!*r || !ldpaths[s] || !end) \ 609 if (!*r || !end) \
409 start = NULL; \ 610 break; \
410 else \ 611 else \
411 start = start + len + 1; \ 612 start = start + len + 1; \
412 } \ 613 } \
413 } \ 614 } \
615 if (*r) { \
616 if (fix_elf > 2 || (fix_elf && **r == '\0')) { \
617 /* just nuke it */ \
618 nuke_it##B: \
619 memset(*r, 0x00, offset); \
620 *r = NULL; \
621 ESET(dyn->d_tag, DT_DEBUG); \
622 ESET(dyn->d_un.d_ptr, 0); \
623 } else if (fix_elf) { \
624 /* try to clean "bad" paths */ \
625 size_t len, tmpdir_len; \
626 char *start, *end; \
627 const char *tmpdir; \
628 start = *r; \
629 tmpdir = (getenv("TMPDIR") ? : "."); \
630 tmpdir_len = strlen(tmpdir); \
631 while (1) { \
632 end = strchr(start, ':'); \
633 if (start == end) { \
634 eat_this_path##B: \
635 len = strlen(end); \
636 memmove(start, end+1, len); \
637 start[len-1] = '\0'; \
638 end = start - 1; \
639 } else if (tmpdir && !strncmp(start, tmpdir, tmpdir_len)) { \
640 if (!end) { \
641 if (start == *r) \
642 goto nuke_it##B; \
643 *--start = '\0'; \
644 } else \
645 goto eat_this_path##B; \
646 } \
647 if (!end) \
648 break; \
649 start = end + 1; \
650 } \
651 if (**r == '\0') \
652 goto nuke_it##B; \
653 } \
654 if (*r) \
414 if (*r) *found_rpath = 1; \ 655 *found_rpath = 1; \
656 } \
415 } \ 657 } \
416 ++dyn; \ 658 ++dyn; \
417 } \ 659 } \
418 } } 660 } }
419 SHOW_RPATH(32) 661 SHOW_RPATH(32)
436 } else if (rpath || runpath) 678 } else if (rpath || runpath)
437 xstrcat(ret, (runpath ? runpath : rpath), ret_len); 679 xstrcat(ret, (runpath ? runpath : rpath), ret_len);
438 else if (!be_quiet) 680 else if (!be_quiet)
439 xstrcat(ret, " - ", ret_len); 681 xstrcat(ret, " - ", ret_len);
440} 682}
683
684#define LDSO_CACHE_MAGIC "ld.so-"
685#define LDSO_CACHE_MAGIC_LEN (sizeof LDSO_CACHE_MAGIC -1)
686#define LDSO_CACHE_VER "1.7.0"
687#define LDSO_CACHE_VER_LEN (sizeof LDSO_CACHE_VER -1)
688#define FLAG_ANY -1
689#define FLAG_TYPE_MASK 0x00ff
690#define FLAG_LIBC4 0x0000
691#define FLAG_ELF 0x0001
692#define FLAG_ELF_LIBC5 0x0002
693#define FLAG_ELF_LIBC6 0x0003
694#define FLAG_REQUIRED_MASK 0xff00
695#define FLAG_SPARC_LIB64 0x0100
696#define FLAG_IA64_LIB64 0x0200
697#define FLAG_X8664_LIB64 0x0300
698#define FLAG_S390_LIB64 0x0400
699#define FLAG_POWERPC_LIB64 0x0500
700#define FLAG_MIPS64_LIBN32 0x0600
701#define FLAG_MIPS64_LIBN64 0x0700
702
703static char *lookup_cache_lib(elfobj *, char *);
704
705#if defined(__GLIBC__) || defined(__UCLIBC__)
706
707static char *lookup_cache_lib(elfobj *elf, char *fname)
708{
709 int fd = 0;
710 char *strs;
711 static char buf[__PAX_UTILS_PATH_MAX] = "";
712 const char *cachefile = "/etc/ld.so.cache";
713 struct stat st;
714
715 typedef struct {
716 char magic[LDSO_CACHE_MAGIC_LEN];
717 char version[LDSO_CACHE_VER_LEN];
718 int nlibs;
719 } header_t;
720 header_t *header;
721
722 typedef struct {
723 int flags;
724 int sooffset;
725 int liboffset;
726 } libentry_t;
727 libentry_t *libent;
728
729 if (fname == NULL)
730 return NULL;
731
732 if (ldcache == 0) {
733 if (stat(cachefile, &st) || (fd = open(cachefile, O_RDONLY)) == -1)
734 return NULL;
735
736 /* cache these values so we only map/unmap the cache file once */
737 ldcache_size = st.st_size;
738 ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0);
739
740 close(fd);
741
742 if (ldcache == (caddr_t)-1) {
743 ldcache = 0;
744 return NULL;
745 }
746
747 if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN))
748 return NULL;
749 if (memcmp (((header_t *) ldcache)->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
750 return NULL;
751 }
752
753 header = (header_t *) ldcache;
754 libent = (libentry_t *) (ldcache + sizeof(header_t));
755 strs = (char *) &libent[header->nlibs];
756
757 for (fd = 0; fd < header->nlibs; fd++) {
758 /* this should be more fine grained, but for now we assume that
759 * diff arches will not be cached together. and we ignore the
760 * the different multilib mips cases. */
761 if (elf->elf_class == ELFCLASS64 && !(libent[fd].flags & FLAG_REQUIRED_MASK))
762 continue;
763 if (elf->elf_class == ELFCLASS32 && (libent[fd].flags & FLAG_REQUIRED_MASK))
764 continue;
765
766 if (strcmp(fname, strs + libent[fd].sooffset) != 0)
767 continue;
768 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
769 }
770 return buf;
771}
772#elif defined(__NetBSD__)
773static char *lookup_cache_lib(elfobj *elf, char *fname)
774{
775 static char buf[__PAX_UTILS_PATH_MAX] = "";
776 static struct stat st;
777
778 char **ldpath;
779 for (ldpath = ldpaths; *ldpath != NULL; ldpath++) {
780 if ((unsigned) snprintf(buf, sizeof(buf), "%s/%s", *ldpath, fname) >= sizeof(buf))
781 continue; /* if the pathname is too long, or something went wrong, ignore */
782
783 if (stat(buf, &st) != 0)
784 continue; /* if the lib doesn't exist in *ldpath, look further */
785
786 /* NetBSD doesn't actually do sanity checks, it just loads the file
787 * and if that doesn't work, continues looking in other directories.
788 * This cannot easily be safely emulated, unfortunately. For now,
789 * just assume that if it exists, it's a valid library. */
790
791 return buf;
792 }
793
794 /* not found in any path */
795 return NULL;
796}
797#else
798#warning Cache support not implemented for your target
799static char *lookup_cache_lib(elfobj *elf, char *fname)
800{
801 return NULL;
802}
803#endif
804
441static char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len) 805static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
442{ 806{
443 unsigned long i; 807 unsigned long i;
444 char *needed; 808 char *needed;
445 void *strtbl_void; 809 void *strtbl_void;
810 char *p;
446 811
447 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL; 812 if ((op==0 && !show_needed) || (op==1 && !find_lib)) return NULL;
448 813
449 strtbl_void = elf_findsecbyname(elf, ".dynstr"); 814 strtbl_void = elf_findsecbyname(elf, ".dynstr");
450 815
455 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 820 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
456 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 821 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
457 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \ 822 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
458 Elf ## B ## _Off offset; \ 823 Elf ## B ## _Off offset; \
459 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 824 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
460 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 825 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
461 offset = EGET(phdr[i].p_offset); \ 826 offset = EGET(phdr[i].p_offset); \
462 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 827 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
463 dyn = DYN ## B (elf->data + offset); \ 828 dyn = DYN ## B (elf->data + offset); \
464 while (EGET(dyn->d_tag) != DT_NULL) { \ 829 while (EGET(dyn->d_tag) != DT_NULL) { \
465 if (EGET(dyn->d_tag) == DT_NEEDED) { \ 830 if (EGET(dyn->d_tag) == DT_NEEDED) { \
470 } \ 835 } \
471 needed = (char*)(elf->data + offset); \ 836 needed = (char*)(elf->data + offset); \
472 if (op == 0) { \ 837 if (op == 0) { \
473 if (!be_wewy_wewy_quiet) { \ 838 if (!be_wewy_wewy_quiet) { \
474 if (*found_needed) xchrcat(ret, ',', ret_len); \ 839 if (*found_needed) xchrcat(ret, ',', ret_len); \
840 if (use_ldcache) \
841 if ((p = lookup_cache_lib(elf, needed)) != NULL) \
842 needed = p; \
475 xstrcat(ret, needed, ret_len); \ 843 xstrcat(ret, needed, ret_len); \
476 } \ 844 } \
477 *found_needed = 1; \ 845 *found_needed = 1; \
478 } else { \ 846 } else { \
479 if (strcmp(find_lib, needed)) return NULL; \ 847 if (!strncmp(find_lib, needed, strlen( !g_match ? needed : find_lib))) { \
480 *found_lib = 1; \ 848 *found_lib = 1; \
481 return (be_wewy_wewy_quiet ? NULL : find_lib); \ 849 return (be_wewy_wewy_quiet ? NULL : needed); \
850 } \
482 } \ 851 } \
483 } \ 852 } \
484 ++dyn; \ 853 ++dyn; \
485 } \ 854 } \
486 } } 855 } }
487 SHOW_NEEDED(32) 856 SHOW_NEEDED(32)
488 SHOW_NEEDED(64) 857 SHOW_NEEDED(64)
858 if (op == 0 && !*found_needed && be_verbose)
859 warn("ELF lacks DT_NEEDED sections: %s", elf->filename);
489 } 860 }
490 861
491 return NULL; 862 return NULL;
492} 863}
493static char *scanelf_file_interp(elfobj *elf, char *found_interp) 864static char *scanelf_file_interp(elfobj *elf, char *found_interp)
512} 883}
513static char *scanelf_file_bind(elfobj *elf, char *found_bind) 884static char *scanelf_file_bind(elfobj *elf, char *found_bind)
514{ 885{
515 unsigned long i; 886 unsigned long i;
516 struct stat s; 887 struct stat s;
888 char dynamic = 0;
517 889
518 if (!show_bind) return NULL; 890 if (!show_bind) return NULL;
519 if (!elf->phdr) return NULL; 891 if (!elf->phdr) return NULL;
520 892
521#define SHOW_BIND(B) \ 893#define SHOW_BIND(B) \
523 Elf ## B ## _Dyn *dyn; \ 895 Elf ## B ## _Dyn *dyn; \
524 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 896 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
525 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 897 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
526 Elf ## B ## _Off offset; \ 898 Elf ## B ## _Off offset; \
527 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 899 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
528 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 900 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
901 dynamic = 1; \
529 offset = EGET(phdr[i].p_offset); \ 902 offset = EGET(phdr[i].p_offset); \
530 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 903 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
531 dyn = DYN ## B (elf->data + offset); \ 904 dyn = DYN ## B (elf->data + offset); \
532 while (EGET(dyn->d_tag) != DT_NULL) { \ 905 while (EGET(dyn->d_tag) != DT_NULL) { \
533 if (EGET(dyn->d_tag) == DT_BIND_NOW || \ 906 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
544 SHOW_BIND(32) 917 SHOW_BIND(32)
545 SHOW_BIND(64) 918 SHOW_BIND(64)
546 919
547 if (be_wewy_wewy_quiet) return NULL; 920 if (be_wewy_wewy_quiet) return NULL;
548 921
922 /* don't output anything if quiet mode and the ELF is static or not setuid */
549 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) { 923 if (be_quiet && (!dynamic || (!fstat(elf->fd, &s) && !(s.st_mode & (S_ISUID|S_ISGID))))) {
550 return NULL; 924 return NULL;
551 } else { 925 } else {
552 *found_bind = 1; 926 *found_bind = 1;
553 return (char *) "LAZY"; 927 return (char *) (dynamic ? "LAZY" : "STATIC");
554 } 928 }
555} 929}
930static char *scanelf_file_soname(elfobj *elf, char *found_soname)
931{
932 unsigned long i;
933 char *soname;
934 void *strtbl_void;
935
936 if (!show_soname) return NULL;
937
938 strtbl_void = elf_findsecbyname(elf, ".dynstr");
939
940 if (elf->phdr && strtbl_void) {
941#define SHOW_SONAME(B) \
942 if (elf->elf_class == ELFCLASS ## B) { \
943 Elf ## B ## _Dyn *dyn; \
944 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
945 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
946 Elf ## B ## _Shdr *strtbl = SHDR ## B (strtbl_void); \
947 Elf ## B ## _Off offset; \
948 /* only look for soname in shared objects */ \
949 if (EGET(ehdr->e_type) != ET_DYN) \
950 return NULL; \
951 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
952 if (EGET(phdr[i].p_type) != PT_DYNAMIC || EGET(phdr[i].p_filesz) == 0) continue; \
953 offset = EGET(phdr[i].p_offset); \
954 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
955 dyn = DYN ## B (elf->data + offset); \
956 while (EGET(dyn->d_tag) != DT_NULL) { \
957 if (EGET(dyn->d_tag) == DT_SONAME) { \
958 offset = EGET(strtbl->sh_offset) + EGET(dyn->d_un.d_ptr); \
959 if (offset >= (Elf ## B ## _Off)elf->len) { \
960 ++dyn; \
961 continue; \
962 } \
963 soname = (char*)(elf->data + offset); \
964 *found_soname = 1; \
965 return (be_wewy_wewy_quiet ? NULL : soname); \
966 } \
967 ++dyn; \
968 } \
969 } }
970 SHOW_SONAME(32)
971 SHOW_SONAME(64)
972 }
973
974 return NULL;
975}
976
556static char *scanelf_file_sym(elfobj *elf, char *found_sym) 977static char *scanelf_file_sym(elfobj *elf, char *found_sym)
557{ 978{
558 unsigned long i; 979 unsigned long i;
980 char *ret;
559 void *symtab_void, *strtab_void; 981 void *symtab_void, *strtab_void;
560 982
561 if (!find_sym) return NULL; 983 if (!find_sym) return NULL;
984 ret = find_sym;
562 985
563 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void); 986 scanelf_file_get_symtabs(elf, &symtab_void, &strtab_void);
564 987
565 if (symtab_void && strtab_void) { 988 if (symtab_void && strtab_void) {
566#define FIND_SYM(B) \ 989#define FIND_SYM(B) \
567 if (elf->elf_class == ELFCLASS ## B) { \ 990 if (elf->elf_class == ELFCLASS ## B) { \
568 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 991 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
569 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 992 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
570 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 993 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
571 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 994 unsigned long cnt = EGET(symtab->sh_entsize); \
572 char *symname; \ 995 char *symname; \
996 if (cnt) \
997 cnt = EGET(symtab->sh_size) / cnt; \
573 for (i = 0; i < cnt; ++i) { \ 998 for (i = 0; i < cnt; ++i) { \
574 if (sym->st_name) { \ 999 if (sym->st_name) { \
1000 /* make sure the symbol name is in acceptable memory range */ \
575 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 1001 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
576 if (*find_sym == '*') { \ 1002 if ((void*)symname > (void*)elf->data_end) { \
1003 warnf("%s: corrupt ELF symbols", elf->filename); \
1004 ++sym; \
1005 continue; \
1006 } \
1007 /* debug display ... show all symbols and some extra info */ \
1008 if (g_match ? rematch(ret, symname, REG_EXTENDED) == 0 : *ret == '*') { \
577 printf("%s(%s) %5lX %15s %s\n", \ 1009 printf("%s(%s) %5lX %15s %s %s\n", \
578 ((*found_sym == 0) ? "\n\t" : "\t"), \ 1010 ((*found_sym == 0) ? "\n\t" : "\t"), \
579 elf->base_filename, \ 1011 elf->base_filename, \
580 (long)sym->st_size, \ 1012 (unsigned long)sym->st_size, \
581 (char *)get_elfstttype(sym->st_info), \ 1013 get_elfstttype(sym->st_info), \
582 symname); \ 1014 sym->st_shndx == SHN_UNDEF ? "U" : "D", symname); \
583 *found_sym = 1; \ 1015 *found_sym = 1; \
584 } else if ((strcmp(find_sym, symname) == 0) || \ 1016 } else { \
585 (strcmp(symname, versioned_symname) == 0)) \ 1017 /* allow the user to specify a comma delimited list of symbols to search for */ \
1018 char *this_sym, *this_sym_ver, *next_sym; \
1019 this_sym = ret; \
1020 this_sym_ver = versioned_symname; \
1021 do { \
1022 next_sym = strchr(this_sym, ','); \
1023 if (next_sym == NULL) \
1024 next_sym = this_sym + strlen(this_sym); \
1025 /* do we want a defined symbol ? */ \
1026 if (*this_sym == '+') { \
1027 if (sym->st_shndx == SHN_UNDEF) \
1028 goto skip_this_sym##B; \
1029 ++this_sym; \
1030 ++this_sym_ver; \
1031 /* do we want an undefined symbol ? */ \
1032 } else if (*this_sym == '-') { \
1033 if (sym->st_shndx != SHN_UNDEF) \
1034 goto skip_this_sym##B; \
1035 ++this_sym; \
1036 ++this_sym_ver; \
1037 } \
1038 /* ok, lets compare the name now */ \
1039 if ((strncmp(this_sym, symname, (next_sym-this_sym)) == 0 && symname[next_sym-this_sym] == '\0') || \
1040 (strncmp(this_sym_ver, symname, strlen(this_sym_ver)) == 0)) { \
1041 if (be_semi_verbose) { \
1042 char buf[126]; \
1043 snprintf(buf, sizeof(buf), "%lX %s %s", \
1044 (unsigned long)sym->st_size, get_elfstttype(sym->st_info), this_sym); \
1045 ret = buf; \
1046 } else \
1047 ret = this_sym; \
586 (*found_sym)++; \ 1048 (*found_sym)++; \
1049 goto break_out; \
1050 } \
1051 skip_this_sym##B: this_sym = next_sym + 1; \
1052 } while (*next_sym != '\0'); \
1053 } \
587 } \ 1054 } \
588 ++sym; \ 1055 ++sym; \
589 } } 1056 } }
590 FIND_SYM(32) 1057 FIND_SYM(32)
591 FIND_SYM(64) 1058 FIND_SYM(64)
592 } 1059 }
593 1060
1061break_out:
594 if (be_wewy_wewy_quiet) return NULL; 1062 if (be_wewy_wewy_quiet) return NULL;
595 1063
596 if (*find_sym != '*' && *found_sym) 1064 if (*find_sym != '*' && *found_sym)
597 return find_sym; 1065 return ret;
598 if (be_quiet) 1066 if (be_quiet)
599 return NULL; 1067 return NULL;
600 else 1068 else
601 return (char *)" - "; 1069 return (char *)" - ";
602} 1070}
1071
1072
1073static char *scanelf_file_sections(elfobj *elf, char *found_section)
1074{
1075 if (!find_section)
1076 return NULL;
1077
1078#define FIND_SECTION(B) \
1079 if (elf->elf_class == ELFCLASS ## B) { \
1080 int invert; \
1081 Elf ## B ## _Shdr *section; \
1082 invert = (*find_section == '!' ? 1 : 0); \
1083 section = SHDR ## B (elf_findsecbyname(elf, find_section+invert)); \
1084 if ((section == NULL && invert) || (section != NULL && !invert)) \
1085 *found_section = 1; \
1086 }
1087 FIND_SECTION(32)
1088 FIND_SECTION(64)
1089
1090 if (be_wewy_wewy_quiet)
1091 return NULL;
1092
1093 if (*found_section)
1094 return find_section;
1095
1096 if (be_quiet)
1097 return NULL;
1098 else
1099 return (char *)" - ";
1100}
1101
603/* scan an elf file and show all the fun stuff */ 1102/* scan an elf file and show all the fun stuff */
604#define prints(str) write(fileno(stdout), str, strlen(str)) 1103#define prints(str) write(fileno(stdout), str, strlen(str))
605static void scanelf_file(const char *filename) 1104static int scanelf_elfobj(elfobj *elf)
606{ 1105{
607 unsigned long i; 1106 unsigned long i;
608 char found_pax, found_phdr, found_relro, found_load, found_textrel, 1107 char found_pax, found_phdr, found_relro, found_load, found_textrel,
609 found_rpath, found_needed, found_interp, found_bind, 1108 found_rpath, found_needed, found_interp, found_bind, found_soname,
610 found_sym, found_lib, found_file, found_textrels; 1109 found_sym, found_lib, found_file, found_textrels, found_section;
611 elfobj *elf;
612 struct stat st;
613 static char *out_buffer = NULL; 1110 static char *out_buffer = NULL;
614 static size_t out_len; 1111 static size_t out_len;
615 1112
616 /* make sure 'filename' exists */
617 if (lstat(filename, &st) == -1) {
618 if (be_verbose > 2) printf("%s: does not exist\n", filename);
619 return;
620 }
621 /* always handle regular files and handle symlinked files if no -y */
622 if (S_ISLNK(st.st_mode)) {
623 if (!scan_symlink) return;
624 stat(filename, &st);
625 }
626 if (!S_ISREG(st.st_mode)) {
627 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
628 return;
629 }
630
631 found_pax = found_phdr = found_relro = found_load = found_textrel = \ 1113 found_pax = found_phdr = found_relro = found_load = found_textrel = \
632 found_rpath = found_needed = found_interp = found_bind = \ 1114 found_rpath = found_needed = found_interp = found_bind = found_soname = \
633 found_sym = found_lib = found_file = found_textrels = 0; 1115 found_sym = found_lib = found_file = found_textrels = found_section = 0;
634 1116
635 /* verify this is real ELF */
636 if ((elf = readelf(filename)) == NULL) {
637 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
638 return;
639 }
640
641 if (be_verbose > 1) 1117 if (be_verbose > 2)
642 printf("%s: scanning file {%s,%s}\n", filename, 1118 printf("%s: scanning file {%s,%s}\n", elf->filename,
643 get_elfeitype(EI_CLASS, elf->elf_class), 1119 get_elfeitype(EI_CLASS, elf->elf_class),
644 get_elfeitype(EI_DATA, elf->data[EI_DATA])); 1120 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
645 else if (be_verbose) 1121 else if (be_verbose > 1)
646 printf("%s: scanning file\n", filename); 1122 printf("%s: scanning file\n", elf->filename);
647 1123
648 /* init output buffer */ 1124 /* init output buffer */
649 if (!out_buffer) { 1125 if (!out_buffer) {
650 out_len = sizeof(char) * 80; 1126 out_len = sizeof(char) * 80;
651 out_buffer = (char*)xmalloc(out_len); 1127 out_buffer = xmalloc(out_len);
652 } 1128 }
653 *out_buffer = '\0'; 1129 *out_buffer = '\0';
654 1130
655 /* show the header */ 1131 /* show the header */
656 if (!be_quiet && show_banner) { 1132 if (!be_quiet && show_banner) {
657 for (i = 0; out_format[i]; ++i) { 1133 for (i = 0; out_format[i]; ++i) {
658 if (!IS_MODIFIER(out_format[i])) continue; 1134 if (!IS_MODIFIER(out_format[i])) continue;
659 1135
660 switch (out_format[++i]) { 1136 switch (out_format[++i]) {
1137 case '+': break;
661 case '%': break; 1138 case '%': break;
662 case '#': break; 1139 case '#': break;
663 case 'F': 1140 case 'F':
664 case 'p': 1141 case 'p':
665 case 'f': prints("FILE "); found_file = 1; break; 1142 case 'f': prints("FILE "); found_file = 1; break;
666 case 'o': prints(" TYPE "); break; 1143 case 'o': prints(" TYPE "); break;
667 case 'x': prints(" PAX "); break; 1144 case 'x': prints(" PAX "); break;
668 case 'e': prints("STK/REL/PTL "); break; 1145 case 'e': prints("STK/REL/PTL "); break;
669 case 't': prints("TEXTREL "); break; 1146 case 't': prints("TEXTREL "); break;
670 case 'r': prints("RPATH "); break; 1147 case 'r': prints("RPATH "); break;
1148 case 'M': prints("CLASS "); break;
671 case 'n': prints("NEEDED "); break; 1149 case 'n': prints("NEEDED "); break;
672 case 'i': prints("INTERP "); break; 1150 case 'i': prints("INTERP "); break;
673 case 'b': prints("BIND "); break; 1151 case 'b': prints("BIND "); break;
1152 case 'S': prints("SONAME "); break;
674 case 's': prints("SYM "); break; 1153 case 's': prints("SYM "); break;
675 case 'N': prints("LIB "); break; 1154 case 'N': prints("LIB "); break;
676 case 'T': prints("TEXTRELS "); break; 1155 case 'T': prints("TEXTRELS "); break;
1156 case 'k': prints("SECTION "); break;
1157 case 'a': prints("ARCH "); break;
1158 case 'O': prints("PERM "); break;
1159 case 'D': prints("ENDIAN "); break;
677 default: warnf("'%c' has no title ?", out_format[i]); 1160 default: warnf("'%c' has no title ?", out_format[i]);
678 } 1161 }
679 } 1162 }
680 if (!found_file) prints("FILE "); 1163 if (!found_file) prints("FILE ");
681 prints("\n"); 1164 prints("\n");
686 /* dump all the good stuff */ 1169 /* dump all the good stuff */
687 for (i = 0; out_format[i]; ++i) { 1170 for (i = 0; out_format[i]; ++i) {
688 const char *out; 1171 const char *out;
689 const char *tmp; 1172 const char *tmp;
690 1173
691 /* make sure we trim leading spaces in quiet mode */
692 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
693 *out_buffer = '\0';
694
695 if (!IS_MODIFIER(out_format[i])) { 1174 if (!IS_MODIFIER(out_format[i])) {
696 xchrcat(&out_buffer, out_format[i], &out_len); 1175 xchrcat(&out_buffer, out_format[i], &out_len);
697 continue; 1176 continue;
698 } 1177 }
699 1178
700 out = NULL; 1179 out = NULL;
701 be_wewy_wewy_quiet = (out_format[i] == '#'); 1180 be_wewy_wewy_quiet = (out_format[i] == '#');
1181 be_semi_verbose = (out_format[i] == '+');
702 switch (out_format[++i]) { 1182 switch (out_format[++i]) {
1183 case '+':
703 case '%': 1184 case '%':
704 case '#': 1185 case '#':
705 xchrcat(&out_buffer, out_format[i], &out_len); break; 1186 xchrcat(&out_buffer, out_format[i], &out_len); break;
706 case 'F': 1187 case 'F':
707 found_file = 1; 1188 found_file = 1;
708 if (be_wewy_wewy_quiet) break; 1189 if (be_wewy_wewy_quiet) break;
709 xstrcat(&out_buffer, filename, &out_len); 1190 xstrcat(&out_buffer, elf->filename, &out_len);
710 break; 1191 break;
711 case 'p': 1192 case 'p':
712 found_file = 1; 1193 found_file = 1;
713 if (be_wewy_wewy_quiet) break; 1194 if (be_wewy_wewy_quiet) break;
714 tmp = filename; 1195 tmp = elf->filename;
715 if (search_path) { 1196 if (search_path) {
716 ssize_t len_search = strlen(search_path); 1197 ssize_t len_search = strlen(search_path);
717 ssize_t len_file = strlen(filename); 1198 ssize_t len_file = strlen(elf->filename);
718 if (!strncmp(filename, search_path, len_search) && \ 1199 if (!strncmp(elf->filename, search_path, len_search) && \
719 len_file > len_search) 1200 len_file > len_search)
720 tmp += len_search; 1201 tmp += len_search;
721 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++; 1202 if (*tmp == '/' && search_path[len_search-1] == '/') tmp++;
722 } 1203 }
723 xstrcat(&out_buffer, tmp, &out_len); 1204 xstrcat(&out_buffer, tmp, &out_len);
724 break; 1205 break;
725 case 'f': 1206 case 'f':
726 found_file = 1; 1207 found_file = 1;
727 if (be_wewy_wewy_quiet) break; 1208 if (be_wewy_wewy_quiet) break;
728 tmp = strrchr(filename, '/'); 1209 tmp = strrchr(elf->filename, '/');
729 tmp = (tmp == NULL ? filename : tmp+1); 1210 tmp = (tmp == NULL ? elf->filename : tmp+1);
730 xstrcat(&out_buffer, tmp, &out_len); 1211 xstrcat(&out_buffer, tmp, &out_len);
731 break; 1212 break;
732 case 'o': out = get_elfetype(elf); break; 1213 case 'o': out = get_elfetype(elf); break;
733 case 'x': out = scanelf_file_pax(elf, &found_pax); break; 1214 case 'x': out = scanelf_file_pax(elf, &found_pax); break;
734 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break; 1215 case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break;
735 case 't': out = scanelf_file_textrel(elf, &found_textrel); break; 1216 case 't': out = scanelf_file_textrel(elf, &found_textrel); break;
736 case 'T': out = scanelf_file_textrels(elf, &found_textrels); break; 1217 case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break;
737 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break; 1218 case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break;
1219 case 'M': out = get_elfeitype(EI_CLASS, elf->data[EI_CLASS]); break;
1220 case 'D': out = get_endian(elf); break;
1221 case 'O': out = getstr_perms(elf->filename); break;
738 case 'n': 1222 case 'n':
739 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break; 1223 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
740 case 'i': out = scanelf_file_interp(elf, &found_interp); break; 1224 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
741 case 'b': out = scanelf_file_bind(elf, &found_bind); break; 1225 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
1226 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
742 case 's': out = scanelf_file_sym(elf, &found_sym); break; 1227 case 's': out = scanelf_file_sym(elf, &found_sym); break;
1228 case 'k': out = scanelf_file_sections(elf, &found_section); break;
1229 case 'a': out = get_elfemtype(elf); break;
743 default: warnf("'%c' has no scan code?", out_format[i]); 1230 default: warnf("'%c' has no scan code?", out_format[i]);
744 } 1231 }
1232 if (out) {
1233 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
1234 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
1235 xstrncat(&out_buffer, out, &out_len, (tmp-out));
1236 else
745 if (out) xstrcat(&out_buffer, out, &out_len); 1237 xstrcat(&out_buffer, out, &out_len);
1238 }
746 } 1239 }
747 1240
748#define FOUND_SOMETHING() \ 1241#define FOUND_SOMETHING() \
749 (found_pax || found_phdr || found_relro || found_load || found_textrel || \ 1242 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
750 found_rpath || found_needed || found_interp || found_bind || \ 1243 found_rpath || found_needed || found_interp || found_bind || \
751 found_sym || found_lib || found_textrels) 1244 found_soname || found_sym || found_lib || found_textrels || found_section )
752 1245
753 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) { 1246 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
754 xchrcat(&out_buffer, ' ', &out_len); 1247 xchrcat(&out_buffer, ' ', &out_len);
755 xstrcat(&out_buffer, filename, &out_len); 1248 xstrcat(&out_buffer, elf->filename, &out_len);
756 } 1249 }
757 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) 1250 if (!be_quiet || (be_quiet && FOUND_SOMETHING())) {
758 puts(out_buffer); 1251 puts(out_buffer);
1252 fflush(stdout);
1253 }
759 1254
1255 return 0;
1256}
1257
1258/* scan a single elf */
1259static int scanelf_elf(const char *filename, int fd, size_t len)
1260{
1261 int ret = 1;
1262 elfobj *elf;
1263
1264 /* verify this is real ELF */
1265 if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) {
1266 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
1267 return ret;
1268 }
1269 switch (match_bits) {
1270 case 32:
1271 if (elf->elf_class != ELFCLASS32)
1272 goto label_done;
1273 break;
1274 case 64:
1275 if (elf->elf_class != ELFCLASS64)
1276 goto label_done;
1277 break;
1278 default: break;
1279 }
1280 if (strlen(match_etypes)) {
1281 char sbuf[126];
1282 strncpy(sbuf, match_etypes, sizeof(sbuf));
1283 if (strchr(match_etypes, ',') != NULL) {
1284 char *p;
1285 while ((p = strrchr(sbuf, ',')) != NULL) {
1286 *p = 0;
1287 if (etype_lookup(p+1) == get_etype(elf))
1288 goto label_ret;
1289 }
1290 }
1291 if (etype_lookup(sbuf) != get_etype(elf))
1292 goto label_done;
1293 }
1294
1295label_ret:
1296 ret = scanelf_elfobj(elf);
1297
1298label_done:
760 unreadelf(elf); 1299 unreadelf(elf);
1300 return ret;
1301}
1302
1303/* scan an archive of elfs */
1304static int scanelf_archive(const char *filename, int fd, size_t len)
1305{
1306 archive_handle *ar;
1307 archive_member *m;
1308 char *ar_buffer;
1309 elfobj *elf;
1310
1311 ar = ar_open_fd(filename, fd);
1312 if (ar == NULL)
1313 return 1;
1314
1315 ar_buffer = (char*)mmap(0, len, PROT_READ | (fix_elf ? PROT_WRITE : 0), (fix_elf ? MAP_SHARED : MAP_PRIVATE), fd, 0);
1316 while ((m=ar_next(ar)) != NULL) {
1317 elf = readelf_buffer(m->name, ar_buffer+lseek(fd,0,SEEK_CUR), m->size);
1318 if (elf) {
1319 scanelf_elfobj(elf);
1320 unreadelf(elf);
1321 }
1322 }
1323 munmap(ar_buffer, len);
1324
1325 return 0;
1326}
1327/* scan a file which may be an elf or an archive or some other magical beast */
1328static int scanelf_file(const char *filename, const struct stat *st_cache)
1329{
1330 const struct stat *st = st_cache;
1331 struct stat symlink_st;
1332 int fd;
1333
1334 /* always handle regular files and handle symlinked files if no -y */
1335 if (S_ISLNK(st->st_mode)) {
1336 if (!scan_symlink) return 1;
1337 stat(filename, &symlink_st);
1338 st = &symlink_st;
1339 }
1340
1341 if (!S_ISREG(st->st_mode)) {
1342 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
1343 return 1;
1344 }
1345
1346 if (match_perms) {
1347 if ((st->st_mode | match_perms) != st->st_mode)
1348 return 1;
1349 }
1350 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1)
1351 return 1;
1352
1353 if (scanelf_elf(filename, fd, st->st_size) == 1 && scan_archives)
1354 /* if it isn't an ELF, maybe it's an .a archive */
1355 scanelf_archive(filename, fd, st->st_size);
1356
1357 close(fd);
1358 return 0;
761} 1359}
762 1360
763/* scan a directory for ET_EXEC files and print when we find one */ 1361/* scan a directory for ET_EXEC files and print when we find one */
764static void scanelf_dir(const char *path) 1362static int scanelf_dir(const char *path)
765{ 1363{
766 register DIR *dir; 1364 register DIR *dir;
767 register struct dirent *dentry; 1365 register struct dirent *dentry;
768 struct stat st_top, st; 1366 struct stat st_top, st;
769 char buf[_POSIX_PATH_MAX]; 1367 char buf[__PAX_UTILS_PATH_MAX];
770 size_t pathlen = 0, len = 0; 1368 size_t pathlen = 0, len = 0;
1369 int ret = 0;
771 1370
772 /* make sure path exists */ 1371 /* make sure path exists */
773 if (lstat(path, &st_top) == -1) { 1372 if (lstat(path, &st_top) == -1) {
774 if (be_verbose > 2) printf("%s: does not exist\n", path); 1373 if (be_verbose > 2) printf("%s: does not exist\n", path);
775 return; 1374 return 1;
776 } 1375 }
777 1376
778 /* ok, if it isn't a directory, assume we can open it */ 1377 /* ok, if it isn't a directory, assume we can open it */
779 if (!S_ISDIR(st_top.st_mode)) { 1378 if (!S_ISDIR(st_top.st_mode)) {
780 scanelf_file(path); 1379 return scanelf_file(path, &st_top);
781 return;
782 } 1380 }
783 1381
784 /* now scan the dir looking for fun stuff */ 1382 /* now scan the dir looking for fun stuff */
785 if ((dir = opendir(path)) == NULL) { 1383 if ((dir = opendir(path)) == NULL) {
786 warnf("could not opendir %s: %s", path, strerror(errno)); 1384 warnf("could not opendir %s: %s", path, strerror(errno));
787 return; 1385 return 1;
788 } 1386 }
789 if (be_verbose) printf("%s: scanning dir\n", path); 1387 if (be_verbose > 1) printf("%s: scanning dir\n", path);
790 1388
791 pathlen = strlen(path); 1389 pathlen = strlen(path);
792 while ((dentry = readdir(dir))) { 1390 while ((dentry = readdir(dir))) {
793 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 1391 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
794 continue; 1392 continue;
796 if (len >= sizeof(buf)) { 1394 if (len >= sizeof(buf)) {
797 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path, 1395 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
798 (unsigned long)len, (unsigned long)sizeof(buf)); 1396 (unsigned long)len, (unsigned long)sizeof(buf));
799 continue; 1397 continue;
800 } 1398 }
801 sprintf(buf, "%s/%s", path, dentry->d_name); 1399 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name);
802 if (lstat(buf, &st) != -1) { 1400 if (lstat(buf, &st) != -1) {
803 if (S_ISREG(st.st_mode)) 1401 if (S_ISREG(st.st_mode))
804 scanelf_file(buf); 1402 ret = scanelf_file(buf, &st);
805 else if (dir_recurse && S_ISDIR(st.st_mode)) { 1403 else if (dir_recurse && S_ISDIR(st.st_mode)) {
806 if (dir_crossmount || (st_top.st_dev == st.st_dev)) 1404 if (dir_crossmount || (st_top.st_dev == st.st_dev))
807 scanelf_dir(buf); 1405 ret = scanelf_dir(buf);
808 } 1406 }
809 } 1407 }
810 } 1408 }
811 closedir(dir); 1409 closedir(dir);
1410 return ret;
812} 1411}
813 1412
814static int scanelf_from_file(char *filename) 1413static int scanelf_from_file(const char *filename)
815{ 1414{
816 FILE *fp = NULL; 1415 FILE *fp = NULL;
817 char *p; 1416 char *p;
818 char path[_POSIX_PATH_MAX]; 1417 char path[__PAX_UTILS_PATH_MAX];
1418 int ret = 0;
819 1419
820 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL)) 1420 if (strcmp(filename, "-") == 0)
821 fp = stdin; 1421 fp = stdin;
822 else if ((fp = fopen(filename, "r")) == NULL) 1422 else if ((fp = fopen(filename, "r")) == NULL)
823 return 1; 1423 return 1;
824 1424
825 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) { 1425 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
826 if ((p = strchr(path, '\n')) != NULL) 1426 if ((p = strchr(path, '\n')) != NULL)
827 *p = 0; 1427 *p = 0;
828 search_path = path; 1428 search_path = path;
829 scanelf_dir(path); 1429 ret = scanelf_dir(path);
830 } 1430 }
831 if (fp != stdin) 1431 if (fp != stdin)
832 fclose(fp); 1432 fclose(fp);
833 return 0; 1433 return ret;
834} 1434}
835 1435
836static void load_ld_so_conf() 1436#if defined(__GLIBC__) || defined(__UCLIBC__) || defined(__NetBSD__)
1437
1438static int load_ld_cache_config(int i, const char *fname)
837{ 1439{
838 FILE *fp = NULL; 1440 FILE *fp = NULL;
839 char *p; 1441 char *p;
840 char path[_POSIX_PATH_MAX]; 1442 char path[__PAX_UTILS_PATH_MAX];
841 int i = 0;
842 1443
843 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 1444 if (i + 1 == ARRAY_SIZE(ldpaths))
844 return; 1445 return i;
845 1446
1447 if ((fp = fopen(fname, "r")) == NULL)
1448 return i;
1449
846 while ((fgets(path, _POSIX_PATH_MAX, fp)) != NULL) { 1450 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
847 if (*path != '/')
848 continue;
849
850 if ((p = strrchr(path, '\r')) != NULL) 1451 if ((p = strrchr(path, '\r')) != NULL)
851 *p = 0; 1452 *p = 0;
852 if ((p = strchr(path, '\n')) != NULL) 1453 if ((p = strchr(path, '\n')) != NULL)
853 *p = 0; 1454 *p = 0;
1455#ifdef __linux__
1456 /* recursive includes of the same file will make this segfault. */
1457 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) {
1458 glob64_t gl;
1459 size_t x;
1460 char gpath[__PAX_UTILS_PATH_MAX];
1461
1462 memset(gpath, 0, sizeof(gpath));
1463
1464 if (path[8] != '/')
1465 snprintf(gpath, sizeof(gpath), "/etc/%s", &path[8]);
1466 else
1467 strncpy(gpath, &path[8], sizeof(gpath));
1468
1469 if ((glob64(gpath, 0, NULL, &gl)) == 0) {
1470 for (x = 0; x < gl.gl_pathc; ++x) {
1471 /* try to avoid direct loops */
1472 if (strcmp(gl.gl_pathv[x], fname) == 0)
1473 continue;
1474 i = load_ld_cache_config(i, gl.gl_pathv[x]);
1475 if (i + 1 >= ARRAY_SIZE(ldpaths)) {
1476 globfree64(&gl);
1477 return i;
1478 }
1479 }
1480 globfree64 (&gl);
1481 continue;
1482 }
1483 }
1484#endif
1485 if (*path != '/')
1486 continue;
854 1487
855 ldpaths[i++] = xstrdup(path); 1488 ldpaths[i++] = xstrdup(path);
856 1489
857 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths)) 1490 if (i + 1 == ARRAY_SIZE(ldpaths))
858 break; 1491 break;
859 } 1492 }
860 ldpaths[i] = NULL; 1493 ldpaths[i] = NULL;
861 1494
862 fclose(fp); 1495 fclose(fp);
1496 return i;
863} 1497}
1498
1499#elif defined(__FreeBSD__) || (__DragonFly__)
1500
1501static int load_ld_cache_config(int i, const char *fname)
1502{
1503 FILE *fp = NULL;
1504 char *b = NULL, *p;
1505 struct elfhints_hdr hdr;
1506
1507 if (i + 1 == ARRAY_SIZE(ldpaths))
1508 return i;
1509
1510 if ((fp = fopen(fname, "r")) == NULL)
1511 return i;
1512
1513 if (fread(&hdr, 1, sizeof(hdr), fp) != sizeof(hdr) ||
1514 hdr.magic != ELFHINTS_MAGIC || hdr.version != 1 ||
1515 fseek(fp, hdr.strtab + hdr.dirlist, SEEK_SET) == -1)
1516 {
1517 fclose(fp);
1518 return i;
1519 }
1520
1521 b = xmalloc(hdr.dirlistlen + 1);
1522 if (fread(b, 1, hdr.dirlistlen+1, fp) != hdr.dirlistlen+1) {
1523 fclose(fp);
1524 free(b);
1525 return i;
1526 }
1527
1528 while ((p = strsep(&b, ":"))) {
1529 if (*p == '\0') continue;
1530 ldpaths[i++] = xstrdup(p);
1531
1532 if (i + 1 == ARRAY_SIZE(ldpaths))
1533 break;
1534 }
1535 ldpaths[i] = NULL;
1536
1537 free(b);
1538 fclose(fp);
1539 return i;
1540}
1541
1542#else
1543
1544#warning Cache config support not implemented for your target
1545static int load_ld_cache_config(int i, const char *fname)
1546{
1547 memset(ldpaths, 0x00, sizeof(ldpaths));
1548}
1549
1550#endif
864 1551
865/* scan /etc/ld.so.conf for paths */ 1552/* scan /etc/ld.so.conf for paths */
866static void scanelf_ldpath() 1553static void scanelf_ldpath(void)
867{ 1554{
868 char scan_l, scan_ul, scan_ull; 1555 char scan_l, scan_ul, scan_ull;
869 int i = 0; 1556 int i = 0;
870 1557
871 if (!ldpaths[0]) 1558 if (!ldpaths[0])
885 if (!scan_ul) scanelf_dir("/usr/lib"); 1572 if (!scan_ul) scanelf_dir("/usr/lib");
886 if (!scan_ull) scanelf_dir("/usr/local/lib"); 1573 if (!scan_ull) scanelf_dir("/usr/local/lib");
887} 1574}
888 1575
889/* scan env PATH for paths */ 1576/* scan env PATH for paths */
890static void scanelf_envpath() 1577static void scanelf_envpath(void)
891{ 1578{
892 char *path, *p; 1579 char *path, *p;
893 1580
894 path = getenv("PATH"); 1581 path = getenv("PATH");
895 if (!path) 1582 if (!path)
903 1590
904 free(path); 1591 free(path);
905} 1592}
906 1593
907 1594
908 1595/* usage / invocation handling functions */ /* Free Flags: c d j u w C G H I J K P Q U W Y Z */
909/* usage / invocation handling functions */
910#define PARSE_FLAGS "plRmyxetrnibs:N:TaqvF:f:o:BhV" 1596#define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:DO:BhV"
911#define a_argument required_argument 1597#define a_argument required_argument
912static struct option const long_opts[] = { 1598static struct option const long_opts[] = {
913 {"path", no_argument, NULL, 'p'}, 1599 {"path", no_argument, NULL, 'p'},
914 {"ldpath", no_argument, NULL, 'l'}, 1600 {"ldpath", no_argument, NULL, 'l'},
915 {"recursive", no_argument, NULL, 'R'}, 1601 {"recursive", no_argument, NULL, 'R'},
916 {"mount", no_argument, NULL, 'm'}, 1602 {"mount", no_argument, NULL, 'm'},
917 {"symlink", no_argument, NULL, 'y'}, 1603 {"symlink", no_argument, NULL, 'y'},
1604 {"archives", no_argument, NULL, 'A'},
1605 {"ldcache", no_argument, NULL, 'L'},
1606 {"fix", no_argument, NULL, 'X'},
1607 {"setpax", a_argument, NULL, 'z'},
918 {"pax", no_argument, NULL, 'x'}, 1608 {"pax", no_argument, NULL, 'x'},
919 {"header", no_argument, NULL, 'e'}, 1609 {"header", no_argument, NULL, 'e'},
920 {"textrel", no_argument, NULL, 't'}, 1610 {"textrel", no_argument, NULL, 't'},
921 {"rpath", no_argument, NULL, 'r'}, 1611 {"rpath", no_argument, NULL, 'r'},
922 {"needed", no_argument, NULL, 'n'}, 1612 {"needed", no_argument, NULL, 'n'},
923 {"interp", no_argument, NULL, 'i'}, 1613 {"interp", no_argument, NULL, 'i'},
924 {"bind", no_argument, NULL, 'b'}, 1614 {"bind", no_argument, NULL, 'b'},
1615 {"soname", no_argument, NULL, 'S'},
925 {"symbol", a_argument, NULL, 's'}, 1616 {"symbol", a_argument, NULL, 's'},
1617 {"section", a_argument, NULL, 'k'},
926 {"lib", a_argument, NULL, 'N'}, 1618 {"lib", a_argument, NULL, 'N'},
1619 {"gmatch", no_argument, NULL, 'g'},
927 {"textrels", no_argument, NULL, 'T'}, 1620 {"textrels", no_argument, NULL, 'T'},
1621 {"etype", a_argument, NULL, 'E'},
1622 {"bits", a_argument, NULL, 'M'},
1623 {"endian", no_argument, NULL, 'D'},
1624 {"perms", a_argument, NULL, 'O'},
928 {"all", no_argument, NULL, 'a'}, 1625 {"all", no_argument, NULL, 'a'},
929 {"quiet", no_argument, NULL, 'q'}, 1626 {"quiet", no_argument, NULL, 'q'},
930 {"verbose", no_argument, NULL, 'v'}, 1627 {"verbose", no_argument, NULL, 'v'},
931 {"format", a_argument, NULL, 'F'}, 1628 {"format", a_argument, NULL, 'F'},
932 {"from", a_argument, NULL, 'f'}, 1629 {"from", a_argument, NULL, 'f'},
940static const char *opts_help[] = { 1637static const char *opts_help[] = {
941 "Scan all directories in PATH environment", 1638 "Scan all directories in PATH environment",
942 "Scan all directories in /etc/ld.so.conf", 1639 "Scan all directories in /etc/ld.so.conf",
943 "Scan directories recursively", 1640 "Scan directories recursively",
944 "Don't recursively cross mount points", 1641 "Don't recursively cross mount points",
945 "Don't scan symlinks\n", 1642 "Don't scan symlinks",
1643 "Scan archives (.a files)",
1644 "Utilize ld.so.cache information (use with -r/-n)",
1645 "Try and 'fix' bad things (use with -r/-e)",
1646 "Sets EI_PAX/PT_PAX_FLAGS to <arg> (use with -Xx)\n",
946 "Print PaX markings", 1647 "Print PaX markings",
947 "Print GNU_STACK/PT_LOAD markings", 1648 "Print GNU_STACK/PT_LOAD markings",
948 "Print TEXTREL information", 1649 "Print TEXTREL information",
949 "Print RPATH information", 1650 "Print RPATH information",
950 "Print NEEDED information", 1651 "Print NEEDED information",
951 "Print INTERP information", 1652 "Print INTERP information",
952 "Print BIND information", 1653 "Print BIND information",
1654 "Print SONAME information",
953 "Find a specified symbol", 1655 "Find a specified symbol",
1656 "Find a specified section",
954 "Find a specified library", 1657 "Find a specified library",
1658 "Use strncmp to match libraries. (use with -N)",
955 "Locate cause of TEXTREL", 1659 "Locate cause of TEXTREL",
1660 "Print only ELF files matching etype ET_DYN,ET_EXEC ...",
1661 "Print only ELF files matching numeric bits",
1662 "Print Endianness",
1663 "Print only ELF files matching octal permissions",
956 "Print all scanned info (-x -e -t -r -n -i -b)\n", 1664 "Print all scanned info (-x -e -t -r -b)\n",
957 "Only output 'bad' things", 1665 "Only output 'bad' things",
958 "Be verbose (can be specified more than once)", 1666 "Be verbose (can be specified more than once)",
959 "Use specified format for output", 1667 "Use specified format for output",
960 "Read input stream from a filename", 1668 "Read input stream from a filename",
961 "Write output stream to a filename", 1669 "Write output stream to a filename",
968/* display usage and exit */ 1676/* display usage and exit */
969static void usage(int status) 1677static void usage(int status)
970{ 1678{
971 unsigned long i; 1679 unsigned long i;
972 printf("* Scan ELF binaries for stuff\n\n" 1680 printf("* Scan ELF binaries for stuff\n\n"
973 "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); 1681 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
974 printf("Options: -[%s]\n", PARSE_FLAGS); 1682 printf("Options: -[%s]\n", PARSE_FLAGS);
975 for (i = 0; long_opts[i].name; ++i) 1683 for (i = 0; long_opts[i].name; ++i)
976 if (long_opts[i].has_arg == no_argument) 1684 if (long_opts[i].has_arg == no_argument)
977 printf(" -%c, --%-13s* %s\n", long_opts[i].val, 1685 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
978 long_opts[i].name, opts_help[i]); 1686 long_opts[i].name, opts_help[i]);
979 else 1687 else
980 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val, 1688 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
981 long_opts[i].name, opts_help[i]); 1689 long_opts[i].name, opts_help[i]);
982 1690
983 if (status != EXIT_SUCCESS) 1691 puts("\nFor more information, see the scanelf(1) manpage");
984 exit(status);
985
986 puts("\nThe format modifiers for the -F option are:");
987 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
988 puts(" t TEXTREL \tr RPATH \tn NEEDED");
989 puts(" i INTERP \tb BIND \ts symbol");
990 puts(" N library \to Type \tT TEXTRELs");
991 puts(" p filename (with search path removed)");
992 puts(" f base filename");
993 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
994
995 exit(status); 1692 exit(status);
996} 1693}
997 1694
998/* parse command line arguments and preform needed actions */ 1695/* parse command line arguments and preform needed actions */
1696#define do_pax_state(option, flag) \
1697 if (islower(option)) { \
1698 flags &= ~PF_##flag; \
1699 flags |= PF_NO##flag; \
1700 } else { \
1701 flags &= ~PF_NO##flag; \
1702 flags |= PF_##flag; \
1703 }
999static void parseargs(int argc, char *argv[]) 1704static int parseargs(int argc, char *argv[])
1000{ 1705{
1001 int i; 1706 int i;
1002 char *from_file = NULL; 1707 const char *from_file = NULL;
1708 int ret = 0;
1003 1709
1004 opterr = 0; 1710 opterr = 0;
1005 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 1711 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
1006 switch (i) { 1712 switch (i) {
1007 1713
1008 case 'V': 1714 case 'V':
1009 printf("%s compiled %s\n%s\n" 1715 printf("pax-utils-%s: %s compiled %s\n%s\n"
1010 "%s written for Gentoo Linux by <solar and vapier @ gentoo.org>\n", 1716 "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
1011 __FILE__, __DATE__, rcsid, argv0); 1717 VERSION, __FILE__, __DATE__, rcsid, argv0);
1012 exit(EXIT_SUCCESS); 1718 exit(EXIT_SUCCESS);
1013 break; 1719 break;
1014 case 'h': usage(EXIT_SUCCESS); break; 1720 case 'h': usage(EXIT_SUCCESS); break;
1015 case 'f': 1721 case 'f':
1016 if (from_file) err("Don't specify -f twice"); 1722 if (from_file) warn("You prob don't want to specify -f twice");
1017 from_file = xstrdup(optarg); 1723 from_file = optarg;
1724 break;
1725 case 'E':
1726 strncpy(match_etypes, optarg, sizeof(match_etypes));
1727 break;
1728 case 'M':
1729 match_bits = atoi(optarg);
1730 if (match_bits == 0) {
1731 if (strcmp(optarg, "ELFCLASS32") == 0)
1732 match_bits = 32;
1733 if (strcmp(optarg, "ELFCLASS64") == 0)
1734 match_bits = 64;
1735 }
1736 break;
1737 case 'O':
1738 if (sscanf(optarg, "%o", &match_perms) == (-1))
1739 match_bits = 0;
1018 break; 1740 break;
1019 case 'o': { 1741 case 'o': {
1020 FILE *fp = NULL;
1021 if ((fp = freopen(optarg, "w", stdout)) == NULL) 1742 if (freopen(optarg, "w", stdout) == NULL)
1022 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1743 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1023 SET_STDOUT(fp);
1024 break; 1744 break;
1025 } 1745 }
1026 1746 case 'k':
1747 if (find_section) warn("You prob don't want to specify -k twice");
1748 find_section = optarg;
1749 break;
1027 case 's': { 1750 case 's': {
1028 size_t len;
1029 if (find_sym) err("Don't specify -s twice"); 1751 if (find_sym) warn("You prob don't want to specify -s twice");
1030 find_sym = xstrdup(optarg); 1752 find_sym = optarg;
1031 len = strlen(find_sym) + 1;
1032 versioned_symname = (char*)xmalloc(sizeof(char) * (len+1)); 1753 versioned_symname = xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1033 sprintf(versioned_symname, "%s@", find_sym); 1754 sprintf(versioned_symname, "%s@", find_sym);
1034 break; 1755 break;
1035 } 1756 }
1036 case 'N': { 1757 case 'N': {
1037 if (find_lib) err("Don't specify -N twice"); 1758 if (find_lib) warn("You prob don't want to specify -N twice");
1038 find_lib = xstrdup(optarg); 1759 find_lib = optarg;
1039 break; 1760 break;
1040 } 1761 }
1041 1762
1042 case 'F': { 1763 case 'F': {
1043 if (out_format) err("Don't specify -F twice"); 1764 if (out_format) warn("You prob don't want to specify -F twice");
1044 out_format = xstrdup(optarg); 1765 out_format = optarg;
1766 break;
1767 }
1768 case 'z': {
1769 unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC);
1770 size_t x;
1771
1772 for (x = 0; x < strlen(optarg); x++) {
1773 switch (optarg[x]) {
1774 case 'p':
1775 case 'P':
1776 do_pax_state(optarg[x], PAGEEXEC);
1045 break; 1777 break;
1778 case 's':
1779 case 'S':
1780 do_pax_state(optarg[x], SEGMEXEC);
1781 break;
1782 case 'm':
1783 case 'M':
1784 do_pax_state(optarg[x], MPROTECT);
1785 break;
1786 case 'e':
1787 case 'E':
1788 do_pax_state(optarg[x], EMUTRAMP);
1789 break;
1790 case 'r':
1791 case 'R':
1792 do_pax_state(optarg[x], RANDMMAP);
1793 break;
1794 case 'x':
1795 case 'X':
1796 do_pax_state(optarg[x], RANDEXEC);
1797 break;
1798 default:
1799 break;
1800 }
1046 } 1801 }
1047 1802 if (!(((flags & PF_PAGEEXEC) && (flags & PF_NOPAGEEXEC)) ||
1803 ((flags & PF_SEGMEXEC) && (flags & PF_NOSEGMEXEC)) ||
1804 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP)) ||
1805 ((flags & PF_RANDEXEC) && (flags & PF_NORANDEXEC)) ||
1806 ((flags & PF_EMUTRAMP) && (flags & PF_NOEMUTRAMP)) ||
1807 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP))))
1808 setpax = flags;
1809 break;
1810 }
1811 case 'g': g_match = 1; break;
1812 case 'L': use_ldcache = 1; break;
1048 case 'y': scan_symlink = 0; break; 1813 case 'y': scan_symlink = 0; break;
1814 case 'A': scan_archives = 1; break;
1049 case 'B': show_banner = 0; break; 1815 case 'B': show_banner = 0; break;
1050 case 'l': scan_ldpath = 1; break; 1816 case 'l': scan_ldpath = 1; break;
1051 case 'p': scan_envpath = 1; break; 1817 case 'p': scan_envpath = 1; break;
1052 case 'R': dir_recurse = 1; break; 1818 case 'R': dir_recurse = 1; break;
1053 case 'm': dir_crossmount = 0; break; 1819 case 'm': dir_crossmount = 0; break;
1820 case 'X': ++fix_elf; break;
1054 case 'x': show_pax = 1; break; 1821 case 'x': show_pax = 1; break;
1055 case 'e': show_phdr = 1; break; 1822 case 'e': show_phdr = 1; break;
1056 case 't': show_textrel = 1; break; 1823 case 't': show_textrel = 1; break;
1057 case 'r': show_rpath = 1; break; 1824 case 'r': show_rpath = 1; break;
1058 case 'n': show_needed = 1; break; 1825 case 'n': show_needed = 1; break;
1059 case 'i': show_interp = 1; break; 1826 case 'i': show_interp = 1; break;
1060 case 'b': show_bind = 1; break; 1827 case 'b': show_bind = 1; break;
1828 case 'S': show_soname = 1; break;
1061 case 'T': show_textrels = 1; break; 1829 case 'T': show_textrels = 1; break;
1062 case 'q': be_quiet = 1; break; 1830 case 'q': be_quiet = 1; break;
1063 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1831 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1064 case 'a': show_pax = show_phdr = show_textrel = show_rpath = \ 1832 case 'a': show_perms = show_pax = show_phdr = show_textrel = show_rpath = show_bind = show_endian = 1; break;
1065 show_needed = show_interp = show_bind = 1; break; 1833 case 'D': show_endian = 1; break;
1066
1067 case ':': 1834 case ':':
1068 err("Option missing parameter\n"); 1835 err("Option '%c' is missing parameter", optopt);
1069 case '?': 1836 case '?':
1070 err("Unknown option\n"); 1837 err("Unknown option '%c' or argument missing", optopt);
1071 default: 1838 default:
1072 err("Unhandled option '%c'", i); 1839 err("Unhandled option '%c'; please report this", i);
1073 }
1074 } 1840 }
1075 1841 }
1842 if (show_textrels && be_verbose) {
1843 if (which("objdump") != NULL)
1844 has_objdump = 1;
1845 }
1076 /* let the format option override all other options */ 1846 /* let the format option override all other options */
1077 if (out_format) { 1847 if (out_format) {
1078 show_pax = show_phdr = show_textrel = show_rpath = \ 1848 show_pax = show_phdr = show_textrel = show_rpath = \
1079 show_needed = show_interp = show_bind = show_textrels = 0; 1849 show_needed = show_interp = show_bind = show_soname = \
1850 show_textrels = show_perms = show_endian = 0;
1080 for (i = 0; out_format[i]; ++i) { 1851 for (i = 0; out_format[i]; ++i) {
1081 if (!IS_MODIFIER(out_format[i])) continue; 1852 if (!IS_MODIFIER(out_format[i])) continue;
1082 1853
1083 switch (out_format[++i]) { 1854 switch (out_format[++i]) {
1855 case '+': break;
1084 case '%': break; 1856 case '%': break;
1085 case '#': break; 1857 case '#': break;
1086 case 'F': break; 1858 case 'F': break;
1087 case 'p': break; 1859 case 'p': break;
1088 case 'f': break; 1860 case 'f': break;
1861 case 'k': break;
1089 case 's': break; 1862 case 's': break;
1090 case 'N': break; 1863 case 'N': break;
1091 case 'o': break; 1864 case 'o': break;
1865 case 'a': break;
1866 case 'M': break;
1867 case 'D': show_endian = 1; break;
1868 case 'O': show_perms = 1; break;
1092 case 'x': show_pax = 1; break; 1869 case 'x': show_pax = 1; break;
1093 case 'e': show_phdr = 1; break; 1870 case 'e': show_phdr = 1; break;
1094 case 't': show_textrel = 1; break; 1871 case 't': show_textrel = 1; break;
1095 case 'r': show_rpath = 1; break; 1872 case 'r': show_rpath = 1; break;
1096 case 'n': show_needed = 1; break; 1873 case 'n': show_needed = 1; break;
1097 case 'i': show_interp = 1; break; 1874 case 'i': show_interp = 1; break;
1098 case 'b': show_bind = 1; break; 1875 case 'b': show_bind = 1; break;
1876 case 'S': show_soname = 1; break;
1099 case 'T': show_textrels = 1; break; 1877 case 'T': show_textrels = 1; break;
1100 default: 1878 default:
1101 err("Invalid format specifier '%c' (byte %i)", 1879 err("Invalid format specifier '%c' (byte %i)",
1102 out_format[i], i+1); 1880 out_format[i], i+1);
1103 } 1881 }
1104 } 1882 }
1105 1883
1106 /* construct our default format */ 1884 /* construct our default format */
1107 } else { 1885 } else {
1108 size_t fmt_len = 30; 1886 size_t fmt_len = 30;
1109 out_format = (char*)xmalloc(sizeof(char) * fmt_len); 1887 out_format = xmalloc(sizeof(char) * fmt_len);
1110 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len); 1888 if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len);
1111 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len); 1889 if (show_pax) xstrcat(&out_format, "%x ", &fmt_len);
1890 if (show_perms) xstrcat(&out_format, "%O ", &fmt_len);
1891 if (show_endian) xstrcat(&out_format, "%D ", &fmt_len);
1112 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len); 1892 if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len);
1113 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); 1893 if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len);
1114 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); 1894 if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len);
1115 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); 1895 if (show_needed) xstrcat(&out_format, "%n ", &fmt_len);
1116 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 1896 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1117 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len); 1897 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1898 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1118 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len); 1899 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1119 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len); 1900 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1901 if (find_section) xstrcat(&out_format, "%k ", &fmt_len);
1120 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len); 1902 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1121 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 1903 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1122 } 1904 }
1123 if (be_verbose > 2) printf("Format: %s\n", out_format); 1905 if (be_verbose > 2) printf("Format: %s\n", out_format);
1124 1906
1125 /* now lets actually do the scanning */ 1907 /* now lets actually do the scanning */
1126 if (scan_ldpath || (show_rpath && be_quiet)) 1908 if (scan_ldpath || use_ldcache)
1127 load_ld_so_conf(); 1909 load_ld_cache_config(0, __PAX_UTILS_DEFAULT_LD_CACHE_CONFIG);
1128 if (scan_ldpath) scanelf_ldpath(); 1910 if (scan_ldpath) scanelf_ldpath();
1129 if (scan_envpath) scanelf_envpath(); 1911 if (scan_envpath) scanelf_envpath();
1912 if (!from_file && optind == argc && ttyname(0) == NULL && !scan_ldpath && !scan_envpath)
1913 from_file = "-";
1130 if (from_file) { 1914 if (from_file) {
1131 scanelf_from_file(from_file); 1915 scanelf_from_file(from_file);
1132 free(from_file);
1133 from_file = *argv; 1916 from_file = *argv;
1134 } 1917 }
1135 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file) 1918 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1136 err("Nothing to scan !?"); 1919 err("Nothing to scan !?");
1137 while (optind < argc) { 1920 while (optind < argc) {
1138 search_path = argv[optind++]; 1921 search_path = argv[optind++];
1139 scanelf_dir(search_path); 1922 ret = scanelf_dir(search_path);
1140 } 1923 }
1141 1924
1142 /* clean up */ 1925 /* clean up */
1143 if (find_sym) {
1144 free(find_sym);
1145 free(versioned_symname); 1926 free(versioned_symname);
1146 }
1147 if (find_lib) free(find_lib);
1148 if (out_format) free(out_format);
1149 for (i = 0; ldpaths[i]; ++i) 1927 for (i = 0; ldpaths[i]; ++i)
1150 free(ldpaths[i]); 1928 free(ldpaths[i]);
1151}
1152 1929
1153 1930 if (ldcache != 0)
1154 1931 munmap(ldcache, ldcache_size);
1155/* utility funcs */
1156static char *xstrdup(const char *s)
1157{
1158 char *ret = strdup(s);
1159 if (!ret) err("Could not strdup(): %s", strerror(errno));
1160 return ret; 1932 return ret;
1161} 1933}
1162 1934
1163static void *xmalloc(size_t size) 1935static char **get_split_env(const char *envvar)
1164{ 1936{
1165 void *ret = malloc(size); 1937 const char *delims = " \t\n";
1166 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size); 1938 char **envvals = NULL;
1167 return ret; 1939 char *env, *s;
1168} 1940 int nentry;
1169 1941
1170static void xstrcat(char **dst, const char *src, size_t *curr_len) 1942 if ((env = getenv(envvar)) == NULL)
1171{ 1943 return NULL;
1172 size_t new_len;
1173 1944
1174 new_len = strlen(*dst) + strlen(src); 1945 env = xstrdup(env);
1175 if (*curr_len <= new_len) { 1946 if (env == NULL)
1176 *curr_len = new_len + (*curr_len / 2); 1947 return NULL;
1177 *dst = realloc(*dst, *curr_len);
1178 if (!*dst)
1179 err("could not realloc %li bytes", (unsigned long)*curr_len);
1180 }
1181 1948
1182 strcat(*dst, src); 1949 s = strtok(env, delims);
1183} 1950 if (s == NULL) {
1951 free(env);
1952 return NULL;
1953 }
1184 1954
1185static inline void xchrcat(char **dst, const char append, size_t *curr_len) 1955 nentry = 0;
1186{ 1956 while (s != NULL) {
1187 static char my_app[2]; 1957 ++nentry;
1188 my_app[0] = append; 1958 envvals = xrealloc(envvals, sizeof(*envvals) * (nentry+1));
1189 my_app[1] = '\0'; 1959 envvals[nentry-1] = s;
1190 xstrcat(dst, my_app, curr_len); 1960 s = strtok(NULL, delims);
1191} 1961 }
1962 envvals[nentry] = NULL;
1192 1963
1964 /* don't want to free(env) as it contains the memory that backs
1965 * the envvals array of strings */
1966 return envvals;
1967}
1968
1969static void parseenv(void)
1970{
1971 qa_textrels = get_split_env("QA_TEXTRELS");
1972 qa_execstack = get_split_env("QA_EXECSTACK");
1973 qa_wx_load = get_split_env("QA_WX_LOAD");
1974}
1975
1976#ifdef __PAX_UTILS_CLEANUP
1977static void cleanup(void)
1978{
1979 free(out_format);
1980 free(qa_textrels);
1981 free(qa_execstack);
1982 free(qa_wx_load);
1983}
1984#endif
1193 1985
1194 1986
1195int main(int argc, char *argv[]) 1987int main(int argc, char *argv[])
1196{ 1988{
1989 int ret;
1197 if (argc < 2) 1990 if (argc < 2)
1198 usage(EXIT_FAILURE); 1991 usage(EXIT_FAILURE);
1992 parseenv();
1199 parseargs(argc, argv); 1993 ret = parseargs(argc, argv);
1200 fclose(stdout); 1994 fclose(stdout);
1201#ifdef __BOUNDS_CHECKING_ON 1995#ifdef __PAX_UTILS_CLEANUP
1202 warn("The calls to add/delete heap should be off by 1 due to the out_buffer not being freed in scanelf_file()"); 1996 cleanup();
1997 warn("The calls to add/delete heap should be off:\n"
1998 "\t- 1 due to the out_buffer not being freed in scanelf_file()\n"
1999 "\t- 1 per QA_TEXTRELS/QA_EXECSTACK/QA_WX_LOAD");
1203#endif 2000#endif
1204 return EXIT_SUCCESS; 2001 return ret;
1205} 2002}
2003
2004
2005/* Match filename against entries in matchlist, return TRUE
2006 * if the file is listed */
2007static int file_matches_list(const char *filename, char **matchlist)
2008{
2009 char **file;
2010 char *match;
2011 char buf[__PAX_UTILS_PATH_MAX];
2012
2013 if (matchlist == NULL)
2014 return 0;
2015
2016 for (file = matchlist; *file != NULL; file++) {
2017 if (search_path) {
2018 snprintf(buf, sizeof(buf), "%s%s", search_path, *file);
2019 match = buf;
2020 } else {
2021 match = *file;
2022 }
2023 if (fnmatch(match, filename, 0) == 0)
2024 return 1;
2025 }
2026 return 0;
2027}

Legend:
Removed from v.1.78  
changed lines
  Added in v.1.188

  ViewVC Help
Powered by ViewVC 1.1.20