From mboxrd@z Thu Jan 1 00:00:00 1970 X-Msuck: nntp://news.gmane.org/gmane.linux.lib.musl.general/382 Path: news.gmane.org!not-for-mail From: =?UTF-8?B?THVrYSBNYXLEjWV0acSH?= Newsgroups: gmane.linux.lib.musl.general Subject: Re: New daily reports - nothing Date: Wed, 10 Aug 2011 13:47:17 +0200 Message-ID: <4E426FC5.7020303@gmail.com> References: <4E39C84F.8060705@gmail.com> <20110803224651.GB11437@openwall.com> <4E3A79B2.8090204@gmail.com> <4E3B331E.7050502@gmail.com> <4E3CC5AC.3070404@gmail.com> <4E3DFB5D.8040008@gmail.com> <20110807073224.GG132@brightrain.aerifal.cx> <4E3F10C7.4060601@gmail.com> <4E40A33F.7090804@gmail.com> <4E41E020.7020109@gmail.com> <20110810013839.GU132@brightrain.aerifal.cx> Reply-To: musl@lists.openwall.com NNTP-Posting-Host: lo.gmane.org Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="------------030903090303090100050203" X-Trace: dough.gmane.org 1312976982 26572 80.91.229.12 (10 Aug 2011 11:49:42 GMT) X-Complaints-To: usenet@dough.gmane.org NNTP-Posting-Date: Wed, 10 Aug 2011 11:49:42 +0000 (UTC) To: musl@lists.openwall.com Original-X-From: musl-return-383-gllmg-musl=m.gmane.org@lists.openwall.com Wed Aug 10 13:49:38 2011 Return-path: Envelope-to: gllmg-musl@lo.gmane.org Original-Received: from mother.openwall.net ([195.42.179.200]) by lo.gmane.org with smtp (Exim 4.69) (envelope-from ) id 1Qr7I2-0008AX-8J for gllmg-musl@lo.gmane.org; Wed, 10 Aug 2011 13:49:38 +0200 Original-Received: (qmail 7826 invoked by uid 550); 10 Aug 2011 11:49:37 -0000 Mailing-List: contact musl-help@lists.openwall.com; run by ezmlm Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: Original-Received: (qmail 7818 invoked from network); 10 Aug 2011 11:49:37 -0000 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=gamma; h=message-id:date:from:user-agent:mime-version:to:subject:references :in-reply-to:content-type; bh=DT3jt4aCOyR+RZrvJD4/NtsUqFyH1Qwg23yvfcPcd20=; b=kKyzqrxRErd8yx/gHYzi5JXMYcByN4JMwB5G0d38cRGnIFDk1PVC9aWox3vLZ8HtLP BmNFLC16upinGRhd86LStlVlkod4V4z6/C+Ud23BUT1yglo4tGtN2Jd+nRqhzECMtvWh m3egbJwCBy4MKRZXGUduAafOfsl9vq5sG8kDM= User-Agent: Mozilla/5.0 (X11; U; Linux x86_64; en-US; rv:1.9.2.18) Gecko/20110626 Icedove/3.1.11 In-Reply-To: <20110810013839.GU132@brightrain.aerifal.cx> Xref: news.gmane.org gmane.linux.lib.musl.general:382 Archived-At: This is a multi-part message in MIME format. --------------030903090303090100050203 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit On 08/10/2011 03:38 AM, Rich Felker wrote: (Thanks for explaining mprotect first of all) > Especially as you're nearing the deadline, I'd like to ask you to > please listen when I make recommendations like this. Sure learning > about mprotect is educational, but in terms of getting stuff done, if > you'd taken my advice several days (a week now?) back about how to > check for writes past the end of the buffer, you would have been able > to spend your time today getting something done rather than wondering > why mprotect wasn't doing what you wanted.... > > Rich The worst thing is, I already do check that: I write '\r' in the last byte of the buffer, and then call the function saying the buffer is size-1 long (so it shows if it gets overwritten). It doesn't even make sense to test for reading/writing beyond size+1, except to test for implementation lunacy. I have no idea why I did that anymore. I should've just removed sigset altogether. I didn't need mprotect, nor wrappers... :-( P.S. Final buf.c thus won't look like the attached file. In it, alloc_bounded() is the broken one - a fixed version may appear somewhere else in the future though. --------------030903090303090100050203 Content-Type: text/x-csrc; name="buf.c" Content-Transfer-Encoding: 8bit Content-Disposition: attachment; filename="buf.c" #include #include #include #include #include #include "common/common.h" #include //strerror_r #include //PATH_MAX #include //mbstowcs #include //getdelim, snprintf #include //confstr, getcwd, gethostname, readlink #include //iconv #include //time, gmtime #include //strfmon /* * Copyright (c) 2011 Luka Marčetić * * Redistribution and use in source and binary forms, with or without * modification, are permitted. * * There's ABSOLUTELY NO WARRANTY, express or implied. */ /** ** \file ** Tests functions for writing beyond string lenght and errno's they set ** tests: confstr, getcwd, getdelim, gethostname, iconv, mbstowcs, snprintf, ** readlink, strfmon, strftime, wcstombs, ttyname_r, strerror_r ** depends: malloc, sigaction, strlen, mkstemp, fdopen,fclose,fileno, strptime ** iconv_open,iconv_close, free, setjmp, longjmp, open,close, ** mmap,mprotect,munmap **/ jmp_buf env; struct sigaction act, oldact[2]; //set by main, used in wrappers: void bridge_sig_jmp(int sig); static void* malloc_bounded(size_t size); static int free_bounded(void* vp); static int wrap_confstr(int name, char *buf, size_t len); static int wrap_getcwd(char *buf, size_t size); static int wrap_getdelim(char **lineptr, size_t *n, int delimiter,FILE *stream); static int wrap_gethostname(char *name, size_t namelen); static int wrap_mbstowcs(wchar_t *pwcs, char *s, size_t n); static int wrap_snprintf(char *s, size_t n, char *format/*, ...*/); static int wrap_readlink(char *path, char *buf, size_t bufsize); static int wrap_strfmon(char *s, size_t maxsize, char *format/*,...*/, float F); static int wrap_strftime(char *s,size_t maxsize,char *format,struct tm *timeptr); static int wrap_wcstombs(char *s, wchar_t *pwcs, size_t n); static int wrap_strerror_r(int errnum, char *strerrbuf, size_t buflen); static int wrap_ttyname_r(int fildes, char *name, size_t namesize); static int wrap_iconv(iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft); //još malloc wrapper thingy---- int main() { iconv_t cd; wchar_t *ws; size_t size; struct tm tm; FILE *stream = NULL; char *s, *fun, *tmp, filename[] = "/tmp/clutsXXXXXX"; int fd, sig, function, wrong, failed, err, err_expected; int ffun[] = {2, 3,8}; //functions that depend on the temporary file(two do) //GLOBAL: act=(struct sigaction){.sa_handler=bridge_sig_jmp, .sa_flags=SA_NODEFER}; failed = 0; function = 1; do { err = wrong = 0; s = fun = tmp = NULL; ws = NULL; stream = NULL; if (seq_has(function, ffun) && (fd=mkstemp(filename)) != -1) { if ((stream=fdopen(fd, "w+b")) == NULL) wrong = -1; } switch(function) { case 1: fun = sreturnf("confstr(_CS_PATH, s, sizeof(s)-1)"); size = confstr(_CS_PATH, NULL, 0); if (size < 2) { wrong = -2; break; } s = malloc_bounded(size); s[size-1] = '\r'; if ((err=wrap_confstr(_CS_PATH, s, size-1)) == -1) wrong = 1; else /*if ((err)) wrong = 5; else */if (s[size-1] != '\r') wrong = 2; break; case 2: fun = sreturnf("getcwd(s, sizeof(s)-1)"); s = malloc(PATH_MAX); size = strlen(getcwd(s, PATH_MAX))+1; free(s); s = NULL; if (size < 2) { wrong = -2; break; } s = malloc_bounded(size); s[size-1] = '\r'; if ((err=wrap_getcwd(s, size-1)) == -1) wrong = 1; else if (s[size-1] != '\r') wrong = 2; else if (err != (err_expected = ERANGE)) wrong = 3; break; case 3: //same for getline fun = sreturnf("getdelim(&s, &, '\\n', stream)"); if (stream == NULL) break; fwrite("123\n", (size = 4), 1, stream); s = malloc_bounded(size); s[size-1] = '\r'; if((err=wrap_getdelim(&s,(size_t[]){size-1},'\n',stream)) == -1) wrong = 1; else if (s[size-1] != '\r') wrong = 2; break; case 4: fun = sreturnf("gethostname(s, sizeof(s)-1)"); s = malloc(HOST_NAME_MAX); gethostname(s, HOST_NAME_MAX); size = strlen(s) + 1; free(s); s = NULL; if (size < 2) { wrong = -2; break; } s = malloc_bounded(size); s[size-1] = '\r'; if ((err=wrap_gethostname(s, size-1)) == -1) wrong = 1; else if (s[size-1] != '\r') wrong = 2; else if (err != (err_expected = ERANGE)) wrong = 3; break; case 5: fun = sreturnf("iconv(&<\"abcd\">, &<4>, &s, &<3>)"); s = malloc_bounded((size = 4)); s[size-1] = '\r'; cd = iconv_open("", ""); err = wrap_iconv( cd, (char **)(char *[]){"abcd"}, (size_t *)(size_t []){size}, (char **)(char *[]){s}, (size_t *)(size_t []){size-1} ); iconv_close(cd); if (err == -1) wrong = 1; else if (s[size-1] != '\r') wrong = 2; else if (err != (err_expected = E2BIG)) wrong = 3; break; case 6: fun = sreturnf("mbstowcs(ws, \"abc\", 3)"); size = 4; ws = malloc_bounded(size * sizeof(wchar_t)); ws[size-1] = L'\r'; if ((err=wrap_mbstowcs(ws, "abcd", size-1)) == -1) wrong = 1; else if (ws[size-1] != L'\r') wrong = 2; else if (err != (err_expected = E2BIG)) wrong = 3; break; case 7: fun = sreturnf("snprintf(s, 3, \"abc\")"); s = malloc_bounded((size = 4)); s[size-1] = '\r'; if ((err=wrap_snprintf(s, size-1, "abc")) == -1) wrong = 1; else if (s[size-1] != '\r') wrong = 2; break; case 8: fun=sreturnf("readlink(\"%s.sym\", s, sizeof(s)-1)", filename); tmp = sreturnf("%s.sym", filename); if (stream == NULL) break; else if (symlink(filename, tmp)) { wrong = 4; break; } s = malloc(PATH_MAX); size = readlink(tmp, s, PATH_MAX); free(s); s = NULL; if (size < 2) { wrong = -2; break; } s = malloc_bounded(size); s[size-1] = '\r'; if ((err=wrap_readlink(tmp, s, size-1)) == -1) wrong = 1; else if (s[size-1] != '\r') wrong = 2; break; case 9: fun = sreturnf("strerror_r(1, s, sizeof(s)-1)"); s = malloc(80); strerror_r(1, s, 80); size = strlen(s); free(s); s = NULL; if (size < 2) { wrong = -2; break; } s = malloc_bounded(size); s[size-1] = '\r'; if ((err = wrap_strerror_r(1, s, size-1)) == -1) wrong = 1; else if (s[size-1] != '\r') wrong = 2; else if (err != (err_expected = ERANGE)) wrong = 3; break; case 10: fun = sreturnf("strfmon(s, sizeof(s)-1, \"%%!i\", 123.0)"); s = malloc(80); size = strfmon(s, 80, "%!i", 123.0) + 1; free(s); s = NULL; if (size < 2) { wrong = -2; break; } s = malloc_bounded(size); s[size-1] = '\r'; if ((err=wrap_strfmon(s, size-1, "%!i", 123.0)) == -1) wrong = 1; else if (s[size-1] != '\r') wrong = 2; else if (err != (err_expected = E2BIG)) wrong = 3; break; case 11: fun = sreturnf("strftime(s, sizeof(s)-1, \"%Y\", tm)"); s = malloc(80); tm = *gmtime((time_t []){time(NULL)}); strftime(s, 80, "%Y", &tm); size = strlen(s) + 1; free(s); s = NULL; if (size < 2) { wrong = -2; break; } s = malloc_bounded(size); s[size-1] = '\r'; if ((err=wrap_strftime(s, size-1, "%Y", &tm)) == -1) wrong = 1; else if (s[size-1] != '\r') wrong = 2; break; case 12: fun = sreturnf("ttyname_r(STDERR_FILENO, s, sizeof(s)-1)"); s = malloc(TTY_NAME_MAX); err = ttyname_r(STDERR_FILENO, s, TTY_NAME_MAX); size = strlen(s) + 1; free(s); s = NULL; if (size < 2) { wrong = -2; break; } s = malloc_bounded(size); s[size-1] = '\r'; if ((err = wrap_ttyname_r(STDERR_FILENO, s, size-1)) == -1) wrong = 1; else if (s[size-1] != '\r') wrong = 2; else if (err != (err_expected = ERANGE)) wrong = 3; break; case 13: fun = sreturnf("wcstombs(s, L\"abc\" 3)"); s = malloc_bounded((size = 4)); s[size-1] = '\r'; if ((err=wrap_wcstombs(s, L"abcd", size-1)) == -1) wrong = 1; else if (s[size-1] != '\r') wrong = 2; break; default: function = 0; //exit while break; } if(((sig=free_bounded(ws)) || (sig=free_bounded(s))) && !wrong) wrong = 6; if (wrong) { ++failed; if (wrong == -2) fprintf( stderr, "%s could not be tested, because a preceeding call to the" " same function returned length (of s) lesser than 2\n", fun ); else if (wrong == -1) fprintf(stderr, "%s is unable to run, opening \"%s\" failed\n", fun, filename); else if (wrong == 1) fprintf(stderr, "%s caused a SIGSEGV!\n", fun); else if (wrong == 2) fprintf(stderr, "%s wrote too many bytes to the buffer\n",fun); else if (wrong == 3) { free(tmp); fprintf(stderr, "%s failed to set errno=%s", fun, (tmp = e_name(err_expected))); free(tmp); fprintf(stderr, " (it is %s)\n", (tmp = e_name(err))); } else if (wrong == 4) fprintf(stderr, "%s was not called," " symlink(\"%s\", \"%s.sym\") failed\n", fun, filename, filename); else if (wrong == 5) { free(tmp); fprintf(stderr, "%s set errno = %s\n", fun, (tmp=e_name(err))); } else if (wrong == 6) fprintf( stderr, "%s caused a signal %d to be received. A pointer passed to" " the function might be errorneously redirected\n", fun, sig ); } free(fun); free(tmp); if (stream != NULL && seq_has(function, ffun)) fclose(stream); } while(function++); return failed; } ///A bridge function for sigaction(), jumps via longjmp() back to a setjmp() void bridge_sig_jmp(int sig) { longjmp(env, sig); return; } /** ** A quasi-implementation of malloc(), which allocates 2 additional words, one ** before the memory segment of the requested size, one after. It protects ** those words against reading/writing, so accessing them raises a SIGSEGV. ** \param size length of the memory segment to be allocated for reading/writing ** \returns a pointer to the allocated memory, NULL on failure ** \warning Needs to be freed by free_bounded(), not the regular free() **/ static void* malloc_bounded(size_t size) { int fd = open("/dev/zero", O_RDWR); size_t *stp = NULL; if (fd != -1) { size += 2 * sizeof(size_t); //+boundry words stp = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); if (stp != MAP_FAILED) { *stp = size; //write metadata to the first word //seal both ends: mprotect(stp, sizeof(size_t), PROT_NONE); mprotect((((char*)stp)+size)-sizeof(size_t), sizeof(size_t), PROT_NONE); ++stp; } else stp = NULL; close(fd); } return (void *)stp; } /** ** A quasi-implementation of free, which uses the metadata hidden in boundry ** words (allocated by malloc_bounded()) to unmap space. ** \param vp the pointer returned by malloc_bounded() ** \returns a caught signal on failure **/ static int free_bounded(void* vp) { size_t *stp = ((size_t *)vp)-1; int sig = 0; if(vp != NULL) { sigaction(SIGABRT, &act, &oldact[0]); sigaction(SIGSEGV, &act, &oldact[0]); if(!(sig = setjmp(env))) { mprotect(stp, sizeof(size_t), PROT_READ); munmap(stp, *stp); } sigaction(SIGSEGV, &oldact[0], NULL); sigaction(SIGABRT, &oldact[0], NULL); } return sig; } ///< Wrappers start here: They take the same~ arguments as the functions that ///< they call, but catch SIGSEGVs, and return error codes on failure static int wrap_confstr(int name, char *buf, size_t len) { int err = 0; sigaction(SIGSEGV, &act, &oldact[0]); if(!setjmp(env)) { if (confstr(name, buf, len) == 0) err = errno; }else err = -1; sigaction(SIGSEGV, &oldact[0], NULL); return err; } static int wrap_getcwd(char *buf, size_t size) { int err = 0; sigaction(SIGSEGV, &act, &oldact[0]); if(!setjmp(env)) { if (getcwd(buf, size) == NULL) err = errno; }else err = -1; sigaction(SIGSEGV, &oldact[0], NULL); return err; } static int wrap_getdelim(char **lineptr, size_t *n, int delimiter, FILE *stream) { int err = 0; sigaction(SIGSEGV, &act, &oldact[0]); if(!setjmp(env)) { if (getdelim(lineptr, n, delimiter, stream) == -1) err = errno; }else err = -1; sigaction(SIGSEGV, &oldact[0], NULL); return err; } static int wrap_gethostname(char *name, size_t namelen) { int err = 0; sigaction(SIGSEGV, &act, &oldact[0]); if(!setjmp(env)) { if (gethostname(name, namelen) == -1) err = errno; }else err = -1; sigaction(SIGSEGV, &oldact[0], NULL); return err; } static int wrap_iconv(iconv_t cd, char **inbuf, size_t *inbytesleft, char **outbuf, size_t *outbytesleft) { int err = 0; sigaction(SIGSEGV, &act, &oldact[0]); if(!setjmp(env)) { if (iconv(cd, inbuf, inbytesleft, outbuf, outbytesleft)==(size_t)-1) err = errno; }else err = -1; sigaction(SIGSEGV, &oldact[0], NULL); return err; } static int wrap_mbstowcs(wchar_t *pwcs, char *s, size_t n) { int err = 0; sigaction(SIGSEGV, &act, &oldact[0]); if(!setjmp(env)) { if (mbstowcs(pwcs, s, n) == (size_t)-1) err = errno; }else err = -1; sigaction(SIGSEGV, &oldact[0], NULL); return err; } static int wrap_snprintf(char *s, size_t n, char *format/*, ...*/) { int err = 0; sigaction(SIGSEGV, &act, &oldact[0]); if(!setjmp(env)) { if (snprintf(s, n, format) < 0) err = errno; }else err = -1; sigaction(SIGSEGV, &oldact[0], NULL); return err; } static int wrap_readlink(char *path, char *buf, size_t bufsize) { int err = 0; sigaction(SIGSEGV, &act, &oldact[0]); if(!setjmp(env)) { if (readlink(path, buf, bufsize) == -1) err = errno; }else err = -1; sigaction(SIGSEGV, &oldact[0], NULL); return err; } static int wrap_strfmon(char *s, size_t maxsize, char *format/*, ...*/, float F) { int err = 0; sigaction(SIGSEGV, &act, &oldact[0]); if(!setjmp(env)) { if (strfmon(s, maxsize, format, F) == -1) err = errno; }else err = -1; sigaction(SIGSEGV, &oldact[0], NULL); return err; } static int wrap_strftime(char *s,size_t maxsize,char *format,struct tm *timeptr) { int err = 0; sigaction(SIGSEGV, &act, &oldact[0]); if(!setjmp(env)) { if (strftime(s, maxsize, format, timeptr) == 0) err = errno; }else err = -1; sigaction(SIGSEGV, &oldact[0], NULL); return err; } static int wrap_wcstombs(char *s, wchar_t *pwcs, size_t n) { int err = 0; sigaction(SIGSEGV, &act, &oldact[0]); if(!setjmp(env)) { if (wcstombs(s, pwcs, n) == (size_t)-1) err = errno; }else err = -1; sigaction(SIGSEGV, &oldact[0], NULL); return err; } static int wrap_strerror_r(int errnum, char *strerrbuf, size_t buflen) { int err = 0; sigaction(SIGSEGV, &act, &oldact[0]); if(!setjmp(env)) err = strerror_r(errnum, strerrbuf, buflen); else err = -1; sigaction(SIGSEGV, &oldact[0], NULL); return err; } static int wrap_ttyname_r(int fildes, char *name, size_t namesize) { int err = 0; sigaction(SIGSEGV, &act, &oldact[0]); if(!setjmp(env)) err = ttyname_r(fildes, name, namesize); else err = -1; sigaction(SIGSEGV, &oldact[0], NULL); return err; } --------------030903090303090100050203--