/[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.117 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.117 2006/01/28 19:47:47 solar 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.117 2006/01/28 19:47:47 solar 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) { \
177 if (ehdr->e_type == ET_DYN || ehdr->e_type == ET_EXEC) \ 289 if (ehdr->e_type == ET_DYN || ehdr->e_type == ET_EXEC) \
178 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)) {\
179 found = found_load; \ 292 found = found_load; \
180 offset = 8; \ 293 offset = 8; \
181 check_flags = PF_W|PF_X; \ 294 check_flags = PF_W|PF_X; \
295 } else continue; \
182 } else \ 296 } else \
183 continue; \ 297 continue; \
184 flags = EGET(phdr[i].p_flags); \ 298 flags = EGET(phdr[i].p_flags); \
185 if (be_quiet && ((flags & check_flags) != check_flags)) \ 299 if (be_quiet && ((flags & check_flags) != check_flags)) \
186 continue; \ 300 continue; \
187 if (fix_elf && ((flags & PF_X) != flags)) { \ 301 if ((EGET(phdr[i].p_type) != PT_LOAD) && (fix_elf && ((flags & PF_X) != flags))) { \
188 ESET(phdr[i].p_flags, flags & (PF_X ^ (size_t)-1)); \ 302 ESET(phdr[i].p_flags, flags & (PF_X ^ (size_t)-1)); \
189 ret[3] = ret[7] = '!'; \ 303 ret[3] = ret[7] = '!'; \
190 flags = EGET(phdr[i].p_flags); \ 304 flags = EGET(phdr[i].p_flags); \
191 } \ 305 } \
192 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \ 306 memcpy(ret+offset, gnu_short_stack_flags(flags), 3); \
196 } else if (elf->shdr != NULL) { \ 310 } else if (elf->shdr != NULL) { \
197 /* no program headers which means this is prob an object file */ \ 311 /* no program headers which means this is prob an object file */ \
198 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \ 312 Elf ## B ## _Shdr *shdr = SHDR ## B (elf->shdr); \
199 Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \ 313 Elf ## B ## _Shdr *strtbl = shdr + EGET(ehdr->e_shstrndx); \
200 char *str; \ 314 char *str; \
201 if ((void*)strtbl > (void*)(elf->data + sizeof(*strtbl))) \ 315 if ((void*)strtbl > (void*)elf->data_end) \
202 goto skip_this_shdr##B; \ 316 goto skip_this_shdr##B; \
203 check_flags = SHF_WRITE|SHF_EXECINSTR; \ 317 check_flags = SHF_WRITE|SHF_EXECINSTR; \
204 for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \ 318 for (i = 0; i < EGET(ehdr->e_shnum); ++i) { \
205 if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \ 319 if (EGET(shdr[i].sh_type) != SHT_PROGBITS) continue; \
206 offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \ 320 offset = EGET(strtbl->sh_offset) + EGET(shdr[i].sh_name); \
234 if (be_wewy_wewy_quiet || (be_quiet && !shown)) 348 if (be_wewy_wewy_quiet || (be_quiet && !shown))
235 return NULL; 349 return NULL;
236 else 350 else
237 return ret; 351 return ret;
238} 352}
353
239static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel) 354static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel)
240{ 355{
241 static const char *ret = "TEXTREL"; 356 static const char *ret = "TEXTREL";
242 unsigned long i; 357 unsigned long i;
243 358
244 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;
245 362
246 if (elf->phdr) { 363 if (elf->phdr) {
247#define SHOW_TEXTREL(B) \ 364#define SHOW_TEXTREL(B) \
248 if (elf->elf_class == ELFCLASS ## B) { \ 365 if (elf->elf_class == ELFCLASS ## B) { \
249 Elf ## B ## _Dyn *dyn; \ 366 Elf ## B ## _Dyn *dyn; \
563#define FLAG_POWERPC_LIB64 0x0500 680#define FLAG_POWERPC_LIB64 0x0500
564#define FLAG_MIPS64_LIBN32 0x0600 681#define FLAG_MIPS64_LIBN32 0x0600
565#define FLAG_MIPS64_LIBN64 0x0700 682#define FLAG_MIPS64_LIBN64 0x0700
566 683
567static char *lookup_cache_lib(elfobj *, char *); 684static char *lookup_cache_lib(elfobj *, char *);
685#if defined(__GLIBC__) || defined(__UCLIBC__)
568static char *lookup_cache_lib(elfobj *elf, char *fname) 686static char *lookup_cache_lib(elfobj *elf, char *fname)
569{ 687{
570 int fd = 0; 688 int fd = 0;
571 char *strs; 689 char *strs;
572 static char buf[__PAX_UTILS_PATH_MAX] = ""; 690 static char buf[__PAX_UTILS_PATH_MAX] = "";
628 continue; 746 continue;
629 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf)); 747 strncpy(buf, strs + libent[fd].liboffset, sizeof(buf));
630 } 748 }
631 return buf; 749 return buf;
632} 750}
633 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
634 758
635static 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)
636{ 760{
637 unsigned long i; 761 unsigned long i;
638 char *needed; 762 char *needed;
713} 837}
714static char *scanelf_file_bind(elfobj *elf, char *found_bind) 838static char *scanelf_file_bind(elfobj *elf, char *found_bind)
715{ 839{
716 unsigned long i; 840 unsigned long i;
717 struct stat s; 841 struct stat s;
842 char dynamic = 0;
718 843
719 if (!show_bind) return NULL; 844 if (!show_bind) return NULL;
720 if (!elf->phdr) return NULL; 845 if (!elf->phdr) return NULL;
721 846
722#define SHOW_BIND(B) \ 847#define SHOW_BIND(B) \
725 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \ 850 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
726 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \ 851 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
727 Elf ## B ## _Off offset; \ 852 Elf ## B ## _Off offset; \
728 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \ 853 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
729 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \ 854 if (EGET(phdr[i].p_type) != PT_DYNAMIC) continue; \
855 dynamic = 1; \
730 offset = EGET(phdr[i].p_offset); \ 856 offset = EGET(phdr[i].p_offset); \
731 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \ 857 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) continue; \
732 dyn = DYN ## B (elf->data + offset); \ 858 dyn = DYN ## B (elf->data + offset); \
733 while (EGET(dyn->d_tag) != DT_NULL) { \ 859 while (EGET(dyn->d_tag) != DT_NULL) { \
734 if (EGET(dyn->d_tag) == DT_BIND_NOW || \ 860 if (EGET(dyn->d_tag) == DT_BIND_NOW || \
749 875
750 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)) {
751 return NULL; 877 return NULL;
752 } else { 878 } else {
753 *found_bind = 1; 879 *found_bind = 1;
754 return (char *) "LAZY"; 880 return (char *) (dynamic ? "LAZY" : "STATIC");
755 } 881 }
756} 882}
757static char *scanelf_file_soname(elfobj *elf, char *found_soname) 883static char *scanelf_file_soname(elfobj *elf, char *found_soname)
758{ 884{
759 unsigned long i; 885 unsigned long i;
821 char *symname; \ 947 char *symname; \
822 if (cnt) \ 948 if (cnt) \
823 cnt = EGET(symtab->sh_size) / cnt; \ 949 cnt = EGET(symtab->sh_size) / cnt; \
824 for (i = 0; i < cnt; ++i) { \ 950 for (i = 0; i < cnt; ++i) { \
825 if (sym->st_name) { \ 951 if (sym->st_name) { \
952 /* make sure the symbol name is in acceptable memory range */ \
826 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)); \
827 if ((void*)symname > (void*)elf->data_end) { \ 954 if ((void*)symname > (void*)elf->data_end) { \
828 warnf("%s: corrupt ELF symbols", elf->filename); \ 955 warnf("%s: corrupt ELF symbols", elf->filename); \
956 ++sym; \
829 continue; \ 957 continue; \
830 } \ 958 } \
959 /* debug display ... show all symbols and some extra info */ \
831 if (*find_sym == '*') { \ 960 if (*ret == '*') { \
832 printf("%s(%s) %5lX %15s %s\n", \ 961 printf("%s(%s) %5lX %15s %s\n", \
833 ((*found_sym == 0) ? "\n\t" : "\t"), \ 962 ((*found_sym == 0) ? "\n\t" : "\t"), \
834 elf->base_filename, \ 963 elf->base_filename, \
835 (unsigned long)sym->st_size, \ 964 (unsigned long)sym->st_size, \
836 get_elfstttype(sym->st_info), \ 965 get_elfstttype(sym->st_info), \
837 symname); \ 966 symname); \
838 *found_sym = 1; \ 967 *found_sym = 1; \
839 } else { \ 968 } else { \
969 /* allow the user to specify a comma delimited list of symbols to search for */ \
840 char *this_sym, *next_sym; \ 970 char *this_sym, *next_sym; \
841 this_sym = find_sym; \ 971 this_sym = ret; \
842 do { \ 972 do { \
843 next_sym = strchr(this_sym, ','); \ 973 next_sym = strchr(this_sym, ','); \
844 if (next_sym == NULL) \ 974 if (next_sym == NULL) \
845 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 */ \
846 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') || \
847 (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 \
848 ret = this_sym; \ 996 ret = this_sym; \
849 (*found_sym)++; \ 997 (*found_sym)++; \
850 goto break_out; \ 998 goto break_out; \
851 } \ 999 } \
852 this_sym = next_sym + 1; \ 1000 skip_this_sym##B: this_sym = next_sym + 1; \
853 } while (*next_sym != '\0'); \ 1001 } while (*next_sym != '\0'); \
854 } \ 1002 } \
855 } \ 1003 } \
856 ++sym; \ 1004 ++sym; \
857 } } 1005 } }
867 if (be_quiet) 1015 if (be_quiet)
868 return NULL; 1016 return NULL;
869 else 1017 else
870 return (char *)" - "; 1018 return (char *)" - ";
871} 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
872/* scan an elf file and show all the fun stuff */ 1051/* scan an elf file and show all the fun stuff */
873#define prints(str) write(fileno(stdout), str, strlen(str)) 1052#define prints(str) write(fileno(stdout), str, strlen(str))
874static int scanelf_elfobj(elfobj *elf) 1053static int scanelf_elfobj(elfobj *elf)
875{ 1054{
876 unsigned long i; 1055 unsigned long i;
877 char found_pax, found_phdr, found_relro, found_load, found_textrel, 1056 char found_pax, found_phdr, found_relro, found_load, found_textrel,
878 found_rpath, found_needed, found_interp, found_bind, found_soname, 1057 found_rpath, found_needed, found_interp, found_bind, found_soname,
879 found_sym, found_lib, found_file, found_textrels; 1058 found_sym, found_lib, found_file, found_textrels, found_section;
880 static char *out_buffer = NULL; 1059 static char *out_buffer = NULL;
881 static size_t out_len; 1060 static size_t out_len;
882 1061
883 found_pax = found_phdr = found_relro = found_load = found_textrel = \ 1062 found_pax = found_phdr = found_relro = found_load = found_textrel = \
884 found_rpath = found_needed = found_interp = found_bind = found_soname = \ 1063 found_rpath = found_needed = found_interp = found_bind = found_soname = \
885 found_sym = found_lib = found_file = found_textrels = 0; 1064 found_sym = found_lib = found_file = found_textrels = found_section = 0;
886 1065
887 if (be_verbose > 2) 1066 if (be_verbose > 2)
888 printf("%s: scanning file {%s,%s}\n", elf->filename, 1067 printf("%s: scanning file {%s,%s}\n", elf->filename,
889 get_elfeitype(EI_CLASS, elf->elf_class), 1068 get_elfeitype(EI_CLASS, elf->elf_class),
890 get_elfeitype(EI_DATA, elf->data[EI_DATA])); 1069 get_elfeitype(EI_DATA, elf->data[EI_DATA]));
902 if (!be_quiet && show_banner) { 1081 if (!be_quiet && show_banner) {
903 for (i = 0; out_format[i]; ++i) { 1082 for (i = 0; out_format[i]; ++i) {
904 if (!IS_MODIFIER(out_format[i])) continue; 1083 if (!IS_MODIFIER(out_format[i])) continue;
905 1084
906 switch (out_format[++i]) { 1085 switch (out_format[++i]) {
1086 case '+': break;
907 case '%': break; 1087 case '%': break;
908 case '#': break; 1088 case '#': break;
909 case 'F': 1089 case 'F':
910 case 'p': 1090 case 'p':
911 case 'f': prints("FILE "); found_file = 1; break; 1091 case 'f': prints("FILE "); found_file = 1; break;
919 case 'b': prints("BIND "); break; 1099 case 'b': prints("BIND "); break;
920 case 'S': prints("SONAME "); break; 1100 case 'S': prints("SONAME "); break;
921 case 's': prints("SYM "); break; 1101 case 's': prints("SYM "); break;
922 case 'N': prints("LIB "); break; 1102 case 'N': prints("LIB "); break;
923 case 'T': prints("TEXTRELS "); break; 1103 case 'T': prints("TEXTRELS "); break;
1104 case 'k': prints("SECTION "); break;
924 default: warnf("'%c' has no title ?", out_format[i]); 1105 default: warnf("'%c' has no title ?", out_format[i]);
925 } 1106 }
926 } 1107 }
927 if (!found_file) prints("FILE "); 1108 if (!found_file) prints("FILE ");
928 prints("\n"); 1109 prints("\n");
933 /* dump all the good stuff */ 1114 /* dump all the good stuff */
934 for (i = 0; out_format[i]; ++i) { 1115 for (i = 0; out_format[i]; ++i) {
935 const char *out; 1116 const char *out;
936 const char *tmp; 1117 const char *tmp;
937 1118
938 /* make sure we trim leading spaces in quiet mode */
939 if (be_quiet && *out_buffer == ' ' && !out_buffer[1])
940 *out_buffer = '\0';
941
942 if (!IS_MODIFIER(out_format[i])) { 1119 if (!IS_MODIFIER(out_format[i])) {
943 xchrcat(&out_buffer, out_format[i], &out_len); 1120 xchrcat(&out_buffer, out_format[i], &out_len);
944 continue; 1121 continue;
945 } 1122 }
946 1123
947 out = NULL; 1124 out = NULL;
948 be_wewy_wewy_quiet = (out_format[i] == '#'); 1125 be_wewy_wewy_quiet = (out_format[i] == '#');
1126 be_semi_verbose = (out_format[i] == '+');
949 switch (out_format[++i]) { 1127 switch (out_format[++i]) {
1128 case '+':
950 case '%': 1129 case '%':
951 case '#': 1130 case '#':
952 xchrcat(&out_buffer, out_format[i], &out_len); break; 1131 xchrcat(&out_buffer, out_format[i], &out_len); break;
953 case 'F': 1132 case 'F':
954 found_file = 1; 1133 found_file = 1;
986 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;
987 case 'i': out = scanelf_file_interp(elf, &found_interp); break; 1166 case 'i': out = scanelf_file_interp(elf, &found_interp); break;
988 case 'b': out = scanelf_file_bind(elf, &found_bind); break; 1167 case 'b': out = scanelf_file_bind(elf, &found_bind); break;
989 case 'S': out = scanelf_file_soname(elf, &found_soname); break; 1168 case 'S': out = scanelf_file_soname(elf, &found_soname); break;
990 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;
991 default: warnf("'%c' has no scan code?", out_format[i]); 1171 default: warnf("'%c' has no scan code?", out_format[i]);
992 } 1172 }
993 if (out) { 1173 if (out) {
994 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */ 1174 /* hack for comma delimited output like `scanelf -s sym1,sym2,sym3` */
995 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL) 1175 if (out_format[i] == 's' && (tmp=strchr(out,',')) != NULL)
1000 } 1180 }
1001 1181
1002#define FOUND_SOMETHING() \ 1182#define FOUND_SOMETHING() \
1003 (found_pax || found_phdr || found_relro || found_load || found_textrel || \ 1183 (found_pax || found_phdr || found_relro || found_load || found_textrel || \
1004 found_rpath || found_needed || found_interp || found_bind || \ 1184 found_rpath || found_needed || found_interp || found_bind || \
1005 found_soname || found_sym || found_lib || found_textrels) 1185 found_soname || found_sym || found_lib || found_textrels || found_section )
1006 1186
1007 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) { 1187 if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) {
1008 xchrcat(&out_buffer, ' ', &out_len); 1188 xchrcat(&out_buffer, ' ', &out_len);
1009 xstrcat(&out_buffer, elf->filename, &out_len); 1189 xstrcat(&out_buffer, elf->filename, &out_len);
1010 } 1190 }
1017} 1197}
1018 1198
1019/* scan a single elf */ 1199/* scan a single elf */
1020static int scanelf_elf(const char *filename, int fd, size_t len) 1200static int scanelf_elf(const char *filename, int fd, size_t len)
1021{ 1201{
1022 int ret; 1202 int ret = 1;
1023 elfobj *elf; 1203 elfobj *elf;
1024 1204
1025 /* verify this is real ELF */ 1205 /* verify this is real ELF */
1026 if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) { 1206 if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) {
1027 if (be_verbose > 2) printf("%s: not an ELF\n", filename); 1207 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
1028 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 }
1029 } 1231 }
1232 if (etype_lookup(sbuf) != get_etype(elf))
1233 goto label_done;
1234 }
1030 1235
1236label_ret:
1031 ret = scanelf_elfobj(elf); 1237 ret = scanelf_elfobj(elf);
1238
1239label_done:
1032 unreadelf(elf); 1240 unreadelf(elf);
1033 return ret; 1241 return ret;
1034} 1242}
1243
1035/* scan an archive of elfs */ 1244/* scan an archive of elfs */
1036static int scanelf_archive(const char *filename, int fd, size_t len) 1245static int scanelf_archive(const char *filename, int fd, size_t len)
1037{ 1246{
1038 archive_handle *ar; 1247 archive_handle *ar;
1039 archive_member *m; 1248 archive_member *m;
1124 if (len >= sizeof(buf)) { 1333 if (len >= sizeof(buf)) {
1125 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path, 1334 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
1126 (unsigned long)len, (unsigned long)sizeof(buf)); 1335 (unsigned long)len, (unsigned long)sizeof(buf));
1127 continue; 1336 continue;
1128 } 1337 }
1129 sprintf(buf, "%s/%s", path, dentry->d_name); 1338 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name);
1130 if (lstat(buf, &st) != -1) { 1339 if (lstat(buf, &st) != -1) {
1131 if (S_ISREG(st.st_mode)) 1340 if (S_ISREG(st.st_mode))
1132 scanelf_file(buf); 1341 scanelf_file(buf);
1133 else if (dir_recurse && S_ISDIR(st.st_mode)) { 1342 else if (dir_recurse && S_ISDIR(st.st_mode)) {
1134 if (dir_crossmount || (st_top.st_dev == st.st_dev)) 1343 if (dir_crossmount || (st_top.st_dev == st.st_dev))
1137 } 1346 }
1138 } 1347 }
1139 closedir(dir); 1348 closedir(dir);
1140} 1349}
1141 1350
1142static int scanelf_from_file(char *filename) 1351static int scanelf_from_file(const char *filename)
1143{ 1352{
1144 FILE *fp = NULL; 1353 FILE *fp = NULL;
1145 char *p; 1354 char *p;
1146 char path[__PAX_UTILS_PATH_MAX]; 1355 char path[__PAX_UTILS_PATH_MAX];
1147 1356
1148 if (((strcmp(filename, "-")) == 0) && (ttyname(0) == NULL)) 1357 if (strcmp(filename, "-") == 0)
1149 fp = stdin; 1358 fp = stdin;
1150 else if ((fp = fopen(filename, "r")) == NULL) 1359 else if ((fp = fopen(filename, "r")) == NULL)
1151 return 1; 1360 return 1;
1152 1361
1153 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) { 1362 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1159 if (fp != stdin) 1368 if (fp != stdin)
1160 fclose(fp); 1369 fclose(fp);
1161 return 0; 1370 return 0;
1162} 1371}
1163 1372
1164static void load_ld_so_conf() 1373#if defined(__GLIBC__) || defined(__UCLIBC__)
1374static int load_ld_so_conf(int i, const char *fname)
1165{ 1375{
1166 FILE *fp = NULL; 1376 FILE *fp = NULL;
1167 char *p; 1377 char *p;
1168 char path[__PAX_UTILS_PATH_MAX]; 1378 char path[__PAX_UTILS_PATH_MAX];
1169 int i = 0;
1170 1379
1171 if ((fp = fopen("/etc/ld.so.conf", "r")) == NULL) 1380 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
1172 return; 1381 return i;
1382
1383 if ((fp = fopen(fname, "r")) == NULL)
1384 return i;
1173 1385
1174 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) { 1386 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) {
1175 if (*path != '/')
1176 continue;
1177
1178 if ((p = strrchr(path, '\r')) != NULL) 1387 if ((p = strrchr(path, '\r')) != NULL)
1179 *p = 0; 1388 *p = 0;
1180 if ((p = strchr(path, '\n')) != NULL) 1389 if ((p = strchr(path, '\n')) != NULL)
1181 *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;
1182 1422
1183 ldpaths[i++] = xstrdup(path); 1423 ldpaths[i++] = xstrdup(path);
1184 1424
1185 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths)) 1425 if (i + 1 == sizeof(ldpaths) / sizeof(*ldpaths))
1186 break; 1426 break;
1187 } 1427 }
1188 ldpaths[i] = NULL; 1428 ldpaths[i] = NULL;
1189 1429
1190 fclose(fp); 1430 fclose(fp);
1431 return i;
1191} 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
1192 1477
1193/* scan /etc/ld.so.conf for paths */ 1478/* scan /etc/ld.so.conf for paths */
1194static void scanelf_ldpath() 1479static void scanelf_ldpath()
1195{ 1480{
1196 char scan_l, scan_ul, scan_ull; 1481 char scan_l, scan_ul, scan_ull;
1230 } 1515 }
1231 1516
1232 free(path); 1517 free(path);
1233} 1518}
1234 1519
1235
1236/* usage / invocation handling functions */ 1520/* usage / invocation handling functions */
1237#define PARSE_FLAGS "plRmyAXxetrnLibSs:gN:TaqvF:f:o:BhV" 1521#define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:BhV"
1238#define a_argument required_argument 1522#define a_argument required_argument
1239static struct option const long_opts[] = { 1523static struct option const long_opts[] = {
1240 {"path", no_argument, NULL, 'p'}, 1524 {"path", no_argument, NULL, 'p'},
1241 {"ldpath", no_argument, NULL, 'l'}, 1525 {"ldpath", no_argument, NULL, 'l'},
1242 {"recursive", no_argument, NULL, 'R'}, 1526 {"recursive", no_argument, NULL, 'R'},
1243 {"mount", no_argument, NULL, 'm'}, 1527 {"mount", no_argument, NULL, 'm'},
1244 {"symlink", no_argument, NULL, 'y'}, 1528 {"symlink", no_argument, NULL, 'y'},
1245 {"archives", no_argument, NULL, 'A'}, 1529 {"archives", no_argument, NULL, 'A'},
1246 {"ldcache", no_argument, NULL, 'L'}, 1530 {"ldcache", no_argument, NULL, 'L'},
1247 {"fix", no_argument, NULL, 'X'}, 1531 {"fix", no_argument, NULL, 'X'},
1532 {"setpax", a_argument, NULL, 'z'},
1248 {"pax", no_argument, NULL, 'x'}, 1533 {"pax", no_argument, NULL, 'x'},
1249 {"header", no_argument, NULL, 'e'}, 1534 {"header", no_argument, NULL, 'e'},
1250 {"textrel", no_argument, NULL, 't'}, 1535 {"textrel", no_argument, NULL, 't'},
1251 {"rpath", no_argument, NULL, 'r'}, 1536 {"rpath", no_argument, NULL, 'r'},
1252 {"needed", no_argument, NULL, 'n'}, 1537 {"needed", no_argument, NULL, 'n'},
1253 {"interp", no_argument, NULL, 'i'}, 1538 {"interp", no_argument, NULL, 'i'},
1254 {"bind", no_argument, NULL, 'b'}, 1539 {"bind", no_argument, NULL, 'b'},
1255 {"soname", no_argument, NULL, 'S'}, 1540 {"soname", no_argument, NULL, 'S'},
1256 {"symbol", a_argument, NULL, 's'}, 1541 {"symbol", a_argument, NULL, 's'},
1542 {"section", a_argument, NULL, 'k'},
1257 {"lib", a_argument, NULL, 'N'}, 1543 {"lib", a_argument, NULL, 'N'},
1258 {"gmatch", no_argument, NULL, 'g'}, 1544 {"gmatch", no_argument, NULL, 'g'},
1259 {"textrels", no_argument, NULL, 'T'}, 1545 {"textrels", no_argument, NULL, 'T'},
1546 {"etype", a_argument, NULL, 'E'},
1547 {"bits", a_argument, NULL, 'M'},
1260 {"all", no_argument, NULL, 'a'}, 1548 {"all", no_argument, NULL, 'a'},
1261 {"quiet", no_argument, NULL, 'q'}, 1549 {"quiet", no_argument, NULL, 'q'},
1262 {"verbose", no_argument, NULL, 'v'}, 1550 {"verbose", no_argument, NULL, 'v'},
1263 {"format", a_argument, NULL, 'F'}, 1551 {"format", a_argument, NULL, 'F'},
1264 {"from", a_argument, NULL, 'f'}, 1552 {"from", a_argument, NULL, 'f'},
1275 "Scan directories recursively", 1563 "Scan directories recursively",
1276 "Don't recursively cross mount points", 1564 "Don't recursively cross mount points",
1277 "Don't scan symlinks", 1565 "Don't scan symlinks",
1278 "Scan archives (.a files)", 1566 "Scan archives (.a files)",
1279 "Utilize ld.so.cache information (use with -r/-n)", 1567 "Utilize ld.so.cache information (use with -r/-n)",
1280 "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",
1281 "Print PaX markings", 1570 "Print PaX markings",
1282 "Print GNU_STACK/PT_LOAD markings", 1571 "Print GNU_STACK/PT_LOAD markings",
1283 "Print TEXTREL information", 1572 "Print TEXTREL information",
1284 "Print RPATH information", 1573 "Print RPATH information",
1285 "Print NEEDED information", 1574 "Print NEEDED information",
1286 "Print INTERP information", 1575 "Print INTERP information",
1287 "Print BIND information", 1576 "Print BIND information",
1288 "Print SONAME information", 1577 "Print SONAME information",
1289 "Find a specified symbol", 1578 "Find a specified symbol",
1579 "Find a specified section",
1290 "Find a specified library", 1580 "Find a specified library",
1291 "Use strncmp to match libraries. (use with -N)", 1581 "Use strncmp to match libraries. (use with -N)",
1292 "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",
1293 "Print all scanned info (-x -e -t -r -b)\n", 1585 "Print all scanned info (-x -e -t -r -b)\n",
1294 "Only output 'bad' things", 1586 "Only output 'bad' things",
1295 "Be verbose (can be specified more than once)", 1587 "Be verbose (can be specified more than once)",
1296 "Use specified format for output", 1588 "Use specified format for output",
1297 "Read input stream from a filename", 1589 "Read input stream from a filename",
1309 printf("* Scan ELF binaries for stuff\n\n" 1601 printf("* Scan ELF binaries for stuff\n\n"
1310 "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);
1311 printf("Options: -[%s]\n", PARSE_FLAGS); 1603 printf("Options: -[%s]\n", PARSE_FLAGS);
1312 for (i = 0; long_opts[i].name; ++i) 1604 for (i = 0; long_opts[i].name; ++i)
1313 if (long_opts[i].has_arg == no_argument) 1605 if (long_opts[i].has_arg == no_argument)
1314 printf(" -%c, --%-13s* %s\n", long_opts[i].val, 1606 printf(" -%c, --%-14s* %s\n", long_opts[i].val,
1315 long_opts[i].name, opts_help[i]); 1607 long_opts[i].name, opts_help[i]);
1316 else 1608 else
1317 printf(" -%c, --%-6s <arg> * %s\n", long_opts[i].val, 1609 printf(" -%c, --%-7s <arg> * %s\n", long_opts[i].val,
1318 long_opts[i].name, opts_help[i]); 1610 long_opts[i].name, opts_help[i]);
1319 1611
1320 if (status != EXIT_SUCCESS) 1612 if (status != EXIT_SUCCESS)
1321 exit(status); 1613 exit(status);
1322 1614
1323 puts("\nThe format modifiers for the -F option are:"); 1615 puts("\nThe format modifiers for the -F option are:");
1324 puts(" F Filename \tx PaX Flags \te STACK/RELRO"); 1616 puts(" F Filename \tx PaX Flags \te STACK/RELRO");
1325 puts(" t TEXTREL \tr RPATH \tn NEEDED"); 1617 puts(" t TEXTREL \tr RPATH \tn NEEDED");
1326 puts(" i INTERP \tb BIND \ts symbol"); 1618 puts(" i INTERP \tb BIND \ts symbol");
1327 puts(" N library \to Type \tT TEXTRELs"); 1619 puts(" N library \to Type \tT TEXTRELs");
1328 puts(" S SONAME"); 1620 puts(" S SONAME \tk section");
1329 puts(" p filename (with search path removed)"); 1621 puts(" p filename (with search path removed)");
1330 puts(" f filename (short name/basename)"); 1622 puts(" f filename (short name/basename)");
1331 puts("Prefix each modifier with '%' (verbose) or '#' (silent)"); 1623 puts("Prefix each modifier with '%' (verbose) or '#' (silent)");
1332 1624
1625 puts("\nELF Etypes:");
1626 print_etypes(stdout);
1627
1333 exit(status); 1628 exit(status);
1334} 1629}
1335 1630
1336/* parse command line arguments and preform needed actions */ 1631/* parse command line arguments and preform needed actions */
1337static void parseargs(int argc, char *argv[]) 1632static void parseargs(int argc, char *argv[])
1338{ 1633{
1339 int i; 1634 int i;
1340 char *from_file = NULL; 1635 const char *from_file = NULL;
1341 1636
1342 opterr = 0; 1637 opterr = 0;
1343 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) {
1344 switch (i) { 1639 switch (i) {
1345 1640
1352 case 'h': usage(EXIT_SUCCESS); break; 1647 case 'h': usage(EXIT_SUCCESS); break;
1353 case 'f': 1648 case 'f':
1354 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");
1355 from_file = optarg; 1650 from_file = optarg;
1356 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;
1357 case 'o': { 1658 case 'o': {
1358 FILE *fp = NULL;
1359 if ((fp = freopen(optarg, "w", stdout)) == NULL) 1659 if (freopen(optarg, "w", stdout) == NULL)
1360 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 1660 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1361 SET_STDOUT(fp);
1362 break; 1661 break;
1363 } 1662 }
1364 1663 case 'k':
1664 if (find_section) warn("You prob don't want to specify -k twice");
1665 find_section = optarg;
1666 break;
1365 case 's': { 1667 case 's': {
1366 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");
1367 find_sym = optarg; 1669 find_sym = optarg;
1368 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1)); 1670 versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1));
1369 sprintf(versioned_symname, "%s@", find_sym); 1671 sprintf(versioned_symname, "%s@", find_sym);
1378 case 'F': { 1680 case 'F': {
1379 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");
1380 out_format = optarg; 1682 out_format = optarg;
1381 break; 1683 break;
1382 } 1684 }
1685 case 'z': {
1686 unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC);
1687 size_t x;
1383 1688
1384 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;
1385 case 'L': use_ldcache = 1; break; 1729 case 'L': use_ldcache = 1; break;
1386 case 'y': scan_symlink = 0; break; 1730 case 'y': scan_symlink = 0; break;
1387 case 'A': scan_archives = 1; break; 1731 case 'A': scan_archives = 1; break;
1388 case 'B': show_banner = 0; break; 1732 case 'B': show_banner = 0; break;
1389 case 'l': scan_ldpath = 1; break; 1733 case 'l': scan_ldpath = 1; break;
1405 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;
1406 1750
1407 case ':': 1751 case ':':
1408 err("Option '%c' is missing parameter", optopt); 1752 err("Option '%c' is missing parameter", optopt);
1409 case '?': 1753 case '?':
1410 err("Unknown option '%c'", optopt); 1754 err("Unknown option '%c' or argument missing", optopt);
1411 default: 1755 default:
1412 err("Unhandled option '%c'; please report this", i); 1756 err("Unhandled option '%c'; please report this", i);
1413 } 1757 }
1414 } 1758 }
1415 1759
1420 show_textrels = 0; 1764 show_textrels = 0;
1421 for (i = 0; out_format[i]; ++i) { 1765 for (i = 0; out_format[i]; ++i) {
1422 if (!IS_MODIFIER(out_format[i])) continue; 1766 if (!IS_MODIFIER(out_format[i])) continue;
1423 1767
1424 switch (out_format[++i]) { 1768 switch (out_format[++i]) {
1769 case '+': break;
1425 case '%': break; 1770 case '%': break;
1426 case '#': break; 1771 case '#': break;
1427 case 'F': break; 1772 case 'F': break;
1428 case 'p': break; 1773 case 'p': break;
1429 case 'f': break; 1774 case 'f': break;
1775 case 'k': break;
1430 case 's': break; 1776 case 's': break;
1431 case 'N': break; 1777 case 'N': break;
1432 case 'o': break; 1778 case 'o': break;
1433 case 'x': show_pax = 1; break; 1779 case 'x': show_pax = 1; break;
1434 case 'e': show_phdr = 1; break; 1780 case 'e': show_phdr = 1; break;
1458 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); 1804 if (show_interp) xstrcat(&out_format, "%i ", &fmt_len);
1459 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len); 1805 if (show_bind) xstrcat(&out_format, "%b ", &fmt_len);
1460 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len); 1806 if (show_soname) xstrcat(&out_format, "%S ", &fmt_len);
1461 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len); 1807 if (show_textrels) xstrcat(&out_format, "%T ", &fmt_len);
1462 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);
1463 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len); 1810 if (find_lib) xstrcat(&out_format, "%N ", &fmt_len);
1464 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len); 1811 if (!be_quiet) xstrcat(&out_format, "%F ", &fmt_len);
1465 } 1812 }
1466 if (be_verbose > 2) printf("Format: %s\n", out_format); 1813 if (be_verbose > 2) printf("Format: %s\n", out_format);
1467 1814
1468 /* now lets actually do the scanning */ 1815 /* now lets actually do the scanning */
1469 if (scan_ldpath || use_ldcache) 1816 if (scan_ldpath || use_ldcache)
1470 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
1471 if (scan_ldpath) scanelf_ldpath(); 1822 if (scan_ldpath) scanelf_ldpath();
1472 if (scan_envpath) scanelf_envpath(); 1823 if (scan_envpath) scanelf_envpath();
1824 if (!from_file && optind == argc && ttyname(0) == NULL)
1825 from_file = "-";
1473 if (from_file) { 1826 if (from_file) {
1474 scanelf_from_file(from_file); 1827 scanelf_from_file(from_file);
1475 from_file = *argv; 1828 from_file = *argv;
1476 } 1829 }
1477 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file) 1830 if (optind == argc && !scan_ldpath && !scan_envpath && !from_file)
1488 1841
1489 if (ldcache != 0) 1842 if (ldcache != 0)
1490 munmap(ldcache, ldcache_size); 1843 munmap(ldcache, ldcache_size);
1491} 1844}
1492 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;
1493 1852
1853 if ((env = getenv(envvar)) == NULL)
1854 return NULL;
1494 1855
1495/* utility funcs */ 1856 env = xstrdup(env);
1496static char *xstrdup(const char *s) 1857 if (env == NULL)
1497{ 1858 return NULL;
1498 char *ret = strdup(s);
1499 if (!ret) err("Could not strdup(): %s", strerror(errno));
1500 return ret;
1501}
1502static void *xmalloc(size_t size)
1503{
1504 void *ret = malloc(size);
1505 if (!ret) err("Could not malloc() %li bytes", (unsigned long)size);
1506 return ret;
1507}
1508static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n)
1509{
1510 size_t new_len;
1511 1859
1512 new_len = strlen(*dst) + strlen(src); 1860 nentry = 0;
1513 if (*curr_len <= new_len) { 1861 for (s = strtok_r(env, " \t\n", &saveptr); s != NULL; s = strtok_r(NULL, " \t\n", &saveptr)) {
1514 *curr_len = new_len + (*curr_len / 2); 1862 if ((envvals = xrealloc(envvals, sizeof(char *)*(nentry+1))) == NULL)
1515 *dst = realloc(*dst, *curr_len); 1863 return NULL;
1516 if (!*dst) 1864 envvals[nentry++] = s;
1517 err("could not realloc() %li bytes", (unsigned long)*curr_len);
1518 } 1865 }
1866 envvals[nentry] = NULL;
1519 1867
1520 if (n) 1868 return envvals;
1521 strncat(*dst, src, n);
1522 else
1523 strcat(*dst, src);
1524} 1869}
1525static inline void xchrcat(char **dst, const char append, size_t *curr_len) 1870
1526{ 1871static void parseenv() {
1527 static char my_app[2]; 1872 qa_textrels=get_split_env("QA_TEXTRELS");
1528 my_app[0] = append; 1873 qa_execstack=get_split_env("QA_EXECSTACK");
1529 my_app[1] = '\0'; 1874 qa_wx_load=get_split_env("QA_WX_LOAD");
1530 xstrcat(dst, my_app, curr_len);
1531} 1875}
1532 1876
1533 1877
1534 1878
1535int main(int argc, char *argv[]) 1879int main(int argc, char *argv[])
1536{ 1880{
1537 if (argc < 2) 1881 if (argc < 2)
1538 usage(EXIT_FAILURE); 1882 usage(EXIT_FAILURE);
1883 parseenv();
1539 parseargs(argc, argv); 1884 parseargs(argc, argv);
1540 fclose(stdout); 1885 fclose(stdout);
1541#ifdef __BOUNDS_CHECKING_ON 1886#ifdef __BOUNDS_CHECKING_ON
1542 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()");
1543#endif 1888#endif

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

  ViewVC Help
Powered by ViewVC 1.1.20