| 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.179 2007/06/09 18:54:44 solar Exp $ |
4 | * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.180 2007/06/09 21:43:53 solar 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 | |
| 10 | #include "paxinc.h" |
10 | #include "paxinc.h" |
| 11 | |
11 | |
| 12 | static const char *rcsid = "$Id: scanelf.c,v 1.179 2007/06/09 18:54:44 solar Exp $"; |
12 | static const char *rcsid = "$Id: scanelf.c,v 1.180 2007/06/09 21:43:53 solar Exp $"; |
| 13 | #define argv0 "scanelf" |
13 | #define argv0 "scanelf" |
| 14 | |
14 | |
| 15 | #define IS_MODIFIER(c) (c == '%' || c == '#' || c == '+') |
15 | #define IS_MODIFIER(c) (c == '%' || c == '#' || c == '+') |
| 16 | |
16 | |
| 17 | /* prototypes */ |
17 | /* prototypes */ |
| … | |
… | |
| 43 | static char scan_symlink = 1; |
43 | static char scan_symlink = 1; |
| 44 | static char scan_archives = 0; |
44 | static char scan_archives = 0; |
| 45 | static char dir_recurse = 0; |
45 | static char dir_recurse = 0; |
| 46 | static char dir_crossmount = 1; |
46 | static char dir_crossmount = 1; |
| 47 | static char show_pax = 0; |
47 | static char show_pax = 0; |
|
|
48 | static char show_perms = 0; |
| 48 | static char show_phdr = 0; |
49 | static char show_phdr = 0; |
| 49 | static char show_textrel = 0; |
50 | static char show_textrel = 0; |
| 50 | static char show_rpath = 0; |
51 | static char show_rpath = 0; |
| 51 | static char show_needed = 0; |
52 | static char show_needed = 0; |
| 52 | static char show_interp = 0; |
53 | static char show_interp = 0; |
| … | |
… | |
| 70 | static char **qa_textrels = NULL; |
71 | static char **qa_textrels = NULL; |
| 71 | static char **qa_execstack = NULL; |
72 | static char **qa_execstack = NULL; |
| 72 | static char **qa_wx_load = NULL; |
73 | static char **qa_wx_load = NULL; |
| 73 | |
74 | |
| 74 | int match_bits = 0; |
75 | int match_bits = 0; |
|
|
76 | unsigned int match_perms = 0; |
| 75 | caddr_t ldcache = 0; |
77 | caddr_t ldcache = 0; |
| 76 | size_t ldcache_size = 0; |
78 | size_t ldcache_size = 0; |
| 77 | unsigned long setpax = 0UL; |
79 | unsigned long setpax = 0UL; |
| 78 | |
80 | |
| 79 | int has_objdump = 0; |
81 | int has_objdump = 0; |
|
|
82 | |
|
|
83 | static char *getstr_perms(const char *fname); |
|
|
84 | static char *getstr_perms(const char *fname) { |
|
|
85 | struct stat st; |
|
|
86 | static char buf[8]; |
|
|
87 | |
|
|
88 | if ((stat(fname, &st)) == (-1)) |
|
|
89 | return (char *) ""; |
|
|
90 | |
|
|
91 | snprintf(buf, sizeof(buf), "%o", st.st_mode); |
|
|
92 | |
|
|
93 | return (char *) buf + 2; |
|
|
94 | } |
| 80 | |
95 | |
| 81 | /* find the path to a file by name */ |
96 | /* find the path to a file by name */ |
| 82 | static char *which(const char *fname) |
97 | static char *which(const char *fname) |
| 83 | { |
98 | { |
| 84 | static char fullpath[BUFSIZ]; |
99 | static char fullpath[BUFSIZ]; |
| … | |
… | |
| 362 | if (be_quiet || be_wewy_wewy_quiet) |
377 | if (be_quiet || be_wewy_wewy_quiet) |
| 363 | return NULL; |
378 | return NULL; |
| 364 | else |
379 | else |
| 365 | return " - "; |
380 | return " - "; |
| 366 | } |
381 | } |
|
|
382 | |
| 367 | static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel) |
383 | static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel) |
| 368 | { |
384 | { |
| 369 | unsigned long s, r, rmax; |
385 | unsigned long s, r, rmax; |
| 370 | void *symtab_void, *strtab_void, *text_void; |
386 | void *symtab_void, *strtab_void, *text_void; |
| 371 | |
387 | |
| … | |
… | |
| 1134 | case 's': prints("SYM "); break; |
1150 | case 's': prints("SYM "); break; |
| 1135 | case 'N': prints("LIB "); break; |
1151 | case 'N': prints("LIB "); break; |
| 1136 | case 'T': prints("TEXTRELS "); break; |
1152 | case 'T': prints("TEXTRELS "); break; |
| 1137 | case 'k': prints("SECTION "); break; |
1153 | case 'k': prints("SECTION "); break; |
| 1138 | case 'a': prints("ARCH "); break; |
1154 | case 'a': prints("ARCH "); break; |
|
|
1155 | case 'O': prints("PERM "); break; |
| 1139 | default: warnf("'%c' has no title ?", out_format[i]); |
1156 | default: warnf("'%c' has no title ?", out_format[i]); |
| 1140 | } |
1157 | } |
| 1141 | } |
1158 | } |
| 1142 | if (!found_file) prints("FILE "); |
1159 | if (!found_file) prints("FILE "); |
| 1143 | prints("\n"); |
1160 | prints("\n"); |
| … | |
… | |
| 1194 | case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break; |
1211 | case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break; |
| 1195 | case 't': out = scanelf_file_textrel(elf, &found_textrel); break; |
1212 | case 't': out = scanelf_file_textrel(elf, &found_textrel); break; |
| 1196 | case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break; |
1213 | case 'T': out = scanelf_file_textrels(elf, &found_textrels, &found_textrel); break; |
| 1197 | case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break; |
1214 | case 'r': scanelf_file_rpath(elf, &found_rpath, &out_buffer, &out_len); break; |
| 1198 | case 'M': out = get_elfeitype(EI_CLASS, elf->data[EI_CLASS]); break; |
1215 | case 'M': out = get_elfeitype(EI_CLASS, elf->data[EI_CLASS]); break; |
|
|
1216 | case 'O': out = getstr_perms(elf->filename); break; |
| 1199 | case 'n': |
1217 | case 'n': |
| 1200 | case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break; |
1218 | case 'N': out = scanelf_file_needed_lib(elf, &found_needed, &found_lib, (out_format[i]=='N'), &out_buffer, &out_len); break; |
| 1201 | case 'i': out = scanelf_file_interp(elf, &found_interp); break; |
1219 | case 'i': out = scanelf_file_interp(elf, &found_interp); break; |
| 1202 | case 'b': out = scanelf_file_bind(elf, &found_bind); break; |
1220 | case 'b': out = scanelf_file_bind(elf, &found_bind); break; |
| 1203 | case 'S': out = scanelf_file_soname(elf, &found_soname); break; |
1221 | case 'S': out = scanelf_file_soname(elf, &found_soname); break; |
| … | |
… | |
| 1318 | if (!S_ISREG(st->st_mode)) { |
1336 | if (!S_ISREG(st->st_mode)) { |
| 1319 | if (be_verbose > 2) printf("%s: skipping non-file\n", filename); |
1337 | if (be_verbose > 2) printf("%s: skipping non-file\n", filename); |
| 1320 | return 1; |
1338 | return 1; |
| 1321 | } |
1339 | } |
| 1322 | |
1340 | |
|
|
1341 | if (match_perms) { |
|
|
1342 | if ((st->st_mode | match_perms) != st->st_mode) |
|
|
1343 | return 1; |
|
|
1344 | } |
| 1323 | if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1) |
1345 | if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1) |
| 1324 | return 1; |
1346 | return 1; |
| 1325 | |
1347 | |
| 1326 | if (scanelf_elf(filename, fd, st->st_size) == 1 && scan_archives) |
1348 | if (scanelf_elf(filename, fd, st->st_size) == 1 && scan_archives) |
| 1327 | /* if it isn't an ELF, maybe it's an .a archive */ |
1349 | /* if it isn't an ELF, maybe it's an .a archive */ |
| … | |
… | |
| 1563 | |
1585 | |
| 1564 | free(path); |
1586 | free(path); |
| 1565 | } |
1587 | } |
| 1566 | |
1588 | |
| 1567 | /* usage / invocation handling functions */ |
1589 | /* usage / invocation handling functions */ |
| 1568 | #define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:BhV" |
1590 | #define PARSE_FLAGS "plRmyAXz:xetrnLibSs:k:gN:TaqvF:f:o:E:M:O:BhV" |
| 1569 | #define a_argument required_argument |
1591 | #define a_argument required_argument |
| 1570 | static struct option const long_opts[] = { |
1592 | static struct option const long_opts[] = { |
| 1571 | {"path", no_argument, NULL, 'p'}, |
1593 | {"path", no_argument, NULL, 'p'}, |
| 1572 | {"ldpath", no_argument, NULL, 'l'}, |
1594 | {"ldpath", no_argument, NULL, 'l'}, |
| 1573 | {"recursive", no_argument, NULL, 'R'}, |
1595 | {"recursive", no_argument, NULL, 'R'}, |
| … | |
… | |
| 1590 | {"lib", a_argument, NULL, 'N'}, |
1612 | {"lib", a_argument, NULL, 'N'}, |
| 1591 | {"gmatch", no_argument, NULL, 'g'}, |
1613 | {"gmatch", no_argument, NULL, 'g'}, |
| 1592 | {"textrels", no_argument, NULL, 'T'}, |
1614 | {"textrels", no_argument, NULL, 'T'}, |
| 1593 | {"etype", a_argument, NULL, 'E'}, |
1615 | {"etype", a_argument, NULL, 'E'}, |
| 1594 | {"bits", a_argument, NULL, 'M'}, |
1616 | {"bits", a_argument, NULL, 'M'}, |
|
|
1617 | {"perms", a_argument, NULL, 'O'}, |
| 1595 | {"all", no_argument, NULL, 'a'}, |
1618 | {"all", no_argument, NULL, 'a'}, |
| 1596 | {"quiet", no_argument, NULL, 'q'}, |
1619 | {"quiet", no_argument, NULL, 'q'}, |
| 1597 | {"verbose", no_argument, NULL, 'v'}, |
1620 | {"verbose", no_argument, NULL, 'v'}, |
| 1598 | {"format", a_argument, NULL, 'F'}, |
1621 | {"format", a_argument, NULL, 'F'}, |
| 1599 | {"from", a_argument, NULL, 'f'}, |
1622 | {"from", a_argument, NULL, 'f'}, |
| … | |
… | |
| 1627 | "Find a specified library", |
1650 | "Find a specified library", |
| 1628 | "Use strncmp to match libraries. (use with -N)", |
1651 | "Use strncmp to match libraries. (use with -N)", |
| 1629 | "Locate cause of TEXTREL", |
1652 | "Locate cause of TEXTREL", |
| 1630 | "Print only ELF files matching etype ET_DYN,ET_EXEC ...", |
1653 | "Print only ELF files matching etype ET_DYN,ET_EXEC ...", |
| 1631 | "Print only ELF files matching numeric bits", |
1654 | "Print only ELF files matching numeric bits", |
|
|
1655 | "Print only ELF files matching octal permissions", |
| 1632 | "Print all scanned info (-x -e -t -r -b)\n", |
1656 | "Print all scanned info (-x -e -t -r -b)\n", |
| 1633 | "Only output 'bad' things", |
1657 | "Only output 'bad' things", |
| 1634 | "Be verbose (can be specified more than once)", |
1658 | "Be verbose (can be specified more than once)", |
| 1635 | "Use specified format for output", |
1659 | "Use specified format for output", |
| 1636 | "Read input stream from a filename", |
1660 | "Read input stream from a filename", |
| … | |
… | |
| 1693 | case 'E': |
1717 | case 'E': |
| 1694 | strncpy(match_etypes, optarg, sizeof(match_etypes)); |
1718 | strncpy(match_etypes, optarg, sizeof(match_etypes)); |
| 1695 | break; |
1719 | break; |
| 1696 | case 'M': |
1720 | case 'M': |
| 1697 | match_bits = atoi(optarg); |
1721 | match_bits = atoi(optarg); |
|
|
1722 | break; |
|
|
1723 | case 'O': |
|
|
1724 | if (sscanf(optarg, "%o", &match_perms) == (-1)) |
|
|
1725 | match_bits = 0; |
| 1698 | break; |
1726 | break; |
| 1699 | case 'o': { |
1727 | case 'o': { |
| 1700 | if (freopen(optarg, "w", stdout) == NULL) |
1728 | if (freopen(optarg, "w", stdout) == NULL) |
| 1701 | err("Could not open output stream '%s': %s", optarg, strerror(errno)); |
1729 | err("Could not open output stream '%s': %s", optarg, strerror(errno)); |
| 1702 | break; |
1730 | break; |
| … | |
… | |
| 1785 | case 'b': show_bind = 1; break; |
1813 | case 'b': show_bind = 1; break; |
| 1786 | case 'S': show_soname = 1; break; |
1814 | case 'S': show_soname = 1; break; |
| 1787 | case 'T': show_textrels = 1; break; |
1815 | case 'T': show_textrels = 1; break; |
| 1788 | case 'q': be_quiet = 1; break; |
1816 | case 'q': be_quiet = 1; break; |
| 1789 | case 'v': be_verbose = (be_verbose % 20) + 1; break; |
1817 | case 'v': be_verbose = (be_verbose % 20) + 1; break; |
| 1790 | case 'a': show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break; |
1818 | case 'a': show_perms = show_pax = show_phdr = show_textrel = show_rpath = show_bind = 1; break; |
| 1791 | |
1819 | |
| 1792 | case ':': |
1820 | case ':': |
| 1793 | err("Option '%c' is missing parameter", optopt); |
1821 | err("Option '%c' is missing parameter", optopt); |
| 1794 | case '?': |
1822 | case '?': |
| 1795 | err("Unknown option '%c' or argument missing", optopt); |
1823 | err("Unknown option '%c' or argument missing", optopt); |
| … | |
… | |
| 1803 | } |
1831 | } |
| 1804 | /* let the format option override all other options */ |
1832 | /* let the format option override all other options */ |
| 1805 | if (out_format) { |
1833 | if (out_format) { |
| 1806 | show_pax = show_phdr = show_textrel = show_rpath = \ |
1834 | show_pax = show_phdr = show_textrel = show_rpath = \ |
| 1807 | show_needed = show_interp = show_bind = show_soname = \ |
1835 | show_needed = show_interp = show_bind = show_soname = \ |
| 1808 | show_textrels = 0; |
1836 | show_textrels = show_perms = 0; |
| 1809 | for (i = 0; out_format[i]; ++i) { |
1837 | for (i = 0; out_format[i]; ++i) { |
| 1810 | if (!IS_MODIFIER(out_format[i])) continue; |
1838 | if (!IS_MODIFIER(out_format[i])) continue; |
| 1811 | |
1839 | |
| 1812 | switch (out_format[++i]) { |
1840 | switch (out_format[++i]) { |
| 1813 | case '+': break; |
1841 | case '+': break; |
| … | |
… | |
| 1820 | case 's': break; |
1848 | case 's': break; |
| 1821 | case 'N': break; |
1849 | case 'N': break; |
| 1822 | case 'o': break; |
1850 | case 'o': break; |
| 1823 | case 'a': break; |
1851 | case 'a': break; |
| 1824 | case 'M': break; |
1852 | case 'M': break; |
|
|
1853 | case 'O': show_perms = 1; break; |
| 1825 | case 'x': show_pax = 1; break; |
1854 | case 'x': show_pax = 1; break; |
| 1826 | case 'e': show_phdr = 1; break; |
1855 | case 'e': show_phdr = 1; break; |
| 1827 | case 't': show_textrel = 1; break; |
1856 | case 't': show_textrel = 1; break; |
| 1828 | case 'r': show_rpath = 1; break; |
1857 | case 'r': show_rpath = 1; break; |
| 1829 | case 'n': show_needed = 1; break; |
1858 | case 'n': show_needed = 1; break; |
| … | |
… | |
| 1841 | } else { |
1870 | } else { |
| 1842 | size_t fmt_len = 30; |
1871 | size_t fmt_len = 30; |
| 1843 | out_format = (char*)xmalloc(sizeof(char) * fmt_len); |
1872 | out_format = (char*)xmalloc(sizeof(char) * fmt_len); |
| 1844 | if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len); |
1873 | if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len); |
| 1845 | if (show_pax) xstrcat(&out_format, "%x ", &fmt_len); |
1874 | if (show_pax) xstrcat(&out_format, "%x ", &fmt_len); |
|
|
1875 | if (show_perms) xstrcat(&out_format, "%O ", &fmt_len); |
| 1846 | if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len); |
1876 | if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len); |
| 1847 | if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); |
1877 | if (show_textrel) xstrcat(&out_format, "%t ", &fmt_len); |
| 1848 | if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); |
1878 | if (show_rpath) xstrcat(&out_format, "%r ", &fmt_len); |
| 1849 | if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); |
1879 | if (show_needed) xstrcat(&out_format, "%n ", &fmt_len); |
| 1850 | if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); |
1880 | if (show_interp) xstrcat(&out_format, "%i ", &fmt_len); |