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

Contents of /pax-utils/pspax.c

Parent Directory Parent Directory | Revision Log Revision Log


Revision 1.52 - (show annotations) (download) (as text)
Wed Apr 10 21:54:44 2013 UTC (16 months, 2 weeks ago) by vapier
Branch: MAIN
CVS Tags: HEAD
Changes since 1.51: +12 -10 lines
File MIME type: text/x-csrc
pspax: fix signed compare warning gcc throws up

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.51 2012/11/18 07:39:45 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 = (uid_t)-1;
42 static gid_t show_gid = (gid_t)-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
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 elfobj *elf;
298 const char *ret;
299
300 snprintf(fname, sizeof(fname), PROC_DIR "/%u/exe", pid);
301 if ((elf = readelf(fname)) == NULL)
302 return NULL;
303 ret = scanelf_file_phdr(elf);
304 unreadelf(elf);
305 return ret;
306 }
307
308 static void pspax(const char *find_name)
309 {
310 register DIR *dir;
311 register struct dirent *de;
312 pid_t pid;
313 pid_t ppid = show_pid;
314 int have_attr, have_addr, wx;
315 struct passwd *pwd;
316 struct stat st;
317 const char *pax, *type, *name, *attr, *addr;
318 char *caps;
319 WRAP_SYSCAP(ssize_t length; cap_t cap_d;)
320
321 WRAP_SYSCAP(cap_d = cap_init());
322
323 dir = opendir(PROC_DIR);
324 if (dir == NULL || chdir(PROC_DIR))
325 errp(PROC_DIR);
326
327 if (access("/proc/self/attr/current", R_OK) != -1)
328 have_attr = 1;
329 else
330 have_attr = 0;
331
332 if ((access("/proc/self/ipaddr", R_OK) != -1) && show_addr)
333 have_addr = 1;
334 else
335 have_addr = 0;
336
337 if (show_banner)
338 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
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 if (find_name && pid) {
348 char *str = get_proc_name(pid);
349 if (!str)
350 continue;
351 if (strcmp(str, find_name) != 0)
352 pid = 0;
353 }
354 if (((ppid > 0) && (pid != ppid)) || !pid)
355 continue;
356
357 wx = get_proc_maps(pid);
358
359 if (noexec != writeexec) {
360 if ((wx == 1) && (writeexec != wx))
361 goto next_pid;
362
363 if ((wx == 0) && writeexec)
364 goto next_pid;
365 }
366
367 pwd = get_proc_passwd(pid);
368 pax = get_proc_status(pid, "PAX");
369 type = get_proc_type(pid);
370 name = get_proc_name(pid);
371 attr = (have_attr ? get_pid_attr(pid) : NULL);
372 addr = (have_addr ? get_pid_addr(pid) : NULL);
373
374 if (pwd) {
375 if (show_uid != (uid_t)-1)
376 if (pwd->pw_uid != show_uid)
377 continue;
378
379 if (show_gid != (gid_t)-1)
380 if (pwd->pw_gid != show_gid)
381 continue;
382 }
383
384 /* this is a non-POSIX function */
385 caps = NULL;
386 WRAP_SYSCAP(capgetp(pid, cap_d));
387 WRAP_SYSCAP(caps = cap_to_text(cap_d, &length));
388
389 if (pwd && strlen(pwd->pw_name) >= 8)
390 pwd->pw_name[8] = 0;
391
392 if (show_all || type) {
393 printf("%-8s %-6d %-6s %-4s %-10s %-16s %-4s %s %s %s\n",
394 pwd ? pwd->pw_name : "--------",
395 pid,
396 pax ? pax : "---",
397 (wx == 1) ? "w|x" : (wx == -1) ? "---" : "w^x",
398 type ? type : "-------",
399 name ? name : "-----",
400 caps ? caps : " = ",
401 attr ? attr : "",
402 addr ? addr : "",
403 show_phdr ? get_proc_phdr(pid) : "");
404 if (verbose && wx)
405 print_executable_mappings(pid);
406 }
407
408 WRAP_SYSCAP(if (caps) cap_free(caps));
409
410 next_pid:
411 continue;
412 }
413 }
414 closedir(dir);
415 }
416
417 /* usage / invocation handling functions */
418 #define PARSE_FLAGS "aeip:u:g:nwWvCBhV"
419 #define a_argument required_argument
420 static struct option const long_opts[] = {
421 {"all", no_argument, NULL, 'a'},
422 {"header", no_argument, NULL, 'e'},
423 {"ipaddr", no_argument, NULL, 'i'},
424 {"pid", a_argument, NULL, 'p'},
425 {"user", a_argument, NULL, 'u'},
426 {"group", a_argument, NULL, 'g'},
427 {"nx", no_argument, NULL, 'n'},
428 {"wx", no_argument, NULL, 'w'},
429 {"wide", no_argument, NULL, 'W'},
430 {"verbose", no_argument, NULL, 'v'},
431 {"nocolor", no_argument, NULL, 'C'},
432 {"nobanner", no_argument, NULL, 'B'},
433 {"help", no_argument, NULL, 'h'},
434 {"version", no_argument, NULL, 'V'},
435 {NULL, no_argument, NULL, 0x0}
436 };
437
438 static const char * const opts_help[] = {
439 "Show all processes",
440 "Print GNU_STACK/PT_LOAD markings",
441 "Print ipaddr info if supported",
442 "Process ID/pid #",
443 "Process user/uid #",
444 "Process group/gid #",
445 "Only display w^x processes",
446 "Only display w|x processes",
447 "Wide output display of cmdline",
448 "Be verbose about executable mappings",
449 "Don't emit color in output",
450 "Don't display the header",
451 "Print this help and exit",
452 "Print version and exit",
453 NULL
454 };
455
456 /* display usage and exit */
457 static void usage(int status)
458 {
459 int i;
460 printf("* List ELF/PaX information about running processes\n\n"
461 "Usage: %s [options]\n\n", argv0);
462 fputs("Options:\n", stdout);
463 for (i = 0; long_opts[i].name; ++i)
464 printf(" -%c, --%-12s* %s\n", long_opts[i].val,
465 long_opts[i].name, opts_help[i]);
466 #ifdef MANLYPAGE
467 for (i = 0; long_opts[i].name; ++i)
468 printf(".TP\n\\fB\\-%c, \\-\\-%s\\fR\n%s\n", long_opts[i].val,
469 long_opts[i].name, opts_help[i]);
470 #endif
471 exit(status);
472 }
473
474 /* parse command line arguments and preform needed actions */
475 static void parseargs(int argc, char *argv[])
476 {
477 int flag;
478 struct passwd *pwd = NULL;
479 struct group *gwd = NULL;
480
481 opterr = 0;
482 while ((flag=getopt_long(argc, argv, PARSE_FLAGS, long_opts, NULL)) != -1) {
483 switch (flag) {
484
485 case 'V': /* version info */
486 printf("pax-utils-%s: %s compiled %s\n%s\n"
487 "%s written for Gentoo by <solar and vapier @ gentoo.org>\n",
488 VERSION, __FILE__, __DATE__, rcsid, argv0);
489 exit(EXIT_SUCCESS);
490 break;
491 case 'h': usage(EXIT_SUCCESS); break;
492
493 case 'C': color_init(true); break;
494 case 'B': show_banner = 0; break;
495 case 'a': show_all = 1; break;
496 case 'e': show_phdr = 1; break;
497 case 'i': show_addr = 1; break;
498 case 'p': show_pid = atoi(optarg); break;
499 case 'n': noexec = 1; writeexec = 0; break;
500 case 'w': noexec = 0; writeexec = 1; break;
501 case 'W': wide_output = 1; break;
502 case 'v': verbose++; break;
503 case 'u':
504 show_uid = atoi(optarg);
505 if (show_uid == 0 && (strcmp(optarg, "0") != 0)) {
506 pwd = getpwnam(optarg);
507 if (pwd)
508 show_uid = pwd->pw_uid;
509 else
510 err("unknown uid");
511 }
512 break;
513 case 'g':
514 show_gid = atoi(optarg);
515 if (show_gid == 0 && (strcmp(optarg, "0") != 0)) {
516 gwd = getgrnam(optarg);
517 if (gwd)
518 show_gid = gwd->gr_gid;
519 else
520 err("unknown gid");
521 }
522 break;
523 case ':':
524 case '?':
525 warn("Unknown option or missing parameter");
526 usage(EXIT_FAILURE);
527 break;
528 default:
529 err("Unhandled option '%c'", flag);
530 break;
531 }
532 }
533 }
534
535 int main(int argc, char *argv[])
536 {
537 char *name = NULL;
538
539 color_init(false);
540 parseargs(argc, argv);
541
542 if ((optind < argc) && (show_pid == 0))
543 name = argv[optind];
544
545 pspax(name);
546
547 NOTE_TO_SELF;
548 return EXIT_SUCCESS;
549 }

  ViewVC Help
Powered by ViewVC 1.1.20