/[gentoo-projects]/pax-utils/pspax.c
Gentoo

Contents of /pax-utils/pspax.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.51 - (hide annotations) (download) (as text)
Sun Nov 18 07:39:45 2012 UTC (21 months ago) by vapier
Branch: MAIN
Changes since 1.50: +1 -4 lines
File MIME type: text/x-csrc
scanelf/pspax: drop PT_LOAD counts since more than "normal" is not a bug and is semi-common with some targets, and the warning has out lived its usefulness -- it was added as an initial sanity check to get a feel for the real world

1 solar 1.1 /******************************************************************************/
2     /* THE BEER-WARE LICENSE (Revision 42): */
3     /* As long as you retain this notice you can do whatever you want with this */
4     /* stuff. If we meet some day, and you think this stuff is worth it, */
5     /* you can buy me a beer in return. Ned Ludd. --solarx */
6     /******************************************************************************/
7    
8     /*
9     * normal compile.
10     * cc -o pspax pspax.c
11 vapier 1.36 * or with libcap.
12 solar 1.1 * cc -o pspax pspax.c -DWANT_SYSCAP -lcap
13     */
14    
15 vapier 1.51 static const char rcsid[] = "$Id: pspax.c,v 1.50 2011/09/27 19:58:09 vapier Exp $";
16 vapier 1.47 const char argv0[] = "pspax";
17 vapier 1.38
18 vapier 1.23 #include "paxinc.h"
19 solar 1.32 #include <grp.h>
20 solar 1.1
21     #ifdef WANT_SYSCAP
22 solar 1.30 # undef _POSIX_SOURCE
23     # include <sys/capability.h>
24     # define WRAP_SYSCAP(x) x
25     #else
26     # define WRAP_SYSCAP(x)
27 solar 1.1 #endif
28    
29     #define PROC_DIR "/proc"
30 vapier 1.6
31     /* variables to control behavior */
32     static char show_all = 0;
33 solar 1.22 static char verbose = 0;
34 vapier 1.6 static char show_banner = 1;
35 solar 1.22 static char show_phdr = 0;
36 solar 1.39 static char show_addr = 0;
37 solar 1.29 static char noexec = 1;
38     static char writeexec = 1;
39 solar 1.46 static char wide_output = 0;
40 solar 1.31 static pid_t show_pid = 0;
41     static uid_t show_uid = -1;
42     static gid_t show_gid = -1;
43    
44 vapier 1.43 static FILE *proc_fopen(pid_t pid, const char *file)
45     {
46     char path[__PAX_UTILS_PATH_MAX];
47     snprintf(path, sizeof(path), PROC_DIR "/%u/%s", pid, file);
48     path[sizeof(path) - 1] = '\0';
49     return fopen(path, "r");
50     }
51    
52 solar 1.46 static char *get_proc_name_cmdline(pid_t pid)
53     {
54     FILE *fp;
55     static char str[1024];
56    
57     fp = proc_fopen(pid, "cmdline");
58     if (fp == NULL)
59     return NULL;
60    
61     if (fscanf(fp, "%s.1023", str) != 1) {
62     fclose(fp);
63     return NULL;
64     }
65     return (str);
66     }
67    
68 vapier 1.5 static char *get_proc_name(pid_t pid)
69 solar 1.1 {
70 vapier 1.5 FILE *fp;
71 vapier 1.43 static char str[BUFSIZ];
72 solar 1.1
73 solar 1.46 if (wide_output)
74     return get_proc_name_cmdline(pid);
75    
76 vapier 1.44 fp = proc_fopen(pid, "stat");
77     if (fp == NULL)
78 vapier 1.6 return NULL;
79 solar 1.1
80 vapier 1.44 if (fscanf(fp, "%*d %s.16", str) != 1) {
81     fclose(fp);
82     return NULL;
83     }
84    
85 solar 1.15 if (*str) {
86     str[strlen(str) - 1] = '\0';
87     str[16] = 0;
88 vapier 1.5 }
89     fclose(fp);
90 vapier 1.43
91 solar 1.15 return (str+1);
92 solar 1.1 }
93    
94 vapier 1.25 static int get_proc_maps(pid_t pid)
95     {
96 solar 1.13 FILE *fp;
97 vapier 1.43 static char str[BUFSIZ];
98 solar 1.13
99 vapier 1.43 if ((fp = proc_fopen(pid, "maps")) == NULL)
100 solar 1.13 return -1;
101    
102 solar 1.15 while (fgets(str, sizeof(str), fp)) {
103 solar 1.13 char *p;
104 solar 1.15 if ((p = strchr(str, ' ')) != NULL) {
105 solar 1.13 if (strlen(p) < 6)
106     continue;
107 solar 1.15 /* 0x0-0x0 rwxp fffff000 00:00 0 */
108     /* 0x0-0x0 R+W+XP fffff000 00:00 0 */
109 vapier 1.38 ++p; /* ' ' */
110     ++p; /* r */
111 solar 1.15 if (*p == '+')
112     ++p;
113     /* FIXME: all of wx, w+, +x, ++ indicate w|x */
114 solar 1.13 if (tolower(*p) == 'w') {
115     ++p;
116     if (*p == '+')
117     ++p;
118     if (tolower(*p) == 'x') {
119     fclose(fp);
120     return 1;
121     }
122     }
123     }
124     }
125     fclose(fp);
126 vapier 1.43
127 solar 1.13 return 0;
128     }
129    
130 vapier 1.25 static int print_executable_mappings(pid_t pid)
131     {
132 solar 1.22 FILE *fp;
133 vapier 1.43 static char str[BUFSIZ];
134 solar 1.22
135 vapier 1.43 if ((fp = proc_fopen(pid, "maps")) == NULL)
136 solar 1.22 return -1;
137    
138     while (fgets(str, sizeof(str), fp)) {
139     char *p;
140     if ((p = strchr(str, ' ')) != NULL) {
141     if (strlen(p) < 6)
142     continue;
143     /* 0x0-0x0 rwxp fffff000 00:00 0 */
144     /* 0x0-0x0 R+W+XP fffff000 00:00 0 */
145 vapier 1.38 ++p; /* ' ' */
146     ++p; /* r */
147 solar 1.22 if (*p == '+')
148     ++p;
149     /* FIXME: all of wx, w+, +x, ++ indicate w|x */
150     if (tolower(*p) == 'w') {
151     ++p;
152     if (*p == '+')
153     ++p;
154     if (tolower(*p) == 'x')
155     printf(" %s", str);
156     }
157     }
158     }
159     fclose(fp);
160 vapier 1.43
161 solar 1.22 return 0;
162     }
163    
164 solar 1.30 #ifdef __BOUNDS_CHECKING_ON
165 vapier 1.36 # define NOTE_TO_SELF warn( \
166 solar 1.30 "This is bullshit but getpwuid() is leaking memory and I wasted a few hrs 1 day tracking it down in pspax\n" \
167     "Later on I forgot I tracked it down before and saw pspax leaking memory so I tracked it down all over again (silly me)\n" \
168     "Hopefully the getpwuid()/nis/nss/pam or whatever wont suck later on in the future.")
169     #else
170 vapier 1.36 # define NOTE_TO_SELF
171 solar 1.30 #endif
172    
173 solar 1.31 static struct passwd *get_proc_passwd(pid_t pid)
174 solar 1.1 {
175 solar 1.15 struct stat st;
176 vapier 1.5 struct passwd *pwd;
177 vapier 1.43 char path[__PAX_UTILS_PATH_MAX];
178 solar 1.1
179 vapier 1.43 snprintf(path, sizeof(path), PROC_DIR "/%u/stat", pid);
180 solar 1.12
181 vapier 1.43 if (stat(path, &st) != -1)
182 vapier 1.5 if ((pwd = getpwuid(st.st_uid)) != NULL)
183     return pwd;
184 vapier 1.43
185 vapier 1.5 return NULL;
186 solar 1.1 }
187    
188 solar 1.18 static char *get_proc_status(pid_t pid, const char *name)
189 solar 1.1 {
190 vapier 1.5 FILE *fp;
191 solar 1.10 size_t len;
192 vapier 1.43 static char str[BUFSIZ];
193 vapier 1.5
194 vapier 1.43 if ((fp = proc_fopen(pid, "status")) == NULL)
195 vapier 1.5 return NULL;
196    
197     len = strlen(name);
198 solar 1.15 while (fgets(str, sizeof(str), fp)) {
199 solar 1.30 if (strncasecmp(str, name, len) != 0)
200     continue;
201     if (str[len] == ':') {
202     fclose(fp);
203     str[strlen(str) - 1] = 0;
204     return (str + len + 2);
205 vapier 1.5 }
206     }
207     fclose(fp);
208 vapier 1.43
209 vapier 1.5 return NULL;
210 solar 1.1 }
211    
212 solar 1.13 static char *get_pid_attr(pid_t pid)
213 solar 1.1 {
214 vapier 1.5 FILE *fp;
215     char *p;
216     static char buf[BUFSIZ];
217 solar 1.10
218 vapier 1.43 if ((fp = proc_fopen(pid, "attr/current")) == NULL)
219     return NULL;
220 solar 1.10
221 vapier 1.5 if (fgets(buf, sizeof(buf), fp) != NULL)
222     if ((p = strchr(buf, '\n')) != NULL)
223     *p = 0;
224     fclose(fp);
225 vapier 1.43
226 vapier 1.5 return buf;
227     }
228    
229 solar 1.39 static char *get_pid_addr(pid_t pid)
230     {
231     FILE *fp;
232     char *p;
233     static char buf[BUFSIZ];
234    
235 vapier 1.43 if ((fp = proc_fopen(pid, "ipaddr")) == NULL)
236     return NULL;
237 solar 1.39
238     if (fgets(buf, sizeof(buf), fp) != NULL)
239     if ((p = strchr(buf, '\n')) != NULL)
240     *p = 0;
241     fclose(fp);
242 vapier 1.43
243 solar 1.39 return buf;
244     }
245    
246 solar 1.13 static const char *get_proc_type(pid_t pid)
247 vapier 1.5 {
248     char fname[32];
249 vapier 1.43 elfobj *elf;
250     const char *ret;
251 vapier 1.5
252 solar 1.13 snprintf(fname, sizeof(fname), PROC_DIR "/%u/exe", pid);
253 vapier 1.5 if ((elf = readelf(fname)) == NULL)
254 vapier 1.43 return NULL;
255     ret = get_elfetype(elf);
256 vapier 1.5 unreadelf(elf);
257     return ret;
258     }
259    
260 solar 1.22 static char *scanelf_file_phdr(elfobj *elf)
261     {
262     static char ret[8];
263 vapier 1.25 unsigned long i, off, multi_stack, multi_load;
264 solar 1.22
265     memcpy(ret, "--- ---\0", 8);
266    
267     multi_stack = multi_load = 0;
268    
269     if (elf->phdr) {
270     uint32_t flags;
271     #define SHOW_PHDR(B) \
272     if (elf->elf_class == ELFCLASS ## B) { \
273     Elf ## B ## _Ehdr *ehdr = EHDR ## B (elf->ehdr); \
274     Elf ## B ## _Phdr *phdr = PHDR ## B (elf->phdr); \
275     for (i = 0; i < EGET(ehdr->e_phnum); i++) { \
276     if (EGET(phdr[i].p_type) == PT_GNU_STACK) { \
277     if (multi_stack++) warnf("%s: multiple PT_GNU_STACK's !?", elf->filename); \
278     off = 0; \
279     } else if (EGET(phdr[i].p_type) == PT_LOAD) { \
280     off = 4; \
281     } else \
282     continue; \
283     flags = EGET(phdr[i].p_flags); \
284     memcpy(ret+off, gnu_short_stack_flags(flags), 3); \
285     } \
286     }
287     SHOW_PHDR(32)
288     SHOW_PHDR(64)
289     }
290    
291     return ret;
292     }
293     /* we scan the elf file two times when the -e flag is given. But we don't need -e very often so big deal */
294     static const char *get_proc_phdr(pid_t pid)
295     {
296     char fname[32];
297 vapier 1.43 elfobj *elf;
298     const char *ret;
299 solar 1.22
300     snprintf(fname, sizeof(fname), PROC_DIR "/%u/exe", pid);
301     if ((elf = readelf(fname)) == NULL)
302 vapier 1.43 return NULL;
303     ret = scanelf_file_phdr(elf);
304 solar 1.22 unreadelf(elf);
305     return ret;
306     }
307    
308 solar 1.31 static void pspax(const char *find_name)
309 vapier 1.5 {
310     register DIR *dir;
311     register struct dirent *de;
312     pid_t pid;
313 solar 1.31 pid_t ppid = show_pid;
314 solar 1.39 int have_attr, have_addr, wx;
315 solar 1.31 struct passwd *pwd;
316 vapier 1.5 struct stat st;
317 vapier 1.45 const char *pax, *type, *name, *attr, *addr;
318     char *caps;
319     WRAP_SYSCAP(ssize_t length; cap_t cap_d;)
320 solar 1.15
321 solar 1.30 WRAP_SYSCAP(cap_d = cap_init());
322 solar 1.12
323 vapier 1.44 dir = opendir(PROC_DIR);
324     if (dir == NULL || chdir(PROC_DIR))
325     errp(PROC_DIR);
326 solar 1.12
327 vapier 1.42 if (access("/proc/self/attr/current", R_OK) != -1)
328 solar 1.12 have_attr = 1;
329     else
330     have_attr = 0;
331    
332 vapier 1.42 if ((access("/proc/self/ipaddr", R_OK) != -1) && show_addr)
333 solar 1.39 have_addr = 1;
334     else
335     have_addr = 0;
336    
337 vapier 1.6 if (show_banner)
338 solar 1.39 printf("%-8s %-6s %-6s %-4s %-10s %-16s %-4s %-4s %s %s\n",
339     "USER", "PID", "PAX", "MAPS", "ETYPE", "NAME", "CAPS", have_attr ? "ATTR" : "",
340     have_addr ? "IPADDR" : "", show_phdr ? "STACK LOAD" : "");
341 vapier 1.5
342     while ((de = readdir(dir))) {
343     errno = 0;
344     stat(de->d_name, &st);
345     if ((errno != ENOENT) && (errno != EACCES)) {
346     pid = (pid_t) atoi((char *) basename((char *) de->d_name));
347 solar 1.28 if (find_name && pid) {
348     char *str = get_proc_name(pid);
349 vapier 1.42 if (!str)
350     continue;
351 solar 1.28 if (strcmp(str, find_name) != 0)
352     pid = 0;
353     }
354 vapier 1.42 if (((ppid > 0) && (pid != ppid)) || !pid)
355 vapier 1.5 continue;
356    
357 solar 1.30 wx = get_proc_maps(pid);
358    
359     if (noexec != writeexec) {
360     if ((wx == 1) && (writeexec != wx))
361     goto next_pid;
362    
363 vapier 1.42 if ((wx == 0) && writeexec)
364 solar 1.30 goto next_pid;
365     }
366 vapier 1.6
367 solar 1.31 pwd = get_proc_passwd(pid);
368 solar 1.18 pax = get_proc_status(pid, "PAX");
369 solar 1.13 type = get_proc_type(pid);
370 vapier 1.6 name = get_proc_name(pid);
371 solar 1.12 attr = (have_attr ? get_pid_attr(pid) : NULL);
372 solar 1.39 addr = (have_addr ? get_pid_addr(pid) : NULL);
373 vapier 1.6
374 vapier 1.42 if (show_uid != -1 && pwd)
375 solar 1.31 if (pwd->pw_uid != show_uid)
376     continue;
377    
378 vapier 1.42 if (show_gid != -1 && pwd)
379 solar 1.31 if (pwd->pw_gid != show_gid)
380     continue;
381    
382 solar 1.30 /* this is a non-POSIX function */
383 vapier 1.45 caps = NULL;
384 solar 1.30 WRAP_SYSCAP(capgetp(pid, cap_d));
385     WRAP_SYSCAP(caps = cap_to_text(cap_d, &length));
386 solar 1.29
387 solar 1.41 if (pwd && strlen(pwd->pw_name) >= 8)
388     pwd->pw_name[8] = 0;
389    
390 solar 1.22 if (show_all || type) {
391 solar 1.39 printf("%-8s %-6d %-6s %-4s %-10s %-16s %-4s %s %s %s\n",
392 solar 1.31 pwd ? pwd->pw_name : "--------",
393 vapier 1.5 pid,
394 vapier 1.6 pax ? pax : "---",
395 solar 1.14 (wx == 1) ? "w|x" : (wx == -1) ? "---" : "w^x",
396 vapier 1.6 type ? type : "-------",
397     name ? name : "-----",
398     caps ? caps : " = ",
399 solar 1.39 attr ? attr : "",
400     addr ? addr : "",
401     show_phdr ? get_proc_phdr(pid) : "");
402 solar 1.22 if (verbose && wx)
403     print_executable_mappings(pid);
404     }
405 solar 1.30
406 vapier 1.42 WRAP_SYSCAP(if (caps) cap_free(caps));
407 solar 1.30
408     next_pid:
409 solar 1.29 continue;
410 vapier 1.5 }
411     }
412     closedir(dir);
413 solar 1.1 }
414    
415 vapier 1.6 /* usage / invocation handling functions */
416 vapier 1.48 #define PARSE_FLAGS "aeip:u:g:nwWvCBhV"
417 solar 1.22 #define a_argument required_argument
418 vapier 1.6 static struct option const long_opts[] = {
419     {"all", no_argument, NULL, 'a'},
420 solar 1.22 {"header", no_argument, NULL, 'e'},
421 solar 1.39 {"ipaddr", no_argument, NULL, 'i'},
422 solar 1.22 {"pid", a_argument, NULL, 'p'},
423 solar 1.31 {"user", a_argument, NULL, 'u'},
424     {"group", a_argument, NULL, 'g'},
425 solar 1.29 {"nx", no_argument, NULL, 'n'},
426     {"wx", no_argument, NULL, 'w'},
427 solar 1.46 {"wide", no_argument, NULL, 'W'},
428 solar 1.22 {"verbose", no_argument, NULL, 'v'},
429 vapier 1.48 {"nocolor", no_argument, NULL, 'C'},
430 vapier 1.6 {"nobanner", no_argument, NULL, 'B'},
431     {"help", no_argument, NULL, 'h'},
432     {"version", no_argument, NULL, 'V'},
433     {NULL, no_argument, NULL, 0x0}
434     };
435 solar 1.46
436 vapier 1.49 static const char * const opts_help[] = {
437 solar 1.22 "Show all processes",
438     "Print GNU_STACK/PT_LOAD markings",
439 solar 1.39 "Print ipaddr info if supported",
440 solar 1.22 "Process ID/pid #",
441 solar 1.37 "Process user/uid #",
442     "Process group/gid #",
443 solar 1.29 "Only display w^x processes",
444     "Only display w|x processes",
445 solar 1.46 "Wide output display of cmdline",
446 solar 1.22 "Be verbose about executable mappings",
447 vapier 1.48 "Don't emit color in output",
448 vapier 1.6 "Don't display the header",
449     "Print this help and exit",
450     "Print version and exit",
451     NULL
452     };
453    
454     /* display usage and exit */
455     static void usage(int status)
456     {
457     int i;
458 solar 1.18 printf("* List ELF/PaX information about running processes\n\n"
459 vapier 1.6 "Usage: %s [options]\n\n", argv0);
460     fputs("Options:\n", stdout);
461     for (i = 0; long_opts[i].name; ++i)
462 vapier 1.36 printf(" -%c, --%-12s* %s\n", long_opts[i].val,
463 vapier 1.6 long_opts[i].name, opts_help[i]);
464     #ifdef MANLYPAGE
465     for (i = 0; long_opts[i].name; ++i)
466 vapier 1.36 printf(".TP\n\\fB\\-%c, \\-\\-%s\\fR\n%s\n", long_opts[i].val,
467 vapier 1.6 long_opts[i].name, opts_help[i]);
468     #endif
469     exit(status);
470     }
471    
472     /* parse command line arguments and preform needed actions */
473 solar 1.31 static void parseargs(int argc, char *argv[])
474 vapier 1.6 {
475     int flag;
476 solar 1.32 struct passwd *pwd = NULL;
477     struct group *gwd = NULL;
478    
479 vapier 1.6 opterr = 0;
480     while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
481     switch (flag) {
482    
483     case 'V': /* version info */
484 vapier 1.21 printf("pax-utils-%s: %s compiled %s\n%s\n"
485     "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
486     VERSION, __FILE__, __DATE__, rcsid, argv0);
487 vapier 1.6 exit(EXIT_SUCCESS);
488     break;
489     case 'h': usage(EXIT_SUCCESS); break;
490    
491 vapier 1.48 case 'C': color_init(true); break;
492 vapier 1.6 case 'B': show_banner = 0; break;
493     case 'a': show_all = 1; break;
494 solar 1.22 case 'e': show_phdr = 1; break;
495 solar 1.39 case 'i': show_addr = 1; break;
496 solar 1.31 case 'p': show_pid = atoi(optarg); break;
497 solar 1.29 case 'n': noexec = 1; writeexec = 0; break;
498     case 'w': noexec = 0; writeexec = 1; break;
499 solar 1.46 case 'W': wide_output = 1; break;
500 solar 1.22 case 'v': verbose++; break;
501 solar 1.32 case 'u':
502 solar 1.35 show_uid = atoi(optarg);
503     if (show_uid == 0 && (strcmp(optarg, "0") != 0)) {
504     pwd = getpwnam(optarg);
505     if (pwd)
506     show_uid = pwd->pw_uid;
507     else
508     err("unknown uid");
509 solar 1.32 }
510     break;
511     case 'g':
512     show_gid = atoi(optarg);
513 solar 1.33 if (show_gid == 0 && (strcmp(optarg, "0") != 0)) {
514 solar 1.32 gwd = getgrnam(optarg);
515     if (gwd)
516     show_gid = gwd->gr_gid;
517     else
518     err("unknown gid");
519     }
520     break;
521 vapier 1.6 case ':':
522     case '?':
523 solar 1.31 warn("Unknown option or missing parameter");
524 vapier 1.6 usage(EXIT_FAILURE);
525     break;
526     default:
527     err("Unhandled option '%c'", flag);
528     break;
529     }
530     }
531     }
532    
533 vapier 1.5 int main(int argc, char *argv[])
534 solar 1.1 {
535 solar 1.28 char *name = NULL;
536    
537 vapier 1.48 color_init(false);
538 solar 1.31 parseargs(argc, argv);
539    
540     if ((optind < argc) && (show_pid == 0))
541 solar 1.28 name = argv[optind];
542    
543 solar 1.31 pspax(name);
544    
545 solar 1.30 NOTE_TO_SELF;
546 vapier 1.5 return EXIT_SUCCESS;
547 solar 1.1 }

  ViewVC Help
Powered by ViewVC 1.1.20