commit: 56905522dfd178685b6225c6be89560cb02c445c Author: Mike Frysinger <vapier <AT> gentoo <DOT> org> AuthorDate: Mon Jun 20 00:37:04 2016 +0000 Commit: Mike Frysinger <vapier <AT> gentoo <DOT> org> CommitDate: Mon Jun 20 00:37:04 2016 +0000 URL: https://gitweb.gentoo.org/proj/pax-utils.git/commit/?id=56905522
pspax: rewrite core loop to use *at funcs This makes the code a bit simpler & robust. pspax.c | 228 ++++++++++++++++++++++++++++++++++++---------------------------- 1 file changed, 128 insertions(+), 100 deletions(-) diff --git a/pspax.c b/pspax.c index c64472c..67b7678 100644 --- a/pspax.c +++ b/pspax.c @@ -40,20 +40,47 @@ static pid_t show_pid = 0; static uid_t show_uid = (uid_t)-1; static gid_t show_gid = (gid_t)-1; -static FILE *proc_fopen(pid_t pid, const char *file) +static int proc_open(int pfd, const char *file) { - char path[__PAX_UTILS_PATH_MAX]; - snprintf(path, sizeof(path), PROC_DIR "/%u/%s", pid, file); - path[sizeof(path) - 1] = '\0'; - return fopen(path, "r"); + return openat(pfd, file, O_RDONLY|O_CLOEXEC); } -static char *get_proc_name_cmdline(pid_t pid) +static FILE *proc_fopen(int pfd, const char *file) +{ + int fd; + FILE *fp; + + fd = proc_open(pfd, file); + if (fd == -1) + return NULL; + + fp = fdopen(fd, "re"); + if (fp == NULL) + close(fd); + + return fp; +} + +static elfobj *proc_readelf(int pfd) +{ + int fd; + elfobj *elf; + + fd = proc_open(pfd, "exe"); + if (fd == -1) + return NULL; + + elf = readelf_fd("proc/exe", fd, 0); + close(fd); + return elf; +} + +static char *get_proc_name_cmdline(int pfd) { FILE *fp; static char str[1024]; - fp = proc_fopen(pid, "cmdline"); + fp = proc_fopen(pfd, "cmdline"); if (fp == NULL) return NULL; @@ -64,15 +91,15 @@ static char *get_proc_name_cmdline(pid_t pid) return (str); } -static char *get_proc_name(pid_t pid) +static char *get_proc_name(int pfd) { FILE *fp; static char str[BUFSIZ]; if (wide_output) - return get_proc_name_cmdline(pid); + return get_proc_name_cmdline(pfd); - fp = proc_fopen(pid, "stat"); + fp = proc_fopen(pfd, "stat"); if (fp == NULL) return NULL; @@ -90,12 +117,12 @@ static char *get_proc_name(pid_t pid) return (str+1); } -static int get_proc_maps(pid_t pid) +static int get_proc_maps(int pfd) { FILE *fp; static char str[BUFSIZ]; - if ((fp = proc_fopen(pid, "maps")) == NULL) + if ((fp = proc_fopen(pfd, "maps")) == NULL) return -1; while (fgets(str, sizeof(str), fp)) { @@ -126,12 +153,12 @@ static int get_proc_maps(pid_t pid) return 0; } -static int print_executable_mappings(pid_t pid) +static int print_executable_mappings(int pfd) { FILE *fp; static char str[BUFSIZ]; - if ((fp = proc_fopen(pid, "maps")) == NULL) + if ((fp = proc_fopen(pfd, "maps")) == NULL) return -1; while (fgets(str, sizeof(str), fp)) { @@ -169,28 +196,24 @@ static int print_executable_mappings(pid_t pid) # define NOTE_TO_SELF #endif -static struct passwd *get_proc_passwd(pid_t pid) +static struct passwd *get_proc_passwd(int pfd) { struct stat st; - struct passwd *pwd; - char path[__PAX_UTILS_PATH_MAX]; - - snprintf(path, sizeof(path), PROC_DIR "/%u/stat", pid); + struct passwd *pwd = NULL; - if (stat(path, &st) != -1) - if ((pwd = getpwuid(st.st_uid)) != NULL) - return pwd; + if (fstatat(pfd, "stat", &st, AT_SYMLINK_NOFOLLOW) != -1) + pwd = getpwuid(st.st_uid); - return NULL; + return pwd; } -static char *get_proc_status(pid_t pid, const char *name) +static char *get_proc_status(int pfd, const char *name) { FILE *fp; size_t len; static char str[BUFSIZ]; - if ((fp = proc_fopen(pid, "status")) == NULL) + if ((fp = proc_fopen(pfd, "status")) == NULL) return NULL; len = strlen(name); @@ -208,13 +231,13 @@ static char *get_proc_status(pid_t pid, const char *name) return NULL; } -static char *get_pid_attr(pid_t pid) +static char *get_pid_attr(int pfd) { FILE *fp; char *p; static char buf[BUFSIZ]; - if ((fp = proc_fopen(pid, "attr/current")) == NULL) + if ((fp = proc_fopen(pfd, "attr/current")) == NULL) return NULL; if (fgets(buf, sizeof(buf), fp) != NULL) @@ -225,13 +248,13 @@ static char *get_pid_attr(pid_t pid) return buf; } -static char *get_pid_addr(pid_t pid) +static char *get_pid_addr(int pfd) { FILE *fp; char *p; static char buf[BUFSIZ]; - if ((fp = proc_fopen(pid, "ipaddr")) == NULL) + if ((fp = proc_fopen(pfd, "ipaddr")) == NULL) return NULL; if (fgets(buf, sizeof(buf), fp) != NULL) @@ -242,15 +265,15 @@ static char *get_pid_addr(pid_t pid) return buf; } -static const char *get_proc_type(pid_t pid) +static const char *get_proc_type(int pfd) { - char fname[32]; elfobj *elf; const char *ret; - snprintf(fname, sizeof(fname), PROC_DIR "/%u/exe", pid); - if ((elf = readelf(fname)) == NULL) + elf = proc_readelf(pfd); + if (elf == NULL) return NULL; + ret = get_elfetype(elf); unreadelf(elf); return ret; @@ -290,15 +313,15 @@ static char *scanelf_file_phdr(elfobj *elf) return ret; } /* we scan the elf file two times when the -e flag is given. But we don't need -e very often so big deal */ -static const char *get_proc_phdr(pid_t pid) +static const char *get_proc_phdr(int pfd) { - char fname[32]; elfobj *elf; const char *ret; - snprintf(fname, sizeof(fname), PROC_DIR "/%u/exe", pid); - if ((elf = readelf(fname)) == NULL) + elf = proc_readelf(pfd); + if (elf == NULL) return NULL; + ret = scanelf_file_phdr(elf); unreadelf(elf); return ret; @@ -312,9 +335,9 @@ static void pspax(const char *find_name) pid_t ppid = show_pid; int have_attr, have_addr, wx; struct passwd *pwd; - struct stat st; const char *pax, *type, *name, *attr, *addr; char *caps; + int pfd; WRAP_SYSCAP(ssize_t length; cap_t cap_d;) WRAP_SYSCAP(cap_d = cap_init()); @@ -339,76 +362,81 @@ static void pspax(const char *find_name) have_addr ? "IPADDR" : "", show_phdr ? "STACK LOAD" : ""); while ((de = readdir(dir))) { - errno = 0; - stat(de->d_name, &st); - if ((errno != ENOENT) && (errno != EACCES)) { - pid = (pid_t) atoi((char *) basename((char *) de->d_name)); - if (find_name && pid) { - char *str = get_proc_name(pid); - if (!str) - continue; - if (strcmp(str, find_name) != 0) - pid = 0; - } - if (((ppid > 0) && (pid != ppid)) || !pid) - continue; + /* Check the name first if it's an int as it's faster. */ + pid = atoi(de->d_name); + if (pid == 0) + continue; - wx = get_proc_maps(pid); + /* Get an open handle so the kernel won't reap on us later. */ + pfd = open(de->d_name, O_RDONLY|O_CLOEXEC|O_PATH|O_DIRECTORY); + if (pfd == -1) + continue; - if (noexec != writeexec) { - if ((wx == 1) && (writeexec != wx)) - goto next_pid; + if (find_name && pid) { + char *str = get_proc_name(pfd); + if (!str) + goto next_pid; + if (strcmp(str, find_name) != 0) + pid = 0; + } + if (ppid > 0 && pid != ppid) + goto next_pid; - if ((wx == 0) && writeexec) - goto next_pid; - } + wx = get_proc_maps(pfd); - pwd = get_proc_passwd(pid); - pax = get_proc_status(pid, "PAX"); - type = get_proc_type(pid); - name = get_proc_name(pid); - attr = (have_attr ? get_pid_attr(pid) : NULL); - addr = (have_addr ? get_pid_addr(pid) : NULL); - - if (pwd) { - if (show_uid != (uid_t)-1) - if (pwd->pw_uid != show_uid) - continue; - - if (show_gid != (gid_t)-1) - if (pwd->pw_gid != show_gid) - continue; - } + if (noexec != writeexec) { + if (wx == 1 && writeexec != wx) + goto next_pid; - /* this is a non-POSIX function */ - caps = NULL; - WRAP_SYSCAP(capgetp(pid, cap_d)); - WRAP_SYSCAP(caps = cap_to_text(cap_d, &length)); - - if (pwd && strlen(pwd->pw_name) >= 8) - pwd->pw_name[8] = 0; - - if (show_all || type) { - printf("%-8s %-6d %-6s %-4s %-10s %-16s %-4s %s %s %s\n", - pwd ? pwd->pw_name : "--------", - pid, - pax ? pax : "---", - (wx == 1) ? "w|x" : (wx == -1) ? "---" : "w^x", - type ? type : "-------", - name ? name : "-----", - caps ? caps : " = ", - attr ? attr : "", - addr ? addr : "", - show_phdr ? get_proc_phdr(pid) : ""); - if (verbose && wx) - print_executable_mappings(pid); - } + if (wx == 0 && writeexec) + goto next_pid; + } - WRAP_SYSCAP(if (caps) cap_free(caps)); + pwd = get_proc_passwd(pfd); + pax = get_proc_status(pfd, "PAX"); + type = get_proc_type(pfd); + name = get_proc_name(pfd); + attr = (have_attr ? get_pid_attr(pfd) : NULL); + addr = (have_addr ? get_pid_addr(pfd) : NULL); - next_pid: - continue; + if (pwd) { + if (show_uid != (uid_t)-1) + if (pwd->pw_uid != show_uid) + goto next_pid; + + if (show_gid != (gid_t)-1) + if (pwd->pw_gid != show_gid) + goto next_pid; + } + + /* this is a non-POSIX function */ + caps = NULL; + WRAP_SYSCAP(capgetp(pfd, cap_d)); + WRAP_SYSCAP(caps = cap_to_text(cap_d, &length)); + + if (pwd && strlen(pwd->pw_name) >= 8) + pwd->pw_name[8] = 0; + + if (show_all || type) { + printf("%-8s %-6d %-6s %-4s %-10s %-16s %-4s %s %s %s\n", + pwd ? pwd->pw_name : "--------", + pid, + pax ? pax : "---", + (wx == 1) ? "w|x" : (wx == -1) ? "---" : "w^x", + type ? type : "-------", + name ? name : "-----", + caps ? caps : " = ", + attr ? attr : "", + addr ? addr : "", + show_phdr ? get_proc_phdr(pfd) : ""); + if (verbose && wx) + print_executable_mappings(pfd); } + + WRAP_SYSCAP(if (caps) cap_free(caps)); + + next_pid: + close(pfd); } closedir(dir); }