/[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.231 Revision 1.232
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/scanelf.c,v 1.231 2011/09/27 19:58:09 vapier Exp $ 4 * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.232 2011/09/27 22:20:07 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.231 2011/09/27 19:58:09 vapier Exp $"; 10static const char rcsid[] = "$Id: scanelf.c,v 1.232 2011/09/27 22:20:07 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;
87 } 87 }
88 88
89 return 0; 89 return 0;
90} 90}
91 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)
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;
118}
119
92/* 1 on failure. 0 otherwise */ 120/* 1 on failure. 0 otherwise */
93static int rematch(const char *regex, const char *match, int cflags) 121static int rematch(const char *regex, const char *match, int cflags)
94{ 122{
95 regex_t preg; 123 regex_t preg;
96 int ret; 124 int ret;
112 regfree(&preg); 140 regfree(&preg);
113 141
114 return ret; 142 return ret;
115} 143}
116 144
117/* sub-funcs for scanelf_file() */ 145/* sub-funcs for scanelf_fileat() */
118static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab) 146static void scanelf_file_get_symtabs(elfobj *elf, void **sym, void **tab)
119{ 147{
120 /* find the best SHT_DYNSYM and SHT_STRTAB sections */ 148 /* find the best SHT_DYNSYM and SHT_STRTAB sections */
121 149
122 /* debug sections */ 150 /* debug sections */
464 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \ 492 printf(" [0x%lX]\n", (unsigned long)offset_tmp); \
465 if (be_verbose && has_objdump) { \ 493 if (be_verbose && has_objdump) { \
466 Elf ## B ## _Addr end_addr = offset_tmp + EGET(func->st_size); \ 494 Elf ## B ## _Addr end_addr = offset_tmp + EGET(func->st_size); \
467 char *sysbuf; \ 495 char *sysbuf; \
468 size_t syslen; \ 496 size_t syslen; \
469 int sysret; \
470 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"; \ 497 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"; \
471 syslen = sizeof(sysfmt) + strlen(elf->filename) + 3 * sizeof(unsigned long) + 1; \ 498 syslen = sizeof(sysfmt) + strlen(elf->filename) + 3 * sizeof(unsigned long) + 1; \
472 sysbuf = xmalloc(syslen); \ 499 sysbuf = xmalloc(syslen); \
473 if (end_addr < r_offset) \ 500 if (end_addr < r_offset) \
474 /* not uncommon when things are optimized out */ \ 501 /* not uncommon when things are optimized out */ \
477 (unsigned long)offset_tmp, \ 504 (unsigned long)offset_tmp, \
478 (unsigned long)end_addr, \ 505 (unsigned long)end_addr, \
479 elf->filename, \ 506 elf->filename, \
480 (unsigned long)r_offset); \ 507 (unsigned long)r_offset); \
481 fflush(stdout); \ 508 fflush(stdout); \
482 sysret = system(sysbuf); \ 509 if (system(sysbuf)) /* don't care */; \
483 fflush(stdout); \ 510 fflush(stdout); \
484 free(sysbuf); \ 511 free(sysbuf); \
485 } \ 512 } \
486 } \ 513 } \
487 } } 514 } }
686static char *lookup_cache_lib(elfobj *elf, char *fname) 713static char *lookup_cache_lib(elfobj *elf, char *fname)
687{ 714{
688 int fd; 715 int fd;
689 char *strs; 716 char *strs;
690 static char buf[__PAX_UTILS_PATH_MAX] = ""; 717 static char buf[__PAX_UTILS_PATH_MAX] = "";
691 const char cachefile[] = "/etc/ld.so.cache"; 718 const char *cachefile = root_rel_path("/etc/ld.so.cache");
692 struct stat st; 719 struct stat st;
693 720
694 typedef struct { 721 typedef struct {
695 char magic[LDSO_CACHE_MAGIC_LEN]; 722 char magic[LDSO_CACHE_MAGIC_LEN];
696 char version[LDSO_CACHE_VER_LEN]; 723 char version[LDSO_CACHE_VER_LEN];
707 734
708 if (fname == NULL) 735 if (fname == NULL)
709 return NULL; 736 return NULL;
710 737
711 if (ldcache == NULL) { 738 if (ldcache == NULL) {
712 if (stat(cachefile, &st)) 739 if (fstatat(root_fd, cachefile, &st, 0))
713 return NULL; 740 return NULL;
714 741
715 fd = open(cachefile, O_RDONLY); 742 fd = openat(root_fd, cachefile, O_RDONLY);
716 if (fd == -1) 743 if (fd == -1)
717 return NULL; 744 return NULL;
718 745
719 /* cache these values so we only map/unmap the cache file once */ 746 /* cache these values so we only map/unmap the cache file once */
720 ldcache_size = st.st_size; 747 ldcache_size = st.st_size;
1480 munmap(ar_buffer, len); 1507 munmap(ar_buffer, len);
1481 1508
1482 return 0; 1509 return 0;
1483} 1510}
1484/* scan a file which may be an elf or an archive or some other magical beast */ 1511/* scan a file which may be an elf or an archive or some other magical beast */
1485static int scanelf_file(const char *filename, const struct stat *st_cache) 1512static int scanelf_fileat(int dir_fd, const char *filename, const struct stat *st_cache)
1486{ 1513{
1487 const struct stat *st = st_cache; 1514 const struct stat *st = st_cache;
1488 struct stat symlink_st; 1515 struct stat symlink_st;
1489 int fd; 1516 int fd;
1490 1517
1491 /* always handle regular files and handle symlinked files if no -y */ 1518 /* always handle regular files and handle symlinked files if no -y */
1492 if (S_ISLNK(st->st_mode)) { 1519 if (S_ISLNK(st->st_mode)) {
1493 if (!scan_symlink) return 1; 1520 if (!scan_symlink)
1521 return 1;
1494 stat(filename, &symlink_st); 1522 fstatat(dir_fd, filename, &symlink_st, 0);
1495 st = &symlink_st; 1523 st = &symlink_st;
1496 } 1524 }
1497 1525
1498 if (!S_ISREG(st->st_mode)) { 1526 if (!S_ISREG(st->st_mode)) {
1499 if (be_verbose > 2) printf("%s: skipping non-file\n", filename); 1527 if (be_verbose > 2) printf("%s: skipping non-file\n", filename);
1502 1530
1503 if (match_perms) { 1531 if (match_perms) {
1504 if ((st->st_mode | match_perms) != st->st_mode) 1532 if ((st->st_mode | match_perms) != st->st_mode)
1505 return 1; 1533 return 1;
1506 } 1534 }
1507 if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1) 1535 fd = openat(dir_fd, filename, (fix_elf ? O_RDWR : O_RDONLY) | O_CLOEXEC);
1536 if (fd == -1)
1508 return 1; 1537 return 1;
1509 1538
1510 if (scanelf_elf(filename, fd, st->st_size) == 1 && scan_archives) 1539 if (scanelf_elf(filename, fd, st->st_size) == 1 && scan_archives)
1511 /* if it isn't an ELF, maybe it's an .a archive */ 1540 /* if it isn't an ELF, maybe it's an .a archive */
1512 scanelf_archive(filename, fd, st->st_size); 1541 scanelf_archive(filename, fd, st->st_size);
1513 1542
1543 /* XXX: unreadelf() implicitly closes its fd */
1514 close(fd); 1544 close(fd);
1515 return 0; 1545 return 0;
1516} 1546}
1517 1547
1518static const char *maybe_add_root(const char *fname, char *buf)
1519{
1520 if (root && strncmp(fname, root, strlen(root))) {
1521 strcpy(buf, root);
1522 strncat(buf, fname, __PAX_UTILS_PATH_MAX - strlen(root) - 1);
1523 fname = buf;
1524 }
1525 return fname;
1526}
1527
1528/* scan a directory for ET_EXEC files and print when we find one */ 1548/* scan a directory for ET_EXEC files and print when we find one */
1529static int scanelf_dir(const char *path) 1549static int scanelf_dirat(int dir_fd, const char *path)
1530{ 1550{
1531 register DIR *dir; 1551 register DIR *dir;
1532 register struct dirent *dentry; 1552 register struct dirent *dentry;
1533 struct stat st_top, st; 1553 struct stat st_top, st;
1534 char buf[__PAX_UTILS_PATH_MAX]; 1554 char buf[__PAX_UTILS_PATH_MAX], *subpath;
1535 char _path[__PAX_UTILS_PATH_MAX];
1536 size_t pathlen = 0, len = 0; 1555 size_t pathlen = 0, len = 0;
1537 int ret = 0; 1556 int ret = 0;
1538 1557 int subdir_fd;
1539 path = maybe_add_root(path, _path);
1540 1558
1541 /* make sure path exists */ 1559 /* make sure path exists */
1542 if (lstat(path, &st_top) == -1) { 1560 if (fstatat(dir_fd, path, &st_top, AT_SYMLINK_NOFOLLOW) == -1) {
1543 if (be_verbose > 2) printf("%s: does not exist\n", path); 1561 if (be_verbose > 2) printf("%s: does not exist\n", path);
1544 return 1; 1562 return 1;
1545 } 1563 }
1546 1564
1547 /* ok, if it isn't a directory, assume we can open it */ 1565 /* ok, if it isn't a directory, assume we can open it */
1548 if (!S_ISDIR(st_top.st_mode)) { 1566 if (!S_ISDIR(st_top.st_mode))
1549 return scanelf_file(path, &st_top); 1567 return scanelf_fileat(dir_fd, path, &st_top);
1550 }
1551 1568
1552 /* now scan the dir looking for fun stuff */ 1569 /* now scan the dir looking for fun stuff */
1553 if ((dir = opendir(path)) == NULL) { 1570 subdir_fd = openat(dir_fd, path, O_RDONLY|O_CLOEXEC);
1571 if (subdir_fd == -1)
1572 dir = NULL;
1573 else
1574 dir = fdopendir(subdir_fd);
1575 if (dir == NULL) {
1576 if (subdir_fd != -1)
1577 close(subdir_fd);
1554 warnf("could not opendir %s: %s", path, strerror(errno)); 1578 warnf("could not opendir %s: %s", path, strerror(errno));
1555 return 1; 1579 return 1;
1556 } 1580 }
1557 if (be_verbose > 1) printf("%s: scanning dir\n", path); 1581 if (be_verbose > 1) printf("%s: scanning dir\n", path);
1558 1582
1559 pathlen = strlen(path); 1583 subpath = stpcpy(buf, path);
1584 *subpath++ = '/';
1585 pathlen = subpath - buf;
1560 while ((dentry = readdir(dir))) { 1586 while ((dentry = readdir(dir))) {
1561 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, "..")) 1587 if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
1562 continue; 1588 continue;
1563 len = (pathlen + 1 + strlen(dentry->d_name) + 1); 1589
1564 if (len >= sizeof(buf)) { 1590 if (fstatat(subdir_fd, dentry->d_name, &st, AT_SYMLINK_NOFOLLOW) == -1)
1565 warnf("Skipping '%s': len > sizeof(buf); %lu > %lu\n", path,
1566 (unsigned long)len, (unsigned long)sizeof(buf));
1567 continue; 1591 continue;
1592
1593 len = strlen(dentry->d_name);
1594 if (len + pathlen + 1 >= sizeof(buf)) {
1595 warnf("Skipping '%s%s': len > sizeof(buf); %zu > %zu\n",
1596 path, dentry->d_name, len + pathlen + 1, sizeof(buf));
1597 continue;
1568 } 1598 }
1569 snprintf(buf, sizeof(buf), "%s%s%s", path, (path[pathlen-1] == '/') ? "" : "/", dentry->d_name); 1599 memcpy(subpath, dentry->d_name, len);
1570 if (lstat(buf, &st) != -1) { 1600 subpath[len] = '\0';
1601
1571 if (S_ISREG(st.st_mode)) 1602 if (S_ISREG(st.st_mode))
1572 ret = scanelf_file(buf, &st); 1603 ret = scanelf_fileat(dir_fd, buf, &st);
1573 else if (dir_recurse && S_ISDIR(st.st_mode)) { 1604 else if (dir_recurse && S_ISDIR(st.st_mode)) {
1574 if (dir_crossmount || (st_top.st_dev == st.st_dev)) 1605 if (dir_crossmount || (st_top.st_dev == st.st_dev))
1575 ret = scanelf_dir(buf); 1606 ret = scanelf_dirat(dir_fd, buf);
1576 }
1577 } 1607 }
1578 } 1608 }
1579 closedir(dir); 1609 closedir(dir);
1610
1580 return ret; 1611 return ret;
1612}
1613static int scanelf_dir(const char *path)
1614{
1615 return scanelf_dirat(root_fd, root_rel_path(path));
1581} 1616}
1582 1617
1583static int scanelf_from_file(const char *filename) 1618static int scanelf_from_file(const char *filename)
1584{ 1619{
1585 FILE *fp; 1620 FILE *fp;
1614static int load_ld_cache_config(int i, const char *fname) 1649static int load_ld_cache_config(int i, const char *fname)
1615{ 1650{
1616 FILE *fp = NULL; 1651 FILE *fp = NULL;
1617 char *p, *path; 1652 char *p, *path;
1618 size_t len; 1653 size_t len;
1619 char _fname[__PAX_UTILS_PATH_MAX]; 1654 int curr_fd = -1;
1620 1655
1621 fname = maybe_add_root(fname, _fname); 1656 fp = fopenat_r(root_fd, root_rel_path(fname));
1622 1657 if (fp == NULL)
1623 if ((fp = fopen(fname, "r")) == NULL)
1624 return i; 1658 return i;
1625 1659
1626 path = NULL; 1660 path = NULL;
1627 len = 0; 1661 len = 0;
1628 while (getline(&path, &len, fp) != -1) { 1662 while (getline(&path, &len, fp) != -1) {
1633 1667
1634 /* recursive includes of the same file will make this segfault. */ 1668 /* recursive includes of the same file will make this segfault. */
1635 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) { 1669 if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) {
1636 glob_t gl; 1670 glob_t gl;
1637 size_t x; 1671 size_t x;
1638 char gpath[__PAX_UTILS_PATH_MAX]; 1672 const char *gpath;
1639 1673
1640 memset(gpath, 0, sizeof(gpath)); 1674 /* re-use existing path buffer ... need to be creative */
1641 if (root)
1642 strcpy(gpath, root);
1643
1644 if (path[8] != '/') 1675 if (path[8] != '/')
1645 snprintf(gpath+strlen(gpath), sizeof(gpath)-strlen(gpath), "/etc/%s", &path[8]); 1676 gpath = memcpy(path + 3, "/etc/", 5);
1646 else 1677 else
1647 strncpy(gpath+strlen(gpath), &path[8], sizeof(gpath)-strlen(gpath)); 1678 gpath = path + 8;
1679 if (root_fd != AT_FDCWD) {
1680 if (curr_fd == -1) {
1681 curr_fd = open(".", O_RDONLY|O_CLOEXEC);
1682 if (fchdir(root_fd))
1683 errp("unable to change to root dir");
1684 }
1685 gpath = root_rel_path(gpath);
1686 }
1648 1687
1649 if (glob(gpath, 0, NULL, &gl) == 0) { 1688 if (glob(gpath, 0, NULL, &gl) == 0) {
1650 for (x = 0; x < gl.gl_pathc; ++x) { 1689 for (x = 0; x < gl.gl_pathc; ++x) {
1651 /* try to avoid direct loops */ 1690 /* try to avoid direct loops */
1652 if (strcmp(gl.gl_pathv[x], fname) == 0) 1691 if (strcmp(gl.gl_pathv[x], fname) == 0)
1653 continue; 1692 continue;
1654 i = load_ld_cache_config(i, gl.gl_pathv[x]); 1693 i = load_ld_cache_config(i, gl.gl_pathv[x]);
1655 } 1694 }
1656 globfree(&gl); 1695 globfree(&gl);
1657 continue;
1658 } 1696 }
1697
1698 /* failed globs are ignored by glibc */
1699 continue;
1659 } 1700 }
1660 1701
1661 if (*path != '/') 1702 if (*path != '/')
1662 continue; 1703 continue;
1663 1704
1664 xarraypush(ldpaths, path, strlen(path)); 1705 xarraypush(ldpaths, path, strlen(path));
1665 } 1706 }
1666 free(path); 1707 free(path);
1667 1708
1668 fclose(fp); 1709 fclose(fp);
1710
1711 if (curr_fd != -1) {
1712 if (fchdir(curr_fd))
1713 /* don't care */;
1714 close(curr_fd);
1715 }
1669 1716
1670 return i; 1717 return i;
1671} 1718}
1672 1719
1673#elif defined(__FreeBSD__) || defined(__DragonFly__) 1720#elif defined(__FreeBSD__) || defined(__DragonFly__)
1675static int load_ld_cache_config(int i, const char *fname) 1722static int load_ld_cache_config(int i, const char *fname)
1676{ 1723{
1677 FILE *fp = NULL; 1724 FILE *fp = NULL;
1678 char *b = NULL, *p; 1725 char *b = NULL, *p;
1679 struct elfhints_hdr hdr; 1726 struct elfhints_hdr hdr;
1680 char _fname[__PAX_UTILS_PATH_MAX];
1681 1727
1682 fname = maybe_add_root(fname, _fname); 1728 fp = fopenat_r(root_fd, root_rel_path(fname));
1683 1729 if (fp == NULL)
1684 if ((fp = fopen(fname, "r")) == NULL)
1685 return i; 1730 return i;
1686 1731
1687 if (fread(&hdr, 1, sizeof(hdr), fp) != sizeof(hdr) || 1732 if (fread(&hdr, 1, sizeof(hdr), fp) != sizeof(hdr) ||
1688 hdr.magic != ELFHINTS_MAGIC || hdr.version != 1 || 1733 hdr.magic != ELFHINTS_MAGIC || hdr.version != 1 ||
1689 fseek(fp, hdr.strtab + hdr.dirlist, SEEK_SET) == -1) 1734 fseek(fp, hdr.strtab + hdr.dirlist, SEEK_SET) == -1)
2013 case 'a': show_perms = show_pax = show_phdr = show_textrel = show_rpath = show_bind = show_endian = 1; break; 2058 case 'a': show_perms = show_pax = show_phdr = show_textrel = show_rpath = show_bind = show_endian = 1; break;
2014 case 'D': show_endian = 1; break; 2059 case 'D': show_endian = 1; break;
2015 case 'I': show_osabi = 1; break; 2060 case 'I': show_osabi = 1; break;
2016 case 'Y': show_eabi = 1; break; 2061 case 'Y': show_eabi = 1; break;
2017 case 128: 2062 case 128:
2018 root = optarg; 2063 root_fd = open(optarg, O_RDONLY|O_CLOEXEC);
2064 if (root_fd == -1)
2065 err("Could not open root: %s", optarg);
2019 break; 2066 break;
2020 case ':': 2067 case ':':
2021 err("Option '%c' is missing parameter", optopt); 2068 err("Option '%c' is missing parameter", optopt);
2022 case '?': 2069 case '?':
2023 err("Unknown option '%c' or argument missing", optopt); 2070 err("Unknown option '%c' or argument missing", optopt);
2192 ret = parseargs(argc, argv); 2239 ret = parseargs(argc, argv);
2193 fclose(stdout); 2240 fclose(stdout);
2194#ifdef __PAX_UTILS_CLEANUP 2241#ifdef __PAX_UTILS_CLEANUP
2195 cleanup(); 2242 cleanup();
2196 warn("The calls to add/delete heap should be off:\n" 2243 warn("The calls to add/delete heap should be off:\n"
2197 "\t- 1 due to the out_buffer not being freed in scanelf_file()\n" 2244 "\t- 1 due to the out_buffer not being freed in scanelf_fileat()\n"
2198 "\t- 1 per QA_TEXTRELS/QA_EXECSTACK/QA_WX_LOAD"); 2245 "\t- 1 per QA_TEXTRELS/QA_EXECSTACK/QA_WX_LOAD");
2199#endif 2246#endif
2200 return ret; 2247 return ret;
2201} 2248}
2202 2249

Legend:
Removed from v.1.231  
changed lines
  Added in v.1.232

  ViewVC Help
Powered by ViewVC 1.1.20