| 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/scanelf.c,v 1.105 2006/01/13 12:12:52 vapier Exp $ |
4 | * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.106 2006/01/14 01:39:55 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 | |
11 | |
| 12 | static const char *rcsid = "$Id: scanelf.c,v 1.105 2006/01/13 12:12:52 vapier Exp $"; |
12 | static const char *rcsid = "$Id: scanelf.c,v 1.106 2006/01/14 01:39:55 vapier Exp $"; |
| 13 | #define argv0 "scanelf" |
13 | #define argv0 "scanelf" |
| 14 | |
14 | |
| 15 | #define IS_MODIFIER(c) (c == '%' || c == '#') |
15 | #define IS_MODIFIER(c) (c == '%' || c == '#') |
| 16 | |
16 | |
| 17 | |
17 | |
| 18 | |
18 | |
| 19 | /* prototypes */ |
19 | /* prototypes */ |
|
|
20 | static int scanelf_elfobj(elfobj *elf); |
| 20 | static int scanelf_elf(const char *filename); |
21 | static int scanelf_elf(const char *filename, int fd, size_t len); |
| 21 | static int scanelf_archive(const char *filename); |
22 | static int scanelf_archive(const char *filename, int fd, size_t len); |
| 22 | static void scanelf_file(const char *filename); |
23 | static void scanelf_file(const char *filename); |
| 23 | static void scanelf_dir(const char *path); |
24 | static void scanelf_dir(const char *path); |
| 24 | static void scanelf_ldpath(); |
25 | static void scanelf_ldpath(void); |
| 25 | static void scanelf_envpath(); |
26 | static void scanelf_envpath(void); |
| 26 | static void usage(int status); |
27 | static void usage(int status); |
| 27 | static void parseargs(int argc, char *argv[]); |
28 | static void parseargs(int argc, char *argv[]); |
| 28 | static char *xstrdup(const char *s); |
29 | static char *xstrdup(const char *s); |
| 29 | static void *xmalloc(size_t size); |
30 | static void *xmalloc(size_t size); |
| 30 | static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n); |
31 | static void xstrncat(char **dst, const char *src, size_t *curr_len, size_t n); |
| … | |
… | |
| 848 | else |
849 | else |
| 849 | return (char *)" - "; |
850 | return (char *)" - "; |
| 850 | } |
851 | } |
| 851 | /* scan an elf file and show all the fun stuff */ |
852 | /* scan an elf file and show all the fun stuff */ |
| 852 | #define prints(str) write(fileno(stdout), str, strlen(str)) |
853 | #define prints(str) write(fileno(stdout), str, strlen(str)) |
| 853 | static int scanelf_elf(const char *filename) |
854 | static int scanelf_elfobj(elfobj *elf) |
| 854 | { |
855 | { |
| 855 | unsigned long i; |
856 | unsigned long i; |
| 856 | char found_pax, found_phdr, found_relro, found_load, found_textrel, |
857 | char found_pax, found_phdr, found_relro, found_load, found_textrel, |
| 857 | found_rpath, found_needed, found_interp, found_bind, found_soname, |
858 | found_rpath, found_needed, found_interp, found_bind, found_soname, |
| 858 | found_sym, found_lib, found_file, found_textrels; |
859 | found_sym, found_lib, found_file, found_textrels; |
| 859 | elfobj *elf; |
|
|
| 860 | static char *out_buffer = NULL; |
860 | static char *out_buffer = NULL; |
| 861 | static size_t out_len; |
861 | static size_t out_len; |
| 862 | |
862 | |
| 863 | found_pax = found_phdr = found_relro = found_load = found_textrel = \ |
863 | found_pax = found_phdr = found_relro = found_load = found_textrel = \ |
| 864 | found_rpath = found_needed = found_interp = found_bind = found_soname = \ |
864 | found_rpath = found_needed = found_interp = found_bind = found_soname = \ |
| 865 | found_sym = found_lib = found_file = found_textrels = 0; |
865 | found_sym = found_lib = found_file = found_textrels = 0; |
| 866 | |
866 | |
| 867 | /* verify this is real ELF */ |
|
|
| 868 | if ((elf = _readelf(filename, !fix_elf)) == NULL) { |
|
|
| 869 | if (be_verbose > 2) printf("%s: not an ELF\n", filename); |
|
|
| 870 | return 1; |
|
|
| 871 | } |
|
|
| 872 | |
|
|
| 873 | if (be_verbose > 1) |
867 | if (be_verbose > 1) |
| 874 | printf("%s: scanning file {%s,%s}\n", filename, |
868 | printf("%s: scanning file {%s,%s}\n", elf->filename, |
| 875 | get_elfeitype(EI_CLASS, elf->elf_class), |
869 | get_elfeitype(EI_CLASS, elf->elf_class), |
| 876 | get_elfeitype(EI_DATA, elf->data[EI_DATA])); |
870 | get_elfeitype(EI_DATA, elf->data[EI_DATA])); |
| 877 | else if (be_verbose) |
871 | else if (be_verbose) |
| 878 | printf("%s: scanning file\n", filename); |
872 | printf("%s: scanning file\n", elf->filename); |
| 879 | |
873 | |
| 880 | /* init output buffer */ |
874 | /* init output buffer */ |
| 881 | if (!out_buffer) { |
875 | if (!out_buffer) { |
| 882 | out_len = sizeof(char) * 80; |
876 | out_len = sizeof(char) * 80; |
| 883 | out_buffer = (char*)xmalloc(out_len); |
877 | out_buffer = (char*)xmalloc(out_len); |
| … | |
… | |
| 937 | case '#': |
931 | case '#': |
| 938 | xchrcat(&out_buffer, out_format[i], &out_len); break; |
932 | xchrcat(&out_buffer, out_format[i], &out_len); break; |
| 939 | case 'F': |
933 | case 'F': |
| 940 | found_file = 1; |
934 | found_file = 1; |
| 941 | if (be_wewy_wewy_quiet) break; |
935 | if (be_wewy_wewy_quiet) break; |
| 942 | xstrcat(&out_buffer, filename, &out_len); |
936 | xstrcat(&out_buffer, elf->filename, &out_len); |
| 943 | break; |
937 | break; |
| 944 | case 'p': |
938 | case 'p': |
| 945 | found_file = 1; |
939 | found_file = 1; |
| 946 | if (be_wewy_wewy_quiet) break; |
940 | if (be_wewy_wewy_quiet) break; |
| 947 | tmp = filename; |
941 | tmp = elf->filename; |
| 948 | if (search_path) { |
942 | if (search_path) { |
| 949 | ssize_t len_search = strlen(search_path); |
943 | ssize_t len_search = strlen(search_path); |
| 950 | ssize_t len_file = strlen(filename); |
944 | ssize_t len_file = strlen(elf->filename); |
| 951 | if (!strncmp(filename, search_path, len_search) && \ |
945 | if (!strncmp(elf->filename, search_path, len_search) && \ |
| 952 | len_file > len_search) |
946 | len_file > len_search) |
| 953 | tmp += len_search; |
947 | tmp += len_search; |
| 954 | if (*tmp == '/' && search_path[len_search-1] == '/') tmp++; |
948 | if (*tmp == '/' && search_path[len_search-1] == '/') tmp++; |
| 955 | } |
949 | } |
| 956 | xstrcat(&out_buffer, tmp, &out_len); |
950 | xstrcat(&out_buffer, tmp, &out_len); |
| 957 | break; |
951 | break; |
| 958 | case 'f': |
952 | case 'f': |
| 959 | found_file = 1; |
953 | found_file = 1; |
| 960 | if (be_wewy_wewy_quiet) break; |
954 | if (be_wewy_wewy_quiet) break; |
| 961 | tmp = strrchr(filename, '/'); |
955 | tmp = strrchr(elf->filename, '/'); |
| 962 | tmp = (tmp == NULL ? filename : tmp+1); |
956 | tmp = (tmp == NULL ? elf->filename : tmp+1); |
| 963 | xstrcat(&out_buffer, tmp, &out_len); |
957 | xstrcat(&out_buffer, tmp, &out_len); |
| 964 | break; |
958 | break; |
| 965 | case 'o': out = get_elfetype(elf); break; |
959 | case 'o': out = get_elfetype(elf); break; |
| 966 | case 'x': out = scanelf_file_pax(elf, &found_pax); break; |
960 | case 'x': out = scanelf_file_pax(elf, &found_pax); break; |
| 967 | case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break; |
961 | case 'e': out = scanelf_file_phdr(elf, &found_phdr, &found_relro, &found_load); break; |
| … | |
… | |
| 990 | found_rpath || found_needed || found_interp || found_bind || \ |
984 | found_rpath || found_needed || found_interp || found_bind || \ |
| 991 | found_soname || found_sym || found_lib || found_textrels) |
985 | found_soname || found_sym || found_lib || found_textrels) |
| 992 | |
986 | |
| 993 | if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) { |
987 | if (!found_file && (!be_quiet || (be_quiet && FOUND_SOMETHING()))) { |
| 994 | xchrcat(&out_buffer, ' ', &out_len); |
988 | xchrcat(&out_buffer, ' ', &out_len); |
| 995 | xstrcat(&out_buffer, filename, &out_len); |
989 | xstrcat(&out_buffer, elf->filename, &out_len); |
| 996 | } |
990 | } |
| 997 | if (!be_quiet || (be_quiet && FOUND_SOMETHING())) { |
991 | if (!be_quiet || (be_quiet && FOUND_SOMETHING())) { |
| 998 | puts(out_buffer); |
992 | puts(out_buffer); |
| 999 | fflush(stdout); |
993 | fflush(stdout); |
| 1000 | } |
994 | } |
| 1001 | |
995 | |
|
|
996 | return 0; |
|
|
997 | } |
|
|
998 | |
|
|
999 | /* scan a single elf */ |
|
|
1000 | static int scanelf_elf(const char *filename, int fd, size_t len) |
|
|
1001 | { |
|
|
1002 | int ret; |
|
|
1003 | elfobj *elf; |
|
|
1004 | |
|
|
1005 | /* verify this is real ELF */ |
|
|
1006 | if ((elf = _readelf_fd(filename, fd, len, !fix_elf)) == NULL) { |
|
|
1007 | if (be_verbose > 2) printf("%s: not an ELF\n", filename); |
|
|
1008 | return 1; |
|
|
1009 | } |
|
|
1010 | |
|
|
1011 | ret = scanelf_elfobj(elf); |
| 1002 | unreadelf(elf); |
1012 | unreadelf(elf); |
|
|
1013 | return ret; |
|
|
1014 | } |
|
|
1015 | /* scan an archive of elfs */ |
|
|
1016 | static int scanelf_archive(const char *filename, int fd, size_t len) |
|
|
1017 | { |
|
|
1018 | archive_handle *ar; |
|
|
1019 | archive_member *m; |
|
|
1020 | char *ar_buffer; |
|
|
1021 | elfobj *elf; |
|
|
1022 | |
|
|
1023 | ar = ar_open_fd(filename, fd); |
|
|
1024 | if (ar == NULL) |
|
|
1025 | return 1; |
|
|
1026 | |
|
|
1027 | ar_buffer = (char*)mmap(0, len, PROT_READ | (fix_elf ? PROT_WRITE : 0), (fix_elf ? MAP_SHARED : MAP_PRIVATE), fd, 0); |
|
|
1028 | while ((m=ar_next(ar)) != NULL) { |
|
|
1029 | elf = readelf_buffer(m->name, ar_buffer+lseek(fd,0,SEEK_CUR), m->size); |
|
|
1030 | if (elf) { |
|
|
1031 | scanelf_elfobj(elf); |
|
|
1032 | unreadelf(elf); |
|
|
1033 | } |
|
|
1034 | } |
|
|
1035 | munmap(ar_buffer, len); |
| 1003 | |
1036 | |
| 1004 | return 0; |
1037 | return 0; |
| 1005 | } |
1038 | } |
| 1006 | |
|
|
| 1007 | /* scan an archive of elfs */ |
|
|
| 1008 | static int scanelf_archive(const char *filename) |
|
|
| 1009 | { |
|
|
| 1010 | archive_handle *ar = ar_open(filename); |
|
|
| 1011 | archive_member *m; |
|
|
| 1012 | while ((m=ar_next(ar)) != NULL) |
|
|
| 1013 | printf("%o %i:%i %s\n", m->mode, m->uid, m->gid, m->name); |
|
|
| 1014 | return 0; |
|
|
| 1015 | } |
|
|
| 1016 | |
|
|
| 1017 | /* scan a file which may be an elf or an archive or some other magical beast */ |
1039 | /* scan a file which may be an elf or an archive or some other magical beast */ |
| 1018 | static void scanelf_file(const char *filename) |
1040 | static void scanelf_file(const char *filename) |
| 1019 | { |
1041 | { |
| 1020 | struct stat st; |
1042 | struct stat st; |
|
|
1043 | int fd; |
| 1021 | |
1044 | |
| 1022 | /* make sure 'filename' exists */ |
1045 | /* make sure 'filename' exists */ |
| 1023 | if (lstat(filename, &st) == -1) { |
1046 | if (lstat(filename, &st) == -1) { |
| 1024 | if (be_verbose > 2) printf("%s: does not exist\n", filename); |
1047 | if (be_verbose > 2) printf("%s: does not exist\n", filename); |
| 1025 | return; |
1048 | return; |
| … | |
… | |
| 1033 | if (!S_ISREG(st.st_mode)) { |
1056 | if (!S_ISREG(st.st_mode)) { |
| 1034 | if (be_verbose > 2) printf("%s: skipping non-file\n", filename); |
1057 | if (be_verbose > 2) printf("%s: skipping non-file\n", filename); |
| 1035 | return; |
1058 | return; |
| 1036 | } |
1059 | } |
| 1037 | |
1060 | |
|
|
1061 | if ((fd=open(filename, (fix_elf ? O_RDWR : O_RDONLY))) == -1) |
|
|
1062 | return; |
|
|
1063 | |
| 1038 | if (scanelf_elf(filename) == 1 && scan_archives) |
1064 | if (scanelf_elf(filename, fd, st.st_size) == 1 && scan_archives) |
| 1039 | /* if it isn't an ELF, maybe it's an .a archive */ |
1065 | /* if it isn't an ELF, maybe it's an .a archive */ |
| 1040 | scanelf_archive(filename); |
1066 | scanelf_archive(filename, fd, st.st_size); |
|
|
1067 | |
|
|
1068 | close(fd); |
| 1041 | } |
1069 | } |
| 1042 | |
1070 | |
| 1043 | /* scan a directory for ET_EXEC files and print when we find one */ |
1071 | /* scan a directory for ET_EXEC files and print when we find one */ |
| 1044 | static void scanelf_dir(const char *path) |
1072 | static void scanelf_dir(const char *path) |
| 1045 | { |
1073 | { |