| 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.104 2006/01/13 11:31:55 vapier Exp $ |
4 | * $Header: /var/cvsroot/gentoo-projects/pax-utils/scanelf.c,v 1.105 2006/01/13 12:12:52 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.104 2006/01/13 11:31:55 vapier Exp $"; |
12 | static const char *rcsid = "$Id: scanelf.c,v 1.105 2006/01/13 12:12:52 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_elf(const char *filename); |
|
|
21 | static int scanelf_archive(const char *filename); |
| 20 | static void scanelf_file(const char *filename); |
22 | static void scanelf_file(const char *filename); |
| 21 | static void scanelf_dir(const char *path); |
23 | static void scanelf_dir(const char *path); |
| 22 | static void scanelf_ldpath(); |
24 | static void scanelf_ldpath(); |
| 23 | static void scanelf_envpath(); |
25 | static void scanelf_envpath(); |
| 24 | static void usage(int status); |
26 | static void usage(int status); |
| … | |
… | |
| 32 | /* variables to control behavior */ |
34 | /* variables to control behavior */ |
| 33 | static char *ldpaths[256]; |
35 | static char *ldpaths[256]; |
| 34 | static char scan_ldpath = 0; |
36 | static char scan_ldpath = 0; |
| 35 | static char scan_envpath = 0; |
37 | static char scan_envpath = 0; |
| 36 | static char scan_symlink = 1; |
38 | static char scan_symlink = 1; |
|
|
39 | static char scan_archives = 0; |
| 37 | static char dir_recurse = 0; |
40 | static char dir_recurse = 0; |
| 38 | static char dir_crossmount = 1; |
41 | static char dir_crossmount = 1; |
| 39 | static char show_pax = 0; |
42 | static char show_pax = 0; |
| 40 | static char show_phdr = 0; |
43 | static char show_phdr = 0; |
| 41 | static char show_textrel = 0; |
44 | static char show_textrel = 0; |
| … | |
… | |
| 845 | else |
848 | else |
| 846 | return (char *)" - "; |
849 | return (char *)" - "; |
| 847 | } |
850 | } |
| 848 | /* scan an elf file and show all the fun stuff */ |
851 | /* scan an elf file and show all the fun stuff */ |
| 849 | #define prints(str) write(fileno(stdout), str, strlen(str)) |
852 | #define prints(str) write(fileno(stdout), str, strlen(str)) |
| 850 | static void scanelf_file(const char *filename) |
853 | static int scanelf_elf(const char *filename) |
| 851 | { |
854 | { |
| 852 | unsigned long i; |
855 | unsigned long i; |
| 853 | char found_pax, found_phdr, found_relro, found_load, found_textrel, |
856 | char found_pax, found_phdr, found_relro, found_load, found_textrel, |
| 854 | found_rpath, found_needed, found_interp, found_bind, found_soname, |
857 | found_rpath, found_needed, found_interp, found_bind, found_soname, |
| 855 | found_sym, found_lib, found_file, found_textrels; |
858 | found_sym, found_lib, found_file, found_textrels; |
| 856 | elfobj *elf; |
859 | elfobj *elf; |
| 857 | struct stat st; |
|
|
| 858 | static char *out_buffer = NULL; |
860 | static char *out_buffer = NULL; |
| 859 | static size_t out_len; |
861 | static size_t out_len; |
| 860 | |
|
|
| 861 | /* make sure 'filename' exists */ |
|
|
| 862 | if (lstat(filename, &st) == -1) { |
|
|
| 863 | if (be_verbose > 2) printf("%s: does not exist\n", filename); |
|
|
| 864 | return; |
|
|
| 865 | } |
|
|
| 866 | /* always handle regular files and handle symlinked files if no -y */ |
|
|
| 867 | if (S_ISLNK(st.st_mode)) { |
|
|
| 868 | if (!scan_symlink) return; |
|
|
| 869 | stat(filename, &st); |
|
|
| 870 | } |
|
|
| 871 | if (!S_ISREG(st.st_mode)) { |
|
|
| 872 | if (be_verbose > 2) printf("%s: skipping non-file\n", filename); |
|
|
| 873 | return; |
|
|
| 874 | } |
|
|
| 875 | |
862 | |
| 876 | found_pax = found_phdr = found_relro = found_load = found_textrel = \ |
863 | found_pax = found_phdr = found_relro = found_load = found_textrel = \ |
| 877 | found_rpath = found_needed = found_interp = found_bind = found_soname = \ |
864 | found_rpath = found_needed = found_interp = found_bind = found_soname = \ |
| 878 | found_sym = found_lib = found_file = found_textrels = 0; |
865 | found_sym = found_lib = found_file = found_textrels = 0; |
| 879 | |
866 | |
| 880 | /* verify this is real ELF */ |
867 | /* verify this is real ELF */ |
| 881 | if ((elf = _readelf(filename, !fix_elf)) == NULL) { |
868 | if ((elf = _readelf(filename, !fix_elf)) == NULL) { |
| 882 | /* if it isn't an ELF, maybe it's an .a archive */ |
|
|
| 883 | archive_handle *ar = ar_open(filename); |
|
|
| 884 | if (be_verbose > 2) printf("%s: not an ELF\n", filename); |
869 | if (be_verbose > 2) printf("%s: not an ELF\n", filename); |
| 885 | return; |
870 | return 1; |
| 886 | } |
871 | } |
| 887 | |
872 | |
| 888 | if (be_verbose > 1) |
873 | if (be_verbose > 1) |
| 889 | printf("%s: scanning file {%s,%s}\n", filename, |
874 | printf("%s: scanning file {%s,%s}\n", filename, |
| 890 | get_elfeitype(EI_CLASS, elf->elf_class), |
875 | get_elfeitype(EI_CLASS, elf->elf_class), |
| … | |
… | |
| 1013 | puts(out_buffer); |
998 | puts(out_buffer); |
| 1014 | fflush(stdout); |
999 | fflush(stdout); |
| 1015 | } |
1000 | } |
| 1016 | |
1001 | |
| 1017 | unreadelf(elf); |
1002 | unreadelf(elf); |
|
|
1003 | |
|
|
1004 | return 0; |
|
|
1005 | } |
|
|
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 */ |
|
|
1018 | static void scanelf_file(const char *filename) |
|
|
1019 | { |
|
|
1020 | struct stat st; |
|
|
1021 | |
|
|
1022 | /* make sure 'filename' exists */ |
|
|
1023 | if (lstat(filename, &st) == -1) { |
|
|
1024 | if (be_verbose > 2) printf("%s: does not exist\n", filename); |
|
|
1025 | return; |
|
|
1026 | } |
|
|
1027 | |
|
|
1028 | /* always handle regular files and handle symlinked files if no -y */ |
|
|
1029 | if (S_ISLNK(st.st_mode)) { |
|
|
1030 | if (!scan_symlink) return; |
|
|
1031 | stat(filename, &st); |
|
|
1032 | } |
|
|
1033 | if (!S_ISREG(st.st_mode)) { |
|
|
1034 | if (be_verbose > 2) printf("%s: skipping non-file\n", filename); |
|
|
1035 | return; |
|
|
1036 | } |
|
|
1037 | |
|
|
1038 | if (scanelf_elf(filename) == 1 && scan_archives) |
|
|
1039 | /* if it isn't an ELF, maybe it's an .a archive */ |
|
|
1040 | scanelf_archive(filename); |
| 1018 | } |
1041 | } |
| 1019 | |
1042 | |
| 1020 | /* scan a directory for ET_EXEC files and print when we find one */ |
1043 | /* scan a directory for ET_EXEC files and print when we find one */ |
| 1021 | static void scanelf_dir(const char *path) |
1044 | static void scanelf_dir(const char *path) |
| 1022 | { |
1045 | { |
| … | |
… | |
| 1161 | free(path); |
1184 | free(path); |
| 1162 | } |
1185 | } |
| 1163 | |
1186 | |
| 1164 | |
1187 | |
| 1165 | /* usage / invocation handling functions */ |
1188 | /* usage / invocation handling functions */ |
| 1166 | #define PARSE_FLAGS "plRmyXxetrnLibSs:gN:TaqvF:f:o:BhV" |
1189 | #define PARSE_FLAGS "plRmyAXxetrnLibSs:gN:TaqvF:f:o:BhV" |
| 1167 | #define a_argument required_argument |
1190 | #define a_argument required_argument |
| 1168 | static struct option const long_opts[] = { |
1191 | static struct option const long_opts[] = { |
| 1169 | {"path", no_argument, NULL, 'p'}, |
1192 | {"path", no_argument, NULL, 'p'}, |
| 1170 | {"ldpath", no_argument, NULL, 'l'}, |
1193 | {"ldpath", no_argument, NULL, 'l'}, |
| 1171 | {"recursive", no_argument, NULL, 'R'}, |
1194 | {"recursive", no_argument, NULL, 'R'}, |
| 1172 | {"mount", no_argument, NULL, 'm'}, |
1195 | {"mount", no_argument, NULL, 'm'}, |
| 1173 | {"symlink", no_argument, NULL, 'y'}, |
1196 | {"symlink", no_argument, NULL, 'y'}, |
|
|
1197 | {"archives", no_argument, NULL, 'A'}, |
|
|
1198 | {"ldcache", no_argument, NULL, 'L'}, |
| 1174 | {"fix", no_argument, NULL, 'X'}, |
1199 | {"fix", no_argument, NULL, 'X'}, |
| 1175 | {"pax", no_argument, NULL, 'x'}, |
1200 | {"pax", no_argument, NULL, 'x'}, |
| 1176 | {"header", no_argument, NULL, 'e'}, |
1201 | {"header", no_argument, NULL, 'e'}, |
| 1177 | {"textrel", no_argument, NULL, 't'}, |
1202 | {"textrel", no_argument, NULL, 't'}, |
| 1178 | {"rpath", no_argument, NULL, 'r'}, |
1203 | {"rpath", no_argument, NULL, 'r'}, |
| 1179 | {"needed", no_argument, NULL, 'n'}, |
1204 | {"needed", no_argument, NULL, 'n'}, |
| 1180 | {"ldcache", no_argument, NULL, 'L'}, |
|
|
| 1181 | {"interp", no_argument, NULL, 'i'}, |
1205 | {"interp", no_argument, NULL, 'i'}, |
| 1182 | {"bind", no_argument, NULL, 'b'}, |
1206 | {"bind", no_argument, NULL, 'b'}, |
| 1183 | {"soname", no_argument, NULL, 'S'}, |
1207 | {"soname", no_argument, NULL, 'S'}, |
| 1184 | {"symbol", a_argument, NULL, 's'}, |
1208 | {"symbol", a_argument, NULL, 's'}, |
| 1185 | {"lib", a_argument, NULL, 'N'}, |
1209 | {"lib", a_argument, NULL, 'N'}, |
| … | |
… | |
| 1201 | "Scan all directories in PATH environment", |
1225 | "Scan all directories in PATH environment", |
| 1202 | "Scan all directories in /etc/ld.so.conf", |
1226 | "Scan all directories in /etc/ld.so.conf", |
| 1203 | "Scan directories recursively", |
1227 | "Scan directories recursively", |
| 1204 | "Don't recursively cross mount points", |
1228 | "Don't recursively cross mount points", |
| 1205 | "Don't scan symlinks", |
1229 | "Don't scan symlinks", |
|
|
1230 | "Scan archives (.a files)", |
|
|
1231 | "Utilize ld.so.cache information (use with -r/-n)", |
| 1206 | "Try and 'fix' bad things (use with -r/-e)\n", |
1232 | "Try and 'fix' bad things (use with -r/-e)\n", |
| 1207 | "Print PaX markings", |
1233 | "Print PaX markings", |
| 1208 | "Print GNU_STACK/PT_LOAD markings", |
1234 | "Print GNU_STACK/PT_LOAD markings", |
| 1209 | "Print TEXTREL information", |
1235 | "Print TEXTREL information", |
| 1210 | "Print RPATH information", |
1236 | "Print RPATH information", |
| 1211 | "Print NEEDED information", |
1237 | "Print NEEDED information", |
| 1212 | "Utilize ld.so.cache information (use with -r/-n)", |
|
|
| 1213 | "Print INTERP information", |
1238 | "Print INTERP information", |
| 1214 | "Print BIND information", |
1239 | "Print BIND information", |
| 1215 | "Print SONAME information", |
1240 | "Print SONAME information", |
| 1216 | "Find a specified symbol", |
1241 | "Find a specified symbol", |
| 1217 | "Find a specified library", |
1242 | "Find a specified library", |
| … | |
… | |
| 1232 | /* display usage and exit */ |
1257 | /* display usage and exit */ |
| 1233 | static void usage(int status) |
1258 | static void usage(int status) |
| 1234 | { |
1259 | { |
| 1235 | unsigned long i; |
1260 | unsigned long i; |
| 1236 | printf("* Scan ELF binaries for stuff\n\n" |
1261 | printf("* Scan ELF binaries for stuff\n\n" |
| 1237 | "Usage: %s [options] <dir1/file1> [dir2 dirN fileN ...]\n\n", argv0); |
1262 | "Usage: %s [options] <dir1/file1> [dir2 dirN file2 fileN ...]\n\n", argv0); |
| 1238 | printf("Options: -[%s]\n", PARSE_FLAGS); |
1263 | printf("Options: -[%s]\n", PARSE_FLAGS); |
| 1239 | for (i = 0; long_opts[i].name; ++i) |
1264 | for (i = 0; long_opts[i].name; ++i) |
| 1240 | if (long_opts[i].has_arg == no_argument) |
1265 | if (long_opts[i].has_arg == no_argument) |
| 1241 | printf(" -%c, --%-13s* %s\n", long_opts[i].val, |
1266 | printf(" -%c, --%-13s* %s\n", long_opts[i].val, |
| 1242 | long_opts[i].name, opts_help[i]); |
1267 | long_opts[i].name, opts_help[i]); |
| … | |
… | |
| 1309 | } |
1334 | } |
| 1310 | |
1335 | |
| 1311 | case 'g': gmatch = 1; /* break; any reason we dont breal; here ? */ |
1336 | case 'g': gmatch = 1; /* break; any reason we dont breal; here ? */ |
| 1312 | case 'L': use_ldcache = 1; break; |
1337 | case 'L': use_ldcache = 1; break; |
| 1313 | case 'y': scan_symlink = 0; break; |
1338 | case 'y': scan_symlink = 0; break; |
|
|
1339 | case 'A': scan_archives = 1; break; |
| 1314 | case 'B': show_banner = 0; break; |
1340 | case 'B': show_banner = 0; break; |
| 1315 | case 'l': scan_ldpath = 1; break; |
1341 | case 'l': scan_ldpath = 1; break; |
| 1316 | case 'p': scan_envpath = 1; break; |
1342 | case 'p': scan_envpath = 1; break; |
| 1317 | case 'R': dir_recurse = 1; break; |
1343 | case 'R': dir_recurse = 1; break; |
| 1318 | case 'm': dir_crossmount = 0; break; |
1344 | case 'm': dir_crossmount = 0; break; |