Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #define _GNU_SOURCE
- #include <linux/limits.h>
- long arg_lgx = ARG_MAX;
- #include <stdio.h>
- #include <string.h>
- #include <stdlib.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <unistd.h>
- #include <setjmp.h>
- #include <stdarg.h>
- #include <sys/param.h>
- #include <sys/wait.h>
- #include <sys/resource.h>
- #include <sys/stat.h>
- #include <sys/personality.h>
- #define FREEME(_ptr) \
- do { \
- if ((_ptr) == NULL) \
- break; \
- free(_ptr); \
- _ptr = NULL; \
- } while (0)
- // original arguments to main
- int pgm_argc;
- char **pgm_argv;
- char **pgm_envp;
- int fdcfg; // file descriptor for cfgfile
- char cfgfile[100]; // config file
- char optcldbuf[1000];
- #define ERRNO_CODE 64 // minimum code for errno
- char *opt_A; // 1=suppress ASLR
- int opt_e; // 1=send empty envp to child
- int opt_n; // 1=suppress big string in argv
- char *opt_M; // symbols to match
- int opt_x; // repeat count
- int opt_s; // 1=sparse history
- int opt_T; // trace level
- int opt_c; // 1=child mode
- char *opt_R; // set RLIMIT_STACK
- size_t opt_L; // hi/lo limit
- int opt_u; // unbuf
- #define POPTALL(_cmd) \
- _cmd(pc,1,"1=do stack probe in child") \
- _cmd(pp,1,"1=do stack probe in parent") \
- _cmd(pl,1,"1=do downward stack probe (lo)") \
- _cmd(ph,1,"1=do upward stack probe (hi)") \
- _cmd(ps,0,"1=show signal number") \
- _cmd(pv,0,"1=print all stack probe addresses") \
- _cmd(pw,0,"1=do stack probe (write/modify)")
- #define _POPTDEF(_opt,_dft,_reason) \
- int opt_##_opt = _dft;
- POPTALL(_POPTDEF)
- typedef long symval_t; // symbol value
- // symbol table entry
- typedef struct {
- const char *tgb_tag; // option char
- union {
- int *tgb_ptr; // pointer to option
- symval_t tgb_val; // option value
- };
- const char *tgb_reason; // reason
- } tgb_t;
- #define TGBEOT \
- { .tgb_tag = NULL }
- #define TGBMORE(_tgb) \
- (_tgb->tgb_tag != NULL)
- #define TGBFORALL(_tga,_tgb) \
- _tgb = _tga; TGBMORE(_tgb); ++_tgb
- #define _POPTTGB(_opt,_dft,_reason) \
- { .tgb_tag = #_opt, .tgb_ptr = &opt_##_opt, .tgb_reason = _reason },
- tgb_t popt_tgb[] = {
- POPTALL(_POPTTGB)
- TGBEOT
- };
- size_t envlen; // bytes used by envp
- //size_t totlen; // total number of bytes used
- long arg_max; // result of _SC_ARG_MAX
- typedef struct {
- int sig_signo; // number
- sighandler_t sig_hdr; // handler
- } sigctl_t;
- // search limits
- size_t lo;
- size_t hi;
- int status; // child status (waitpid)
- #define SYMALL(_cmd) \
- _cmd(MAIN,"address of main function") \
- _cmd(ENVP,"pointer to environ vector") \
- _cmd(ENVLEN,"calculated length of environ") \
- _cmd(E2A,"offset of envp/argv") \
- _cmd(ARGV,"pointer to argv vector") \
- _cmd(ARGLEN,"calculated length of argv") \
- _cmd(A2S,"offset of argv/stkptr") \
- _cmd(STKPTR,"main stack frame") \
- _cmd(STKHI,"highest valid stack address") \
- _cmd(STKLO,"lowest valid stack address") \
- _cmd(STKSIZ,"maximum stack size") \
- _cmd(ENVOFF,"offset of envp from stkhi") \
- _cmd(ARGOFF,"offset of argv from stkhi") \
- _cmd(STKOFF,"offset of stkptr from stkhi")
- #define SYMDEF(_sym,_reason) \
- _sym##_IDX,
- enum {
- SYMALL(SYMDEF)
- SYMDEFMAX
- };
- #define SYMTGB(_sym,_reason) \
- { .tgb_tag = #_sym, .tgb_val = _sym##_IDX, .tgb_reason = _reason },
- tgb_t symdef_tgb[] = {
- SYMALL(SYMTGB)
- TGBEOT
- };
- // symbol history
- typedef struct hist_ hist_t;
- struct hist_ {
- union {
- symval_t *hist_ptr; // symbol array
- symval_t hist_val; // symbol value
- };
- int hist_try; // try index value
- hist_t *hist_next;
- };
- hist_t *histlist; // history list
- // symbol match control (if we have opt_M)
- int matchany = -1; // 1=or (vs. and)
- char *matchav[100];
- #ifndef MATCHALL
- #define MATCHALL "STKPTR,STKLO,STKHI,ARGLEN,ARGOFF"
- #endif
- char matchall[] = MATCHALL;
- // unit to force opt_c on
- #ifndef CLDFD
- #define CLDFD 37
- #endif
- #define VP(_ptr) ((void *) (_ptr)) // remove qualifiers
- volatile int probe_signo; // stkprobe signal number
- sigjmp_buf probe_jmpbuf; // stkprobe jump buffer
- volatile unsigned char *probe_cp; // stkprobe probe address pointer
- // pointer printing [I hate %p ;-(]
- #define PTR_FMT "%16.16lX"
- #define PTR_PRT(_p) ((unsigned long) (_p))
- #ifndef PAGE_SHIFT
- #define PAGE_SHIFT 12
- #endif
- #ifndef PAGE_SIZE
- #define PAGE_SIZE (1 << PAGE_SHIFT)
- #endif
- #ifndef PAGE_MASK
- #define PAGE_MASK (PAGE_SIZE - 1)
- #endif
- #define sysfaultx(_code,_fmt...) \
- do { \
- fprintf(stderr,_fmt); \
- exit(_code); \
- } while (0);
- #define sysfault(_fmt...) \
- sysfaultx(99,_fmt)
- #ifndef DEBUG
- #if _USE_ZPRT_
- #define DEBUG 1
- #else
- #define DEBUG 0
- #endif
- #endif
- #define dbgprt(_lvl,_fmt...) \
- do { \
- if (DEBUG && (opt_T >= _lvl)) \
- fprintf(stderr,_fmt); \
- } while (0)
- FILE *xfout; // output stream
- // prtf -- diverted printf
- int __attribute__((format(printf,1,2)))
- prtf(const char *fmt,...)
- {
- va_list ap;
- FILE *xf;
- int len;
- xf = xfout;
- if (xf == NULL) {
- if (opt_c)
- sysfault("prtf: child null xfout\n");
- xf = stdout;
- }
- va_start(ap,fmt);
- len = vfprintf(xf,fmt,ap);
- va_end(ap);
- if (len < 0)
- sysfault("prtf: unable to vprintf fd=%d -- %s\n",
- fileno(xf),strerror(errno));
- return len;
- }
- // argvlen -- get bytes used by argv/envp pointer
- size_t
- argvlen(char **argv)
- {
- size_t totlen = 0;
- for (; *argv != NULL; ++argv) {
- size_t slen = strlen(*argv);
- // add in string length + EOS
- totlen += slen;
- totlen += 1;
- // add in amount of space taken up by the pointer to the string
- totlen += sizeof(char *);
- }
- // space taken up by trailing NULL pointer
- totlen += sizeof(char *);
- return totlen;
- }
- // tgblocbytag -- find entry by symbol string
- tgb_t *
- tgblocbytag(tgb_t *tga,const char *tag)
- {
- tgb_t *tgb;
- for (TGBFORALL(tga,tgb)) {
- if (strcmp(tgb->tgb_tag,tag) == 0)
- break;
- }
- return tgb;
- }
- // strmake -- create large string
- char *
- strmake(size_t explen)
- {
- char *bp;
- char *buf;
- // allow for pointer itself
- explen -= sizeof(char *);
- // allow for EOS
- explen -= 1;
- buf = malloc(explen + 1);
- if (buf == NULL)
- sysfault("strmake: malloc failure explen=%zu\n",explen);
- // fill in the string
- for (bp = buf; explen > 0; --explen, ++bp)
- *bp = (explen % 26) + 'A';
- *bp = 0;
- return buf;
- }
- // tagout -- output a symbol tag
- int
- tagout(const char *tag)
- {
- int len;
- len = 0;
- if (tag != NULL) {
- len += prtf("%s",tag);
- while (len < 9)
- len += prtf(" ");
- }
- return len;
- }
- // whyout -- output reason
- void
- whyout(const char *tag)
- {
- tgb_t *tgb;
- tgb = tgblocbytag(symdef_tgb,tag);
- if (TGBMORE(tgb))
- prtf(" -- %s",tgb->tgb_reason);
- }
- // outlen -- output a length
- void
- outlen(int opt,const char *tag,unsigned long len)
- {
- tagout(tag);
- prtf(PTR_FMT " %lu %.3fMB",
- PTR_PRT(len),len,(double) len / 1e6);
- if (tag != NULL) {
- whyout(tag);
- prtf("\n");
- }
- }
- // outptr -- output a pointer
- void
- outptr(int opt,const char *tag,void *ptr)
- {
- tagout(tag);
- prtf(PTR_FMT,PTR_PRT(ptr));
- if (tag != NULL) {
- whyout(tag);
- prtf("\n");
- }
- }
- // outcalc -- output length of argv list
- void
- outcalc(int opt,const char *tag,void *ptr)
- {
- outlen(0,tag,argvlen(ptr));
- }
- // cfgpush -- send configuration to child
- void
- cfgpush(char **argv)
- {
- // open config file
- fdcfg = open(cfgfile,O_RDWR | O_TRUNC | O_CREAT,0644);
- if (fdcfg < 0)
- sysfault("cfgpush: unable to open '%s' -- %s\n",
- cfgfile,strerror(errno));
- // attach a stream to it
- FILE *xfcfg = fdopen(fdcfg,"r+");
- if (xfcfg == NULL)
- sysfault("cfgpush: unable to fdopen '%s' -- %s\n",
- cfgfile,strerror(errno));
- // push all arguments
- for (; *argv != NULL; ++argv)
- fprintf(xfcfg," %s",*argv);
- fprintf(xfcfg,"\n");
- fflush(xfcfg);
- // pass file to child
- if (dup2(fdcfg,CLDFD) < 0)
- sysfault("cfgpush: unable to dup2 -- %s\n",strerror(errno));
- fclose(xfcfg);
- close(fdcfg);
- // rewind the stream for child
- fdcfg = CLDFD;
- if (lseek(fdcfg,0,0) < 0)
- sysfault("cfgpush: unable to rewind cfgfile -- %s\n",strerror(errno));
- }
- // cfgpop -- get data from child
- symval_t *
- cfgpop(void)
- {
- char *cp;
- tgb_t *tgb;
- symval_t val;
- char buf[1000];
- static symval_t arr_static[SYMDEFMAX];
- symval_t *arr;
- dbgprt(1,"cfgpop: ENTER\n");
- // attach a stream to it
- FILE *xfin = fopen(cfgfile,"r");
- if (xfin == NULL)
- sysfault("cfgpop: unable to fopen '%s' -- %s\n",
- cfgfile,strerror(errno));
- // get buffer to return values
- int len = SYMDEFMAX * sizeof(*arr);
- arr = opt_s ? arr_static : malloc(len);
- memset(arr,0,len);
- dbgprt(1,"cfgpop: ARR arr=%p len=%d\n",arr,len);
- while (1) {
- cp = fgets(buf,sizeof(buf),xfin);
- if (cp == NULL)
- break;
- cp = strchr(buf,'\n');
- if (cp != NULL)
- *cp = 0;
- prtf("%s\n",buf);
- // get symbol name
- cp = strtok(buf," ");
- if (cp == NULL)
- continue;
- // get definition
- tgb = tgblocbytag(symdef_tgb,cp);
- if (! TGBMORE(tgb))
- continue;
- // get value (hex)
- cp = strtok(NULL," ");
- if (cp == NULL)
- continue;
- val = strtoll(cp,&cp,16);
- // store value
- dbgprt(2,"cfgpop: SETVAL val=%16.16lX\n",val);
- arr[tgb->tgb_val] = val;
- }
- fclose(xfin);
- dbgprt(1,"cfgpop: EXIT\n");
- return arr;
- }
- // histfetch -- fetch value
- symval_t
- histfetch(hist_t *hist,int arridx)
- {
- symval_t curval;
- if (opt_s)
- curval = hist->hist_val;
- else
- curval = hist->hist_ptr[arridx];
- return curval;
- }
- // cfginit -- initialize match symbols list
- void
- cfginit(void)
- {
- char *bp = opt_M;
- char *sym;
- char **av;
- // decide on "and" or "or" operation
- matchany = *bp;
- switch (matchany) {
- case 'a':
- case '&':
- matchany = 0;
- ++bp;
- break;
- case 'o':
- case '|':
- matchany = 1;
- ++bp;
- break;
- default:
- matchany = 0;
- break;
- }
- prtf("cfginit: %s\n",matchany ? "MATCHANY" : "MATCHALL");
- // split the list
- av = matchav;
- while (1) {
- sym = strtok(bp,",");
- bp = NULL;
- if (sym == NULL)
- break;
- prtf("cfginit: SYMBOL '%s'\n",sym);
- if (sym[0] == '@') {
- bp = matchall;
- continue;
- }
- *av++ = sym;
- }
- *av = NULL;
- int symcnt = av - matchav;
- if ((symcnt > 1) && opt_s)
- sysfault("cfginit: symcnt=%d conflicts with -s\n",symcnt);
- }
- // cfgmatch -- scan list for existing value
- int
- cfgmatch(hist_t *histcur,symval_t *curarr)
- {
- char **av;
- char *sym;
- symval_t oldval;
- symval_t curval;
- int matchflg = 0;
- for (av = matchav; *av != NULL; ++av) {
- matchflg = 0;
- sym = *av;
- // get match index
- tgb_t *tgb = tgblocbytag(symdef_tgb,sym);
- if (! TGBMORE(tgb))
- sysfault("cfgmatch: unknown match symbol -- '%s'\n",sym);
- int arridx = tgb->tgb_val;
- // get previous/old value
- oldval = histfetch(histcur,arridx);
- // get current value
- curval = curarr[arridx];
- matchflg = (oldval == curval);
- dbgprt(2,"cfgmatch: EXPMATCH arridx=%d sym='%s' curval=%16.16lX matchflg=%d\n",
- arridx,sym,curval,matchflg);
- dbgprt(2,"cfgmatch: ACTMATCH oldval=%16.16lX hist_try=%d matchflg=%d\n",
- oldval,histcur->hist_try,matchflg);
- // stop on any match
- if (matchany) {
- if (matchflg)
- break;
- }
- // stop only if all symbols match
- else {
- if (! matchflg)
- break;
- }
- }
- return matchflg;
- }
- // cfgcmp -- compare data
- int
- cfgcmp(int tryidx,symval_t *curarr)
- {
- hist_t *hcur;
- hist_t *hnew;
- symval_t oldval;
- symval_t curval;
- int matchflg = 0;
- dbgprt(1,"cfgcmp: ENTER tryidx=%d\n",tryidx);
- // find match
- for (hcur = histlist; hcur != NULL; hcur = hcur->hist_next) {
- matchflg = cfgmatch(hcur,curarr);
- if (matchflg)
- break;
- }
- // find the tail
- hist_t *hprev = NULL;
- for (hist_t *hist = histlist; hist != NULL; hist = hist->hist_next)
- hprev = hist;
- // link new entry
- hnew = calloc(1,sizeof(hist_t));
- if (hprev != NULL)
- hprev->hist_next = hnew;
- else
- histlist = hnew;
- // FIXME/CAE -- this is broken
- curval = 0;
- // store new value
- if (opt_s)
- hnew->hist_val = curval;
- else
- hnew->hist_ptr = curarr;
- // remember when we did this
- hnew->hist_try = tryidx;
- do {
- tgb_t *tgb;
- if (! matchflg)
- break;
- if (hcur == NULL)
- break;
- prtf("MATCH %d/%d\n",hcur->hist_try,hnew->hist_try);
- for (TGBFORALL(symdef_tgb,tgb)) {
- int arridx = tgb->tgb_val;
- oldval = histfetch(hcur,arridx);
- curval = histfetch(hnew,arridx);
- if (oldval == curval)
- continue;
- prtf("DIF ");
- tagout(tgb->tgb_tag);
- prtf(" %16.16lX %16.16lX\n",oldval,curval);
- }
- } while (0);
- dbgprt(1,"cfgcmp: EXIT matchflg=%d\n",matchflg);
- return matchflg;
- }
- // dowait -- wait for child
- int
- dowait(int tryidx,pid_t pid)
- {
- int signo = 0;
- int matchflg = 0;
- int code = 7;
- symval_t *arr = NULL;
- do {
- waitpid(pid,&status,0);
- if (WIFSTOPPED(status)) {
- signo = WSTOPSIG(status);
- break;
- }
- if (WIFEXITED(status)) {
- code = WEXITSTATUS(status);
- break;
- }
- if (WIFSIGNALED(status)) {
- signo = WTERMSIG(status);
- break;
- }
- } while (0);
- dbgprt(1,"dowait: STATUS status=%8.8X code=%d signo=%d\n",
- status,code,signo);
- #if PARERR
- prtf("PAR/EXECVP %d -- %s\n",code,strerror(code));
- #endif
- do {
- int ecode = code;
- if (code >= ERRNO_CODE) {
- ecode -= ERRNO_CODE;
- // the only error we get should be E2BIG as the exit code
- if (ecode == E2BIG)
- break;
- }
- if (signo != 0)
- sysfault("dowait: child signal -- status=%8.8X signo=%d\n",
- status,signo);
- if (code != 0) {
- sysfault("dowait: child fault -- status=%8.8X code=%d/%d -- %s\n",
- status,code,ecode,
- (ecode != code) ? strerror(code) : "error")
- }
- // get back results
- arr = cfgpop();
- // process the data
- if (opt_M != NULL)
- matchflg = cfgcmp(tryidx,arr);
- if (matchflg) {
- code = 1;
- break;
- }
- } while (0);
- #if 0
- if (opt_s)
- FREEMEIF(arr);
- #endif
- return code;
- }
- // doaslr -- set/clear ASLR
- unsigned int
- doaslr(int who)
- {
- unsigned int pernew = ADDR_NO_RANDOMIZE;
- unsigned int perchk = 0xFFFFFFFF;
- unsigned int perold = perchk;
- do {
- char *cp = opt_A;
- if (cp == NULL)
- break;
- // decide if we should do it now
- int when = 'c';
- switch (*cp) {
- case 'c':
- case 'p':
- case 'q':
- when = *cp++;
- break;
- }
- if (when == 'q') {
- if (who != 'p')
- break;
- }
- else {
- if (when != who)
- break;
- }
- perold = personality(perchk);
- // decide on enable/disable
- int disflg;
- if (*cp == 0)
- disflg = 1;
- else
- disflg = strtol(cp,&cp,10);
- if (disflg)
- pernew = perold | pernew;
- else
- pernew = perold & ~pernew;
- int err;
- switch (when) {
- case 'q':
- pernew = perold;
- break;
- default:
- err = personality(pernew);
- if (err < 0)
- sysfault("doaslr: unable to set perold=%8.8X pernew=%8.8X -- %s\n",
- perold,pernew,strerror(errno));
- perchk = personality(perchk);
- if (perchk != pernew)
- sysfault("doaslr: mismatch pernew=%8.8X perchk=%8.8X\n",
- pernew,perchk);
- break;
- }
- prtf("ASLR perold=%8.8X pernew=%8.8X perchk=%8.8X\n",
- perold,pernew,perchk);
- } while (0);
- return perold;
- }
- // doexec -- execute child program
- void
- doexec(size_t totlen)
- {
- size_t explen;
- int code;
- char *cp;
- char *str;
- char *argv_main[80];
- char **avmain = argv_main;
- char *argv_cfg[80];
- char **avcfg = argv_cfg;
- char *envx[1];
- char **envp;
- char Tbuf[100];
- char popt[20][20];
- // get size of argv string (minus space taken by envp)
- explen = totlen;
- explen -= envlen;
- *avmain++ = pgm_argv[0];
- // add child probe options
- if (opt_pc) {
- tgb_t *tgb;
- int idx = 0;
- for (TGBFORALL(popt_tgb,tgb), ++idx) {
- cp = popt[idx];
- sprintf(cp,"-%s=%d",tgb->tgb_tag,*tgb->tgb_ptr);
- *avcfg++ = cp;
- }
- }
- // add large string to arguments
- if (opt_n)
- str = NULL;
- else
- str = strmake(explen);
- if (str != NULL)
- *avmain++ = str;
- if (opt_T) {
- sprintf(Tbuf,"-T%d",opt_T);
- *avcfg++ = Tbuf;
- }
- if (opt_u)
- *avcfg++ = "-u";
- *avmain = NULL;
- *avcfg = NULL;
- for (int tryidx = 0; tryidx < opt_x; ++tryidx) {
- prtf("\n");
- prtf("LO:%zu TOT:%zu HI:%zu TRY:%d\n",lo,totlen,hi,tryidx);
- // send config options to child
- cfgpush(argv_cfg);
- pid_t pid = fork();
- if (pid < 0)
- sysfault("doexec: fork fault -- %s\n",strerror(errno));
- // parent
- if (pid != 0) {
- if (dowait(tryidx,pid))
- break;
- continue;
- }
- // setup envp
- if (opt_e) {
- envx[0] = NULL;
- envp = envx;
- }
- else
- envp = pgm_envp;
- // setup ASLR
- doaslr('c');
- // execute child program
- execvpe(pgm_argv[0],argv_main,envp);
- // with too much data we get E2BIG
- code = errno + ERRNO_CODE;
- #if CLDERR
- prtf("CLD/EXECVP %d -- %s\n",code,strerror(code));
- #endif
- exit(code);
- } while (0);
- FREEME(str);
- }
- // rlimget -- get stack size limits
- void
- rlimget(struct rlimit *rlim,const char *tag)
- {
- unsigned long lim;
- getrlimit(RLIMIT_STACK,rlim);
- for (int idx = 0; idx <= 1; ++idx) {
- prtf("rlimget: %s/%s",tag,(idx == 0) ? "CUR" : "MAX");
- switch (idx) {
- case 0:
- lim = rlim->rlim_cur;
- break;
- default:
- lim = rlim->rlim_max;
- break;
- }
- prtf(" %16.16lX %lu %.3fMB\n",lim,lim,(double) lim / 1e6);
- }
- }
- // sigprobe -- probe signal handler
- void
- sigprobe(int signo)
- {
- // signal we got
- probe_signo = signo;
- // recover gracefully
- siglongjmp(probe_jmpbuf,1);
- }
- // stkprobe -- probe stack limits
- void *
- stkprobe(void *sp,int inc,const char *tag)
- {
- unsigned long adr = (unsigned long) sp;
- static sigctl_t siglist[] = {
- { .sig_signo = SIGSEGV },
- { .sig_signo = SIGBUS },
- { .sig_signo = 0 }
- };
- sigctl_t *sig;
- char *cp;
- // set up our signal handler
- for (sig = siglist; sig->sig_signo != 0; ++sig)
- sig->sig_hdr = signal(sig->sig_signo,sigprobe);
- // align probe address downwards to page
- adr &= ~PAGE_MASK;
- // increment by size of page
- inc *= PAGE_SIZE;
- do {
- // arm the exception catcher
- if (sigsetjmp(probe_jmpbuf,1))
- break;
- // probe all [page aligned] addresses until a segfault occurs
- while (1) {
- probe_cp = VP(adr);
- // show the address
- if (opt_pv) {
- outptr(0,"PROBE",VP(probe_cp));
- fflush(stdout);
- }
- // force a probe
- if (opt_pw)
- *probe_cp |= 0;
- else
- (void) *probe_cp;
- // advance to next page
- adr += inc;
- }
- } while (0);
- cp = VP(probe_cp);
- // show the last _valid_ address
- if (0 && (! opt_pv))
- outptr(0,"FINAL",cp);
- if (inc < 0)
- cp += PAGE_SIZE;
- else
- cp -= 1;
- outptr(0,tag,cp);
- // show signal
- if (opt_ps)
- prtf("SIGNAL %d\n",probe_signo);
- // restore all
- for (sig = siglist; sig->sig_signo != 0; ++sig)
- signal(sig->sig_signo,sig->sig_hdr);
- return cp;
- }
- // sizget -- get # of bytes
- size_t
- sizget(char *cp)
- {
- size_t len;
- len = strtol(cp,&cp,10);
- switch (*cp) {
- case 'K':
- case 'k':
- len *= 1024;
- break;
- case 'M':
- case 'm':
- len *= 1024;
- len *= 1024;
- break;
- }
- return len;
- }
- // optmain -- main options
- int
- optmain(int argc,char **argv,const char *who)
- {
- char *cp;
- int ac;
- char **av;
- int len;
- tgb_t *tgb;
- // prescan for -T
- for (ac = argc, av = argv; ac > 0; --ac, ++av) {
- cp = *av;
- if (*cp != '-')
- break;
- cp += 2;
- switch (cp[-1]) {
- case 'T': // trace level
- opt_T = (*cp != 0) ? atoi(cp) : DEBUG;
- dbgprt(1,"%s: PRESCAN opt_T=%d cp='%s'\n",who,opt_T,cp - 2);
- break;
- }
- }
- // get options
- for (ac = argc, av = argv; ac > 0; --ac, ++av) {
- cp = *av;
- if (*cp != '-')
- break;
- dbgprt(1,"%s: OPTION cp='%s'\n",who,cp);
- cp += 2;
- switch (cp[-1]) {
- case 'A':
- opt_A = cp;
- break;
- case 'e':
- opt_e = 1;
- break;
- case 'n':
- opt_n = 1;
- break;
- case 'p':
- cp -= 1;
- for (TGBFORALL(popt_tgb,tgb)) {
- len = strlen(tgb->tgb_tag);
- if (strncmp(cp,tgb->tgb_tag,len) == 0) {
- cp += len;
- if (*cp == '=')
- ++cp;
- if (*cp == 0)
- *tgb->tgb_ptr = ! *tgb->tgb_ptr;
- else
- *tgb->tgb_ptr = atoi(cp);
- break;
- }
- }
- break;
- case 'L':
- opt_L = (*cp != 0) ? sizget(cp) : (16 * 1024);
- break;
- case 'R':
- opt_R = cp;
- break;
- case 's':
- opt_s = ! opt_s;
- break;
- case 'T':
- break;
- case 'M':
- if (*cp == 0)
- cp = "STKHI";
- opt_M = cp;
- break;
- case 'u':
- opt_u = ! opt_u;
- break;
- case 'x':
- opt_x = (*cp != 0) ? atoi(cp) : 2;
- break;
- }
- }
- ac = av - argv;
- return ac;
- }
- // optcld -- parse child options from file and open output stream
- void
- optcld(int fd)
- {
- const char *err;
- int len;
- char *bp;
- char *cp;
- int argc;
- char **av;
- char *argv[1000];
- // force child mode
- opt_c = 1;
- do {
- err = NULL;
- bp = optcldbuf;
- // simulate fgets
- len = read(fd,bp,sizeof(optcldbuf));
- if (len < 0) {
- err = "unable to read";
- break;
- }
- bp[len] = 0;
- av = argv;
- while (1) {
- cp = strtok(bp," \t\n");
- bp = NULL;
- if (cp == NULL)
- break;
- *av++ = cp;
- }
- *av = NULL;
- argc = av - argv;
- optmain(argc,argv,"optcld");
- // set up file for return of child values ...
- if (lseek(fd,0,0) < 0) {
- err = "unable to rewind";
- break;
- }
- if (ftruncate(fd,0) < 0) {
- err = "unable to ftruncate";
- break;
- }
- xfout = fdopen(fd,"w");
- if (xfout == NULL) {
- err = "unable to xfout";
- break;
- }
- if (! opt_u)
- setlinebuf(xfout);
- } while (0);
- if (err != NULL)
- sysfault("optcld: %s fd=%d -- %s\n",err,fd,strerror(errno));
- }
- int
- main(int argc,char **argv,char **envp)
- {
- char *cp;
- unsigned long dif;
- pgm_argc = argc;
- pgm_argv = argv;
- pgm_envp = envp;
- // length of envp area
- envlen = argvlen(envp);
- arg_max = sysconf(_SC_ARG_MAX);
- // skip program name
- --argc;
- ++argv;
- int ac = optmain(argc,argv,"optmain");
- argc -= ac;
- argv += ac;
- // hack so we recognize child mode (see doexec)
- struct stat st;
- if (fstat(CLDFD,&st) == 0)
- optcld(CLDFD);
- if (! opt_u) {
- setlinebuf(stdout);
- setlinebuf(stderr);
- }
- dbgprt(1,"main: PID %d\n",getpid());
- if (opt_x <= 0)
- opt_x = 1;
- void *stkptr = __builtin_frame_address(0);
- outptr(0,"MAIN",main);
- outptr(1,"ENVP",pgm_envp);
- outcalc(0,"ENVLEN",pgm_envp);
- dif = (VP(pgm_envp) - VP(pgm_argv)) + 1;
- outlen(0,"E2A",dif);
- outptr(1,"ARGV",pgm_argv);
- outcalc(0,"ARGLEN",pgm_argv);
- dif = (VP(pgm_argv) - stkptr) + 1;
- outlen(0,"A2S",dif);
- // show stack
- outptr(0,"STKPTR",stkptr);
- do {
- void *stklo = NULL;
- void *stkhi = NULL;
- // decide if we're allowed to probe
- if (opt_c) {
- if (! opt_pc)
- break;
- }
- else {
- if (! opt_pp)
- break;
- }
- if (opt_ph)
- stkhi = stkprobe(stkptr,1,"STKHI");
- if (opt_pl)
- stklo = stkprobe(stkptr,-1,"STKLO");
- if (opt_ph && opt_pl) {
- dif = (stkhi - stklo) + 1;
- outlen(0,"STKSIZ",dif);
- }
- if (opt_ph) {
- dif = (stkhi - VP(pgm_envp)) + 1;
- outlen(0,"ENVOFF",dif);
- dif = (stkhi - VP(pgm_argv)) + 1;
- outlen(0,"ARGOFF",dif);
- dif = (stkhi - stkptr) + 1;
- outlen(0,"STKOFF",dif);
- }
- } while (0);
- // child just exits
- if (opt_c) {
- if (xfout != NULL)
- fclose(xfout);
- exit(0);
- }
- // set ASLR in parent
- doaslr('p');
- // set RLIMIT_STACK
- do {
- if (opt_R == NULL)
- break;
- size_t Rsize = sizget(opt_R);
- prtf("rlimget: ARG %zu\n",Rsize);
- if (Rsize == 0)
- break;
- struct rlimit rlim;
- rlimget(&rlim,"OLD");
- rlim.rlim_cur = Rsize;
- setrlimit(RLIMIT_STACK,&rlim);
- rlimget(&rlim,"NEW");
- } while (0);
- // show some sizes/limits
- prtf("arg_lgx: %zu\n",arg_lgx);
- prtf("arg_max: %zu\n",arg_max);
- prtf("envlen: %zu\n",envlen);
- // locate config file
- cp = getenv("HOME");
- if (cp == NULL)
- cp = "/tmp";
- sprintf(cfgfile,"%s/argmax.cfg",cp);
- // initialize matching
- if (opt_M != NULL)
- cfginit();
- // do binary search for maximum size of argv bytes
- if (opt_L) {
- lo = opt_L;
- hi = opt_L;
- }
- else {
- lo = 32;
- hi = 100000000;
- }
- while (lo <= hi) {
- size_t mid = (lo + hi) / 2;
- doexec(mid);
- if (status == 0)
- lo = mid + 1;
- else
- hi = mid - 1;
- }
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement