/[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.229 Revision 1.235
1/* 1/*
2 * Copyright 2003-2007 Gentoo Foundation 2 * Copyright 2003-2007 Gentoo Foundation
3 * Distributed under the terms of the GNU General Public License v2 3 * Distributed under the terms of the GNU General Public License v2
4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.229 2011/09/27 19:29:19 vapier Exp $ 4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/Attic/scanelf.c,v 1.235 2011/12/13 05:12:14 vapier Exp $
5 * 5 *
6 * Copyright 2003-2007 Ned Ludd - <solar@gentoo.org> 6 * Copyright 2003-2007 Ned Ludd - <solar@gentoo.org>
7 * Copyright 2004-2007 Mike Frysinger - <vapier@gentoo.org> 7 * Copyright 2004-2007 Mike Frysinger - <vapier@gentoo.org>
8 */ 8 */
9 9
10static const char *rcsid = "$Id: scanelf.c,v 1.229 2011/09/27 19:29:19 vapier Exp $"; 10static const char rcsid[] = "$Id: scanelf.c,v 1.235 2011/12/13 05:12:14 vapier Exp $";
11const char argv0[] = "scanelf"; 11const char argv0[] = "scanelf";
12 12
13#include "paxinc.h" 13#include "paxinc.h"
14 14
15#define IS_MODIFIER(c) (c == '%' || c == '#' || c == '+') 15#define IS_MODIFIER(c) (c == '%' || c == '#' || c == '+')
57static char use_ldcache = 0; 57static char use_ldcache = 0;
58 58
59static char **qa_textrels = NULL; 59static char **qa_textrels = NULL;
60static char **qa_execstack = NULL; 60static char **qa_execstack = NULL;
61static char **qa_wx_load = NULL; 61static char **qa_wx_load = NULL;
62static char *root; 62static int root_fd = AT_FDCWD;
63 63
64static int match_bits = 0; 64static int match_bits = 0;
65static unsigned int match_perms = 0; 65static unsigned int match_perms = 0;
66static void *ldcache = NULL; 66static void *ldcache = NULL;
67static size_t ldcache_size = 0; 67static size_t ldcache_size = 0;
68static unsigned long setpax = 0UL; 68static unsigned long setpax = 0UL;
69 69
70static int has_objdump = 0; 70static int has_objdump = 0;
71 71
72/* find the path to a file by name */ 72/* find the path to a file by name */
73static char *which(const char *fname) 73static int bin_in_path(const char *fname)
74{ 74{
75 static char fullpath[__PAX_UTILS_PATH_MAX]; 75 char fullpath[__PAX_UTILS_PATH_MAX];
76 char *path, *p; 76 char *path, *p;
77 77
78 path = getenv("PATH"); 78 path = getenv("PATH");
79 if (!path) 79 if (!path)
80 return NULL; 80 return 0;
81 81
82 path = xstrdup(path);
83 while ((p = strrchr(path, ':')) != NULL) { 82 while ((p = strrchr(path, ':')) != NULL) {
84 snprintf(fullpath, sizeof(fullpath), "%s/%s", p + 1, fname); 83 snprintf(fullpath, sizeof(fullpath), "%s/%s", p + 1, fname);
85 *p = 0; 84 *p = 0;
86 if (access(fullpath, R_OK) != -1) { 85 if (access(fullpath, R_OK) != -1)
87 free(path); 86 return 1;
88 return fullpath;
89 } 87 }
90 } 88
91 free(path); 89 return 0;
90}
91
92static FILE *fopenat_r(int dir_fd, const char *path)
93{
94 int fd = openat(dir_fd, path, O_RDONLY|O_CLOEXEC);
95 if (fd == -1)
92 return NULL; 96 return NULL;
97 return fdopen(fd, "re");
98}
99
100static const char *root_rel_path(const char *path)
101{
102 /*
103 * openat() will ignore the dirfd if path starts with
104 * a /, so consume all of that noise
105 *
106 * XXX: we don't handle relative paths like ../ that
107 * break out of the --root option, but for now, just
108 * don't do that :P.
109 */
110 if (root_fd != AT_FDCWD) {
111 while (*path == '/')
112 ++path;
113 if (*path == '\0')
114 path = ".";
115 }
116
117 return path;
93} 118}
94 119
95/* 1 on failure. 0 otherwise */ 120/* 1 on failure. 0 otherwise */
96static int rematch(const char *regex, const char *match, int cflags) 121static int rematch(const char *regex, const char *match, int cflags)
97{ 122{
115 regfree(&preg); 140 regfree(&preg);
116 141
117 return ret; 142 return ret;
118} 143}
119 144
120/* sub-funcs for scanelf_file() */ 145/* sub-funcs for scanelf_fileat() */
121static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab) 146static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **str)
122{ 147{
123 /* find the best SHT_DYNSYM and SHT_STRTAB sections */ 148 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
124 149
125 /* debug sections */ 150 /* debug sections */
126 void *symtab = elf_findsecbyname(elf, ".symtab"); 151 void *symtab = elf_findsecbyname(elf, ".symtab");
138 } else \ 163 } else \
139 *sym = symtab ? symtab : dynsym; \ 164 *sym = symtab ? symtab : dynsym; \
140 if (strtab && dynstr) { \ 165 if (strtab && dynstr) { \
141 Elf ## B ## _Shdr *estrtab = strtab; \ 166 Elf ## B ## _Shdr *estrtab = strtab; \
142 Elf ## B ## _Shdr *edynstr = dynstr; \ 167 Elf ## B ## _Shdr *edynstr = dynstr; \
143 *tab = (EGET(estrtab->sh_size) > EGET(edynstr->sh_size)) ? strtab : dynstr; \ 168 *str = (EGET(estrtab->sh_size) > EGET(edynstr->sh_size)) ? strtab : dynstr; \
144 } else \ 169 } else \
145 *tab = strtab ? strtab : dynstr; \ 170 *str = strtab ? strtab : dynstr; \
146 } 171 }
147 GET_SYMTABS(32) 172 GET_SYMTABS(32)
148 GET_SYMTABS(64) 173 GET_SYMTABS(64)
174
175 if (*sym && *str)
176 return;
177
178 /*
179 * damn, they're really going to make us work for it huh?
180 * reconstruct the section header info out of the dynamic
181 * tags so we can see what symbols this guy uses at runtime.
182 */
183#define GET_SYMTABS_DT(B) \
184 if (elf->elf_class == ELFCLASS ## B) { \
185 size_t i; \
186 static Elf ## B ## _Shdr sym_shdr, str_shdr; \
187 Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
188 Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
189 Elf ## B ## _Addr vsym, vstr, vhash, vgnu_hash; \
190 Elf ## B ## _Dyn *dyn; \
191 Elf ## B ## _Off offset; \
192 \
193 /* lookup symbols used at runtime with DT_SYMTAB / DT_STRTAB */ \
194 vsym = vstr = vhash = vgnu_hash = 0; \
195 memset(&sym_shdr, 0, sizeof(sym_shdr)); \
196 memset(&str_shdr, 0, sizeof(str_shdr)); \
197 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
198 if (EGET(phdr[i].p_type) != PT_DYNAMIC) \
199 continue; \
200 \
201 offset = EGET(phdr[i].p_offset); \
202 if (offset >= elf->len - sizeof(Elf ## B ## _Dyn)) \
203 continue; \
204 \
205 dyn = DYN ## B (elf->vdata + offset); \
206 while (EGET(dyn->d_tag) != DT_NULL) { \
207 switch (EGET(dyn->d_tag)) { \
208 case DT_SYMTAB: vsym = EGET(dyn->d_un.d_val); break; \
209 case DT_SYMENT: sym_shdr.sh_entsize = dyn->d_un.d_val; break; \
210 case DT_STRTAB: vstr = EGET(dyn->d_un.d_val); break; \
211 case DT_STRSZ: str_shdr.sh_size = dyn->d_un.d_val; break; \
212 case DT_HASH: vhash = EGET(dyn->d_un.d_val); break; \
213 /*case DT_GNU_HASH: vgnu_hash = EGET(dyn->d_un.d_val); break;*/ \
214 } \
215 ++dyn; \
216 } \
217 if (vsym && vstr) \
218 break; \
219 } \
220 if (!vsym || !vstr || !(vhash || vgnu_hash)) \
221 return; \
222 \
223 /* calc offset into the ELF by finding the load addr of the syms */ \
224 for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
225 Elf ## B ## _Addr vaddr = EGET(phdr[i].p_vaddr); \
226 Elf ## B ## _Addr filesz = EGET(phdr[i].p_filesz); \
227 offset = EGET(phdr[i].p_offset); \
228 \
229 if (EGET(phdr[i].p_type) != PT_LOAD) \
230 continue; \
231 \
232 if (vhash >= vaddr && vhash < vaddr + filesz) { \
233 /* Scan the hash table to see how many entries we have */ \
234 Elf32_Word max_sym_idx = 0; \
235 Elf32_Word *hashtbl = elf->vdata + offset + (vhash - vaddr); \
236 Elf32_Word b, nbuckets = EGET(hashtbl[0]); \
237 Elf32_Word nchains = EGET(hashtbl[1]); \
238 Elf32_Word *buckets = &hashtbl[2]; \
239 Elf32_Word *chains = &buckets[nbuckets]; \
240 Elf32_Word sym_idx; \
241 \
242 for (b = 0; b < nbuckets; ++b) { \
243 if (!buckets[b]) \
244 continue; \
245 for (sym_idx = buckets[b]; sym_idx < nchains && sym_idx; sym_idx = chains[sym_idx]) \
246 if (max_sym_idx < sym_idx) \
247 max_sym_idx = sym_idx; \
248 } \
249 ESET(sym_shdr.sh_size, sym_shdr.sh_entsize * max_sym_idx); \
250 } \
251 \
252 if (vsym >= vaddr && vsym < vaddr + filesz) { \
253 ESET(sym_shdr.sh_offset, offset + (vsym - vaddr)); \
254 *sym = &sym_shdr; \
255 } \
256 \
257 if (vstr >= vaddr && vstr < vaddr + filesz) { \
258 ESET(str_shdr.sh_offset, offset + (vstr - vaddr)); \
259 *str = &str_shdr; \
260 } \
261 } \
262 }
263 GET_SYMTABS_DT(32)
264 GET_SYMTABS_DT(64)
149} 265}
150 266
151static char *scanelf_file_pax(elfobj *elf, char *found_pax) 267static char *scanelf_file_pax(elfobj *elf, char *found_pax)
152{ 268{
153 static char ret[7]; 269 static char ret[7];
467 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \ 583 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
468 if (be_verbose && has_objdump) { \ 584 if (be_verbose && has_objdump) { \
469 Elf ## B ## _Addr end_addr = offset_tmp + EGET(func->st_size); \ 585 Elf ## B ## _Addr end_addr = offset_tmp + EGET(func->st_size); \
470 char *sysbuf; \ 586 char *sysbuf; \
471 size_t syslen; \ 587 size_t syslen; \
472 int sysret; \
473 const char sysfmt[] = "objdump -r -R -d -w -l --start-address=0x%lX --stop-address=0x%lX %s | grep --color -i -C 3 '.*[[:space:]]%lX:[[:space:]]*R_.*'\n"; \ 588 const char sysfmt[] = "objdump -r -R -d -w -l --start-address=0x%lX --stop-address=0x%lX %s | grep --color -i -C 3 '.*[[:space:]]%lX:[[:space:]]*R_.*'\n"; \
474 syslen = sizeof(sysfmt) + strlen(elf->filename) + 3 * sizeof(unsigned long) + 1; \ 589 syslen = sizeof(sysfmt) + strlen(elf->filename) + 3 * sizeof(unsigned long) + 1; \
475 sysbuf = xmalloc(syslen); \ 590 sysbuf = xmalloc(syslen); \
476 if (end_addr < r_offset) \ 591 if (end_addr < r_offset) \
477 /* not uncommon when things are optimized out */ \ 592 /* not uncommon when things are optimized out */ \
480 (unsigned long)offset_tmp, \ 595 (unsigned long)offset_tmp, \
481 (unsigned long)end_addr, \ 596 (unsigned long)end_addr, \
482 elf->filename, \ 597 elf->filename, \
483 (unsigned long)r_offset); \ 598 (unsigned long)r_offset); \
484 fflush(stdout); \ 599 fflush(stdout); \
485 sysret = system(sysbuf); \ 600 if (system(sysbuf)) /* don't care */; \
486 fflush(stdout); \ 601 fflush(stdout); \
487 free(sysbuf); \ 602 free(sysbuf); \
488 } \ 603 } \
489 } \ 604 } \
490 } } 605 } }
689static char *lookup_cache_lib(elfobj *elf, char *fname) 804static char *lookup_cache_lib(elfobj *elf, char *fname)
690{ 805{
691 int fd; 806 int fd;
692 char *strs; 807 char *strs;
693 static char buf[__PAX_UTILS_PATH_MAX] = ""; 808 static char buf[__PAX_UTILS_PATH_MAX] = "";
694 const char cachefile[] = "/etc/ld.so.cache"; 809 const char *cachefile = root_rel_path("/etc/ld.so.cache");
695 struct stat st; 810 struct stat st;
696 811
697 typedef struct { 812 typedef struct {
698 char magic[LDSO_CACHE_MAGIC_LEN]; 813 char magic[LDSO_CACHE_MAGIC_LEN];
699 char version[LDSO_CACHE_VER_LEN]; 814 char version[LDSO_CACHE_VER_LEN];
710 825
711 if (fname == NULL) 826 if (fname == NULL)
712 return NULL; 827 return NULL;
713 828
714 if (ldcache == NULL) { 829 if (ldcache == NULL) {
715 if (stat(cachefile, &st)) 830 if (fstatat(root_fd, cachefile, &st, 0))
716 return NULL; 831 return NULL;
717 832
718 fd = open(cachefile, O_RDONLY); 833 fd = openat(root_fd, cachefile, O_RDONLY);
719 if (fd == -1) 834 if (fd == -1)
720 return NULL; 835 return NULL;
721 836
722 /* cache these values so we only map/unmap the cache file once */ 837 /* cache these values so we only map/unmap the cache file once */
723 ldcache_size = st.st_size; 838 ldcache_size = st.st_size;
1157 next_sym[-1] = saved; 1272 next_sym[-1] = saved;
1158} 1273}
1159 1274
1160static const char *scanelf_file_sym(elfobj *elf, char *found_sym) 1275static const char *scanelf_file_sym(elfobj *elf, char *found_sym)
1161{ 1276{
1162 unsigned long i;
1163 char *ret; 1277 char *ret;
1164 void *symtab_void, *strtab_void; 1278 void *symtab_void, *strtab_void;
1165 1279
1166 if (!find_sym) return NULL; 1280 if (!find_sym) return NULL;
1167 ret = NULL; 1281 ret = NULL;
1172#define FIND_SYM(B) \ 1286#define FIND_SYM(B) \
1173 if (elf->elf_class == ELFCLASS ## B) { \ 1287 if (elf->elf_class == ELFCLASS ## B) { \
1174 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \ 1288 Elf ## B ## _Shdr *symtab = SHDR ## B (symtab_void); \
1175 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \ 1289 Elf ## B ## _Shdr *strtab = SHDR ## B (strtab_void); \
1176 Elf ## B ## _Sym *sym = SYM ## B (elf->vdata + EGET(symtab->sh_offset)); \ 1290 Elf ## B ## _Sym *sym = SYM ## B (elf->vdata + EGET(symtab->sh_offset)); \
1177 unsigned long cnt = EGET(symtab->sh_entsize); \ 1291 Elf ## B ## _Word i, cnt = EGET(symtab->sh_entsize); \
1178 char *symname; \ 1292 char *symname; \
1179 size_t ret_len = 0; \ 1293 size_t ret_len = 0; \
1180 if (cnt) \ 1294 if (cnt) \
1181 cnt = EGET(symtab->sh_size) / cnt; \ 1295 cnt = EGET(symtab->sh_size) / cnt; \
1182 for (i = 0; i < cnt; ++i) { \ 1296 for (i = 0; i < cnt; ++i) { \
1199 EGET(sym->st_shndx), \ 1313 EGET(sym->st_shndx), \
1200 /* st_size can be 64bit, but no one is really that big, so screw em */ \ 1314 /* st_size can be 64bit, but no one is really that big, so screw em */ \
1201 EGET(sym->st_size)); \ 1315 EGET(sym->st_size)); \
1202 } \ 1316 } \
1203 ++sym; \ 1317 ++sym; \
1204 } } 1318 } \
1319 }
1205 FIND_SYM(32) 1320 FIND_SYM(32)
1206 FIND_SYM(64) 1321 FIND_SYM(64)
1207 } 1322 }
1208 1323
1209break_out: 1324break_out:
1419 elfobj *elf; 1534 elfobj *elf;
1420 1535
1421 /* verify this is real ELF */ 1536 /* verify this is real ELF */
1422 if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) { 1537 if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) {
1423 if (be_verbose > 2) printf("%s: not an ELF\n", filename); 1538 if (be_verbose > 2) printf("%s: not an ELF\n", filename);
1424 return ret; 1539 return 2;
1425 } 1540 }
1426 switch (match_bits) { 1541 switch (match_bits) {
1427 case 32: 1542 case 32:
1428 if (elf->elf_class != ELFCLASS32) 1543 if (elf->elf_class != ELFCLASS32)
1429 goto label_done; 1544 goto label_done;
1483 munmap(ar_buffer, len); 1598 munmap(ar_buffer, len);
1484 1599
1485 return 0; 1600 return 0;
1486} 1601}
1487/* scan a file which may be an elf or an archive or some other magical beast */ 1602/* scan a file which may be an elf or an archive or some other magical beast */
1488static int scanelf_file(const char *filename, const struct stat *st_cache) 1603static int scanelf_fileat(int dir_fd, const char *filename, const struct stat *st_cache)
1489{ 1604{
1490 const struct stat *st = st_cache; 1605 const struct stat *st = st_cache;
1491 struct stat symlink_st; 1606 struct stat symlink_st;
1492 int fd; 1607 int fd;
1493 1608
1494 /* always handle regular files and handle symlinked files if no -y */ 1609 /* always handle regular files and handle symlinked files if no -y */
1495 if (S_ISLNK(st->st_mode)) { 1610 if (S_ISLNK(st->st_mode)) {
1496 if (!scan_symlink) return 1; 1611 if (!scan_symlink)
1612 return 1;
1497 stat(filename, &symlink_st); 1613 fstatat(dir_fd, filename, &symlink_st, 0);
1498 st = &symlink_st; 1614 st = &symlink_st;
1499 } 1615 }
1500 1616
1501 if (!S_ISREG(st->st_mode)) { 1617 if (!S_ISREG(st->st_mode)) {
1502 if (be_verbose > 2) printf("%s: skipping non-file\n", filename); 1618 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
1505 1621
1506 if (match_perms) { 1622 if (match_perms) {
1507 if ((st->st_mode | match_perms) != st->st_mode) 1623 if ((st->st_mode | match_perms) != st->st_mode)
1508 return 1; 1624 return 1;
1509 } 1625 }
1510 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1) 1626 fd = openat(dir_fd, filename, (fix_elf ? O_RDWR : O_RDONLY) | O_CLOEXEC);
1627 if (fd == -1)
1511 return 1; 1628 return 1;
1512 1629
1513 if (scanelf_elf(filename, fd, st->st_size) == 1 && scan_archives) 1630 if (scanelf_elf(filename, fd, st->st_size) == 2) {
1514 /* if it isn't an ELF, maybe it's an .a archive */ 1631 /* if it isn't an ELF, maybe it's an .a archive */
1632 if (scan_archives)
1515 scanelf_archive(filename, fd, st->st_size); 1633 scanelf_archive(filename, fd, st->st_size);
1516 1634
1635 /*
1636 * unreadelf() implicitly closes its fd, so only close it
1637 * when we are returning it in the non-ELF case
1638 */
1517 close(fd); 1639 close(fd);
1640 }
1641
1518 return 0; 1642 return 0;
1519} 1643}
1520 1644
1521static const char *maybe_add_root(const char *fname, char *buf)
1522{
1523 if (root && strncmp(fname, root, strlen(root))) {
1524 strcpy(buf, root);
1525 strncat(buf, fname, __PAX_UTILS_PATH_MAX - strlen(root) - 1);
1526 fname = buf;
1527 }
1528 return fname;
1529}
1530
1531/* scan a directory for ET_EXEC files and print when we find one */ 1645/* scan a directory for ET_EXEC files and print when we find one */
1532static int scanelf_dir(const char *path) 1646static int scanelf_dirat(int dir_fd, const char *path)
1533{ 1647{
1534 register DIR *dir; 1648 register DIR *dir;
1535 register struct dirent *dentry; 1649 register struct dirent *dentry;
1536 struct stat st_top, st; 1650 struct stat st_top, st;
1537 char buf[__PAX_UTILS_PATH_MAX]; 1651 char buf[__PAX_UTILS_PATH_MAX], *subpath;
1538 char _path[__PAX_UTILS_PATH_MAX];
1539 size_t pathlen = 0, len = 0; 1652 size_t pathlen = 0, len = 0;
1540 int ret = 0; 1653 int ret = 0;
1541 1654 int subdir_fd;
1542 path = maybe_add_root(path, _path);
1543 1655
1544 /* make sure path exists */ 1656 /* make sure path exists */
1545 if (lstat(path, &st_top) == -1) { 1657 if (fstatat(dir_fd, path, &st_top, AT_SYMLINK_NOFOLLOW) == -1) {
1546 if (be_verbose > 2) printf("%s: does not exist\n", path); 1658 if (be_verbose > 2) printf("%s: does not exist\n", path);
1547 return 1; 1659 return 1;
1548 } 1660 }
1549 1661
1550 /* ok, if it isn't a directory, assume we can open it */ 1662 /* ok, if it isn't a directory, assume we can open it */
1551 if (!S_ISDIR(st_top.st_mode)) { 1663 if (!S_ISDIR(st_top.st_mode))
1552 return scanelf_file(path, &st_top); 1664 return scanelf_fileat(dir_fd, path, &st_top);
1553 }
1554 1665
1555 /* now scan the dir looking for fun stuff */ 1666 /* now scan the dir looking for fun stuff */
1556 if ((dir = opendir(path)) == NULL) { 1667 subdir_fd = openat(dir_fd, path, O_RDONLY|O_CLOEXEC);
1668 if (subdir_fd == -1)
1669 dir = NULL;
1670 else
1671 dir = fdopendir(subdir_fd);
1672 if (dir == NULL) {
1673 if (subdir_fd != -1)
1674 close(subdir_fd);
1557 warnf("could not opendir %s: %s", path, strerror(errno)); 1675 warnf("could not opendir %s: %s", path, strerror(errno));
1558 return 1; 1676 return 1;
1559 } 1677 }
1560 if (be_verbose > 1) printf("%s: scanning dir\n", path); 1678 if (be_verbose > 1) printf("%s: scanning dir\n", path);
1561 1679
1562 pathlen = strlen(path); 1680 subpath = stpcpy(buf, path);
1681 *subpath++ = '/';
1682 pathlen = subpath - buf;
1563 while ((dentry = readdir(dir))) { 1683 while ((dentry = readdir(dir))) {
1564 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 1684 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
1565 continue; 1685 continue;
1566 len = (pathlen + 1 + strlen(dentry->d_name) + 1); 1686
1567 if (len >= sizeof(buf)) { 1687 if (fstatat(subdir_fd, dentry->d_name, &st, AT_SYMLINK_NOFOLLOW) == -1)
1568 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
1569 (unsigned long)len, (unsigned long)sizeof(buf));
1570 continue; 1688 continue;
1689
1690 len = strlen(dentry->d_name);
1691 if (len + pathlen + 1 >= sizeof(buf)) {
1692 warnf("Skipping '%s%s': len > sizeof(buf); %zu > %zu\n",
1693 path, dentry->d_name, len + pathlen + 1, sizeof(buf));
1694 continue;
1571 } 1695 }
1572 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name); 1696 memcpy(subpath, dentry->d_name, len);
1573 if (lstat(buf, &st) != -1) { 1697 subpath[len] = '\0';
1698
1574 if (S_ISREG(st.st_mode)) 1699 if (S_ISREG(st.st_mode))
1575 ret = scanelf_file(buf, &st); 1700 ret = scanelf_fileat(dir_fd, buf, &st);
1576 else if (dir_recurse && S_ISDIR(st.st_mode)) { 1701 else if (dir_recurse && S_ISDIR(st.st_mode)) {
1577 if (dir_crossmount || (st_top.st_dev == st.st_dev)) 1702 if (dir_crossmount || (st_top.st_dev == st.st_dev))
1578 ret = scanelf_dir(buf); 1703 ret = scanelf_dirat(dir_fd, buf);
1579 }
1580 } 1704 }
1581 } 1705 }
1582 closedir(dir); 1706 closedir(dir);
1707
1583 return ret; 1708 return ret;
1584} 1709}
1710static int scanelf_dir(const char *path)
1711{
1712 return scanelf_dirat(root_fd, root_rel_path(path));
1713}
1585 1714
1586static int scanelf_from_file(const char *filename) 1715static int scanelf_from_file(const char *filename)
1587{ 1716{
1588 FILE *fp = NULL; 1717 FILE *fp;
1589 char *p; 1718 char *p, *path;
1590 char path[__PAX_UTILS_PATH_MAX]; 1719 size_t len;
1591 int ret = 0; 1720 int ret;
1592 1721
1593 if (strcmp(filename, "-") == 0) 1722 if (strcmp(filename, "-") == 0)
1594 fp = stdin; 1723 fp = stdin;
1595 else if ((fp = fopen(filename, "r")) == NULL) 1724 else if ((fp = fopen(filename, "r")) == NULL)
1596 return 1; 1725 return 1;
1597 1726
1598 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) { 1727 path = NULL;
1728 len = 0;
1729 ret = 0;
1730 while (getline(&path, &len, fp) != -1) {
1599 if ((p = strchr(path, '\n')) != NULL) 1731 if ((p = strchr(path, '\n')) != NULL)
1600 *p = 0; 1732 *p = 0;
1601 search_path = path; 1733 search_path = path;
1602 ret = scanelf_dir(path); 1734 ret = scanelf_dir(path);
1603 } 1735 }
1736 free(path);
1737
1604 if (fp != stdin) 1738 if (fp != stdin)
1605 fclose(fp); 1739 fclose(fp);
1740
1606 return ret; 1741 return ret;
1607} 1742}
1608 1743
1609#if defined(__GLIBC__) || defined(__UCLIBC__) || defined(__NetBSD__) 1744#if defined(__GLIBC__) || defined(__UCLIBC__) || defined(__NetBSD__)
1610 1745
1611static int load_ld_cache_config(int i, const char *fname) 1746static int load_ld_cache_config(int i, const char *fname)
1612{ 1747{
1613 FILE *fp = NULL; 1748 FILE *fp = NULL;
1614 char *p; 1749 char *p, *path;
1615 char path[__PAX_UTILS_PATH_MAX]; 1750 size_t len;
1616 char _fname[__PAX_UTILS_PATH_MAX]; 1751 int curr_fd = -1;
1617 1752
1618 fname = maybe_add_root(fname, _fname); 1753 fp = fopenat_r(root_fd, root_rel_path(fname));
1619 1754 if (fp == NULL)
1620 if ((fp = fopen(fname, "r")) == NULL)
1621 return i; 1755 return i;
1622 1756
1623 while ((fgets(path, __PAX_UTILS_PATH_MAX, fp)) != NULL) { 1757 path = NULL;
1758 len = 0;
1759 while (getline(&path, &len, fp) != -1) {
1624 if ((p = strrchr(path, '\r')) != NULL) 1760 if ((p = strrchr(path, '\r')) != NULL)
1625 *p = 0; 1761 *p = 0;
1626 if ((p = strchr(path, '\n')) != NULL) 1762 if ((p = strchr(path, '\n')) != NULL)
1627 *p = 0; 1763 *p = 0;
1628 1764
1629 /* recursive includes of the same file will make this segfault. */ 1765 /* recursive includes of the same file will make this segfault. */
1630 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) { 1766 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) {
1631 glob_t gl; 1767 glob_t gl;
1632 size_t x; 1768 size_t x;
1633 char gpath[__PAX_UTILS_PATH_MAX]; 1769 const char *gpath;
1634 1770
1635 memset(gpath, 0, sizeof(gpath)); 1771 /* re-use existing path buffer ... need to be creative */
1636 if (root)
1637 strcpy(gpath, root);
1638
1639 if (path[8] != '/') 1772 if (path[8] != '/')
1640 snprintf(gpath+strlen(gpath), sizeof(gpath)-strlen(gpath), "/etc/%s", &path[8]); 1773 gpath = memcpy(path + 3, "/etc/", 5);
1641 else 1774 else
1642 strncpy(gpath+strlen(gpath), &path[8], sizeof(gpath)-strlen(gpath)); 1775 gpath = path + 8;
1776 if (root_fd != AT_FDCWD) {
1777 if (curr_fd == -1) {
1778 curr_fd = open(".", O_RDONLY|O_CLOEXEC);
1779 if (fchdir(root_fd))
1780 errp("unable to change to root dir");
1781 }
1782 gpath = root_rel_path(gpath);
1783 }
1643 1784
1644 if (glob(gpath, 0, NULL, &gl) == 0) { 1785 if (glob(gpath, 0, NULL, &gl) == 0) {
1645 for (x = 0; x < gl.gl_pathc; ++x) { 1786 for (x = 0; x < gl.gl_pathc; ++x) {
1646 /* try to avoid direct loops */ 1787 /* try to avoid direct loops */
1647 if (strcmp(gl.gl_pathv[x], fname) == 0) 1788 if (strcmp(gl.gl_pathv[x], fname) == 0)
1648 continue; 1789 continue;
1649 i = load_ld_cache_config(i, gl.gl_pathv[x]); 1790 i = load_ld_cache_config(i, gl.gl_pathv[x]);
1650 } 1791 }
1651 globfree(&gl); 1792 globfree(&gl);
1652 continue;
1653 } 1793 }
1794
1795 /* failed globs are ignored by glibc */
1796 continue;
1654 } 1797 }
1655 1798
1656 if (*path != '/') 1799 if (*path != '/')
1657 continue; 1800 continue;
1658 1801
1659 xarraypush(ldpaths, path, strlen(path)); 1802 xarraypush_str(ldpaths, path);
1660 } 1803 }
1804 free(path);
1661 1805
1662 fclose(fp); 1806 fclose(fp);
1807
1808 if (curr_fd != -1) {
1809 if (fchdir(curr_fd))
1810 /* don't care */;
1811 close(curr_fd);
1812 }
1813
1663 return i; 1814 return i;
1664} 1815}
1665 1816
1666#elif defined(__FreeBSD__) || defined(__DragonFly__) 1817#elif defined(__FreeBSD__) || defined(__DragonFly__)
1667 1818
1668static int load_ld_cache_config(int i, const char *fname) 1819static int load_ld_cache_config(int i, const char *fname)
1669{ 1820{
1670 FILE *fp = NULL; 1821 FILE *fp = NULL;
1671 char *b = NULL, *p; 1822 char *b = NULL, *p;
1672 struct elfhints_hdr hdr; 1823 struct elfhints_hdr hdr;
1673 char _fname[__PAX_UTILS_PATH_MAX];
1674 1824
1675 fname = maybe_add_root(fname, _fname); 1825 fp = fopenat_r(root_fd, root_rel_path(fname));
1676 1826 if (fp == NULL)
1677 if ((fp = fopen(fname, "r")) == NULL)
1678 return i; 1827 return i;
1679 1828
1680 if (fread(&hdr, 1, sizeof(hdr), fp) != sizeof(hdr) || 1829 if (fread(&hdr, 1, sizeof(hdr), fp) != sizeof(hdr) ||
1681 hdr.magic != ELFHINTS_MAGIC || hdr.version != 1 || 1830 hdr.magic != ELFHINTS_MAGIC || hdr.version != 1 ||
1682 fseek(fp, hdr.strtab + hdr.dirlist, SEEK_SET) == -1) 1831 fseek(fp, hdr.strtab + hdr.dirlist, SEEK_SET) == -1)
1693 } 1842 }
1694 1843
1695 while ((p = strsep(&b, ":"))) { 1844 while ((p = strsep(&b, ":"))) {
1696 if (*p == '\0') 1845 if (*p == '\0')
1697 continue; 1846 continue;
1698 xarraypush(ldpaths, p, strlen(p)); 1847 xarraypush_str(ldpaths, p);
1699 } 1848 }
1700 1849
1701 free(b); 1850 free(b);
1702 fclose(fp); 1851 fclose(fp);
1703 return i; 1852 return i;
1920 if (freopen(optarg, "w", stdout) == NULL) 2069 if (freopen(optarg, "w", stdout) == NULL)
1921 err("Could not open output stream '%s': %s", optarg, strerror(errno)); 2070 err("Could not open output stream '%s': %s", optarg, strerror(errno));
1922 break; 2071 break;
1923 } 2072 }
1924 case 'k': 2073 case 'k':
1925 xarraypush(find_section_arr, optarg, strlen(optarg)); 2074 xarraypush_str(find_section_arr, optarg);
1926 break; 2075 break;
1927 case 's': { 2076 case 's': {
1928 if (find_sym) warn("You prob don't want to specify -s twice"); 2077 if (find_sym) warn("You prob don't want to specify -s twice");
1929 find_sym = optarg; 2078 find_sym = optarg;
1930 break; 2079 break;
1931 } 2080 }
1932 case 'N': 2081 case 'N':
1933 xarraypush(find_lib_arr, optarg, strlen(optarg)); 2082 xarraypush_str(find_lib_arr, optarg);
1934 break; 2083 break;
1935 case 'F': { 2084 case 'F': {
1936 if (out_format) warn("You prob don't want to specify -F twice"); 2085 if (out_format) warn("You prob don't want to specify -F twice");
1937 out_format = optarg; 2086 out_format = optarg;
1938 break; 2087 break;
2006 case 'a': show_perms = show_pax = show_phdr = show_textrel = show_rpath = show_bind = show_endian = 1; break; 2155 case 'a': show_perms = show_pax = show_phdr = show_textrel = show_rpath = show_bind = show_endian = 1; break;
2007 case 'D': show_endian = 1; break; 2156 case 'D': show_endian = 1; break;
2008 case 'I': show_osabi = 1; break; 2157 case 'I': show_osabi = 1; break;
2009 case 'Y': show_eabi = 1; break; 2158 case 'Y': show_eabi = 1; break;
2010 case 128: 2159 case 128:
2011 root = optarg; 2160 root_fd = open(optarg, O_RDONLY|O_CLOEXEC);
2161 if (root_fd == -1)
2162 err("Could not open root: %s", optarg);
2012 break; 2163 break;
2013 case ':': 2164 case ':':
2014 err("Option '%c' is missing parameter", optopt); 2165 err("Option '%c' is missing parameter", optopt);
2015 case '?': 2166 case '?':
2016 err("Unknown option '%c' or argument missing", optopt); 2167 err("Unknown option '%c' or argument missing", optopt);
2017 default: 2168 default:
2018 err("Unhandled option '%c'; please report this", i); 2169 err("Unhandled option '%c'; please report this", i);
2019 } 2170 }
2020 } 2171 }
2021 if (show_textrels && be_verbose) { 2172 if (show_textrels && be_verbose)
2022 if (which("objdump") != NULL) 2173 has_objdump = bin_in_path("objdump");
2023 has_objdump = 1;
2024 }
2025 /* flatten arrays for display */ 2174 /* flatten arrays for display */
2026 if (array_cnt(find_lib_arr)) 2175 if (array_cnt(find_lib_arr))
2027 find_lib = array_flatten_str(find_lib_arr); 2176 find_lib = array_flatten_str(find_lib_arr);
2028 if (array_cnt(find_section_arr)) 2177 if (array_cnt(find_section_arr))
2029 find_section = array_flatten_str(find_section_arr); 2178 find_section = array_flatten_str(find_section_arr);
2187 ret = parseargs(argc, argv); 2336 ret = parseargs(argc, argv);
2188 fclose(stdout); 2337 fclose(stdout);
2189#ifdef __PAX_UTILS_CLEANUP 2338#ifdef __PAX_UTILS_CLEANUP
2190 cleanup(); 2339 cleanup();
2191 warn("The calls to add/delete heap should be off:\n" 2340 warn("The calls to add/delete heap should be off:\n"
2192 "\t- 1 due to the out_buffer not being freed in scanelf_file()\n" 2341 "\t- 1 due to the out_buffer not being freed in scanelf_fileat()\n"
2193 "\t- 1 per QA_TEXTRELS/QA_EXECSTACK/QA_WX_LOAD"); 2342 "\t- 1 per QA_TEXTRELS/QA_EXECSTACK/QA_WX_LOAD");
2194#endif 2343#endif
2195 return ret; 2344 return ret;
2196} 2345}
2197 2346

Legend:
Removed from v.1.229  
changed lines
  Added in v.1.235

  ViewVC Help
Powered by ViewVC 1.1.20