From 8b04273f899173353a90b17d465fec2451d4dbd9 Mon Sep 17 00:00:00 2001 From: albert <> Date: Wed, 17 Sep 2003 21:58:32 +0000 Subject: [PATCH] EVIL_PROC_HACK --- NEWS | 4 + proc/library.map | 4 +- proc/readproc.c | 315 +++++++++++++++++++---------------------------- proc/readproc.h | 22 ++-- ps/common.h | 2 + ps/display.c | 10 +- 6 files changed, 152 insertions(+), 205 deletions(-) diff --git a/NEWS b/NEWS index 284fcfb3..c8f729b2 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,7 @@ +procps-3.1.12 --> procps-3.1.13 + +no seLinux for now (new kernel interface) + procps-3.1.11 --> procps-3.1.12 ps: explicit width ("ps -o pid,wchan:42,args") diff --git a/proc/library.map b/proc/library.map index 52ebcc28..810440d6 100644 --- a/proc/library.map +++ b/proc/library.map @@ -1,8 +1,8 @@ -_3_1_5 { +_3_1_12 { global: __cyg_profile_func_enter; __cyg_profile_func_exit; main; - readproc; readproctab; ps_readproc; look_up_our_self; escape_command; + readproc; readproctab; look_up_our_self; escape_command; escape_str; escape_strlist; openproc; closeproc; tty_to_dev; dev_to_tty; open_psdb_message; open_psdb; wchan; diff --git a/proc/readproc.c b/proc/readproc.c index dada3a3b..4f83024e 100644 --- a/proc/readproc.c +++ b/proc/readproc.c @@ -31,6 +31,7 @@ #include #endif +// sometimes it's easier to do this manually, w/o gcc helping #ifdef PROF extern void __cyg_profile_func_enter(void*,void*); #define ENTER(x) __cyg_profile_func_enter((void*)x,(void*)x) @@ -40,52 +41,6 @@ extern void __cyg_profile_func_enter(void*,void*); #define LEAVE(x) #endif -/* initiate a process table scan - */ -PROCTAB* openproc(int flags, ...) { - va_list ap; - PROCTAB* PT = xmalloc(sizeof(PROCTAB)); - - if (flags & PROC_PID) - PT->procfs = NULL; - else if (!(PT->procfs = opendir("/proc"))) - return NULL; - PT->flags = flags; - va_start(ap, flags); /* Init args list */ - if (flags & PROC_PID) - PT->pids = va_arg(ap, pid_t*); - else if (flags & PROC_UID) { - PT->uids = va_arg(ap, uid_t*); - PT->nuid = va_arg(ap, int); - } - va_end(ap); /* Clean up args list */ - return PT; -} - -/* terminate a process table scan - */ -void closeproc(PROCTAB* PT) { - if (PT){ - if (PT->procfs) closedir(PT->procfs); - free(PT); - } -} - -/* deallocate the space allocated by readproc if the passed rbuf was NULL - */ -void freeproc(proc_t* p) { - if (!p) /* in case p is NULL */ - return; - /* ptrs are after strings to avoid copying memory when building them. */ - /* so free is called on the address of the address of strvec[0]. */ - if (p->cmdline) - free((void*)*p->cmdline); - if (p->environ) - free((void*)*p->environ); - free(p); -} - - /////////////////////////////////////////////////////////////////////////// typedef struct status_table_struct { @@ -505,66 +460,23 @@ int read_cmdline(char *restrict const dst, unsigned sz, unsigned pid){ i < n && l[i] == x; \ } ) -/* readproc: return a pointer to a proc_t filled with requested info about the - * next process available matching the restriction set. If no more such - * processes are available, return a null pointer (boolean false). Use the - * passed buffer instead of allocating space if it is non-NULL. */ +////////////////////////////////////////////////////////////////////////////////// +// This reads process info from /proc in the traditional way, for one process. +// The pid (tgid? tid?) is already in p, and a path to it in path, with some +// room to spare. +static proc_t* simple_readproc(PROCTAB *restrict const PT, proc_t *restrict const p, char *restrict const path) { + static struct stat sb; // stat() buffer + static char sbuf[1024]; // buffer for stat,statm + unsigned flags = PT->flags; -/* This is optimized so that if a PID list is given, only those files are - * searched for in /proc. If other lists are given in addition to the PID list, - * the same logic can follow through as for the no-PID list case. This is - * fairly complex, but it does try to not to do any unnecessary work. - */ -proc_t* readproc(PROCTAB* PT, proc_t* p) { - static struct direct *ent; /* dirent handle */ - static struct stat sb; /* stat buffer */ - static char path[32], sbuf[1024]; /* bufs for stat,statm */ -#ifdef FLASK_LINUX - security_id_t secsid; -#endif - pid_t pid; // saved until we have a proc_t allocated for sure - - /* loop until a proc matching restrictions is found or no more processes */ - /* I know this could be a while loop -- this way is easier to indent ;-) */ -next_proc: /* get next PID for consideration */ - -/*printf("PT->flags is 0x%08x\n", PT->flags);*/ -#define flags (PT->flags) - - if (flags & PROC_PID) { - pid = *(PT->pids)++; - if (unlikely(!pid)) return NULL; - snprintf(path, sizeof path, "/proc/%d", pid); - } else { /* get next numeric /proc ent */ - for (;;) { - ent = readdir(PT->procfs); - if(unlikely(unlikely(!ent) || unlikely(!ent->d_name))) return NULL; - if(likely( likely(*ent->d_name > '0') && likely(*ent->d_name <= '9') )) break; - } - pid = strtoul(ent->d_name, NULL, 10); - memcpy(path, "/proc/", 6); - strcpy(path+6, ent->d_name); // trust /proc to not contain evil top-level entries -// snprintf(path, sizeof path, "/proc/%s", ent->d_name); - } -#ifdef FLASK_LINUX - if ( stat_secure(path, &sb, &secsid) == -1 ) /* no such dirent (anymore) */ -#else if (unlikely(stat(path, &sb) == -1)) /* no such dirent (anymore) */ -#endif goto next_proc; if ((flags & PROC_UID) && !XinLN(uid_t, sb.st_uid, PT->uids, PT->nuid)) goto next_proc; /* not one of the requested uids */ - if (!p) - p = xcalloc(p, sizeof *p); /* passed buf or alloced mem */ - p->euid = sb.st_uid; /* need a way to get real uid */ p->egid = sb.st_gid; /* need a way to get real gid */ -#ifdef FLASK_LINUX - p->secsid = secsid; -#endif - p->pid = pid; if (flags & PROC_FILLSTAT) { /* read, parse /proc/#/stat */ if (unlikely( file2str(path, "stat", sbuf, sizeof sbuf) == -1 )) @@ -572,7 +484,7 @@ next_proc: /* get next PID for consideration */ stat2proc(sbuf, p); /* parse /proc/#/stat */ } - if (unlikely(flags & PROC_FILLMEM)) { /* read, parse /proc/#/statm */ + if (unlikely(flags & PROC_FILLMEM)) { /* read, parse /proc/#/statm */ if (likely( file2str(path, "statm", sbuf, sizeof sbuf) != -1 )) statm2proc(sbuf, p); /* ignore statm errors here */ } /* statm fields just zero */ @@ -614,10 +526,54 @@ next_proc: /* get next PID for consideration */ p->environ = NULL; return p; +next_proc: + return NULL; } -#undef flags -/* ps_readproc: return a pointer to a proc_t filled with requested info about the +////////////////////////////////////////////////////////////////////////////////// +// This finds processes in /proc in the traditional way. +// Return non-zero on success. +static int simple_nextpid(PROCTAB *restrict const PT, proc_t *restrict const p, char *restrict const path) { + static struct direct *ent; /* dirent handle */ + for (;;) { + ent = readdir(PT->procfs); + if(unlikely(unlikely(!ent) || unlikely(!ent->d_name))) return 0; + if(likely( likely(*ent->d_name > '0') && likely(*ent->d_name <= '9') )) break; + } + p->pid = strtoul(ent->d_name, NULL, 10); + memcpy(path, "/proc/", 6); + strcpy(path+6, ent->d_name); // trust /proc to not contain evil top-level entries + return 1; +} + +#define PROCPATHLEN 64 // must hold /proc/2000222000/task/2000222000/cmdline + +////////////////////////////////////////////////////////////////////////////////// +// This "finds" processes in a list that was given to openproc(). +// Return non-zero on success. (pid was handy) +static int listed_nextpid(PROCTAB *restrict const PT, proc_t *restrict const p, char *restrict const path) { + pid_t pid = *(PT->pids)++; + if(likely( pid )){ + snprintf(path, PROCPATHLEN, "/proc/%d", pid); + p->pid = pid; + } + return pid; +} + +////////////////////////////////////////////////////////////////////////////////// +// This "finds" processes by guessing every possible one of them. +// Return non-zero on success. (pid was handy) +static int stupid_nextpid(PROCTAB *restrict const PT, proc_t *restrict const p, char *restrict const path) { + pid_t pid = --PT->u; + if(likely( pid )){ + snprintf(path, PROCPATHLEN, "/proc/%d", pid); + p->pid = pid; + } + return pid; +} + +////////////////////////////////////////////////////////////////////////////////// +/* readproc: return a pointer to a proc_t filled with requested info about the * next process available matching the restriction set. If no more such * processes are available, return a null pointer (boolean false). Use the * passed buffer instead of allocating space if it is non-NULL. */ @@ -627,99 +583,86 @@ next_proc: /* get next PID for consideration */ * the same logic can follow through as for the no-PID list case. This is * fairly complex, but it does try to not to do any unnecessary work. */ -proc_t* ps_readproc(PROCTAB* PT, proc_t* p) { - static struct direct *ent; /* dirent handle */ - static struct stat sb; /* stat buffer */ - static char path[32], sbuf[1024]; /* bufs for stat,statm */ -#ifdef FLASK_LINUX - security_id_t secsid; -#endif - pid_t pid; // saved until we have a proc_t allocated for sure +proc_t* readproc(PROCTAB *restrict const PT, proc_t *restrict p) { + static char path[PROCPATHLEN]; // must hold /proc/2000222000/task/2000222000/cmdline + proc_t *ret; + proc_t *saved_p; - /* loop until a proc matching restrictions is found or no more processes */ - /* I know this could be a while loop -- this way is easier to indent ;-) */ -next_proc: /* get next PID for consideration */ + saved_p = p; + if(!p) p = xcalloc(p, sizeof *p); /* passed buf or alloced mem */ -/*printf("PT->flags is 0x%08x\n", PT->flags);*/ -#define flags (PT->flags) + for(;;){ + // fills in the path and the p->pid + if (unlikely(! PT->finder(PT,p,path) )) goto out; - for (;;) { - ent = readdir(PT->procfs); - if(unlikely(unlikely(!ent) || unlikely(!ent->d_name))) return NULL; - if(likely( likely(*ent->d_name > '0') && likely(*ent->d_name <= '9') )) break; - } - pid = strtoul(ent->d_name, NULL, 10); - memcpy(path, "/proc/", 6); - strcpy(path+6, ent->d_name); // trust /proc to not contain evil top-level entries -// snprintf(path, sizeof path, "/proc/%s", ent->d_name); + // go read the process data + ret = PT->reader(PT,p,path); + if(ret) return ret; + } -#ifdef FLASK_LINUX - if (stat_secure(path, &sb, &secsid) == -1) /* no such dirent (anymore) */ -#else - if (stat(path, &sb) == -1) /* no such dirent (anymore) */ -#endif - goto next_proc; - - if (!p) - p = xcalloc(p, sizeof *p); /* passed buf or alloced mem */ - - p->euid = sb.st_uid; /* need a way to get real uid */ - p->egid = sb.st_gid; /* need a way to get real gid */ -#ifdef FLASK_LINUX - p->secsid = secsid; -#endif - p->pid = pid; - - if ((file2str(path, "stat", sbuf, sizeof sbuf)) == -1) - goto next_proc; /* error reading /proc/#/stat */ - stat2proc(sbuf, p); /* parse /proc/#/stat */ - - if (flags & PROC_FILLMEM) { /* read, parse /proc/#/statm */ - if ((file2str(path, "statm", sbuf, sizeof sbuf)) != -1 ) - statm2proc(sbuf, p); /* ignore statm errors here */ - } /* statm fields just zero */ - - /* if (flags & PROC_FILLSTATUS) { */ /* read, parse /proc/#/status */ - if ((file2str(path, "status", sbuf, sizeof sbuf)) != -1 ){ - status2proc(sbuf, p); - } -/* }*/ - - /* some number->text resolving which is time consuming */ - if (flags & PROC_FILLUSR){ - strncpy(p->euser, user_from_uid(p->euid), sizeof p->euser); -/* if(flags & PROC_FILLSTATUS) { */ - strncpy(p->ruser, user_from_uid(p->ruid), sizeof p->ruser); - strncpy(p->suser, user_from_uid(p->suid), sizeof p->suser); - strncpy(p->fuser, user_from_uid(p->fuid), sizeof p->fuser); -/* }*/ - } - - /* some number->text resolving which is time consuming */ - if (flags & PROC_FILLGRP){ - strncpy(p->egroup, group_from_gid(p->egid), sizeof p->egroup); -/* if(flags & PROC_FILLSTATUS) { */ - strncpy(p->rgroup, group_from_gid(p->rgid), sizeof p->rgroup); - strncpy(p->sgroup, group_from_gid(p->sgid), sizeof p->sgroup); - strncpy(p->fgroup, group_from_gid(p->fgid), sizeof p->fgroup); -/* }*/ - } - - if ((flags & PROC_FILLCOM) || (flags & PROC_FILLARG)) /* read+parse /proc/#/cmdline */ - p->cmdline = file2strvec(path, "cmdline"); - else - p->cmdline = NULL; - - if (flags & PROC_FILLENV) /* read+parse /proc/#/environ */ - p->environ = file2strvec(path, "environ"); - else - p->environ = NULL; - - return p; +out: + if(!saved_p) free(p); + return NULL; +} + +////////////////////////////////////////////////////////////////////////////////// + +// initiate a process table scan +PROCTAB* openproc(int flags, ...) { + va_list ap; + PROCTAB* PT = xmalloc(sizeof(PROCTAB)); + + PT->reader = simple_readproc; + if (flags & PROC_PID){ + PT->procfs = NULL; + PT->finder = listed_nextpid; + }else{ + PT->procfs = opendir("/proc"); + if(!PT->procfs) return NULL; + PT->finder = simple_nextpid; + } + PT->flags = flags; + + if(getenv("EVIL_PROC_HACK")){ + PT->finder = stupid_nextpid; + PT->u = 10000; + } + + va_start(ap, flags); /* Init args list */ + if (flags & PROC_PID) + PT->pids = va_arg(ap, pid_t*); + else if (flags & PROC_UID) { + PT->uids = va_arg(ap, uid_t*); + PT->nuid = va_arg(ap, int); + } + va_end(ap); /* Clean up args list */ + + return PT; +} + +// terminate a process table scan +void closeproc(PROCTAB* PT) { + if (PT){ + if (PT->procfs) closedir(PT->procfs); + free(PT); + } +} + +// deallocate the space allocated by readproc if the passed rbuf was NULL +void freeproc(proc_t* p) { + if (!p) /* in case p is NULL */ + return; + /* ptrs are after strings to avoid copying memory when building them. */ + /* so free is called on the address of the address of strvec[0]. */ + if (p->cmdline) + free((void*)*p->cmdline); + if (p->environ) + free((void*)*p->environ); + free(p); } -#undef flags +////////////////////////////////////////////////////////////////////////////////// void look_up_our_self(proc_t *p) { char sbuf[1024]; diff --git a/proc/readproc.h b/proc/readproc.h index 5529d467..6fbcd851 100644 --- a/proc/readproc.h +++ b/proc/readproc.h @@ -150,17 +150,18 @@ typedef struct proc_t { #include typedef struct PROCTAB { DIR* procfs; - int flags; + int(*finder)(struct PROCTAB *restrict const, proc_t *restrict const, char *restrict const); + proc_t*(*reader)(struct PROCTAB *restrict const, proc_t *restrict const, char *restrict const); + unsigned flags; pid_t* pids; /* pids of the procs */ uid_t* uids; /* uids of procs */ int nuid; /* cannot really sentinel-terminate unsigned short[] */ -#ifdef FLASK_LINUX - security_id_t* sids; /* SIDs of the procs */ -#endif + int i; // generic + unsigned u; // generic + void * vp; // generic } PROCTAB; -/* initialize a PROCTAB structure holding needed call-to-call persistent data - */ +// initialize a PROCTAB structure holding needed call-to-call persistent data extern PROCTAB* openproc(int flags, ... /* pid_t*|uid_t*|dev_t*|char* [, int n] */ ); @@ -171,14 +172,11 @@ extern PROCTAB* openproc(int flags, ... /* pid_t*|uid_t*|dev_t*|char* [, int n] */ extern proc_t** readproctab(int flags, ... /* same as openproc */ ); -/* clean-up open files, etc from the openproc() - */ +// clean-up open files, etc from the openproc() extern void closeproc(PROCTAB* PT); -/* retrieve the next process matching the criteria set by the openproc() - */ -extern proc_t* readproc(PROCTAB* PT, proc_t* return_buf); -extern proc_t* ps_readproc(PROCTAB* PT, proc_t* return_buf); +// retrieve the next process matching the criteria set by the openproc() +extern proc_t* readproc(PROCTAB *restrict const PT, proc_t *restrict const return_buf); // warning: interface may change extern int read_cmdline(char *restrict const dst, unsigned sz, unsigned pid); diff --git a/ps/common.h b/ps/common.h index 48d4cff5..e9ba85be 100644 --- a/ps/common.h +++ b/ps/common.h @@ -71,6 +71,8 @@ /******************* PS DEFINE *******************/ +#define needs_for_select (PROC_FILLSTAT | PROC_FILLSTATUS) + /* personality control flags */ #define PER_BROKEN_o 0x0001 #define PER_BSD_h 0x0002 diff --git a/ps/display.c b/ps/display.c index d9a39a7f..2d5222b5 100644 --- a/ps/display.c +++ b/ps/display.c @@ -242,13 +242,13 @@ static void compute_needs(void){ static void simple_spew(void){ proc_t buf; PROCTAB* ptp; - ptp = openproc(needs_for_format | needs_for_sort); + ptp = openproc(needs_for_format | needs_for_sort | needs_for_select); if(!ptp) { fprintf(stderr, "Error: can not access /proc.\n"); exit(1); } memset(&buf, '#', sizeof(proc_t)); - while(ps_readproc(ptp,&buf)){ + while(readproc(ptp,&buf)){ if(want_this_proc(&buf)) show_one_proc(&buf); if(buf.cmdline) free((void*)*buf.cmdline); // ought to reuse if(buf.environ) free((void*)*buf.environ); // ought to reuse @@ -381,16 +381,16 @@ static void fancy_spew(void){ proc_t *retbuf = NULL; PROCTAB *restrict ptp; int n = 0; /* number of processes & index into array */ - ptp = openproc(needs_for_format | needs_for_sort); + ptp = openproc(needs_for_format | needs_for_sort | needs_for_select); if(!ptp) { fprintf(stderr, "Error: can not access /proc.\n"); exit(1); } - while((retbuf = ps_readproc(ptp,retbuf))){ + while((retbuf = readproc(ptp,retbuf))){ if(want_this_proc(retbuf)){ fill_pcpu(retbuf); // in case we might sort by %cpu processes[n++] = retbuf; - retbuf = NULL; /* NULL asks ps_readproc to allocate */ + retbuf = NULL; // NULL asks readproc to allocate } } if(retbuf) free(retbuf);