/[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.111 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.111 2006/01/20 00:23:32 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.111 2006/01/20 00:23:32 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("%s: corrupt ELF symbol", elf->filename); \ 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) \
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)); \
822 if ((void*)symname > (void*)elf->data) { \ 954 if ((void*)symname > (void*)elf->data_end) { \
823 warn("%s: corrupt ELF symbols", elf->filename); \ 955 warnf("%s: corrupt ELF symbols", elf->filename); \
956 ++sym; \
824 continue; \ 957 continue; \
825 } \ 958 } \
959 /* debug display ... show all symbols and some extra info */ \
826 if (*find_sym == '*') { \ 960 if (*ret == '*') { \
827 printf("%s(%s) %5lX %15s %s\n", \ 961 printf("%s(%s) %5lX %15s %s\n", \
828 ((*found_sym == 0) ? "\n\t" : "\t"), \ 962 ((*found_sym == 0) ? "\n\t" : "\t"), \
829 elf->base_filename, \ 963 elf->base_filename, \
830 (unsigned long)sym->st_size, \ 964 (unsigned long)sym->st_size, \
831 get_elfstttype(sym->st_info), \ 965 get_elfstttype(sym->st_info), \
832 symname); \ 966 symname); \
833 *found_sym = 1; \ 967 *found_sym = 1; \
834 } else { \ 968 } else { \
969 /* allow the user to specify a comma delimited list of symbols to search for */ \
835 char *this_sym, *next_sym; \ 970 char *this_sym, *next_sym; \
836 this_sym = find_sym; \ 971 this_sym = ret; \
837 do { \ 972 do { \
838 next_sym = strchr(this_sym, ','); \ 973 next_sym = strchr(this_sym, ','); \
839 if (next_sym == NULL) \ 974 if (next_sym == NULL) \
840 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 */ \
841 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') || \
842 (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 \
843 ret = this_sym; \ 996 ret = this_sym; \
844 (*found_sym)++; \ 997 (*found_sym)++; \
845 goto break_out; \ 998 goto break_out; \
846 } \ 999 } \
847 this_sym = next_sym + 1; \ 1000 skip_this_sym##B: this_sym = next_sym + 1; \
848 } while (*next_sym != '\0'); \ 1001 } while (*next_sym != '\0'); \
849 } \ 1002 } \
850 } \ 1003 } \
851 ++sym; \ 1004 ++sym; \
852 } } 1005 } }
862 if (be_quiet) 1015 if (be_quiet)
863 return NULL; 1016 return NULL;
864 else 1017 else
865 return (char *)" - "; 1018 return (char *)" - ";
866} 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
867/* scan an elf file and show all the fun stuff */ 1051/* scan an elf file and show all the fun stuff */
868#define prints(str) write(fileno(stdout), str, strlen(str)) 1052#define prints(str) write(fileno(stdout), str, strlen(str))
869static int scanelf_elfobj(elfobj *elf) 1053static int scanelf_elfobj(elfobj *elf)
870{ 1054{
871 unsigned long i; 1055 unsigned long i;
872 char found_pax, found_phdr, found_relro, found_load, found_textrel, 1056 char found_pax, found_phdr, found_relro, found_load, found_textrel,
873 found_rpath, found_needed, found_interp, found_bind, found_soname, 1057 found_rpath, found_needed, found_interp, found_bind, found_soname,
874 found_sym, found_lib, found_file, found_textrels; 1058 found_sym, found_lib, found_file, found_textrels, found_section;
875 static char *out_buffer = NULL; 1059 static char *out_buffer = NULL;
876 static size_t out_len; 1060 static size_t out_len;
877 1061
878 found_pax = found_phdr = found_relro = found_load = found_textrel = \ 1062 found_pax = found_phdr = found_relro = found_load = found_textrel = \
879 found_rpath = found_needed = found_interp = found_bind = found_soname = \ 1063 found_rpath = found_needed = found_interp = found_bind = found_soname = \
880 found_sym = found_lib = found_file = found_textrels = 0; 1064 found_sym = found_lib = found_file = found_textrels = found_section = 0;
881 1065
882 if (be_verbose > 1) 1066 if (be_verbose > 2)
883 printf("%s: scanning file {%s,%s}\n", elf->filename, 1067 printf("%s: scanning file {%s,%s}\n", elf->filename,
884 get_elfeitype(EI_CLASS, elf->elf_class), 1068 get_elfeitype(EI_CLASS, elf->elf_class),
885 get_elfeitype(EI_DATA, elf->data[EI_DATA])); 1069 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
886 else if (be_verbose) 1070 else if (be_verbose > 1)
887 printf("%s: scanning file\n", elf->filename); 1071 printf("%s: scanning file\n", elf->filename);
888 1072
889 /* init output buffer */ 1073 /* init output buffer */
890 if (!out_buffer) { 1074 if (!out_buffer) {
891 out_len = sizeof(char) * 80; 1075 out_len = sizeof(char) * 80;
897 if (!be_quiet && show_banner) { 1081 if (!be_quiet && show_banner) {
898 for (i = 0; out_format[i]; ++i) { 1082 for (i = 0; out_format[i]; ++i) {
899 if (!IS_MODIFIER(out_format[i])) continue; 1083 if (!IS_MODIFIER(out_format[i])) continue;
900 1084
901 switch (out_format[++i]) { 1085 switch (out_format[++i]) {
1086 case '+': break;
902 case '%': break; 1087 case '%': break;
903 case '#': break; 1088 case '#': break;
904 case 'F': 1089 case 'F':
905 case 'p': 1090 case 'p':
906 case 'f': prints("FILE "); found_file = 1; break; 1091 case 'f': prints("FILE "); found_file = 1; break;
914 case 'b': prints("BIND "); break; 1099 case 'b': prints("BIND "); break;
915 case 'S': prints("SONAME "); break; 1100 case 'S': prints("SONAME "); break;
916 case 's': prints("SYM "); break; 1101 case 's': prints("SYM "); break;
917 case 'N': prints("LIB "); break; 1102 case 'N': prints("LIB "); break;
918 case 'T': prints("TEXTRELS "); break; 1103 case 'T': prints("TEXTRELS "); break;
1104 case 'k': prints("SECTION "); break;
919 default: warnf("'%c' has no title ?", out_format[i]); 1105 default: warnf("'%c' has no title ?", out_format[i]);
920 } 1106 }
921 } 1107 }
922 if (!found_file) prints("FILE "); 1108 if (!found_file) prints("FILE ");
923 prints("\n"); 1109 prints("\n");
928 /* dump all the good stuff */ 1114 /* dump all the good stuff */
929 for (i = 0; out_format[i]; ++i) { 1115 for (i = 0; out_format[i]; ++i) {
930 const char *out; 1116 const char *out;
931 const char *tmp; 1117 const char *tmp;
932 1118
933 /* make sure we trim leading spaces in quiet mode */
934 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
935 *out_buffer = '\0';
936
937 if (!IS_MODIFIER(out_format[i])) { 1119 if (!IS_MODIFIER(out_format[i])) {
938 xchrcat(&out_buffer, out_format[i], &out_len); 1120 xchrcat(&out_buffer, out_format[i], &out_len);
939 continue; 1121 continue;
940 } 1122 }
941 1123
942 out = NULL; 1124 out = NULL;
943 be_wewy_wewy_quiet = (out_format[i] == '#'); 1125 be_wewy_wewy_quiet = (out_format[i] == '#');
1126 be_semi_verbose = (out_format[i] == '+');
944 switch (out_format[++i]) { 1127 switch (out_format[++i]) {
1128 case '+':
945 case '%': 1129 case '%':
946 case '#': 1130 case '#':
947 xchrcat(&out_buffer, out_format[i], &out_len); break; 1131 xchrcat(&out_buffer, out_format[i], &out_len); break;
948 case 'F': 1132 case 'F':
949 found_file = 1; 1133 found_file = 1;
981 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;
982 case 'i': out = scanelf_file_interp(elf, &found_interp); break; 1166 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
983 case 'b': out = scanelf_file_bind(elf, &found_bind); break; 1167 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
984 case 'S': out = scanelf_file_soname(elf, &found_soname); break; 1168 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
985 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;
986 default: warnf("'%c' has no scan code?", out_format[i]); 1171 default: warnf("'%c' has no scan code?", out_format[i]);
987 } 1172 }
988 if (out) { 1173 if (out) {
989 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */ 1174 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
990 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL) 1175 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
995 } 1180 }
996 1181
997#define FOUND_SOMETHING() \ 1182#define FOUND_SOMETHING() \
998 (found_pax || found_phdr || found_relro || found_load || found_textrel || \ 1183 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
999 found_rpath || found_needed || found_interp || found_bind || \ 1184 found_rpath || found_needed || found_interp || found_bind || \
1000 found_soname || found_sym || found_lib || found_textrels) 1185 found_soname || found_sym || found_lib || found_textrels || found_section )
1001 1186
1002 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) { 1187 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
1003 xchrcat(&out_buffer, ' ', &out_len); 1188 xchrcat(&out_buffer, ' ', &out_len);
1004 xstrcat(&out_buffer, elf->filename, &out_len); 1189 xstrcat(&out_buffer, elf->filename, &out_len);
1005 } 1190 }
1012} 1197}
1013 1198
1014/* scan a single elf */ 1199/* scan a single elf */
1015static int scanelf_elf(const char *filename, int fd, size_t len) 1200static int scanelf_elf(const char *filename, int fd, size_t len)
1016{ 1201{
1017 int ret; 1202 int ret = 1;
1018 elfobj *elf; 1203 elfobj *elf;
1019 1204
1020 /* verify this is real ELF */ 1205 /* verify this is real ELF */
1021 if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) { 1206 if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) {
1022 if (be_verbose > 2) printf("%s: not an ELF\n", filename); 1207 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
1023 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 }
1024 } 1231 }
1232 if (etype_lookup(sbuf) != get_etype(elf))
1233 goto label_done;
1234 }
1025 1235
1236label_ret:
1026 ret = scanelf_elfobj(elf); 1237 ret = scanelf_elfobj(elf);
1238
1239label_done:
1027 unreadelf(elf); 1240 unreadelf(elf);
1028 return ret; 1241 return ret;
1029} 1242}
1243
1030/* scan an archive of elfs */ 1244/* scan an archive of elfs */
1031static int scanelf_archive(const char *filename, int fd, size_t len) 1245static int scanelf_archive(const char *filename, int fd, size_t len)
1032{ 1246{
1033 archive_handle *ar; 1247 archive_handle *ar;
1034 archive_member *m; 1248 archive_member *m;
1107 /* now scan the dir looking for fun stuff */ 1321 /* now scan the dir looking for fun stuff */
1108 if ((dir = opendir(path)) == NULL) { 1322 if ((dir = opendir(path)) == NULL) {
1109 warnf("could not opendir %s: %s", path, strerror(errno)); 1323 warnf("could not opendir %s: %s", path, strerror(errno));
1110 return; 1324 return;
1111 } 1325 }
1112 if (be_verbose) printf("%s: scanning dir\n", path); 1326 if (be_verbose > 1) printf("%s: scanning dir\n", path);
1113 1327
1114 pathlen = strlen(path); 1328 pathlen = strlen(path);
1115 while ((dentry = readdir(dir))) { 1329 while ((dentry = readdir(dir))) {
1116 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 1330 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
1117 continue; 1331 continue;
1119 if (len >= sizeof(buf)) { 1333 if (len >= sizeof(buf)) {
1120 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path, 1334 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
1121 (unsigned long)len, (unsigned long)sizeof(buf)); 1335 (unsigned long)len, (unsigned long)sizeof(buf));
1122 continue; 1336 continue;
1123 } 1337 }
1124 sprintf(buf, "%s/%s", path, dentry->d_name); 1338 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name);
1125 if (lstat(buf, &st) != -1) { 1339 if (lstat(buf, &st) != -1) {
1126 if (S_ISREG(st.st_mode)) 1340 if (S_ISREG(st.st_mode))
1127 scanelf_file(buf); 1341 scanelf_file(buf);
1128 else if (dir_recurse && S_ISDIR(st.st_mode)) { 1342 else if (dir_recurse && S_ISDIR(st.st_mode)) {
1129 if (dir_crossmount || (st_top.st_dev == st.st_dev)) 1343 if (dir_crossmount || (st_top.st_dev == st.st_dev))
1132 } 1346 }
1133 } 1347 }
1134 closedir(dir); 1348 closedir(dir);
1135} 1349}
1136 1350
1137static int scanelf_from_file(char *filename) 1351static int scanelf_from_file(const char *filename)
1138{ 1352{
1139 FILE *fp = NULL; 1353 FILE *fp = NULL;
1140 char *p; 1354 char *p;
1141 char path[__PAX_UTILS_PATH_MAX]; 1355 char path[__PAX_UTILS_PATH_MAX];
1142 1356
1143 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL)) 1357 if (strcmp(filename, "-") == 0)
1144 fp = stdin; 1358 fp = stdin;
1145 else if ((fp = fopen(filename, "r")) == NULL) 1359 else if ((fp = fopen(filename, "r")) == NULL)
1146 return 1; 1360 return 1;
1147 1361
1148 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) { 1362 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1154 if (fp != stdin) 1368 if (fp != stdin)
1155 fclose(fp); 1369 fclose(fp);
1156 return 0; 1370 return 0;
1157} 1371}
1158 1372
1159static void load_ld_so_conf() 1373#if defined(__GLIBC__) || defined(__UCLIBC__)
1374static int load_ld_so_conf(int i, const char *fname)
1160{ 1375{
1161 FILE *fp = NULL; 1376 FILE *fp = NULL;
1162 char *p; 1377 char *p;
1163 char path[__PAX_UTILS_PATH_MAX]; 1378 char path[__PAX_UTILS_PATH_MAX];
1164 int i = 0;
1165 1379
1166 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 1380 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
1167 return; 1381 return i;
1382
1383 if ((fp = fopen(fname, "r")) == NULL)
1384 return i;
1168 1385
1169 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) { 1386 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1170 if (*path != '/')
1171 continue;
1172
1173 if ((p = strrchr(path, '\r')) != NULL) 1387 if ((p = strrchr(path, '\r')) != NULL)
1174 *p = 0; 1388 *p = 0;
1175 if ((p = strchr(path, '\n')) != NULL) 1389 if ((p = strchr(path, '\n')) != NULL)
1176 *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;
1177 1422
1178 ldpaths[i++] = xstrdup(path); 1423 ldpaths[i++] = xstrdup(path);
1179 1424
1180 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths)) 1425 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
1181 break; 1426 break;
1182 } 1427 }
1183 ldpaths[i] = NULL; 1428 ldpaths[i] = NULL;
1184 1429
1185 fclose(fp); 1430 fclose(fp);
1431 return i;
1186} 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
1187 1477
1188/* scan /etc/ld.so.conf for paths */ 1478/* scan /etc/ld.so.conf for paths */
1189static void scanelf_ldpath() 1479static void scanelf_ldpath()
1190{ 1480{
1191 char scan_l, scan_ul, scan_ull; 1481 char scan_l, scan_ul, scan_ull;
1225 } 1515 }
1226 1516
1227 free(path); 1517 free(path);
1228} 1518}
1229 1519
1230
1231/* usage / invocation handling functions */ 1520/* usage / invocation handling functions */
1232#define PARSE_FLAGS "plRmyAXxetrnLibSs:gN:TaqvF:f:o:BhV" 1521#define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:BhV"
1233#define a_argument required_argument 1522#define a_argument required_argument
1234static struct option const long_opts[] = { 1523static struct option const long_opts[] = {
1235 {"path", no_argument, NULL, 'p'}, 1524 {"path", no_argument, NULL, 'p'},
1236 {"ldpath", no_argument, NULL, 'l'}, 1525 {"ldpath", no_argument, NULL, 'l'},
1237 {"recursive", no_argument, NULL, 'R'}, 1526 {"recursive", no_argument, NULL, 'R'},
1238 {"mount", no_argument, NULL, 'm'}, 1527 {"mount", no_argument, NULL, 'm'},
1239 {"symlink", no_argument, NULL, 'y'}, 1528 {"symlink", no_argument, NULL, 'y'},
1240 {"archives", no_argument, NULL, 'A'}, 1529 {"archives", no_argument, NULL, 'A'},
1241 {"ldcache", no_argument, NULL, 'L'}, 1530 {"ldcache", no_argument, NULL, 'L'},
1242 {"fix", no_argument, NULL, 'X'}, 1531 {"fix", no_argument, NULL, 'X'},
1532 {"setpax", a_argument, NULL, 'z'},
1243 {"pax", no_argument, NULL, 'x'}, 1533 {"pax", no_argument, NULL, 'x'},
1244 {"header", no_argument, NULL, 'e'}, 1534 {"header", no_argument, NULL, 'e'},
1245 {"textrel", no_argument, NULL, 't'}, 1535 {"textrel", no_argument, NULL, 't'},
1246 {"rpath", no_argument, NULL, 'r'}, 1536 {"rpath", no_argument, NULL, 'r'},
1247 {"needed", no_argument, NULL, 'n'}, 1537 {"needed", no_argument, NULL, 'n'},
1248 {"interp", no_argument, NULL, 'i'}, 1538 {"interp", no_argument, NULL, 'i'},
1249 {"bind", no_argument, NULL, 'b'}, 1539 {"bind", no_argument, NULL, 'b'},
1250 {"soname", no_argument, NULL, 'S'}, 1540 {"soname", no_argument, NULL, 'S'},
1251 {"symbol", a_argument, NULL, 's'}, 1541 {"symbol", a_argument, NULL, 's'},
1542 {"section", a_argument, NULL, 'k'},
1252 {"lib", a_argument, NULL, 'N'}, 1543 {"lib", a_argument, NULL, 'N'},
1253 {"gmatch", no_argument, NULL, 'g'}, 1544 {"gmatch", no_argument, NULL, 'g'},
1254 {"textrels", no_argument, NULL, 'T'}, 1545 {"textrels", no_argument, NULL, 'T'},
1546 {"etype", a_argument, NULL, 'E'},
1547 {"bits", a_argument, NULL, 'M'},
1255 {"all", no_argument, NULL, 'a'}, 1548 {"all", no_argument, NULL, 'a'},
1256 {"quiet", no_argument, NULL, 'q'}, 1549 {"quiet", no_argument, NULL, 'q'},
1257 {"verbose", no_argument, NULL, 'v'}, 1550 {"verbose", no_argument, NULL, 'v'},
1258 {"format", a_argument, NULL, 'F'}, 1551 {"format", a_argument, NULL, 'F'},
1259 {"from", a_argument, NULL, 'f'}, 1552 {"from", a_argument, NULL, 'f'},
1270 "Scan directories recursively", 1563 "Scan directories recursively",
1271 "Don't recursively cross mount points", 1564 "Don't recursively cross mount points",
1272 "Don't scan symlinks", 1565 "Don't scan symlinks",
1273 "Scan archives (.a files)", 1566 "Scan archives (.a files)",
1274 "Utilize ld.so.cache information (use with -r/-n)", 1567 "Utilize ld.so.cache information (use with -r/-n)",
1275 "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",
1276 "Print PaX markings", 1570 "Print PaX markings",
1277 "Print GNU_STACK/PT_LOAD markings", 1571 "Print GNU_STACK/PT_LOAD markings",
1278 "Print TEXTREL information", 1572 "Print TEXTREL information",
1279 "Print RPATH information", 1573 "Print RPATH information",
1280 "Print NEEDED information", 1574 "Print NEEDED information",
1281 "Print INTERP information", 1575 "Print INTERP information",
1282 "Print BIND information", 1576 "Print BIND information",
1283 "Print SONAME information", 1577 "Print SONAME information",
1284 "Find a specified symbol", 1578 "Find a specified symbol",
1579 "Find a specified section",
1285 "Find a specified library", 1580 "Find a specified library",
1286 "Use strncmp to match libraries. (use with -N)", 1581 "Use strncmp to match libraries. (use with -N)",
1287 "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",
1288 "Print all scanned info (-x -e -t -r -b)\n", 1585 "Print all scanned info (-x -e -t -r -b)\n",
1289 "Only output 'bad' things", 1586 "Only output 'bad' things",
1290 "Be verbose (can be specified more than once)", 1587 "Be verbose (can be specified more than once)",
1291 "Use specified format for output", 1588 "Use specified format for output",
1292 "Read input stream from a filename", 1589 "Read input stream from a filename",
1304 printf("* Scan ELF binaries for stuff\n\n" 1601 printf("* Scan ELF binaries for stuff\n\n"
1305 "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);
1306 printf("Options: -[%s]\n", PARSE_FLAGS); 1603 printf("Options: -[%s]\n", PARSE_FLAGS);
1307 for (i = 0; long_opts[i].name; ++i) 1604 for (i = 0; long_opts[i].name; ++i)
1308 if (long_opts[i].has_arg == no_argument) 1605 if (long_opts[i].has_arg == no_argument)
1309 printf(" -%c, --%-13s* %s\n", long_opts[i].val, 1606 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
1310 long_opts[i].name, opts_help[i]); 1607 long_opts[i].name, opts_help[i]);
1311 else 1608 else
1312 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val, 1609 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
1313 long_opts[i].name, opts_help[i]); 1610 long_opts[i].name, opts_help[i]);
1314 1611
1315 if (status != EXIT_SUCCESS) 1612 if (status != EXIT_SUCCESS)
1316 exit(status); 1613 exit(status);
1317 1614
1318 puts("\nThe format modifiers for the -F option are:"); 1615 puts("\nThe format modifiers for the -F option are:");
1319 puts(" F Filename \tx PaX Flags \te STACK/RELRO"); 1616 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
1320 puts(" t TEXTREL \tr RPATH \tn NEEDED"); 1617 puts(" t TEXTREL \tr RPATH \tn NEEDED");
1321 puts(" i INTERP \tb BIND \ts symbol"); 1618 puts(" i INTERP \tb BIND \ts symbol");
1322 puts(" N library \to Type \tT TEXTRELs"); 1619 puts(" N library \to Type \tT TEXTRELs");
1323 puts(" S SONAME"); 1620 puts(" S SONAME \tk section");
1324 puts(" p filename (with search path removed)"); 1621 puts(" p filename (with search path removed)");
1325 puts(" f filename (short name/basename)"); 1622 puts(" f filename (short name/basename)");
1326 puts("Prefix each modifier with '%' (verbose) or '#' (silent)"); 1623 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1327 1624
1625 puts("\nELF Etypes:");
1626 print_etypes(stdout);
1627
1328 exit(status); 1628 exit(status);
1329} 1629}
1330 1630
1331/* parse command line arguments and preform needed actions */ 1631/* parse command line arguments and preform needed actions */
1332static void parseargs(int argc, char *argv[]) 1632static void parseargs(int argc, char *argv[])
1333{ 1633{
1334 int i; 1634 int i;
1335 char *from_file = NULL; 1635 const char *from_file = NULL;
1336 1636
1337 opterr = 0; 1637 opterr = 0;
1338 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) {
1339 switch (i) { 1639 switch (i) {
1340 1640
1347 case 'h': usage(EXIT_SUCCESS); break; 1647 case 'h': usage(EXIT_SUCCESS); break;
1348 case 'f': 1648 case 'f':
1349 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");
1350 from_file = optarg; 1650 from_file = optarg;
1351 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;
1352 case 'o': { 1658 case 'o': {
1353 FILE *fp = NULL;
1354 if ((fp = freopen(optarg, "w", stdout)) == NULL) 1659 if (freopen(optarg, "w", stdout) == NULL)
1355 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1660 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1356 SET_STDOUT(fp);
1357 break; 1661 break;
1358 } 1662 }
1359 1663 case 'k':
1664 if (find_section) warn("You prob don't want to specify -k twice");
1665 find_section = optarg;
1666 break;
1360 case 's': { 1667 case 's': {
1361 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");
1362 find_sym = optarg; 1669 find_sym = optarg;
1363 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1)); 1670 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1364 sprintf(versioned_symname, "%s@", find_sym); 1671 sprintf(versioned_symname, "%s@", find_sym);
1373 case 'F': { 1680 case 'F': {
1374 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");
1375 out_format = optarg; 1682 out_format = optarg;
1376 break; 1683 break;
1377 } 1684 }
1685 case 'z': {
1686 unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC);
1687 size_t x;
1378 1688
1379 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;
1380 case 'L': use_ldcache = 1; break; 1729 case 'L': use_ldcache = 1; break;
1381 case 'y': scan_symlink = 0; break; 1730 case 'y': scan_symlink = 0; break;
1382 case 'A': scan_archives = 1; break; 1731 case 'A': scan_archives = 1; break;
1383 case 'B': show_banner = 0; break; 1732 case 'B': show_banner = 0; break;
1384 case 'l': scan_ldpath = 1; break; 1733 case 'l': scan_ldpath = 1; break;
1398 case 'q': be_quiet = 1; break; 1747 case 'q': be_quiet = 1; break;
1399 case 'v': be_verbose = (be_verbose % 20) + 1; break; 1748 case 'v': be_verbose = (be_verbose % 20) + 1; break;
1400 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;
1401 1750
1402 case ':': 1751 case ':':
1403 err("Option missing parameter\n"); 1752 err("Option '%c' is missing parameter", optopt);
1404 case '?': 1753 case '?':
1405 err("Unknown option\n"); 1754 err("Unknown option '%c' or argument missing", optopt);
1406 default: 1755 default:
1407 err("Unhandled option '%c'", i); 1756 err("Unhandled option '%c'; please report this", i);
1408 } 1757 }
1409 } 1758 }
1410 1759
1411 /* let the format option override all other options */ 1760 /* let the format option override all other options */
1412 if (out_format) { 1761 if (out_format) {
1415 show_textrels = 0; 1764 show_textrels = 0;
1416 for (i = 0; out_format[i]; ++i) { 1765 for (i = 0; out_format[i]; ++i) {
1417 if (!IS_MODIFIER(out_format[i])) continue; 1766 if (!IS_MODIFIER(out_format[i])) continue;
1418 1767
1419 switch (out_format[++i]) { 1768 switch (out_format[++i]) {
1769 case '+': break;
1420 case '%': break; 1770 case '%': break;
1421 case '#': break; 1771 case '#': break;
1422 case 'F': break; 1772 case 'F': break;
1423 case 'p': break; 1773 case 'p': break;
1424 case 'f': break; 1774 case 'f': break;
1775 case 'k': break;
1425 case 's': break; 1776 case 's': break;
1426 case 'N': break; 1777 case 'N': break;
1427 case 'o': break; 1778 case 'o': break;
1428 case 'x': show_pax = 1; break; 1779 case 'x': show_pax = 1; break;
1429 case 'e': show_phdr = 1; break; 1780 case 'e': show_phdr = 1; break;
1453 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 1804 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1454 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len); 1805 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1455 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len); 1806 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1456 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len); 1807 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1457 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);
1458 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len); 1810 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1459 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 1811 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1460 } 1812 }
1461 if (be_verbose > 2) printf("Format: %s\n", out_format); 1813 if (be_verbose > 2) printf("Format: %s\n", out_format);
1462 1814
1463 /* now lets actually do the scanning */ 1815 /* now lets actually do the scanning */
1464 if (scan_ldpath || use_ldcache) 1816 if (scan_ldpath || use_ldcache)
1465 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
1466 if (scan_ldpath) scanelf_ldpath(); 1822 if (scan_ldpath) scanelf_ldpath();
1467 if (scan_envpath) scanelf_envpath(); 1823 if (scan_envpath) scanelf_envpath();
1824 if (!from_file && optind == argc && ttyname(0) == NULL)
1825 from_file = "-";
1468 if (from_file) { 1826 if (from_file) {
1469 scanelf_from_file(from_file); 1827 scanelf_from_file(from_file);
1470 from_file = *argv; 1828 from_file = *argv;
1471 } 1829 }
1472 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file) 1830 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1483 1841
1484 if (ldcache != 0) 1842 if (ldcache != 0)
1485 munmap(ldcache, ldcache_size); 1843 munmap(ldcache, ldcache_size);
1486} 1844}
1487 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;
1488 1852
1853 if ((env = getenv(envvar)) == NULL)
1854 return NULL;
1489 1855
1490/* utility funcs */ 1856 env = xstrdup(env);
1491static char *xstrdup(const char *s) 1857 if (env == NULL)
1492{ 1858 return NULL;
1493 char *ret = strdup(s);
1494 if (!ret) err("Could not strdup(): %s", strerror(errno));
1495 return ret;
1496}
1497static void *xmalloc(size_t size)
1498{
1499 void *ret = malloc(size);
1500 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1501 return ret;
1502}
1503static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
1504{
1505 size_t new_len;
1506 1859
1507 new_len = strlen(*dst) + strlen(src); 1860 nentry = 0;
1508 if (*curr_len <= new_len) { 1861 for (s = strtok_r(env, " \t\n", &saveptr); s != NULL; s = strtok_r(NULL, " \t\n", &saveptr)) {
1509 *curr_len = new_len + (*curr_len / 2); 1862 if ((envvals = xrealloc(envvals, sizeof(char *)*(nentry+1))) == NULL)
1510 *dst = realloc(*dst, *curr_len); 1863 return NULL;
1511 if (!*dst) 1864 envvals[nentry++] = s;
1512 err("could not realloc() %li bytes", (unsigned long)*curr_len);
1513 } 1865 }
1866 envvals[nentry] = NULL;
1514 1867
1515 if (n) 1868 return envvals;
1516 strncat(*dst, src, n);
1517 else
1518 strcat(*dst, src);
1519} 1869}
1520static inline void xchrcat(char **dst, const char append, size_t *curr_len) 1870
1521{ 1871static void parseenv() {
1522 static char my_app[2]; 1872 qa_textrels=get_split_env("QA_TEXTRELS");
1523 my_app[0] = append; 1873 qa_execstack=get_split_env("QA_EXECSTACK");
1524 my_app[1] = '\0'; 1874 qa_wx_load=get_split_env("QA_WX_LOAD");
1525 xstrcat(dst, my_app, curr_len);
1526} 1875}
1527 1876
1528 1877
1529 1878
1530int main(int argc, char *argv[]) 1879int main(int argc, char *argv[])
1531{ 1880{
1532 if (argc < 2) 1881 if (argc < 2)
1533 usage(EXIT_FAILURE); 1882 usage(EXIT_FAILURE);
1883 parseenv();
1534 parseargs(argc, argv); 1884 parseargs(argc, argv);
1535 fclose(stdout); 1885 fclose(stdout);
1536#ifdef __BOUNDS_CHECKING_ON 1886#ifdef __BOUNDS_CHECKING_ON
1537 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()");
1538#endif 1888#endif

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

  ViewVC Help
Powered by ViewVC 1.1.20