/[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.110 Revision 1.146
1/* 1/*
2 * Copyright 2003-2006 Gentoo Foundation 2 * Copyright 2003-2006 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.110 2006/01/20 00:21:03 vapier Exp $ 4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.146 2006/05/14 21:04:25 vapier Exp $
5 * 5 *
6 * Copyright 2003-2006 Ned Ludd - <solar@gentoo.org> 6 * Copyright 2003-2006 Ned Ludd - <solar@gentoo.org>
7 * Copyright 2004-2006 Mike Frysinger - <vapier@gentoo.org> 7 * Copyright 2004-2006 Mike Frysinger - <vapier@gentoo.org>
8 */ 8 */
9 9
10#include "paxinc.h" 10#include "paxinc.h"
11#if defined(__GLIBC__) || defined(__UCLIBC__)
12 #include <glob.h>
13#endif
14#if defined(__FreeBSD__) || defined(__DragonFly__)
15 #include <elf-hints.h>
16#endif
11 17
12static const char *rcsid = "$Id: scanelf.c,v 1.110 2006/01/20 00:21:03 vapier Exp $"; 18static const char *rcsid = "$Id: scanelf.c,v 1.146 2006/05/14 21:04:25 vapier Exp $";
13#define argv0 "scanelf" 19#define argv0 "scanelf"
14 20
15#define IS_MODIFIER(c) (c == '%' || c == '#') 21#define IS_MODIFIER(c) (c == '%' || c == '#' || c == '+')
16 22
23#define do_state(option, flag) \
24 if (islower(option)) { \
25 flags &= ~PF_##flag; \
26 flags |= PF_NO##flag; \
27 } else { \
28 flags &= ~PF_NO##flag; \
29 flags |= PF_##flag; \
30 }
17 31
18 32
19/* prototypes */ 33/* prototypes */
34static int file_matches_list(const char *filename, char **matchlist);
20static int scanelf_elfobj(elfobj *elf); 35static int scanelf_elfobj(elfobj *elf);
21static int scanelf_elf(const char *filename, int fd, size_t len); 36static int scanelf_elf(const char *filename, int fd, size_t len);
22static int scanelf_archive(const char *filename, int fd, size_t len); 37static int scanelf_archive(const char *filename, int fd, size_t len);
23static void scanelf_file(const char *filename); 38static void scanelf_file(const char *filename);
24static void scanelf_dir(const char *path); 39static void scanelf_dir(const char *path);
25static void scanelf_ldpath(void); 40static void scanelf_ldpath(void);
26static void scanelf_envpath(void); 41static void scanelf_envpath(void);
27static void usage(int status); 42static void usage(int status);
43static char **get_split_env(const char *envvar);
44static void parseenv(void);
28static void parseargs(int argc, char *argv[]); 45static void parseargs(int argc, char *argv[]);
29static char *xstrdup(const char *s); 46static char *xstrdup(const char *s);
30static void *xmalloc(size_t size); 47static void *xmalloc(size_t size);
48static void *xrealloc(void *ptr, size_t size);
31static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n); 49static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n);
32#define xstrcat(dst,src,curr_len) xstrncat(dst,src,curr_len,0) 50#define xstrcat(dst,src,curr_len) xstrncat(dst,src,curr_len,0)
33static inline void xchrcat(char **dst, const char append, size_t *curr_len); 51static inline void xchrcat(char **dst, const char append, size_t *curr_len);
34 52
35/* variables to control behavior */ 53/* variables to control behavior */
54static char match_etypes[126] = "";
36static char *ldpaths[256]; 55static char *ldpaths[256];
37static char scan_ldpath = 0; 56static char scan_ldpath = 0;
38static char scan_envpath = 0; 57static char scan_envpath = 0;
39static char scan_symlink = 1; 58static char scan_symlink = 1;
40static char scan_archives = 0; 59static char scan_archives = 0;
51static char show_textrels = 0; 70static char show_textrels = 0;
52static char show_banner = 1; 71static char show_banner = 1;
53static char be_quiet = 0; 72static char be_quiet = 0;
54static char be_verbose = 0; 73static char be_verbose = 0;
55static char be_wewy_wewy_quiet = 0; 74static char be_wewy_wewy_quiet = 0;
75static char be_semi_verbose = 0;
56static char *find_sym = NULL, *versioned_symname = NULL; 76static char *find_sym = NULL, *versioned_symname = NULL;
57static char *find_lib = NULL; 77static char *find_lib = NULL;
78static char *find_section = NULL;
58static char *out_format = NULL; 79static char *out_format = NULL;
59static char *search_path = NULL; 80static char *search_path = NULL;
60static char fix_elf = 0; 81static char fix_elf = 0;
61static char gmatch = 0; 82static char gmatch = 0;
62static char use_ldcache = 0; 83static char use_ldcache = 0;
63 84
85static char **qa_textrels = NULL;
86static char **qa_execstack = NULL;
87static char **qa_wx_load = NULL;
64 88
89int match_bits = 0;
65caddr_t ldcache = 0; 90caddr_t ldcache = 0;
66size_t ldcache_size = 0; 91size_t ldcache_size = 0;
92unsigned long setpax = 0UL;
93
94/* utility funcs */
95static char *xstrdup(const char *s)
96{
97 char *ret = strdup(s);
98 if (!ret) err("Could not strdup(): %s", strerror(errno));
99 return ret;
100}
101static void *xmalloc(size_t size)
102{
103 void *ret = malloc(size);
104 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
105 return ret;
106}
107static void *xrealloc(void *ptr, size_t size)
108{
109 void *ret = realloc(ptr, size);
110 if (!ret) err("Could not realloc() %li bytes", (unsigned long)size);
111 return ret;
112}
113static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
114{
115 size_t new_len;
116
117 new_len = strlen(*dst) + strlen(src);
118 if (*curr_len <= new_len) {
119 *curr_len = new_len + (*curr_len / 2);
120 *dst = realloc(*dst, *curr_len);
121 if (!*dst)
122 err("could not realloc() %li bytes", (unsigned long)*curr_len);
123 }
124
125 if (n)
126 strncat(*dst, src, n);
127 else
128 strcat(*dst, src);
129}
130static inline void xchrcat(char **dst, const char append, size_t *curr_len)
131{
132 static char my_app[2];
133 my_app[0] = append;
134 my_app[1] = '\0';
135 xstrcat(dst, my_app, curr_len);
136}
137
138/* Match filename against entries in matchlist, return TRUE
139 * if the file is listed */
140static int file_matches_list(const char *filename, char **matchlist) {
141 char **file;
142 char *match;
143 char buf[__PAX_UTILS_PATH_MAX];
144
145 if (matchlist == NULL)
146 return 0;
147
148 for (file = matchlist; *file != NULL; file++) {
149 if (search_path) {
150 snprintf(buf,__PAX_UTILS_PATH_MAX, "%s%s", search_path, *file);
151 match=buf;
152 } else {
153 match=*file;
154 }
155 if (fnmatch(match, filename, 0) == 0)
156 return 1; /* TRUE */
157 }
158 return 0; /* FALSE */
159}
67 160
68/* sub-funcs for scanelf_file() */ 161/* sub-funcs for scanelf_file() */
69static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab) 162static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
70{ 163{
71 /* find the best SHT_DYNSYM and SHT_STRTAB sections */ 164 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
90 } \ 183 } \
91 } 184 }
92 GET_SYMTABS(32) 185 GET_SYMTABS(32)
93 GET_SYMTABS(64) 186 GET_SYMTABS(64)
94} 187}
188
95static char *scanelf_file_pax(elfobj *elf, char *found_pax) 189static char *scanelf_file_pax(elfobj *elf, char *found_pax)
96{ 190{
97 static char ret[7]; 191 static char ret[7];
98 unsigned long i, shown; 192 unsigned long i, shown;
99 193
108 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 202 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
109 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 203 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
110 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 204 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
111 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \ 205 if (EGET(phdr[i].p_type) != PT_PAX_FLAGS) \
112 continue; \ 206 continue; \
113 if (be_quiet && (EGET(phdr[i].p_flags) == 10240)) \ 207 if (fix_elf && setpax) { \
208 /* set the paxctl flags */ \
209 ESET(phdr[i].p_flags, setpax); \
210 } \
211 if (be_quiet && (EGET(phdr[i].p_flags) == (PF_NOEMUTRAMP | PF_NORANDEXEC))) \
114 continue; \ 212 continue; \
115 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \ 213 memcpy(ret, pax_short_pf_flags(EGET(phdr[i].p_flags)), 6); \
116 *found_pax = 1; \ 214 *found_pax = 1; \
117 ++shown; \ 215 ++shown; \
118 break; \ 216 break; \
119 } \ 217 } \
120 } 218 }
121 SHOW_PAX(32) 219 SHOW_PAX(32)
122 SHOW_PAX(64) 220 SHOW_PAX(64)
221 }
222
223
224 if (fix_elf && setpax) {
225 /* set the chpax settings */
226 if (elf->elf_class == ELFCLASS32) {
227 if (EHDR32(elf->ehdr)->e_type == ET_DYN || EHDR32(elf->ehdr)->e_type == ET_EXEC)
228 ESET(EHDR32(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
229 } else {
230 if (EHDR64(elf->ehdr)->e_type == ET_DYN || EHDR64(elf->ehdr)->e_type == ET_EXEC)
231 ESET(EHDR64(elf->ehdr)->e_ident[EI_PAX], pax_pf2hf_flags(setpax));
232 }
123 } 233 }
124 234
125 /* fall back to EI_PAX if no PT_PAX was found */ 235 /* fall back to EI_PAX if no PT_PAX was found */
126 if (!*ret) { 236 if (!*ret) {
127 static char *paxflags; 237 static char *paxflags;
163 if (elf->phdr != NULL) { \ 273 if (elf->phdr != NULL) { \
164 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 274 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
165 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \ 275 for (i = 0; i < EGET(ehdr->e_phnum); ++i) { \
166 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \ 276 if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
167 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \ 277 if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
278 if (!file_matches_list(elf->filename, qa_execstack)) {\
168 found = found_phdr; \ 279 found = found_phdr; \
169 offset = 0; \ 280 offset = 0; \
170 check_flags = PF_X; \ 281 check_flags = PF_X; \
282 } else continue; \
171 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \ 283 } else if (EGET(phdr[i].p_type) == PT_GNU_RELRO) { \
172 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \ 284 if (multi_relro++) warnf("%s: multiple PT_GNU_RELRO's !?", elf->filename); \
173 found = found_relro; \ 285 found = found_relro; \
174 offset = 4; \ 286 offset = 4; \
175 check_flags = PF_X; \ 287 check_flags = PF_X; \
176 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \ 288 } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
289 if (ehdr->e_type == ET_DYN || ehdr->e_type == ET_EXEC) \
177 if (multi_load++ > max_pt_load) warnf("%s: more than %i PT_LOAD's !?", elf->filename, max_pt_load); \ 290 if (multi_load++ > max_pt_load) warnf("%s: more than %i PT_LOAD's !?", elf->filename, max_pt_load); \
291 if (!file_matches_list(elf->filename, qa_wx_load)) {\
178 found = found_load; \ 292 found = found_load; \
179 offset = 8; \ 293 offset = 8; \
180 check_flags = PF_W|PF_X; \ 294 check_flags = PF_W|PF_X; \
295 } else continue; \
181 } else \ 296 } else \
182 continue; \ 297 continue; \
183 flags = EGET(phdr[i].p_flags); \ 298 flags = EGET(phdr[i].p_flags); \
184 if (be_quiet && ((flags & check_flags) != check_flags)) \ 299 if (be_quiet && ((flags & check_flags) != check_flags)) \
185 continue; \ 300 continue; \
186 if (fix_elf && ((flags & PF_X) != flags)) { \ 301 if ((EGET(phdr[i].p_type) != PT_LOAD) && (fix_elf && ((flags & PF_X) != flags))) { \
187 ESET(phdr[i].p_flags, flags & (PF_X ^ (size_t)-1)); \ 302 ESET(phdr[i].p_flags, flags & (PF_X ^ (size_t)-1)); \
188 ret[3] = ret[7] = '!'; \ 303 ret[3] = ret[7] = '!'; \
189 flags = EGET(phdr[i].p_flags); \ 304 flags = EGET(phdr[i].p_flags); \
190 } \ 305 } \
191 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \ 306 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
195 } else if (elf->shdr != NULL) { \ 310 } else if (elf->shdr != NULL) { \
196 /* no program headers which means this is prob an object file */ \ 311 /* no program headers which means this is prob an object file */ \
197 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \ 312 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
198 Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \ 313 Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \
199 char *str; \ 314 char *str; \
200 if ((void*)strtbl > (void*)(elf->data + sizeof(*strtbl))) \ 315 if ((void*)strtbl > (void*)elf->data_end) \
201 goto skip_this_shdr##B; \ 316 goto skip_this_shdr##B; \
202 check_flags = SHF_WRITE|SHF_EXECINSTR; \ 317 check_flags = SHF_WRITE|SHF_EXECINSTR; \
203 for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \ 318 for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \
204 if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \ 319 if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \
205 offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \ 320 offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \
233 if (be_wewy_wewy_quiet || (be_quiet && !shown)) 348 if (be_wewy_wewy_quiet || (be_quiet && !shown))
234 return NULL; 349 return NULL;
235 else 350 else
236 return ret; 351 return ret;
237} 352}
353
238static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 354static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
239{ 355{
240 static const char *ret = "TEXTREL"; 356 static const char *ret = "TEXTREL";
241 unsigned long i; 357 unsigned long i;
242 358
243 if (!show_textrel && !show_textrels) return NULL; 359 if (!show_textrel && !show_textrels) return NULL;
360
361 if (file_matches_list(elf->filename, qa_textrels)) return NULL;
244 362
245 if (elf->phdr) { 363 if (elf->phdr) {
246#define SHOW_TEXTREL(B) \ 364#define SHOW_TEXTREL(B) \
247 if (elf->elf_class == ELFCLASS ## B) { \ 365 if (elf->elf_class == ELFCLASS ## B) { \
248 Elf ## B ## _Dyn *dyn; \ 366 Elf ## B ## _Dyn *dyn; \
331 if (be_verbose <= 2) continue; \ 449 if (be_verbose <= 2) continue; \
332 } else \ 450 } else \
333 *found_textrels = 1; \ 451 *found_textrels = 1; \
334 /* locate this relocation symbol name */ \ 452 /* locate this relocation symbol name */ \
335 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 453 sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
336 if ((void*)sym > (void*)elf->data) { \ 454 if ((void*)sym > (void*)elf->data_end) { \
337 warn("corrupt ELF symbol"); \ 455 warn("%s: corrupt ELF symbol", elf->filename); \
338 continue; \ 456 continue; \
339 } \ 457 } \
340 sym_max = ELF ## B ## _R_SYM(r_info); \ 458 sym_max = ELF ## B ## _R_SYM(r_info); \
341 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \ 459 if (sym_max * EGET(symtab->sh_entsize) < symtab->sh_size) \
342 sym += sym_max; \ 460 sym += sym_max; \
562#define FLAG_POWERPC_LIB64 0x0500 680#define FLAG_POWERPC_LIB64 0x0500
563#define FLAG_MIPS64_LIBN32 0x0600 681#define FLAG_MIPS64_LIBN32 0x0600
564#define FLAG_MIPS64_LIBN64 0x0700 682#define FLAG_MIPS64_LIBN64 0x0700
565 683
566static char *lookup_cache_lib(elfobj *, char *); 684static char *lookup_cache_lib(elfobj *, char *);
685#if defined(__GLIBC__) || defined(__UCLIBC__)
567static char *lookup_cache_lib(elfobj *elf, char *fname) 686static char *lookup_cache_lib(elfobj *elf, char *fname)
568{ 687{
569 int fd = 0; 688 int fd = 0;
570 char *strs; 689 char *strs;
571 static char buf[__PAX_UTILS_PATH_MAX] = ""; 690 static char buf[__PAX_UTILS_PATH_MAX] = "";
597 ldcache_size = st.st_size; 716 ldcache_size = st.st_size;
598 ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0); 717 ldcache = mmap(0, ldcache_size, PROT_READ, MAP_SHARED, fd, 0);
599 718
600 close(fd); 719 close(fd);
601 720
602 if (ldcache == (caddr_t)-1) 721 if (ldcache == (caddr_t)-1) {
722 ldcache = 0;
603 return NULL; 723 return NULL;
724 }
604 725
605 if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN)) 726 if (memcmp(((header_t *) ldcache)->magic, LDSO_CACHE_MAGIC, LDSO_CACHE_MAGIC_LEN))
606 return NULL; 727 return NULL;
607 if (memcmp (((header_t *) ldcache)->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN)) 728 if (memcmp (((header_t *) ldcache)->version, LDSO_CACHE_VER, LDSO_CACHE_VER_LEN))
608 return NULL; 729 return NULL;
625 continue; 746 continue;
626 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf)); 747 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
627 } 748 }
628 return buf; 749 return buf;
629} 750}
630 751#else
752#warning Cache support not implemented for your current target.
753static char *lookup_cache_lib(elfobj *elf, char *fname)
754{
755 return NULL;
756}
757#endif
631 758
632static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len) 759static const char *scanelf_file_needed_lib(elfobj *elf, char *found_needed, char *found_lib, int op, char **ret, size_t *ret_len)
633{ 760{
634 unsigned long i; 761 unsigned long i;
635 char *needed; 762 char *needed;
710} 837}
711static char *scanelf_file_bind(elfobj *elf, char *found_bind) 838static char *scanelf_file_bind(elfobj *elf, char *found_bind)
712{ 839{
713 unsigned long i; 840 unsigned long i;
714 struct stat s; 841 struct stat s;
842 char dynamic = 0;
715 843
716 if (!show_bind) return NULL; 844 if (!show_bind) return NULL;
717 if (!elf->phdr) return NULL; 845 if (!elf->phdr) return NULL;
718 846
719#define SHOW_BIND(B) \ 847#define SHOW_BIND(B) \
722 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 850 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
723 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 851 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
724 Elf ## B ## _Off offset; \ 852 Elf ## B ## _Off offset; \
725 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 853 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
726 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 854 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
855 dynamic = 1; \
727 offset = EGET(phdr[i].p_offset); \ 856 offset = EGET(phdr[i].p_offset); \
728 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 857 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
729 dyn = DYN ## B (elf->data + offset); \ 858 dyn = DYN ## B (elf->data + offset); \
730 while (EGET(dyn->d_tag) != DT_NULL) { \ 859 while (EGET(dyn->d_tag) != DT_NULL) { \
731 if (EGET(dyn->d_tag) == DT_BIND_NOW || \ 860 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
746 875
747 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) { 876 if (be_quiet && !fstat(elf->fd, &s) && !(s.st_mode & S_ISUID || s.st_mode & S_ISGID)) {
748 return NULL; 877 return NULL;
749 } else { 878 } else {
750 *found_bind = 1; 879 *found_bind = 1;
751 return (char *) "LAZY"; 880 return (char *) (dynamic ? "LAZY" : "STATIC");
752 } 881 }
753} 882}
754static char *scanelf_file_soname(elfobj *elf, char *found_soname) 883static char *scanelf_file_soname(elfobj *elf, char *found_soname)
755{ 884{
756 unsigned long i; 885 unsigned long i;
812#define FIND_SYM(B) \ 941#define FIND_SYM(B) \
813 if (elf->elf_class == ELFCLASS ## B) { \ 942 if (elf->elf_class == ELFCLASS ## B) { \
814 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 943 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
815 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 944 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
816 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \ 945 Elf ## B ## _Sym *sym = SYM ## B (elf->data + EGET(symtab->sh_offset)); \
817 unsigned long cnt = EGET(symtab->sh_size) / EGET(symtab->sh_entsize); \ 946 unsigned long cnt = EGET(symtab->sh_entsize); \
818 char *symname; \ 947 char *symname; \
948 if (cnt) \
949 cnt = EGET(symtab->sh_size) / cnt; \
819 for (i = 0; i < cnt; ++i) { \ 950 for (i = 0; i < cnt; ++i) { \
820 if (sym->st_name) { \ 951 if (sym->st_name) { \
952 /* make sure the symbol name is in acceptable memory range */ \
821 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \ 953 symname = (char *)(elf->data + EGET(strtab->sh_offset) + EGET(sym->st_name)); \
954 if ((void*)symname > (void*)elf->data_end) { \
955 warnf("%s: corrupt ELF symbols", elf->filename); \
956 ++sym; \
957 continue; \
958 } \
959 /* debug display ... show all symbols and some extra info */ \
822 if (*find_sym == '*') { \ 960 if (*ret == '*') { \
823 printf("%s(%s) %5lX %15s %s\n", \ 961 printf("%s(%s) %5lX %15s %s\n", \
824 ((*found_sym == 0) ? "\n\t" : "\t"), \ 962 ((*found_sym == 0) ? "\n\t" : "\t"), \
825 elf->base_filename, \ 963 elf->base_filename, \
826 (unsigned long)sym->st_size, \ 964 (unsigned long)sym->st_size, \
827 get_elfstttype(sym->st_info), \ 965 get_elfstttype(sym->st_info), \
828 symname); \ 966 symname); \
829 *found_sym = 1; \ 967 *found_sym = 1; \
830 } else { \ 968 } else { \
969 /* allow the user to specify a comma delimited list of symbols to search for */ \
831 char *this_sym, *next_sym; \ 970 char *this_sym, *next_sym; \
832 this_sym = find_sym; \ 971 this_sym = ret; \
833 do { \ 972 do { \
834 next_sym = strchr(this_sym, ','); \ 973 next_sym = strchr(this_sym, ','); \
835 if (next_sym == NULL) \ 974 if (next_sym == NULL) \
836 next_sym = this_sym + strlen(this_sym); \ 975 next_sym = this_sym + strlen(this_sym); \
976 /* do we want a defined symbol ? */ \
977 if (*this_sym == '+') { \
978 if (sym->st_shndx == SHN_UNDEF) \
979 goto skip_this_sym##B; \
980 ++this_sym; \
981 /* do we want an undefined symbol ? */ \
982 } else if (*this_sym == '-') { \
983 if (sym->st_shndx != SHN_UNDEF) \
984 goto skip_this_sym##B; \
985 ++this_sym; \
986 } \
987 /* ok, lets compare the name now */ \
837 if ((strncmp(this_sym, symname, (next_sym-this_sym)) == 0 && symname[next_sym-this_sym] == '\0') || \ 988 if ((strncmp(this_sym, symname, (next_sym-this_sym)) == 0 && symname[next_sym-this_sym] == '\0') || \
838 (strcmp(symname, versioned_symname) == 0)) { \ 989 (strncmp(symname, versioned_symname, strlen(versioned_symname)) == 0)) { \
990 if (be_semi_verbose) { \
991 char buf[126]; \
992 snprintf(buf, sizeof(buf), "%lX %s %s", \
993 (unsigned long)sym->st_size, get_elfstttype(sym->st_info), this_sym); \
994 ret = buf; \
995 } else \
839 ret = this_sym; \ 996 ret = this_sym; \
840 (*found_sym)++; \ 997 (*found_sym)++; \
841 goto break_out; \ 998 goto break_out; \
842 } \ 999 } \
843 this_sym = next_sym + 1; \ 1000 skip_this_sym##B: this_sym = next_sym + 1; \
844 } while (*next_sym != '\0'); \ 1001 } while (*next_sym != '\0'); \
845 } \ 1002 } \
846 } \ 1003 } \
847 ++sym; \ 1004 ++sym; \
848 } } 1005 } }
858 if (be_quiet) 1015 if (be_quiet)
859 return NULL; 1016 return NULL;
860 else 1017 else
861 return (char *)" - "; 1018 return (char *)" - ";
862} 1019}
1020
1021
1022static char *scanelf_file_sections(elfobj *elf, char *found_section)
1023{
1024 if (!find_section)
1025 return NULL;
1026
1027#define FIND_SECTION(B) \
1028 if (elf->elf_class == ELFCLASS ## B) { \
1029 int invert; \
1030 Elf ## B ## _Shdr *section; \
1031 invert = (*find_section == '!' ? 1 : 0); \
1032 section = SHDR ## B (elf_findsecbyname(elf, find_section+invert)); \
1033 if ((section == NULL && invert) || (section != NULL && !invert)) \
1034 *found_section = 1; \
1035 }
1036 FIND_SECTION(32)
1037 FIND_SECTION(64)
1038
1039 if (be_wewy_wewy_quiet)
1040 return NULL;
1041
1042 if (*found_section)
1043 return find_section;
1044
1045 if (be_quiet)
1046 return NULL;
1047 else
1048 return (char *)" - ";
1049}
1050
863/* scan an elf file and show all the fun stuff */ 1051/* scan an elf file and show all the fun stuff */
864#define prints(str) write(fileno(stdout), str, strlen(str)) 1052#define prints(str) write(fileno(stdout), str, strlen(str))
865static int scanelf_elfobj(elfobj *elf) 1053static int scanelf_elfobj(elfobj *elf)
866{ 1054{
867 unsigned long i; 1055 unsigned long i;
868 char found_pax, found_phdr, found_relro, found_load, found_textrel, 1056 char found_pax, found_phdr, found_relro, found_load, found_textrel,
869 found_rpath, found_needed, found_interp, found_bind, found_soname, 1057 found_rpath, found_needed, found_interp, found_bind, found_soname,
870 found_sym, found_lib, found_file, found_textrels; 1058 found_sym, found_lib, found_file, found_textrels, found_section;
871 static char *out_buffer = NULL; 1059 static char *out_buffer = NULL;
872 static size_t out_len; 1060 static size_t out_len;
873 1061
874 found_pax = found_phdr = found_relro = found_load = found_textrel = \ 1062 found_pax = found_phdr = found_relro = found_load = found_textrel = \
875 found_rpath = found_needed = found_interp = found_bind = found_soname = \ 1063 found_rpath = found_needed = found_interp = found_bind = found_soname = \
876 found_sym = found_lib = found_file = found_textrels = 0; 1064 found_sym = found_lib = found_file = found_textrels = found_section = 0;
877 1065
878 if (be_verbose > 1) 1066 if (be_verbose > 2)
879 printf("%s: scanning file {%s,%s}\n", elf->filename, 1067 printf("%s: scanning file {%s,%s}\n", elf->filename,
880 get_elfeitype(EI_CLASS, elf->elf_class), 1068 get_elfeitype(EI_CLASS, elf->elf_class),
881 get_elfeitype(EI_DATA, elf->data[EI_DATA])); 1069 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
882 else if (be_verbose) 1070 else if (be_verbose > 1)
883 printf("%s: scanning file\n", elf->filename); 1071 printf("%s: scanning file\n", elf->filename);
884 1072
885 /* init output buffer */ 1073 /* init output buffer */
886 if (!out_buffer) { 1074 if (!out_buffer) {
887 out_len = sizeof(char) * 80; 1075 out_len = sizeof(char) * 80;
893 if (!be_quiet && show_banner) { 1081 if (!be_quiet && show_banner) {
894 for (i = 0; out_format[i]; ++i) { 1082 for (i = 0; out_format[i]; ++i) {
895 if (!IS_MODIFIER(out_format[i])) continue; 1083 if (!IS_MODIFIER(out_format[i])) continue;
896 1084
897 switch (out_format[++i]) { 1085 switch (out_format[++i]) {
1086 case '+': break;
898 case '%': break; 1087 case '%': break;
899 case '#': break; 1088 case '#': break;
900 case 'F': 1089 case 'F':
901 case 'p': 1090 case 'p':
902 case 'f': prints("FILE "); found_file = 1; break; 1091 case 'f': prints("FILE "); found_file = 1; break;
910 case 'b': prints("BIND "); break; 1099 case 'b': prints("BIND "); break;
911 case 'S': prints("SONAME "); break; 1100 case 'S': prints("SONAME "); break;
912 case 's': prints("SYM "); break; 1101 case 's': prints("SYM "); break;
913 case 'N': prints("LIB "); break; 1102 case 'N': prints("LIB "); break;
914 case 'T': prints("TEXTRELS "); break; 1103 case 'T': prints("TEXTRELS "); break;
1104 case 'k': prints("SECTION "); break;
915 default: warnf("'%c' has no title ?", out_format[i]); 1105 default: warnf("'%c' has no title ?", out_format[i]);
916 } 1106 }
917 } 1107 }
918 if (!found_file) prints("FILE "); 1108 if (!found_file) prints("FILE ");
919 prints("\n"); 1109 prints("\n");
924 /* dump all the good stuff */ 1114 /* dump all the good stuff */
925 for (i = 0; out_format[i]; ++i) { 1115 for (i = 0; out_format[i]; ++i) {
926 const char *out; 1116 const char *out;
927 const char *tmp; 1117 const char *tmp;
928 1118
929 /* make sure we trim leading spaces in quiet mode */
930 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
931 *out_buffer = '\0';
932
933 if (!IS_MODIFIER(out_format[i])) { 1119 if (!IS_MODIFIER(out_format[i])) {
934 xchrcat(&out_buffer, out_format[i], &out_len); 1120 xchrcat(&out_buffer, out_format[i], &out_len);
935 continue; 1121 continue;
936 } 1122 }
937 1123
938 out = NULL; 1124 out = NULL;
939 be_wewy_wewy_quiet = (out_format[i] == '#'); 1125 be_wewy_wewy_quiet = (out_format[i] == '#');
1126 be_semi_verbose = (out_format[i] == '+');
940 switch (out_format[++i]) { 1127 switch (out_format[++i]) {
1128 case '+':
941 case '%': 1129 case '%':
942 case '#': 1130 case '#':
943 xchrcat(&out_buffer, out_format[i], &out_len); break; 1131 xchrcat(&out_buffer, out_format[i], &out_len); break;
944 case 'F': 1132 case 'F':
945 found_file = 1; 1133 found_file = 1;
977 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break; 1165 case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break;
978 case 'i': out = scanelf_file_interp(elf, &found_interp); break; 1166 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
979 case 'b': out = scanelf_file_bind(elf, &found_bind); break; 1167 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
980 case 'S': out = scanelf_file_soname(elf, &found_soname); break; 1168 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
981 case 's': out = scanelf_file_sym(elf, &found_sym); break; 1169 case 's': out = scanelf_file_sym(elf, &found_sym); break;
1170 case 'k': out = scanelf_file_sections(elf, &found_section); break;
982 default: warnf("'%c' has no scan code?", out_format[i]); 1171 default: warnf("'%c' has no scan code?", out_format[i]);
983 } 1172 }
984 if (out) { 1173 if (out) {
985 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */ 1174 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
986 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL) 1175 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
991 } 1180 }
992 1181
993#define FOUND_SOMETHING() \ 1182#define FOUND_SOMETHING() \
994 (found_pax || found_phdr || found_relro || found_load || found_textrel || \ 1183 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
995 found_rpath || found_needed || found_interp || found_bind || \ 1184 found_rpath || found_needed || found_interp || found_bind || \
996 found_soname || found_sym || found_lib || found_textrels) 1185 found_soname || found_sym || found_lib || found_textrels || found_section )
997 1186
998 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) { 1187 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
999 xchrcat(&out_buffer, ' ', &out_len); 1188 xchrcat(&out_buffer, ' ', &out_len);
1000 xstrcat(&out_buffer, elf->filename, &out_len); 1189 xstrcat(&out_buffer, elf->filename, &out_len);
1001 } 1190 }
1008} 1197}
1009 1198
1010/* scan a single elf */ 1199/* scan a single elf */
1011static int scanelf_elf(const char *filename, int fd, size_t len) 1200static int scanelf_elf(const char *filename, int fd, size_t len)
1012{ 1201{
1013 int ret; 1202 int ret = 1;
1014 elfobj *elf; 1203 elfobj *elf;
1015 1204
1016 /* verify this is real ELF */ 1205 /* verify this is real ELF */
1017 if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) { 1206 if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) {
1018 if (be_verbose > 2) printf("%s: not an ELF\n", filename); 1207 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
1019 return 1; 1208 return ret;
1209 }
1210 switch (match_bits) {
1211 case 32:
1212 if (elf->elf_class != ELFCLASS32)
1213 goto label_done;
1214 break;
1215 case 64:
1216 if (elf->elf_class != ELFCLASS64)
1217 goto label_done;
1218 break;
1219 default: break;
1220 }
1221 if (strlen(match_etypes)) {
1222 char sbuf[126];
1223 strncpy(sbuf, match_etypes, sizeof(sbuf));
1224 if (strchr(match_etypes, ',') != NULL) {
1225 char *p;
1226 while((p = strrchr(sbuf, ',')) != NULL) {
1227 *p = 0;
1228 if (etype_lookup(p+1) == get_etype(elf))
1229 goto label_ret;
1230 }
1020 } 1231 }
1232 if (etype_lookup(sbuf) != get_etype(elf))
1233 goto label_done;
1234 }
1021 1235
1236label_ret:
1022 ret = scanelf_elfobj(elf); 1237 ret = scanelf_elfobj(elf);
1238
1239label_done:
1023 unreadelf(elf); 1240 unreadelf(elf);
1024 return ret; 1241 return ret;
1025} 1242}
1243
1026/* scan an archive of elfs */ 1244/* scan an archive of elfs */
1027static int scanelf_archive(const char *filename, int fd, size_t len) 1245static int scanelf_archive(const char *filename, int fd, size_t len)
1028{ 1246{
1029 archive_handle *ar; 1247 archive_handle *ar;
1030 archive_member *m; 1248 archive_member *m;
1103 /* now scan the dir looking for fun stuff */ 1321 /* now scan the dir looking for fun stuff */
1104 if ((dir = opendir(path)) == NULL) { 1322 if ((dir = opendir(path)) == NULL) {
1105 warnf("could not opendir %s: %s", path, strerror(errno)); 1323 warnf("could not opendir %s: %s", path, strerror(errno));
1106 return; 1324 return;
1107 } 1325 }
1108 if (be_verbose) printf("%s: scanning dir\n", path); 1326 if (be_verbose > 1) printf("%s: scanning dir\n", path);
1109 1327
1110 pathlen = strlen(path); 1328 pathlen = strlen(path);
1111 while ((dentry = readdir(dir))) { 1329 while ((dentry = readdir(dir))) {
1112 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 1330 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
1113 continue; 1331 continue;
1115 if (len >= sizeof(buf)) { 1333 if (len >= sizeof(buf)) {
1116 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path, 1334 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
1117 (unsigned long)len, (unsigned long)sizeof(buf)); 1335 (unsigned long)len, (unsigned long)sizeof(buf));
1118 continue; 1336 continue;
1119 } 1337 }
1120 sprintf(buf, "%s/%s", path, dentry->d_name); 1338 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name);
1121 if (lstat(buf, &st) != -1) { 1339 if (lstat(buf, &st) != -1) {
1122 if (S_ISREG(st.st_mode)) 1340 if (S_ISREG(st.st_mode))
1123 scanelf_file(buf); 1341 scanelf_file(buf);
1124 else if (dir_recurse && S_ISDIR(st.st_mode)) { 1342 else if (dir_recurse && S_ISDIR(st.st_mode)) {
1125 if (dir_crossmount || (st_top.st_dev == st.st_dev)) 1343 if (dir_crossmount || (st_top.st_dev == st.st_dev))
1128 } 1346 }
1129 } 1347 }
1130 closedir(dir); 1348 closedir(dir);
1131} 1349}
1132 1350
1133static int scanelf_from_file(char *filename) 1351static int scanelf_from_file(const char *filename)
1134{ 1352{
1135 FILE *fp = NULL; 1353 FILE *fp = NULL;
1136 char *p; 1354 char *p;
1137 char path[__PAX_UTILS_PATH_MAX]; 1355 char path[__PAX_UTILS_PATH_MAX];
1138 1356
1139 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL)) 1357 if (strcmp(filename, "-") == 0)
1140 fp = stdin; 1358 fp = stdin;
1141 else if ((fp = fopen(filename, "r")) == NULL) 1359 else if ((fp = fopen(filename, "r")) == NULL)
1142 return 1; 1360 return 1;
1143 1361
1144 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) { 1362 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1150 if (fp != stdin) 1368 if (fp != stdin)
1151 fclose(fp); 1369 fclose(fp);
1152 return 0; 1370 return 0;
1153} 1371}
1154 1372
1155static void load_ld_so_conf() 1373#if defined(__GLIBC__) || defined(__UCLIBC__)
1374static int load_ld_so_conf(int i, const char *fname)
1156{ 1375{
1157 FILE *fp = NULL; 1376 FILE *fp = NULL;
1158 char *p; 1377 char *p;
1159 char path[__PAX_UTILS_PATH_MAX]; 1378 char path[__PAX_UTILS_PATH_MAX];
1160 int i = 0;
1161 1379
1162 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 1380 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
1163 return; 1381 return i;
1382
1383 if ((fp = fopen(fname, "r")) == NULL)
1384 return i;
1164 1385
1165 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) { 1386 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1166 if (*path != '/')
1167 continue;
1168
1169 if ((p = strrchr(path, '\r')) != NULL) 1387 if ((p = strrchr(path, '\r')) != NULL)
1170 *p = 0; 1388 *p = 0;
1171 if ((p = strchr(path, '\n')) != NULL) 1389 if ((p = strchr(path, '\n')) != NULL)
1172 *p = 0; 1390 *p = 0;
1391 // recursive includes of the same file will make this segfault.
1392 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) {
1393 glob64_t gl;
1394 size_t x;
1395 char gpath[__PAX_UTILS_PATH_MAX];
1396
1397 memset(gpath, 0, sizeof(gpath));
1398
1399 if (path[8] != '/')
1400 snprintf(gpath, sizeof(gpath), "/etc/%s", &path[8]);
1401 else
1402 strncpy(gpath, &path[8], sizeof(gpath));
1403
1404 if ((glob64(gpath, 0, NULL, &gl)) == 0) {
1405 for (x = 0; x < gl.gl_pathc; ++x) {
1406 /* try to avoid direct loops */
1407 if (strcmp(gl.gl_pathv[x], fname) == 0)
1408 continue;
1409 i = load_ld_so_conf(i, gl.gl_pathv[x]);
1410 if (i + 1 >= sizeof(ldpaths) / sizeof(*ldpaths)) {
1411 globfree64(&gl);
1412 return i;
1413 }
1414 }
1415 globfree64 (&gl);
1416 continue;
1417 } else
1418 abort();
1419 }
1420 if (*path != '/')
1421 continue;
1173 1422
1174 ldpaths[i++] = xstrdup(path); 1423 ldpaths[i++] = xstrdup(path);
1175 1424
1176 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths)) 1425 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
1177 break; 1426 break;
1178 } 1427 }
1179 ldpaths[i] = NULL; 1428 ldpaths[i] = NULL;
1180 1429
1181 fclose(fp); 1430 fclose(fp);
1431 return i;
1182} 1432}
1433#endif
1434
1435#if defined(__FreeBSD__) || (__DragonFly__)
1436static int load_ld_so_hints(int i, const char *fname)
1437{
1438 FILE *fp = NULL;
1439 char *b = NULL, *p;
1440 struct elfhints_hdr hdr;
1441
1442 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
1443 return i;
1444
1445 if ((fp = fopen(fname, "r")) == NULL)
1446 return i;
1447
1448 if ( fread(&hdr, 1, sizeof(hdr), fp) != sizeof(hdr) ||
1449 hdr.magic != ELFHINTS_MAGIC || hdr.version != 1 ||
1450 fseek(fp, hdr.strtab + hdr.dirlist, SEEK_SET) == -1
1451 ) {
1452 fclose(fp);
1453 return i;
1454 }
1455
1456 b = (char*)malloc(hdr.dirlistlen+1);
1457 if ( fread(b, 1, hdr.dirlistlen+1, fp) != hdr.dirlistlen+1 ) {
1458 fclose(fp);
1459 free(b);
1460 return i;
1461 }
1462
1463 while ( (p = strsep(&b, ":")) ) {
1464 if ( *p == '\0' ) continue;
1465 ldpaths[i++] = xstrdup(p);
1466
1467 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
1468 break;
1469 }
1470 ldpaths[i] = NULL;
1471
1472 free(b);
1473 fclose(fp);
1474 return i;
1475}
1476#endif
1183 1477
1184/* scan /etc/ld.so.conf for paths */ 1478/* scan /etc/ld.so.conf for paths */
1185static void scanelf_ldpath() 1479static void scanelf_ldpath()
1186{ 1480{
1187 char scan_l, scan_ul, scan_ull; 1481 char scan_l, scan_ul, scan_ull;
1221 } 1515 }
1222 1516
1223 free(path); 1517 free(path);
1224} 1518}
1225 1519
1226
1227/* usage / invocation handling functions */ 1520/* usage / invocation handling functions */
1228#define PARSE_FLAGS "plRmyAXxetrnLibSs:gN:TaqvF:f:o:BhV" 1521#define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:BhV"
1229#define a_argument required_argument 1522#define a_argument required_argument
1230static struct option const long_opts[] = { 1523static struct option const long_opts[] = {
1231 {"path", no_argument, NULL, 'p'}, 1524 {"path", no_argument, NULL, 'p'},
1232 {"ldpath", no_argument, NULL, 'l'}, 1525 {"ldpath", no_argument, NULL, 'l'},
1233 {"recursive", no_argument, NULL, 'R'}, 1526 {"recursive", no_argument, NULL, 'R'},
1234 {"mount", no_argument, NULL, 'm'}, 1527 {"mount", no_argument, NULL, 'm'},
1235 {"symlink", no_argument, NULL, 'y'}, 1528 {"symlink", no_argument, NULL, 'y'},
1236 {"archives", no_argument, NULL, 'A'}, 1529 {"archives", no_argument, NULL, 'A'},
1237 {"ldcache", no_argument, NULL, 'L'}, 1530 {"ldcache", no_argument, NULL, 'L'},
1238 {"fix", no_argument, NULL, 'X'}, 1531 {"fix", no_argument, NULL, 'X'},
1532 {"setpax", a_argument, NULL, 'z'},
1239 {"pax", no_argument, NULL, 'x'}, 1533 {"pax", no_argument, NULL, 'x'},
1240 {"header", no_argument, NULL, 'e'}, 1534 {"header", no_argument, NULL, 'e'},
1241 {"textrel", no_argument, NULL, 't'}, 1535 {"textrel", no_argument, NULL, 't'},
1242 {"rpath", no_argument, NULL, 'r'}, 1536 {"rpath", no_argument, NULL, 'r'},
1243 {"needed", no_argument, NULL, 'n'}, 1537 {"needed", no_argument, NULL, 'n'},
1244 {"interp", no_argument, NULL, 'i'}, 1538 {"interp", no_argument, NULL, 'i'},
1245 {"bind", no_argument, NULL, 'b'}, 1539 {"bind", no_argument, NULL, 'b'},
1246 {"soname", no_argument, NULL, 'S'}, 1540 {"soname", no_argument, NULL, 'S'},
1247 {"symbol", a_argument, NULL, 's'}, 1541 {"symbol", a_argument, NULL, 's'},
1542 {"section", a_argument, NULL, 'k'},
1248 {"lib", a_argument, NULL, 'N'}, 1543 {"lib", a_argument, NULL, 'N'},
1249 {"gmatch", no_argument, NULL, 'g'}, 1544 {"gmatch", no_argument, NULL, 'g'},
1250 {"textrels", no_argument, NULL, 'T'}, 1545 {"textrels", no_argument, NULL, 'T'},
1546 {"etype", a_argument, NULL, 'E'},
1547 {"bits", a_argument, NULL, 'M'},
1251 {"all", no_argument, NULL, 'a'}, 1548 {"all", no_argument, NULL, 'a'},
1252 {"quiet", no_argument, NULL, 'q'}, 1549 {"quiet", no_argument, NULL, 'q'},
1253 {"verbose", no_argument, NULL, 'v'}, 1550 {"verbose", no_argument, NULL, 'v'},
1254 {"format", a_argument, NULL, 'F'}, 1551 {"format", a_argument, NULL, 'F'},
1255 {"from", a_argument, NULL, 'f'}, 1552 {"from", a_argument, NULL, 'f'},
1266 "Scan directories recursively", 1563 "Scan directories recursively",
1267 "Don't recursively cross mount points", 1564 "Don't recursively cross mount points",
1268 "Don't scan symlinks", 1565 "Don't scan symlinks",
1269 "Scan archives (.a files)", 1566 "Scan archives (.a files)",
1270 "Utilize ld.so.cache information (use with -r/-n)", 1567 "Utilize ld.so.cache information (use with -r/-n)",
1271 "Try and 'fix' bad things (use with -r/-e)\n", 1568 "Try and 'fix' bad things (use with -r/-e)",
1569 "Sets EI_PAX/PT_PAX_FLAGS to <arg> (use with -Xx)\n",
1272 "Print PaX markings", 1570 "Print PaX markings",
1273 "Print GNU_STACK/PT_LOAD markings", 1571 "Print GNU_STACK/PT_LOAD markings",
1274 "Print TEXTREL information", 1572 "Print TEXTREL information",
1275 "Print RPATH information", 1573 "Print RPATH information",
1276 "Print NEEDED information", 1574 "Print NEEDED information",
1277 "Print INTERP information", 1575 "Print INTERP information",
1278 "Print BIND information", 1576 "Print BIND information",
1279 "Print SONAME information", 1577 "Print SONAME information",
1280 "Find a specified symbol", 1578 "Find a specified symbol",
1579 "Find a specified section",
1281 "Find a specified library", 1580 "Find a specified library",
1282 "Use strncmp to match libraries. (use with -N)", 1581 "Use strncmp to match libraries. (use with -N)",
1283 "Locate cause of TEXTREL", 1582 "Locate cause of TEXTREL",
1583 "Print only ELF files matching etype ET_DYN,ET_EXEC ...",
1584 "Print only ELF files matching numeric bits",
1284 "Print all scanned info (-x -e -t -r -b)\n", 1585 "Print all scanned info (-x -e -t -r -b)\n",
1285 "Only output 'bad' things", 1586 "Only output 'bad' things",
1286 "Be verbose (can be specified more than once)", 1587 "Be verbose (can be specified more than once)",
1287 "Use specified format for output", 1588 "Use specified format for output",
1288 "Read input stream from a filename", 1589 "Read input stream from a filename",
1300 printf("* Scan ELF binaries for stuff\n\n" 1601 printf("* Scan ELF binaries for stuff\n\n"
1301 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0); 1602 "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0);
1302 printf("Options: -[%s]\n", PARSE_FLAGS); 1603 printf("Options: -[%s]\n", PARSE_FLAGS);
1303 for (i = 0; long_opts[i].name; ++i) 1604 for (i = 0; long_opts[i].name; ++i)
1304 if (long_opts[i].has_arg == no_argument) 1605 if (long_opts[i].has_arg == no_argument)
1305 printf(" -%c, --%-13s* %s\n", long_opts[i].val, 1606 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
1306 long_opts[i].name, opts_help[i]); 1607 long_opts[i].name, opts_help[i]);
1307 else 1608 else
1308 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val, 1609 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
1309 long_opts[i].name, opts_help[i]); 1610 long_opts[i].name, opts_help[i]);
1310 1611
1311 if (status != EXIT_SUCCESS) 1612 if (status != EXIT_SUCCESS)
1312 exit(status); 1613 exit(status);
1313 1614
1314 puts("\nThe format modifiers for the -F option are:"); 1615 puts("\nThe format modifiers for the -F option are:");
1315 puts(" F Filename \tx PaX Flags \te STACK/RELRO"); 1616 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
1316 puts(" t TEXTREL \tr RPATH \tn NEEDED"); 1617 puts(" t TEXTREL \tr RPATH \tn NEEDED");
1317 puts(" i INTERP \tb BIND \ts symbol"); 1618 puts(" i INTERP \tb BIND \ts symbol");
1318 puts(" N library \to Type \tT TEXTRELs"); 1619 puts(" N library \to Type \tT TEXTRELs");
1319 puts(" S SONAME"); 1620 puts(" S SONAME \tk section");
1320 puts(" p filename (with search path removed)"); 1621 puts(" p filename (with search path removed)");
1321 puts(" f filename (short name/basename)"); 1622 puts(" f filename (short name/basename)");
1322 puts("Prefix each modifier with '%' (verbose) or '#' (silent)"); 1623 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1323 1624
1625 puts("\nELF Etypes:");
1626 print_etypes(stdout);
1627
1324 exit(status); 1628 exit(status);
1325} 1629}
1326 1630
1327/* parse command line arguments and preform needed actions */ 1631/* parse command line arguments and preform needed actions */
1328static void parseargs(int argc, char *argv[]) 1632static void parseargs(int argc, char *argv[])
1329{ 1633{
1330 int i; 1634 int i;
1331 char *from_file = NULL; 1635 const char *from_file = NULL;
1332 1636
1333 opterr = 0; 1637 opterr = 0;
1334 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) { 1638 while ((i=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
1335 switch (i) { 1639 switch (i) {
1336 1640
1343 case 'h': usage(EXIT_SUCCESS); break; 1647 case 'h': usage(EXIT_SUCCESS); break;
1344 case 'f': 1648 case 'f':
1345 if (from_file) warn("You prob don't want to specify -f twice"); 1649 if (from_file) warn("You prob don't want to specify -f twice");
1346 from_file = optarg; 1650 from_file = optarg;
1347 break; 1651 break;
1652 case 'E':
1653 strncpy(match_etypes, optarg, sizeof(match_etypes));
1654 break;
1655 case 'M':
1656 match_bits = atoi(optarg);
1657 break;
1348 case 'o': { 1658 case 'o': {
1349 FILE *fp = NULL;
1350 if ((fp = freopen(optarg, "w", stdout)) == NULL) 1659 if (freopen(optarg, "w", stdout) == NULL)
1351 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1660 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1352 SET_STDOUT(fp);
1353 break; 1661 break;
1354 } 1662 }
1355 1663 case 'k':
1664 if (find_section) warn("You prob don't want to specify -k twice");
1665 find_section = optarg;
1666 break;
1356 case 's': { 1667 case 's': {
1357 if (find_sym) warn("You prob don't want to specify -s twice"); 1668 if (find_sym) warn("You prob don't want to specify -s twice");
1358 find_sym = optarg; 1669 find_sym = optarg;
1359 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1)); 1670 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1360 sprintf(versioned_symname, "%s@", find_sym); 1671 sprintf(versioned_symname, "%s@", find_sym);
1369 case 'F': { 1680 case 'F': {
1370 if (out_format) warn("You prob don't want to specify -F twice"); 1681 if (out_format) warn("You prob don't want to specify -F twice");
1371 out_format = optarg; 1682 out_format = optarg;
1372 break; 1683 break;
1373 } 1684 }
1685 case 'z': {
1686 unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC);
1687 size_t x;
1374 1688
1375 case 'g': gmatch = 1; /* break; any reason we dont breal; here ? */ 1689 for (x = 0 ; x < strlen(optarg); x++) {
1690 switch(optarg[x]) {
1691 case 'p':
1692 case 'P':
1693 do_state(optarg[x], PAGEEXEC);
1694 break;
1695 case 's':
1696 case 'S':
1697 do_state(optarg[x], SEGMEXEC);
1698 break;
1699 case 'm':
1700 case 'M':
1701 do_state(optarg[x], MPROTECT);
1702 break;
1703 case 'e':
1704 case 'E':
1705 do_state(optarg[x], EMUTRAMP);
1706 break;
1707 case 'r':
1708 case 'R':
1709 do_state(optarg[x], RANDMMAP);
1710 break;
1711 case 'x':
1712 case 'X':
1713 do_state(optarg[x], RANDEXEC);
1714 break;
1715 default:
1716 break;
1717 }
1718 }
1719 if (!(((flags & PF_PAGEEXEC) && (flags & PF_NOPAGEEXEC)) ||
1720 ((flags & PF_SEGMEXEC) && (flags & PF_NOSEGMEXEC)) ||
1721 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP)) ||
1722 ((flags & PF_RANDEXEC) && (flags & PF_NORANDEXEC)) ||
1723 ((flags & PF_EMUTRAMP) && (flags & PF_NOEMUTRAMP)) ||
1724 ((flags & PF_RANDMMAP) && (flags & PF_NORANDMMAP))))
1725 setpax = flags;
1726 break;
1727 }
1728 case 'g': gmatch = 1; break;
1376 case 'L': use_ldcache = 1; break; 1729 case 'L': use_ldcache = 1; break;
1377 case 'y': scan_symlink = 0; break; 1730 case 'y': scan_symlink = 0; break;
1378 case 'A': scan_archives = 1; break; 1731 case 'A': scan_archives = 1; break;
1379 case 'B': show_banner = 0; break; 1732 case 'B': show_banner = 0; break;
1380 case 'l': scan_ldpath = 1; break; 1733 case 'l': scan_ldpath = 1; break;
1394 case 'q': be_quiet = 1; break; 1747 case 'q': be_quiet = 1; break;
1395 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1748 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1396 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break; 1749 case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break;
1397 1750
1398 case ':': 1751 case ':':
1399 err("Option missing parameter\n"); 1752 err("Option '%c' is missing parameter", optopt);
1400 case '?': 1753 case '?':
1401 err("Unknown option\n"); 1754 err("Unknown option '%c' or argument missing", optopt);
1402 default: 1755 default:
1403 err("Unhandled option '%c'", i); 1756 err("Unhandled option '%c'; please report this", i);
1404 } 1757 }
1405 } 1758 }
1406 1759
1407 /* let the format option override all other options */ 1760 /* let the format option override all other options */
1408 if (out_format) { 1761 if (out_format) {
1411 show_textrels = 0; 1764 show_textrels = 0;
1412 for (i = 0; out_format[i]; ++i) { 1765 for (i = 0; out_format[i]; ++i) {
1413 if (!IS_MODIFIER(out_format[i])) continue; 1766 if (!IS_MODIFIER(out_format[i])) continue;
1414 1767
1415 switch (out_format[++i]) { 1768 switch (out_format[++i]) {
1769 case '+': break;
1416 case '%': break; 1770 case '%': break;
1417 case '#': break; 1771 case '#': break;
1418 case 'F': break; 1772 case 'F': break;
1419 case 'p': break; 1773 case 'p': break;
1420 case 'f': break; 1774 case 'f': break;
1775 case 'k': break;
1421 case 's': break; 1776 case 's': break;
1422 case 'N': break; 1777 case 'N': break;
1423 case 'o': break; 1778 case 'o': break;
1424 case 'x': show_pax = 1; break; 1779 case 'x': show_pax = 1; break;
1425 case 'e': show_phdr = 1; break; 1780 case 'e': show_phdr = 1; break;
1449 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 1804 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1450 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len); 1805 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1451 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len); 1806 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1452 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len); 1807 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1453 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len); 1808 if (find_sym) xstrcat(&out_format, "%s ", &fmt_len);
1809 if (find_section) xstrcat(&out_format, "%k ", &fmt_len);
1454 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len); 1810 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1455 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 1811 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1456 } 1812 }
1457 if (be_verbose > 2) printf("Format: %s\n", out_format); 1813 if (be_verbose > 2) printf("Format: %s\n", out_format);
1458 1814
1459 /* now lets actually do the scanning */ 1815 /* now lets actually do the scanning */
1460 if (scan_ldpath || use_ldcache) 1816 if (scan_ldpath || use_ldcache)
1461 load_ld_so_conf(); 1817#if defined(__GLIBC__) || defined(__UCLIBC__)
1818 load_ld_so_conf(0, "/etc/ld.so.conf");
1819#elif defined(__FreeBSD__) || defined(__DragonFly__)
1820 load_ld_so_hints(0, _PATH_ELF_HINTS);
1821#endif
1462 if (scan_ldpath) scanelf_ldpath(); 1822 if (scan_ldpath) scanelf_ldpath();
1463 if (scan_envpath) scanelf_envpath(); 1823 if (scan_envpath) scanelf_envpath();
1824 if (!from_file && optind == argc && ttyname(0) == NULL)
1825 from_file = "-";
1464 if (from_file) { 1826 if (from_file) {
1465 scanelf_from_file(from_file); 1827 scanelf_from_file(from_file);
1466 from_file = *argv; 1828 from_file = *argv;
1467 } 1829 }
1468 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file) 1830 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1479 1841
1480 if (ldcache != 0) 1842 if (ldcache != 0)
1481 munmap(ldcache, ldcache_size); 1843 munmap(ldcache, ldcache_size);
1482} 1844}
1483 1845
1846static char **get_split_env(const char *envvar) {
1847 char **envvals = NULL;
1848 char *saveptr = NULL;
1849 char *env;
1850 char *s;
1851 int nentry;
1484 1852
1853 if ((env = getenv(envvar)) == NULL)
1854 return NULL;
1485 1855
1486/* utility funcs */ 1856 env = xstrdup(env);
1487static char *xstrdup(const char *s) 1857 if (env == NULL)
1488{ 1858 return NULL;
1489 char *ret = strdup(s);
1490 if (!ret) err("Could not strdup(): %s", strerror(errno));
1491 return ret;
1492}
1493static void *xmalloc(size_t size)
1494{
1495 void *ret = malloc(size);
1496 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1497 return ret;
1498}
1499static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
1500{
1501 size_t new_len;
1502 1859
1503 new_len = strlen(*dst) + strlen(src); 1860 nentry = 0;
1504 if (*curr_len <= new_len) { 1861 for (s = strtok_r(env, " \t\n", &saveptr); s != NULL; s = strtok_r(NULL, " \t\n", &saveptr)) {
1505 *curr_len = new_len + (*curr_len / 2); 1862 if ((envvals = xrealloc(envvals, sizeof(char *)*(nentry+1))) == NULL)
1506 *dst = realloc(*dst, *curr_len); 1863 return NULL;
1507 if (!*dst) 1864 envvals[nentry++] = s;
1508 err("could not realloc() %li bytes", (unsigned long)*curr_len);
1509 } 1865 }
1866 envvals[nentry] = NULL;
1510 1867
1511 if (n) 1868 return envvals;
1512 strncat(*dst, src, n);
1513 else
1514 strcat(*dst, src);
1515} 1869}
1516static inline void xchrcat(char **dst, const char append, size_t *curr_len) 1870
1517{ 1871static void parseenv() {
1518 static char my_app[2]; 1872 qa_textrels=get_split_env("QA_TEXTRELS");
1519 my_app[0] = append; 1873 qa_execstack=get_split_env("QA_EXECSTACK");
1520 my_app[1] = '\0'; 1874 qa_wx_load=get_split_env("QA_WX_LOAD");
1521 xstrcat(dst, my_app, curr_len);
1522} 1875}
1523 1876
1524 1877
1525 1878
1526int main(int argc, char *argv[]) 1879int main(int argc, char *argv[])
1527{ 1880{
1528 if (argc < 2) 1881 if (argc < 2)
1529 usage(EXIT_FAILURE); 1882 usage(EXIT_FAILURE);
1883 parseenv();
1530 parseargs(argc, argv); 1884 parseargs(argc, argv);
1531 fclose(stdout); 1885 fclose(stdout);
1532#ifdef __BOUNDS_CHECKING_ON 1886#ifdef __BOUNDS_CHECKING_ON
1533 warn("The calls to add/delete heap should be off by 1 due to the out_buffer not being freed in scanelf_file()"); 1887 warn("The calls to add/delete heap should be off by 1 due to the out_buffer not being freed in scanelf_file()");
1534#endif 1888#endif

Legend:
Removed from v.1.110  
changed lines
  Added in v.1.146

  ViewVC Help
Powered by ViewVC 1.1.20