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

Contents of /pax-utils/pspax.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.50 - (show annotations) (download) (as text)
Tue Sep 27 19:58:09 2011 UTC (19 months, 3 weeks ago) by vapier
Branch: MAIN
Changes since 1.49: +1 -1 lines
File MIME type: text/x-csrc
simplify rcsid a little

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

  ViewVC Help
Powered by ViewVC 1.1.13