Advertisement
cae7291

argmax -- probe argv/envp max size (ASLR)

Sep 25th, 2020
529
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 24.19 KB | None | 0 0
  1. #define _GNU_SOURCE
  2. #include <linux/limits.h>
  3.  
  4. long arg_lgx = ARG_MAX;
  5.  
  6. #include <stdio.h>
  7. #include <string.h>
  8. #include <stdlib.h>
  9. #include <errno.h>
  10. #include <fcntl.h>
  11. #include <unistd.h>
  12. #include <setjmp.h>
  13. #include <stdarg.h>
  14.  
  15. #include <sys/param.h>
  16.  
  17. #include <sys/wait.h>
  18. #include <sys/resource.h>
  19. #include <sys/stat.h>
  20.  
  21. #include <sys/personality.h>
  22.  
  23. #define FREEME(_ptr) \
  24. do { \
  25. if ((_ptr) == NULL) \
  26. break; \
  27. free(_ptr); \
  28. _ptr = NULL; \
  29. } while (0)
  30.  
  31. // original arguments to main
  32. int pgm_argc;
  33. char **pgm_argv;
  34. char **pgm_envp;
  35.  
  36. int fdcfg; // file descriptor for cfgfile
  37. char cfgfile[100]; // config file
  38. char optcldbuf[1000];
  39.  
  40. #define ERRNO_CODE 64 // minimum code for errno
  41.  
  42. char *opt_A; // 1=suppress ASLR
  43. int opt_e; // 1=send empty envp to child
  44. int opt_n; // 1=suppress big string in argv
  45. char *opt_M; // symbols to match
  46. int opt_x; // repeat count
  47. int opt_s; // 1=sparse history
  48. int opt_T; // trace level
  49. int opt_c; // 1=child mode
  50. char *opt_R; // set RLIMIT_STACK
  51. size_t opt_L; // hi/lo limit
  52. int opt_u; // unbuf
  53.  
  54. #define POPTALL(_cmd) \
  55. _cmd(pc,1,"1=do stack probe in child") \
  56. _cmd(pp,1,"1=do stack probe in parent") \
  57. _cmd(pl,1,"1=do downward stack probe (lo)") \
  58. _cmd(ph,1,"1=do upward stack probe (hi)") \
  59. _cmd(ps,0,"1=show signal number") \
  60. _cmd(pv,0,"1=print all stack probe addresses") \
  61. _cmd(pw,0,"1=do stack probe (write/modify)")
  62.  
  63. #define _POPTDEF(_opt,_dft,_reason) \
  64. int opt_##_opt = _dft;
  65.  
  66. POPTALL(_POPTDEF)
  67.  
  68. typedef long symval_t; // symbol value
  69.  
  70. // symbol table entry
  71. typedef struct {
  72. const char *tgb_tag; // option char
  73. union {
  74. int *tgb_ptr; // pointer to option
  75. symval_t tgb_val; // option value
  76. };
  77. const char *tgb_reason; // reason
  78. } tgb_t;
  79.  
  80. #define TGBEOT \
  81. { .tgb_tag = NULL }
  82.  
  83. #define TGBMORE(_tgb) \
  84. (_tgb->tgb_tag != NULL)
  85.  
  86. #define TGBFORALL(_tga,_tgb) \
  87. _tgb = _tga; TGBMORE(_tgb); ++_tgb
  88.  
  89. #define _POPTTGB(_opt,_dft,_reason) \
  90. { .tgb_tag = #_opt, .tgb_ptr = &opt_##_opt, .tgb_reason = _reason },
  91. tgb_t popt_tgb[] = {
  92. POPTALL(_POPTTGB)
  93. TGBEOT
  94. };
  95.  
  96. size_t envlen; // bytes used by envp
  97. //size_t totlen; // total number of bytes used
  98. long arg_max; // result of _SC_ARG_MAX
  99.  
  100. typedef struct {
  101. int sig_signo; // number
  102. sighandler_t sig_hdr; // handler
  103. } sigctl_t;
  104.  
  105. // search limits
  106. size_t lo;
  107. size_t hi;
  108.  
  109. int status; // child status (waitpid)
  110.  
  111. #define SYMALL(_cmd) \
  112. _cmd(MAIN,"address of main function") \
  113. _cmd(ENVP,"pointer to environ vector") \
  114. _cmd(ENVLEN,"calculated length of environ") \
  115. _cmd(E2A,"offset of envp/argv") \
  116. _cmd(ARGV,"pointer to argv vector") \
  117. _cmd(ARGLEN,"calculated length of argv") \
  118. _cmd(A2S,"offset of argv/stkptr") \
  119. _cmd(STKPTR,"main stack frame") \
  120. _cmd(STKHI,"highest valid stack address") \
  121. _cmd(STKLO,"lowest valid stack address") \
  122. _cmd(STKSIZ,"maximum stack size") \
  123. _cmd(ENVOFF,"offset of envp from stkhi") \
  124. _cmd(ARGOFF,"offset of argv from stkhi") \
  125. _cmd(STKOFF,"offset of stkptr from stkhi")
  126.  
  127. #define SYMDEF(_sym,_reason) \
  128. _sym##_IDX,
  129. enum {
  130. SYMALL(SYMDEF)
  131. SYMDEFMAX
  132. };
  133.  
  134. #define SYMTGB(_sym,_reason) \
  135. { .tgb_tag = #_sym, .tgb_val = _sym##_IDX, .tgb_reason = _reason },
  136. tgb_t symdef_tgb[] = {
  137. SYMALL(SYMTGB)
  138. TGBEOT
  139. };
  140.  
  141. // symbol history
  142. typedef struct hist_ hist_t;
  143. struct hist_ {
  144. union {
  145. symval_t *hist_ptr; // symbol array
  146. symval_t hist_val; // symbol value
  147. };
  148. int hist_try; // try index value
  149. hist_t *hist_next;
  150. };
  151.  
  152. hist_t *histlist; // history list
  153.  
  154. // symbol match control (if we have opt_M)
  155. int matchany = -1; // 1=or (vs. and)
  156. char *matchav[100];
  157. #ifndef MATCHALL
  158. #define MATCHALL "STKPTR,STKLO,STKHI,ARGLEN,ARGOFF"
  159. #endif
  160. char matchall[] = MATCHALL;
  161.  
  162. // unit to force opt_c on
  163. #ifndef CLDFD
  164. #define CLDFD 37
  165. #endif
  166.  
  167. #define VP(_ptr) ((void *) (_ptr)) // remove qualifiers
  168.  
  169. volatile int probe_signo; // stkprobe signal number
  170. sigjmp_buf probe_jmpbuf; // stkprobe jump buffer
  171. volatile unsigned char *probe_cp; // stkprobe probe address pointer
  172.  
  173. // pointer printing [I hate %p ;-(]
  174. #define PTR_FMT "%16.16lX"
  175. #define PTR_PRT(_p) ((unsigned long) (_p))
  176.  
  177. #ifndef PAGE_SHIFT
  178. #define PAGE_SHIFT 12
  179. #endif
  180.  
  181. #ifndef PAGE_SIZE
  182. #define PAGE_SIZE (1 << PAGE_SHIFT)
  183. #endif
  184.  
  185. #ifndef PAGE_MASK
  186. #define PAGE_MASK (PAGE_SIZE - 1)
  187. #endif
  188.  
  189. #define sysfaultx(_code,_fmt...) \
  190. do { \
  191. fprintf(stderr,_fmt); \
  192. exit(_code); \
  193. } while (0);
  194.  
  195. #define sysfault(_fmt...) \
  196. sysfaultx(99,_fmt)
  197.  
  198. #ifndef DEBUG
  199. #if _USE_ZPRT_
  200. #define DEBUG 1
  201. #else
  202. #define DEBUG 0
  203. #endif
  204. #endif
  205.  
  206. #define dbgprt(_lvl,_fmt...) \
  207. do { \
  208. if (DEBUG && (opt_T >= _lvl)) \
  209. fprintf(stderr,_fmt); \
  210. } while (0)
  211.  
  212. FILE *xfout; // output stream
  213.  
  214. // prtf -- diverted printf
  215. int __attribute__((format(printf,1,2)))
  216. prtf(const char *fmt,...)
  217. {
  218. va_list ap;
  219. FILE *xf;
  220. int len;
  221.  
  222. xf = xfout;
  223.  
  224. if (xf == NULL) {
  225. if (opt_c)
  226. sysfault("prtf: child null xfout\n");
  227. xf = stdout;
  228. }
  229.  
  230. va_start(ap,fmt);
  231. len = vfprintf(xf,fmt,ap);
  232. va_end(ap);
  233.  
  234. if (len < 0)
  235. sysfault("prtf: unable to vprintf fd=%d -- %s\n",
  236. fileno(xf),strerror(errno));
  237.  
  238. return len;
  239. }
  240.  
  241. // argvlen -- get bytes used by argv/envp pointer
  242. size_t
  243. argvlen(char **argv)
  244. {
  245. size_t totlen = 0;
  246.  
  247. for (; *argv != NULL; ++argv) {
  248. size_t slen = strlen(*argv);
  249.  
  250. // add in string length + EOS
  251. totlen += slen;
  252. totlen += 1;
  253.  
  254. // add in amount of space taken up by the pointer to the string
  255. totlen += sizeof(char *);
  256. }
  257.  
  258. // space taken up by trailing NULL pointer
  259. totlen += sizeof(char *);
  260.  
  261. return totlen;
  262. }
  263.  
  264. // tgblocbytag -- find entry by symbol string
  265. tgb_t *
  266. tgblocbytag(tgb_t *tga,const char *tag)
  267. {
  268. tgb_t *tgb;
  269.  
  270. for (TGBFORALL(tga,tgb)) {
  271. if (strcmp(tgb->tgb_tag,tag) == 0)
  272. break;
  273. }
  274.  
  275. return tgb;
  276. }
  277.  
  278. // strmake -- create large string
  279. char *
  280. strmake(size_t explen)
  281. {
  282. char *bp;
  283. char *buf;
  284.  
  285. // allow for pointer itself
  286. explen -= sizeof(char *);
  287.  
  288. // allow for EOS
  289. explen -= 1;
  290.  
  291. buf = malloc(explen + 1);
  292. if (buf == NULL)
  293. sysfault("strmake: malloc failure explen=%zu\n",explen);
  294.  
  295. // fill in the string
  296. for (bp = buf; explen > 0; --explen, ++bp)
  297. *bp = (explen % 26) + 'A';
  298. *bp = 0;
  299.  
  300. return buf;
  301. }
  302.  
  303. // tagout -- output a symbol tag
  304. int
  305. tagout(const char *tag)
  306. {
  307. int len;
  308.  
  309. len = 0;
  310.  
  311. if (tag != NULL) {
  312. len += prtf("%s",tag);
  313. while (len < 9)
  314. len += prtf(" ");
  315. }
  316.  
  317. return len;
  318. }
  319.  
  320. // whyout -- output reason
  321. void
  322. whyout(const char *tag)
  323. {
  324. tgb_t *tgb;
  325.  
  326. tgb = tgblocbytag(symdef_tgb,tag);
  327. if (TGBMORE(tgb))
  328. prtf(" -- %s",tgb->tgb_reason);
  329. }
  330.  
  331. // outlen -- output a length
  332. void
  333. outlen(int opt,const char *tag,unsigned long len)
  334. {
  335.  
  336. tagout(tag);
  337.  
  338. prtf(PTR_FMT " %lu %.3fMB",
  339. PTR_PRT(len),len,(double) len / 1e6);
  340.  
  341. if (tag != NULL) {
  342. whyout(tag);
  343. prtf("\n");
  344. }
  345. }
  346.  
  347. // outptr -- output a pointer
  348. void
  349. outptr(int opt,const char *tag,void *ptr)
  350. {
  351.  
  352. tagout(tag);
  353.  
  354. prtf(PTR_FMT,PTR_PRT(ptr));
  355.  
  356. if (tag != NULL) {
  357. whyout(tag);
  358. prtf("\n");
  359. }
  360. }
  361.  
  362. // outcalc -- output length of argv list
  363. void
  364. outcalc(int opt,const char *tag,void *ptr)
  365. {
  366.  
  367. outlen(0,tag,argvlen(ptr));
  368. }
  369.  
  370. // cfgpush -- send configuration to child
  371. void
  372. cfgpush(char **argv)
  373. {
  374.  
  375. // open config file
  376. fdcfg = open(cfgfile,O_RDWR | O_TRUNC | O_CREAT,0644);
  377. if (fdcfg < 0)
  378. sysfault("cfgpush: unable to open '%s' -- %s\n",
  379. cfgfile,strerror(errno));
  380.  
  381. // attach a stream to it
  382. FILE *xfcfg = fdopen(fdcfg,"r+");
  383. if (xfcfg == NULL)
  384. sysfault("cfgpush: unable to fdopen '%s' -- %s\n",
  385. cfgfile,strerror(errno));
  386.  
  387. // push all arguments
  388. for (; *argv != NULL; ++argv)
  389. fprintf(xfcfg," %s",*argv);
  390. fprintf(xfcfg,"\n");
  391. fflush(xfcfg);
  392.  
  393. // pass file to child
  394. if (dup2(fdcfg,CLDFD) < 0)
  395. sysfault("cfgpush: unable to dup2 -- %s\n",strerror(errno));
  396.  
  397. fclose(xfcfg);
  398. close(fdcfg);
  399.  
  400. // rewind the stream for child
  401. fdcfg = CLDFD;
  402. if (lseek(fdcfg,0,0) < 0)
  403. sysfault("cfgpush: unable to rewind cfgfile -- %s\n",strerror(errno));
  404. }
  405.  
  406. // cfgpop -- get data from child
  407. symval_t *
  408. cfgpop(void)
  409. {
  410. char *cp;
  411. tgb_t *tgb;
  412. symval_t val;
  413. char buf[1000];
  414. static symval_t arr_static[SYMDEFMAX];
  415. symval_t *arr;
  416.  
  417. dbgprt(1,"cfgpop: ENTER\n");
  418.  
  419. // attach a stream to it
  420. FILE *xfin = fopen(cfgfile,"r");
  421. if (xfin == NULL)
  422. sysfault("cfgpop: unable to fopen '%s' -- %s\n",
  423. cfgfile,strerror(errno));
  424.  
  425. // get buffer to return values
  426. int len = SYMDEFMAX * sizeof(*arr);
  427. arr = opt_s ? arr_static : malloc(len);
  428. memset(arr,0,len);
  429. dbgprt(1,"cfgpop: ARR arr=%p len=%d\n",arr,len);
  430.  
  431. while (1) {
  432. cp = fgets(buf,sizeof(buf),xfin);
  433. if (cp == NULL)
  434. break;
  435.  
  436. cp = strchr(buf,'\n');
  437. if (cp != NULL)
  438. *cp = 0;
  439.  
  440. prtf("%s\n",buf);
  441.  
  442. // get symbol name
  443. cp = strtok(buf," ");
  444. if (cp == NULL)
  445. continue;
  446.  
  447. // get definition
  448. tgb = tgblocbytag(symdef_tgb,cp);
  449. if (! TGBMORE(tgb))
  450. continue;
  451.  
  452. // get value (hex)
  453. cp = strtok(NULL," ");
  454. if (cp == NULL)
  455. continue;
  456. val = strtoll(cp,&cp,16);
  457.  
  458. // store value
  459. dbgprt(2,"cfgpop: SETVAL val=%16.16lX\n",val);
  460. arr[tgb->tgb_val] = val;
  461. }
  462.  
  463. fclose(xfin);
  464.  
  465. dbgprt(1,"cfgpop: EXIT\n");
  466.  
  467. return arr;
  468. }
  469.  
  470. // histfetch -- fetch value
  471. symval_t
  472. histfetch(hist_t *hist,int arridx)
  473. {
  474. symval_t curval;
  475.  
  476. if (opt_s)
  477. curval = hist->hist_val;
  478. else
  479. curval = hist->hist_ptr[arridx];
  480.  
  481. return curval;
  482. }
  483.  
  484. // cfginit -- initialize match symbols list
  485. void
  486. cfginit(void)
  487. {
  488. char *bp = opt_M;
  489. char *sym;
  490. char **av;
  491.  
  492. // decide on "and" or "or" operation
  493. matchany = *bp;
  494. switch (matchany) {
  495. case 'a':
  496. case '&':
  497. matchany = 0;
  498. ++bp;
  499. break;
  500. case 'o':
  501. case '|':
  502. matchany = 1;
  503. ++bp;
  504. break;
  505. default:
  506. matchany = 0;
  507. break;
  508. }
  509. prtf("cfginit: %s\n",matchany ? "MATCHANY" : "MATCHALL");
  510.  
  511. // split the list
  512. av = matchav;
  513. while (1) {
  514. sym = strtok(bp,",");
  515. bp = NULL;
  516.  
  517. if (sym == NULL)
  518. break;
  519.  
  520. prtf("cfginit: SYMBOL '%s'\n",sym);
  521.  
  522. if (sym[0] == '@') {
  523. bp = matchall;
  524. continue;
  525. }
  526.  
  527. *av++ = sym;
  528. }
  529. *av = NULL;
  530.  
  531. int symcnt = av - matchav;
  532. if ((symcnt > 1) && opt_s)
  533. sysfault("cfginit: symcnt=%d conflicts with -s\n",symcnt);
  534. }
  535.  
  536. // cfgmatch -- scan list for existing value
  537. int
  538. cfgmatch(hist_t *histcur,symval_t *curarr)
  539. {
  540. char **av;
  541. char *sym;
  542. symval_t oldval;
  543. symval_t curval;
  544. int matchflg = 0;
  545.  
  546. for (av = matchav; *av != NULL; ++av) {
  547. matchflg = 0;
  548. sym = *av;
  549.  
  550. // get match index
  551. tgb_t *tgb = tgblocbytag(symdef_tgb,sym);
  552. if (! TGBMORE(tgb))
  553. sysfault("cfgmatch: unknown match symbol -- '%s'\n",sym);
  554. int arridx = tgb->tgb_val;
  555.  
  556. // get previous/old value
  557. oldval = histfetch(histcur,arridx);
  558.  
  559. // get current value
  560. curval = curarr[arridx];
  561.  
  562. matchflg = (oldval == curval);
  563.  
  564. dbgprt(2,"cfgmatch: EXPMATCH arridx=%d sym='%s' curval=%16.16lX matchflg=%d\n",
  565. arridx,sym,curval,matchflg);
  566.  
  567. dbgprt(2,"cfgmatch: ACTMATCH oldval=%16.16lX hist_try=%d matchflg=%d\n",
  568. oldval,histcur->hist_try,matchflg);
  569.  
  570. // stop on any match
  571. if (matchany) {
  572. if (matchflg)
  573. break;
  574. }
  575.  
  576. // stop only if all symbols match
  577. else {
  578. if (! matchflg)
  579. break;
  580. }
  581. }
  582.  
  583. return matchflg;
  584. }
  585.  
  586. // cfgcmp -- compare data
  587. int
  588. cfgcmp(int tryidx,symval_t *curarr)
  589. {
  590. hist_t *hcur;
  591. hist_t *hnew;
  592. symval_t oldval;
  593. symval_t curval;
  594. int matchflg = 0;
  595.  
  596. dbgprt(1,"cfgcmp: ENTER tryidx=%d\n",tryidx);
  597.  
  598. // find match
  599. for (hcur = histlist; hcur != NULL; hcur = hcur->hist_next) {
  600. matchflg = cfgmatch(hcur,curarr);
  601. if (matchflg)
  602. break;
  603. }
  604.  
  605. // find the tail
  606. hist_t *hprev = NULL;
  607. for (hist_t *hist = histlist; hist != NULL; hist = hist->hist_next)
  608. hprev = hist;
  609.  
  610. // link new entry
  611. hnew = calloc(1,sizeof(hist_t));
  612. if (hprev != NULL)
  613. hprev->hist_next = hnew;
  614. else
  615. histlist = hnew;
  616.  
  617. // FIXME/CAE -- this is broken
  618. curval = 0;
  619.  
  620. // store new value
  621. if (opt_s)
  622. hnew->hist_val = curval;
  623. else
  624. hnew->hist_ptr = curarr;
  625.  
  626. // remember when we did this
  627. hnew->hist_try = tryidx;
  628.  
  629. do {
  630. tgb_t *tgb;
  631.  
  632. if (! matchflg)
  633. break;
  634. if (hcur == NULL)
  635. break;
  636.  
  637. prtf("MATCH %d/%d\n",hcur->hist_try,hnew->hist_try);
  638.  
  639. for (TGBFORALL(symdef_tgb,tgb)) {
  640. int arridx = tgb->tgb_val;
  641.  
  642. oldval = histfetch(hcur,arridx);
  643. curval = histfetch(hnew,arridx);
  644. if (oldval == curval)
  645. continue;
  646.  
  647. prtf("DIF ");
  648. tagout(tgb->tgb_tag);
  649. prtf(" %16.16lX %16.16lX\n",oldval,curval);
  650. }
  651. } while (0);
  652.  
  653. dbgprt(1,"cfgcmp: EXIT matchflg=%d\n",matchflg);
  654.  
  655. return matchflg;
  656. }
  657.  
  658. // dowait -- wait for child
  659. int
  660. dowait(int tryidx,pid_t pid)
  661. {
  662. int signo = 0;
  663. int matchflg = 0;
  664. int code = 7;
  665. symval_t *arr = NULL;
  666.  
  667. do {
  668. waitpid(pid,&status,0);
  669.  
  670. if (WIFSTOPPED(status)) {
  671. signo = WSTOPSIG(status);
  672. break;
  673. }
  674.  
  675. if (WIFEXITED(status)) {
  676. code = WEXITSTATUS(status);
  677. break;
  678. }
  679.  
  680. if (WIFSIGNALED(status)) {
  681. signo = WTERMSIG(status);
  682. break;
  683. }
  684. } while (0);
  685. dbgprt(1,"dowait: STATUS status=%8.8X code=%d signo=%d\n",
  686. status,code,signo);
  687. #if PARERR
  688. prtf("PAR/EXECVP %d -- %s\n",code,strerror(code));
  689. #endif
  690.  
  691. do {
  692. int ecode = code;
  693.  
  694. if (code >= ERRNO_CODE) {
  695. ecode -= ERRNO_CODE;
  696.  
  697. // the only error we get should be E2BIG as the exit code
  698. if (ecode == E2BIG)
  699. break;
  700. }
  701.  
  702. if (signo != 0)
  703. sysfault("dowait: child signal -- status=%8.8X signo=%d\n",
  704. status,signo);
  705.  
  706. if (code != 0) {
  707. sysfault("dowait: child fault -- status=%8.8X code=%d/%d -- %s\n",
  708. status,code,ecode,
  709. (ecode != code) ? strerror(code) : "error")
  710. }
  711.  
  712. // get back results
  713. arr = cfgpop();
  714.  
  715. // process the data
  716. if (opt_M != NULL)
  717. matchflg = cfgcmp(tryidx,arr);
  718.  
  719. if (matchflg) {
  720. code = 1;
  721. break;
  722. }
  723. } while (0);
  724.  
  725. #if 0
  726. if (opt_s)
  727. FREEMEIF(arr);
  728. #endif
  729.  
  730. return code;
  731. }
  732.  
  733. // doaslr -- set/clear ASLR
  734. unsigned int
  735. doaslr(int who)
  736. {
  737. unsigned int pernew = ADDR_NO_RANDOMIZE;
  738. unsigned int perchk = 0xFFFFFFFF;
  739. unsigned int perold = perchk;
  740.  
  741. do {
  742. char *cp = opt_A;
  743. if (cp == NULL)
  744. break;
  745.  
  746. // decide if we should do it now
  747. int when = 'c';
  748. switch (*cp) {
  749. case 'c':
  750. case 'p':
  751. case 'q':
  752. when = *cp++;
  753. break;
  754. }
  755. if (when == 'q') {
  756. if (who != 'p')
  757. break;
  758. }
  759. else {
  760. if (when != who)
  761. break;
  762. }
  763.  
  764. perold = personality(perchk);
  765.  
  766. // decide on enable/disable
  767. int disflg;
  768. if (*cp == 0)
  769. disflg = 1;
  770. else
  771. disflg = strtol(cp,&cp,10);
  772. if (disflg)
  773. pernew = perold | pernew;
  774. else
  775. pernew = perold & ~pernew;
  776.  
  777. int err;
  778. switch (when) {
  779. case 'q':
  780. pernew = perold;
  781. break;
  782.  
  783. default:
  784. err = personality(pernew);
  785. if (err < 0)
  786. sysfault("doaslr: unable to set perold=%8.8X pernew=%8.8X -- %s\n",
  787. perold,pernew,strerror(errno));
  788.  
  789. perchk = personality(perchk);
  790. if (perchk != pernew)
  791. sysfault("doaslr: mismatch pernew=%8.8X perchk=%8.8X\n",
  792. pernew,perchk);
  793. break;
  794. }
  795.  
  796. prtf("ASLR perold=%8.8X pernew=%8.8X perchk=%8.8X\n",
  797. perold,pernew,perchk);
  798. } while (0);
  799.  
  800. return perold;
  801. }
  802.  
  803. // doexec -- execute child program
  804. void
  805. doexec(size_t totlen)
  806. {
  807. size_t explen;
  808. int code;
  809. char *cp;
  810. char *str;
  811. char *argv_main[80];
  812. char **avmain = argv_main;
  813. char *argv_cfg[80];
  814. char **avcfg = argv_cfg;
  815. char *envx[1];
  816. char **envp;
  817. char Tbuf[100];
  818. char popt[20][20];
  819.  
  820. // get size of argv string (minus space taken by envp)
  821. explen = totlen;
  822. explen -= envlen;
  823.  
  824. *avmain++ = pgm_argv[0];
  825.  
  826. // add child probe options
  827. if (opt_pc) {
  828. tgb_t *tgb;
  829. int idx = 0;
  830. for (TGBFORALL(popt_tgb,tgb), ++idx) {
  831. cp = popt[idx];
  832. sprintf(cp,"-%s=%d",tgb->tgb_tag,*tgb->tgb_ptr);
  833. *avcfg++ = cp;
  834. }
  835. }
  836.  
  837. // add large string to arguments
  838. if (opt_n)
  839. str = NULL;
  840. else
  841. str = strmake(explen);
  842. if (str != NULL)
  843. *avmain++ = str;
  844.  
  845. if (opt_T) {
  846. sprintf(Tbuf,"-T%d",opt_T);
  847. *avcfg++ = Tbuf;
  848. }
  849.  
  850. if (opt_u)
  851. *avcfg++ = "-u";
  852.  
  853. *avmain = NULL;
  854. *avcfg = NULL;
  855.  
  856. for (int tryidx = 0; tryidx < opt_x; ++tryidx) {
  857. prtf("\n");
  858. prtf("LO:%zu TOT:%zu HI:%zu TRY:%d\n",lo,totlen,hi,tryidx);
  859.  
  860. // send config options to child
  861. cfgpush(argv_cfg);
  862.  
  863. pid_t pid = fork();
  864.  
  865. if (pid < 0)
  866. sysfault("doexec: fork fault -- %s\n",strerror(errno));
  867.  
  868. // parent
  869. if (pid != 0) {
  870. if (dowait(tryidx,pid))
  871. break;
  872. continue;
  873. }
  874.  
  875. // setup envp
  876. if (opt_e) {
  877. envx[0] = NULL;
  878. envp = envx;
  879. }
  880. else
  881. envp = pgm_envp;
  882.  
  883. // setup ASLR
  884. doaslr('c');
  885.  
  886. // execute child program
  887. execvpe(pgm_argv[0],argv_main,envp);
  888.  
  889. // with too much data we get E2BIG
  890. code = errno + ERRNO_CODE;
  891. #if CLDERR
  892. prtf("CLD/EXECVP %d -- %s\n",code,strerror(code));
  893. #endif
  894.  
  895. exit(code);
  896. } while (0);
  897.  
  898. FREEME(str);
  899. }
  900.  
  901. // rlimget -- get stack size limits
  902. void
  903. rlimget(struct rlimit *rlim,const char *tag)
  904. {
  905. unsigned long lim;
  906.  
  907. getrlimit(RLIMIT_STACK,rlim);
  908.  
  909. for (int idx = 0; idx <= 1; ++idx) {
  910. prtf("rlimget: %s/%s",tag,(idx == 0) ? "CUR" : "MAX");
  911.  
  912. switch (idx) {
  913. case 0:
  914. lim = rlim->rlim_cur;
  915. break;
  916. default:
  917. lim = rlim->rlim_max;
  918. break;
  919. }
  920.  
  921. prtf(" %16.16lX %lu %.3fMB\n",lim,lim,(double) lim / 1e6);
  922. }
  923. }
  924.  
  925. // sigprobe -- probe signal handler
  926. void
  927. sigprobe(int signo)
  928. {
  929.  
  930. // signal we got
  931. probe_signo = signo;
  932.  
  933. // recover gracefully
  934. siglongjmp(probe_jmpbuf,1);
  935. }
  936.  
  937. // stkprobe -- probe stack limits
  938. void *
  939. stkprobe(void *sp,int inc,const char *tag)
  940. {
  941. unsigned long adr = (unsigned long) sp;
  942. static sigctl_t siglist[] = {
  943. { .sig_signo = SIGSEGV },
  944. { .sig_signo = SIGBUS },
  945. { .sig_signo = 0 }
  946. };
  947. sigctl_t *sig;
  948. char *cp;
  949.  
  950. // set up our signal handler
  951. for (sig = siglist; sig->sig_signo != 0; ++sig)
  952. sig->sig_hdr = signal(sig->sig_signo,sigprobe);
  953.  
  954. // align probe address downwards to page
  955. adr &= ~PAGE_MASK;
  956.  
  957. // increment by size of page
  958. inc *= PAGE_SIZE;
  959.  
  960. do {
  961. // arm the exception catcher
  962. if (sigsetjmp(probe_jmpbuf,1))
  963. break;
  964.  
  965. // probe all [page aligned] addresses until a segfault occurs
  966. while (1) {
  967. probe_cp = VP(adr);
  968.  
  969. // show the address
  970. if (opt_pv) {
  971. outptr(0,"PROBE",VP(probe_cp));
  972. fflush(stdout);
  973. }
  974.  
  975. // force a probe
  976. if (opt_pw)
  977. *probe_cp |= 0;
  978. else
  979. (void) *probe_cp;
  980.  
  981. // advance to next page
  982. adr += inc;
  983. }
  984. } while (0);
  985.  
  986. cp = VP(probe_cp);
  987.  
  988. // show the last _valid_ address
  989. if (0 && (! opt_pv))
  990. outptr(0,"FINAL",cp);
  991. if (inc < 0)
  992. cp += PAGE_SIZE;
  993. else
  994. cp -= 1;
  995. outptr(0,tag,cp);
  996.  
  997. // show signal
  998. if (opt_ps)
  999. prtf("SIGNAL %d\n",probe_signo);
  1000.  
  1001. // restore all
  1002. for (sig = siglist; sig->sig_signo != 0; ++sig)
  1003. signal(sig->sig_signo,sig->sig_hdr);
  1004.  
  1005. return cp;
  1006. }
  1007.  
  1008. // sizget -- get # of bytes
  1009. size_t
  1010. sizget(char *cp)
  1011. {
  1012. size_t len;
  1013.  
  1014. len = strtol(cp,&cp,10);
  1015.  
  1016. switch (*cp) {
  1017. case 'K':
  1018. case 'k':
  1019. len *= 1024;
  1020. break;
  1021.  
  1022. case 'M':
  1023. case 'm':
  1024. len *= 1024;
  1025. len *= 1024;
  1026. break;
  1027. }
  1028.  
  1029. return len;
  1030. }
  1031.  
  1032. // optmain -- main options
  1033. int
  1034. optmain(int argc,char **argv,const char *who)
  1035. {
  1036. char *cp;
  1037. int ac;
  1038. char **av;
  1039. int len;
  1040. tgb_t *tgb;
  1041.  
  1042. // prescan for -T
  1043. for (ac = argc, av = argv; ac > 0; --ac, ++av) {
  1044. cp = *av;
  1045. if (*cp != '-')
  1046. break;
  1047.  
  1048. cp += 2;
  1049. switch (cp[-1]) {
  1050. case 'T': // trace level
  1051. opt_T = (*cp != 0) ? atoi(cp) : DEBUG;
  1052. dbgprt(1,"%s: PRESCAN opt_T=%d cp='%s'\n",who,opt_T,cp - 2);
  1053. break;
  1054. }
  1055. }
  1056.  
  1057. // get options
  1058. for (ac = argc, av = argv; ac > 0; --ac, ++av) {
  1059. cp = *av;
  1060. if (*cp != '-')
  1061. break;
  1062.  
  1063. dbgprt(1,"%s: OPTION cp='%s'\n",who,cp);
  1064.  
  1065. cp += 2;
  1066. switch (cp[-1]) {
  1067. case 'A':
  1068. opt_A = cp;
  1069. break;
  1070.  
  1071. case 'e':
  1072. opt_e = 1;
  1073. break;
  1074.  
  1075. case 'n':
  1076. opt_n = 1;
  1077. break;
  1078.  
  1079. case 'p':
  1080. cp -= 1;
  1081. for (TGBFORALL(popt_tgb,tgb)) {
  1082. len = strlen(tgb->tgb_tag);
  1083.  
  1084. if (strncmp(cp,tgb->tgb_tag,len) == 0) {
  1085. cp += len;
  1086.  
  1087. if (*cp == '=')
  1088. ++cp;
  1089.  
  1090. if (*cp == 0)
  1091. *tgb->tgb_ptr = ! *tgb->tgb_ptr;
  1092. else
  1093. *tgb->tgb_ptr = atoi(cp);
  1094. break;
  1095. }
  1096. }
  1097. break;
  1098.  
  1099. case 'L':
  1100. opt_L = (*cp != 0) ? sizget(cp) : (16 * 1024);
  1101. break;
  1102.  
  1103. case 'R':
  1104. opt_R = cp;
  1105. break;
  1106.  
  1107. case 's':
  1108. opt_s = ! opt_s;
  1109. break;
  1110.  
  1111. case 'T':
  1112. break;
  1113.  
  1114. case 'M':
  1115. if (*cp == 0)
  1116. cp = "STKHI";
  1117. opt_M = cp;
  1118. break;
  1119.  
  1120. case 'u':
  1121. opt_u = ! opt_u;
  1122. break;
  1123.  
  1124. case 'x':
  1125. opt_x = (*cp != 0) ? atoi(cp) : 2;
  1126. break;
  1127. }
  1128. }
  1129.  
  1130. ac = av - argv;
  1131.  
  1132. return ac;
  1133. }
  1134.  
  1135. // optcld -- parse child options from file and open output stream
  1136. void
  1137. optcld(int fd)
  1138. {
  1139. const char *err;
  1140. int len;
  1141. char *bp;
  1142. char *cp;
  1143. int argc;
  1144. char **av;
  1145. char *argv[1000];
  1146.  
  1147. // force child mode
  1148. opt_c = 1;
  1149.  
  1150. do {
  1151. err = NULL;
  1152.  
  1153. bp = optcldbuf;
  1154.  
  1155. // simulate fgets
  1156. len = read(fd,bp,sizeof(optcldbuf));
  1157. if (len < 0) {
  1158. err = "unable to read";
  1159. break;
  1160. }
  1161. bp[len] = 0;
  1162.  
  1163. av = argv;
  1164.  
  1165. while (1) {
  1166. cp = strtok(bp," \t\n");
  1167. bp = NULL;
  1168.  
  1169. if (cp == NULL)
  1170. break;
  1171.  
  1172. *av++ = cp;
  1173. }
  1174.  
  1175. *av = NULL;
  1176. argc = av - argv;
  1177.  
  1178. optmain(argc,argv,"optcld");
  1179.  
  1180. // set up file for return of child values ...
  1181.  
  1182. if (lseek(fd,0,0) < 0) {
  1183. err = "unable to rewind";
  1184. break;
  1185. }
  1186.  
  1187. if (ftruncate(fd,0) < 0) {
  1188. err = "unable to ftruncate";
  1189. break;
  1190. }
  1191.  
  1192. xfout = fdopen(fd,"w");
  1193. if (xfout == NULL) {
  1194. err = "unable to xfout";
  1195. break;
  1196. }
  1197.  
  1198. if (! opt_u)
  1199. setlinebuf(xfout);
  1200. } while (0);
  1201.  
  1202. if (err != NULL)
  1203. sysfault("optcld: %s fd=%d -- %s\n",err,fd,strerror(errno));
  1204. }
  1205.  
  1206. int
  1207. main(int argc,char **argv,char **envp)
  1208. {
  1209. char *cp;
  1210. unsigned long dif;
  1211.  
  1212. pgm_argc = argc;
  1213. pgm_argv = argv;
  1214. pgm_envp = envp;
  1215.  
  1216. // length of envp area
  1217. envlen = argvlen(envp);
  1218.  
  1219. arg_max = sysconf(_SC_ARG_MAX);
  1220.  
  1221. // skip program name
  1222. --argc;
  1223. ++argv;
  1224.  
  1225. int ac = optmain(argc,argv,"optmain");
  1226. argc -= ac;
  1227. argv += ac;
  1228.  
  1229. // hack so we recognize child mode (see doexec)
  1230. struct stat st;
  1231. if (fstat(CLDFD,&st) == 0)
  1232. optcld(CLDFD);
  1233.  
  1234. if (! opt_u) {
  1235. setlinebuf(stdout);
  1236. setlinebuf(stderr);
  1237. }
  1238.  
  1239. dbgprt(1,"main: PID %d\n",getpid());
  1240.  
  1241. if (opt_x <= 0)
  1242. opt_x = 1;
  1243.  
  1244. void *stkptr = __builtin_frame_address(0);
  1245.  
  1246. outptr(0,"MAIN",main);
  1247.  
  1248. outptr(1,"ENVP",pgm_envp);
  1249. outcalc(0,"ENVLEN",pgm_envp);
  1250.  
  1251. dif = (VP(pgm_envp) - VP(pgm_argv)) + 1;
  1252. outlen(0,"E2A",dif);
  1253.  
  1254. outptr(1,"ARGV",pgm_argv);
  1255. outcalc(0,"ARGLEN",pgm_argv);
  1256.  
  1257. dif = (VP(pgm_argv) - stkptr) + 1;
  1258. outlen(0,"A2S",dif);
  1259.  
  1260. // show stack
  1261. outptr(0,"STKPTR",stkptr);
  1262.  
  1263. do {
  1264. void *stklo = NULL;
  1265. void *stkhi = NULL;
  1266.  
  1267. // decide if we're allowed to probe
  1268. if (opt_c) {
  1269. if (! opt_pc)
  1270. break;
  1271. }
  1272. else {
  1273. if (! opt_pp)
  1274. break;
  1275. }
  1276.  
  1277. if (opt_ph)
  1278. stkhi = stkprobe(stkptr,1,"STKHI");
  1279. if (opt_pl)
  1280. stklo = stkprobe(stkptr,-1,"STKLO");
  1281.  
  1282. if (opt_ph && opt_pl) {
  1283. dif = (stkhi - stklo) + 1;
  1284. outlen(0,"STKSIZ",dif);
  1285. }
  1286.  
  1287. if (opt_ph) {
  1288. dif = (stkhi - VP(pgm_envp)) + 1;
  1289. outlen(0,"ENVOFF",dif);
  1290.  
  1291. dif = (stkhi - VP(pgm_argv)) + 1;
  1292. outlen(0,"ARGOFF",dif);
  1293.  
  1294. dif = (stkhi - stkptr) + 1;
  1295. outlen(0,"STKOFF",dif);
  1296. }
  1297. } while (0);
  1298.  
  1299. // child just exits
  1300. if (opt_c) {
  1301. if (xfout != NULL)
  1302. fclose(xfout);
  1303. exit(0);
  1304. }
  1305.  
  1306. // set ASLR in parent
  1307. doaslr('p');
  1308.  
  1309. // set RLIMIT_STACK
  1310. do {
  1311. if (opt_R == NULL)
  1312. break;
  1313.  
  1314. size_t Rsize = sizget(opt_R);
  1315. prtf("rlimget: ARG %zu\n",Rsize);
  1316.  
  1317. if (Rsize == 0)
  1318. break;
  1319.  
  1320. struct rlimit rlim;
  1321.  
  1322. rlimget(&rlim,"OLD");
  1323.  
  1324. rlim.rlim_cur = Rsize;
  1325. setrlimit(RLIMIT_STACK,&rlim);
  1326.  
  1327. rlimget(&rlim,"NEW");
  1328. } while (0);
  1329.  
  1330. // show some sizes/limits
  1331. prtf("arg_lgx: %zu\n",arg_lgx);
  1332. prtf("arg_max: %zu\n",arg_max);
  1333. prtf("envlen: %zu\n",envlen);
  1334.  
  1335. // locate config file
  1336. cp = getenv("HOME");
  1337. if (cp == NULL)
  1338. cp = "/tmp";
  1339. sprintf(cfgfile,"%s/argmax.cfg",cp);
  1340.  
  1341. // initialize matching
  1342. if (opt_M != NULL)
  1343. cfginit();
  1344.  
  1345. // do binary search for maximum size of argv bytes
  1346. if (opt_L) {
  1347. lo = opt_L;
  1348. hi = opt_L;
  1349. }
  1350. else {
  1351. lo = 32;
  1352. hi = 100000000;
  1353. }
  1354. while (lo <= hi) {
  1355. size_t mid = (lo + hi) / 2;
  1356.  
  1357. doexec(mid);
  1358.  
  1359. if (status == 0)
  1360. lo = mid + 1;
  1361. else
  1362. hi = mid - 1;
  1363. }
  1364.  
  1365. return 0;
  1366. }
  1367.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement