| 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.185 2007/08/18 04:59:32 vapier Exp $ |
4 | * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.186 2007/08/20 09:54:15 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 | |
|
|
10 | static const char *rcsid = "$Id: scanelf.c,v 1.186 2007/08/20 09:54:15 vapier Exp $"; |
|
|
11 | const char * const argv0 = "scanelf"; |
|
|
12 | |
| 10 | #include "paxinc.h" |
13 | #include "paxinc.h" |
| 11 | |
|
|
| 12 | static const char *rcsid = "$Id: scanelf.c,v 1.185 2007/08/18 04:59:32 vapier Exp $"; |
|
|
| 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 */ |
| 18 | static int file_matches_list(const char *filename, char **matchlist); |
18 | static int file_matches_list(const char *filename, char **matchlist); |
| … | |
… | |
| 25 | static void scanelf_envpath(void); |
25 | static void scanelf_envpath(void); |
| 26 | static void usage(int status); |
26 | static void usage(int status); |
| 27 | static char **get_split_env(const char *envvar); |
27 | static char **get_split_env(const char *envvar); |
| 28 | static void parseenv(void); |
28 | static void parseenv(void); |
| 29 | static int parseargs(int argc, char *argv[]); |
29 | static int parseargs(int argc, char *argv[]); |
| 30 | static char *xstrdup(const char *s); |
|
|
| 31 | static void *xmalloc(size_t size); |
|
|
| 32 | static void *xrealloc(void *ptr, size_t size); |
|
|
| 33 | static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n); |
|
|
| 34 | #define xstrcat(dst,src,curr_len) xstrncat(dst,src,curr_len,0) |
|
|
| 35 | static inline void xchrcat(char **dst, const char append, size_t *curr_len); |
|
|
| 36 | static int rematch(const char *regex, const char *match, int cflags); |
30 | static int rematch(const char *regex, const char *match, int cflags); |
| 37 | |
31 | |
| 38 | /* variables to control behavior */ |
32 | /* variables to control behavior */ |
| 39 | static char match_etypes[126] = ""; |
33 | static char match_etypes[126] = ""; |
| 40 | static char *ldpaths[256]; |
34 | static char *ldpaths[256]; |
| … | |
… | |
| 80 | unsigned long setpax = 0UL; |
74 | unsigned long setpax = 0UL; |
| 81 | |
75 | |
| 82 | int has_objdump = 0; |
76 | int has_objdump = 0; |
| 83 | |
77 | |
| 84 | static char *getstr_perms(const char *fname); |
78 | static char *getstr_perms(const char *fname); |
| 85 | static char *getstr_perms(const char *fname) { |
79 | static char *getstr_perms(const char *fname) |
|
|
80 | { |
| 86 | struct stat st; |
81 | struct stat st; |
| 87 | static char buf[8]; |
82 | static char buf[8]; |
| 88 | |
83 | |
| 89 | if ((stat(fname, &st)) == (-1)) |
84 | if ((stat(fname, &st)) == (-1)) |
| 90 | return (char *) ""; |
85 | return (char *) ""; |
| … | |
… | |
| 339 | return NULL; |
334 | return NULL; |
| 340 | else |
335 | else |
| 341 | return ret; |
336 | return ret; |
| 342 | } |
337 | } |
| 343 | |
338 | |
|
|
339 | /* |
|
|
340 | * See if this ELF contains a DT_TEXTREL tag in any of its |
|
|
341 | * PT_DYNAMIC sections. |
|
|
342 | */ |
| 344 | static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel) |
343 | static const char *scanelf_file_textrel(elfobj *elf, char *found_textrel) |
| 345 | { |
344 | { |
| 346 | static const char *ret = "TEXTREL"; |
345 | static const char *ret = "TEXTREL"; |
| 347 | unsigned long i; |
346 | unsigned long i; |
| 348 | |
347 | |
| … | |
… | |
| 379 | return NULL; |
378 | return NULL; |
| 380 | else |
379 | else |
| 381 | return " - "; |
380 | return " - "; |
| 382 | } |
381 | } |
| 383 | |
382 | |
|
|
383 | /* |
|
|
384 | * Scan the .text section to see if there are any relocations in it. |
|
|
385 | * Should rewrite this to check PT_LOAD sections that are marked |
|
|
386 | * Executable rather than the section named '.text'. |
|
|
387 | */ |
| 384 | static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel) |
388 | static char *scanelf_file_textrels(elfobj *elf, char *found_textrels, char *found_textrel) |
| 385 | { |
389 | { |
| 386 | unsigned long s, r, rmax; |
390 | unsigned long s, r, rmax; |
| 387 | void *symtab_void, *strtab_void, *text_void; |
391 | void *symtab_void, *strtab_void, *text_void; |
| 388 | |
392 | |
| … | |
… | |
| 1120 | printf("%s: scanning file\n", elf->filename); |
1124 | printf("%s: scanning file\n", elf->filename); |
| 1121 | |
1125 | |
| 1122 | /* init output buffer */ |
1126 | /* init output buffer */ |
| 1123 | if (!out_buffer) { |
1127 | if (!out_buffer) { |
| 1124 | out_len = sizeof(char) * 80; |
1128 | out_len = sizeof(char) * 80; |
| 1125 | out_buffer = (char*)xmalloc(out_len); |
1129 | out_buffer = xmalloc(out_len); |
| 1126 | } |
1130 | } |
| 1127 | *out_buffer = '\0'; |
1131 | *out_buffer = '\0'; |
| 1128 | |
1132 | |
| 1129 | /* show the header */ |
1133 | /* show the header */ |
| 1130 | if (!be_quiet && show_banner) { |
1134 | if (!be_quiet && show_banner) { |
| … | |
… | |
| 1278 | if (strlen(match_etypes)) { |
1282 | if (strlen(match_etypes)) { |
| 1279 | char sbuf[126]; |
1283 | char sbuf[126]; |
| 1280 | strncpy(sbuf, match_etypes, sizeof(sbuf)); |
1284 | strncpy(sbuf, match_etypes, sizeof(sbuf)); |
| 1281 | if (strchr(match_etypes, ',') != NULL) { |
1285 | if (strchr(match_etypes, ',') != NULL) { |
| 1282 | char *p; |
1286 | char *p; |
| 1283 | while((p = strrchr(sbuf, ',')) != NULL) { |
1287 | while ((p = strrchr(sbuf, ',')) != NULL) { |
| 1284 | *p = 0; |
1288 | *p = 0; |
| 1285 | if (etype_lookup(p+1) == get_etype(elf)) |
1289 | if (etype_lookup(p+1) == get_etype(elf)) |
| 1286 | goto label_ret; |
1290 | goto label_ret; |
| 1287 | } |
1291 | } |
| 1288 | } |
1292 | } |
| … | |
… | |
| 1449 | if ((p = strrchr(path, '\r')) != NULL) |
1453 | if ((p = strrchr(path, '\r')) != NULL) |
| 1450 | *p = 0; |
1454 | *p = 0; |
| 1451 | if ((p = strchr(path, '\n')) != NULL) |
1455 | if ((p = strchr(path, '\n')) != NULL) |
| 1452 | *p = 0; |
1456 | *p = 0; |
| 1453 | #ifdef __linux__ |
1457 | #ifdef __linux__ |
| 1454 | // recursive includes of the same file will make this segfault. |
1458 | /* recursive includes of the same file will make this segfault. */ |
| 1455 | if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) { |
1459 | if ((memcmp(path, "include", 7) == 0) && isblank(path[7])) { |
| 1456 | glob64_t gl; |
1460 | glob64_t gl; |
| 1457 | size_t x; |
1461 | size_t x; |
| 1458 | char gpath[__PAX_UTILS_PATH_MAX]; |
1462 | char gpath[__PAX_UTILS_PATH_MAX]; |
| 1459 | |
1463 | |
| … | |
… | |
| 1514 | { |
1518 | { |
| 1515 | fclose(fp); |
1519 | fclose(fp); |
| 1516 | return i; |
1520 | return i; |
| 1517 | } |
1521 | } |
| 1518 | |
1522 | |
| 1519 | b = (char*)malloc(hdr.dirlistlen+1); |
1523 | b = xmalloc(hdr.dirlistlen + 1); |
| 1520 | if (fread(b, 1, hdr.dirlistlen+1, fp) != hdr.dirlistlen+1) { |
1524 | if (fread(b, 1, hdr.dirlistlen+1, fp) != hdr.dirlistlen+1) { |
| 1521 | fclose(fp); |
1525 | fclose(fp); |
| 1522 | free(b); |
1526 | free(b); |
| 1523 | return i; |
1527 | return i; |
| 1524 | } |
1528 | } |
| … | |
… | |
| 1746 | find_section = optarg; |
1750 | find_section = optarg; |
| 1747 | break; |
1751 | break; |
| 1748 | case 's': { |
1752 | case 's': { |
| 1749 | if (find_sym) warn("You prob don't want to specify -s twice"); |
1753 | if (find_sym) warn("You prob don't want to specify -s twice"); |
| 1750 | find_sym = optarg; |
1754 | find_sym = optarg; |
| 1751 | versioned_symname = (char*)xmalloc(sizeof(char) * (strlen(find_sym)+1+1)); |
1755 | versioned_symname = xmalloc(sizeof(char) * (strlen(find_sym)+1+1)); |
| 1752 | sprintf(versioned_symname, "%s@", find_sym); |
1756 | sprintf(versioned_symname, "%s@", find_sym); |
| 1753 | break; |
1757 | break; |
| 1754 | } |
1758 | } |
| 1755 | case 'N': { |
1759 | case 'N': { |
| 1756 | if (find_lib) warn("You prob don't want to specify -N twice"); |
1760 | if (find_lib) warn("You prob don't want to specify -N twice"); |
| … | |
… | |
| 1765 | } |
1769 | } |
| 1766 | case 'z': { |
1770 | case 'z': { |
| 1767 | unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC); |
1771 | unsigned long flags = (PF_NOEMUTRAMP | PF_NORANDEXEC); |
| 1768 | size_t x; |
1772 | size_t x; |
| 1769 | |
1773 | |
| 1770 | for (x = 0 ; x < strlen(optarg); x++) { |
1774 | for (x = 0; x < strlen(optarg); x++) { |
| 1771 | switch(optarg[x]) { |
1775 | switch (optarg[x]) { |
| 1772 | case 'p': |
1776 | case 'p': |
| 1773 | case 'P': |
1777 | case 'P': |
| 1774 | do_pax_state(optarg[x], PAGEEXEC); |
1778 | do_pax_state(optarg[x], PAGEEXEC); |
| 1775 | break; |
1779 | break; |
| 1776 | case 's': |
1780 | case 's': |
| … | |
… | |
| 1880 | } |
1884 | } |
| 1881 | |
1885 | |
| 1882 | /* construct our default format */ |
1886 | /* construct our default format */ |
| 1883 | } else { |
1887 | } else { |
| 1884 | size_t fmt_len = 30; |
1888 | size_t fmt_len = 30; |
| 1885 | out_format = (char*)xmalloc(sizeof(char) * fmt_len); |
1889 | out_format = xmalloc(sizeof(char) * fmt_len); |
| 1886 | if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len); |
1890 | if (!be_quiet) xstrcat(&out_format, "%o ", &fmt_len); |
| 1887 | if (show_pax) xstrcat(&out_format, "%x ", &fmt_len); |
1891 | if (show_pax) xstrcat(&out_format, "%x ", &fmt_len); |
| 1888 | if (show_perms) xstrcat(&out_format, "%O ", &fmt_len); |
1892 | if (show_perms) xstrcat(&out_format, "%O ", &fmt_len); |
| 1889 | if (show_endian) xstrcat(&out_format, "%D ", &fmt_len); |
1893 | if (show_endian) xstrcat(&out_format, "%D ", &fmt_len); |
| 1890 | if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len); |
1894 | if (show_phdr) xstrcat(&out_format, "%e ", &fmt_len); |
| … | |
… | |
| 1998 | #endif |
2002 | #endif |
| 1999 | return ret; |
2003 | return ret; |
| 2000 | } |
2004 | } |
| 2001 | |
2005 | |
| 2002 | |
2006 | |
| 2003 | |
|
|
| 2004 | /* utility funcs */ |
|
|
| 2005 | static char *xstrdup(const char *s) |
|
|
| 2006 | { |
|
|
| 2007 | char *ret = strdup(s); |
|
|
| 2008 | if (!ret) err("Could not strdup(): %s", strerror(errno)); |
|
|
| 2009 | return ret; |
|
|
| 2010 | } |
|
|
| 2011 | static void *xmalloc(size_t size) |
|
|
| 2012 | { |
|
|
| 2013 | void *ret = malloc(size); |
|
|
| 2014 | if (!ret) err("Could not malloc() %li bytes", (unsigned long)size); |
|
|
| 2015 | return ret; |
|
|
| 2016 | } |
|
|
| 2017 | static void *xrealloc(void *ptr, size_t size) |
|
|
| 2018 | { |
|
|
| 2019 | void *ret = realloc(ptr, size); |
|
|
| 2020 | if (!ret) err("Could not realloc() %li bytes", (unsigned long)size); |
|
|
| 2021 | return ret; |
|
|
| 2022 | } |
|
|
| 2023 | static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n) |
|
|
| 2024 | { |
|
|
| 2025 | size_t new_len; |
|
|
| 2026 | |
|
|
| 2027 | new_len = strlen(*dst) + strlen(src); |
|
|
| 2028 | if (*curr_len <= new_len) { |
|
|
| 2029 | *curr_len = new_len + (*curr_len / 2); |
|
|
| 2030 | *dst = realloc(*dst, *curr_len); |
|
|
| 2031 | if (!*dst) |
|
|
| 2032 | err("could not realloc() %li bytes", (unsigned long)*curr_len); |
|
|
| 2033 | } |
|
|
| 2034 | |
|
|
| 2035 | if (n) |
|
|
| 2036 | strncat(*dst, src, n); |
|
|
| 2037 | else |
|
|
| 2038 | strcat(*dst, src); |
|
|
| 2039 | } |
|
|
| 2040 | static inline void xchrcat(char **dst, const char append, size_t *curr_len) |
|
|
| 2041 | { |
|
|
| 2042 | static char my_app[2]; |
|
|
| 2043 | my_app[0] = append; |
|
|
| 2044 | my_app[1] = '\0'; |
|
|
| 2045 | xstrcat(dst, my_app, curr_len); |
|
|
| 2046 | } |
|
|
| 2047 | |
|
|
| 2048 | /* Match filename against entries in matchlist, return TRUE |
2007 | /* Match filename against entries in matchlist, return TRUE |
| 2049 | * if the file is listed */ |
2008 | * if the file is listed */ |
| 2050 | static int file_matches_list(const char *filename, char **matchlist) |
2009 | static int file_matches_list(const char *filename, char **matchlist) |
| 2051 | { |
2010 | { |
| 2052 | char **file; |
2011 | char **file; |