On Sun, 26 Nov 2017 19:56:03 +0000, kshe wrote: > Hi, > > Shortly after recallocarray(3) was introduced, it was put into use for > several objects internal to the stdio library "to avoid leaving detritus > in memory when resizing buffers". However, in the end, this memory is > still released by plain free(3) calls. > > The same reason that motivated the change to recallocarray(3) should > also entail that to freezero(3), where applicable. Currently, a > suitable overflow from a malloc(3)ed buffer could allow an attacker to > retrieve lines previously read by fgetln(3), as well as data previously > written using the fprintf(3) family of functions, even long after the > corresponding streams have been closed and even if the programmer was > very careful explicitly to discard all the manually allocated objects > that could have contained sensitive data. The diff below makes such > attacks much less likely to succeed, so that one can read and write > secrets to files with stdio functions more safely, id est without the > undesirable side effect of leaving parts of those secrets in heap memory > afterwards.
The diff previously attached was one of my early drafts where I only marked the relevant calls. Please ignore it. Here is the real patch I intended to send. Index: asprintf.c =================================================================== RCS file: /cvs/src/lib/libc/stdio/asprintf.c,v retrieving revision 1.25 diff -u -p -r1.25 asprintf.c --- asprintf.c 17 Mar 2017 14:53:08 -0000 1.25 +++ asprintf.c 26 Oct 2017 23:30:57 -0000 @@ -61,7 +61,7 @@ asprintf(char **str, const char *fmt, .. return (ret); err: - free(f._bf._base); + freezero(f._bf._base, f._bf._size); f._bf._base = NULL; *str = NULL; errno = ENOMEM; Index: fclose.c =================================================================== RCS file: /cvs/src/lib/libc/stdio/fclose.c,v retrieving revision 1.10 diff -u -p -r1.10 fclose.c --- fclose.c 31 Aug 2015 02:53:57 -0000 1.10 +++ fclose.c 26 Oct 2017 23:30:57 -0000 @@ -51,7 +51,7 @@ fclose(FILE *fp) if (fp->_close != NULL && (*fp->_close)(fp->_cookie) < 0) r = EOF; if (fp->_flags & __SMBF) - free((char *)fp->_bf._base); + freezero(fp->_bf._base, fp->_bf._size); if (HASUB(fp)) FREEUB(fp); if (HASLB(fp)) Index: fmemopen.c =================================================================== RCS file: /cvs/src/lib/libc/stdio/fmemopen.c,v retrieving revision 1.3 diff -u -p -r1.3 fmemopen.c --- fmemopen.c 31 Aug 2015 02:53:57 -0000 1.3 +++ fmemopen.c 26 Oct 2017 23:30:57 -0000 @@ -107,7 +107,7 @@ fmemopen_close_free(void *v) { struct state *st = v; - free(st->string); + freezero(st->string, st->size); free(st); return (0); Index: freopen.c =================================================================== RCS file: /cvs/src/lib/libc/stdio/freopen.c,v retrieving revision 1.16 diff -u -p -r1.16 freopen.c --- freopen.c 21 Sep 2016 04:38:56 -0000 1.16 +++ freopen.c 26 Oct 2017 23:30:57 -0000 @@ -106,7 +106,7 @@ freopen(const char *file, const char *mo if (isopen && f != wantfd) (void) (*fp->_close)(fp->_cookie); if (fp->_flags & __SMBF) - free((char *)fp->_bf._base); + freezero(fp->_bf._base, fp->_bf._size); fp->_w = 0; fp->_r = 0; fp->_p = NULL; Index: local.h =================================================================== RCS file: /cvs/src/lib/libc/stdio/local.h,v retrieving revision 1.25 diff -u -p -r1.25 local.h --- local.h 23 May 2016 00:21:48 -0000 1.25 +++ local.h 26 Oct 2017 23:30:57 -0000 @@ -82,7 +82,7 @@ __END_HIDDEN_DECLS #define HASUB(fp) (_UB(fp)._base != NULL) #define FREEUB(fp) { \ if (_UB(fp)._base != (fp)->_ubuf) \ - free(_UB(fp)._base); \ + freezero(_UB(fp)._base, _UB(fp)._size); \ _UB(fp)._base = NULL; \ } @@ -91,7 +91,7 @@ __END_HIDDEN_DECLS */ #define HASLB(fp) ((fp)->_lb._base != NULL) #define FREELB(fp) { \ - free((char *)(fp)->_lb._base); \ + freezero((fp)->_lb._base, (fp)->_lb._size); \ (fp)->_lb._base = NULL; \ } Index: setvbuf.c =================================================================== RCS file: /cvs/src/lib/libc/stdio/setvbuf.c,v retrieving revision 1.14 diff -u -p -r1.14 setvbuf.c --- setvbuf.c 21 Sep 2016 04:38:56 -0000 1.14 +++ setvbuf.c 26 Oct 2017 23:30:57 -0000 @@ -70,7 +70,7 @@ setvbuf(FILE *fp, char *buf, int mode, s fp->_r = fp->_lbfsize = 0; flags = fp->_flags; if (flags & __SMBF) - free(fp->_bf._base); + freezero(fp->_bf._base, fp->_bf._size); flags &= ~(__SLBF | __SNBF | __SMBF | __SOPT | __SNPT | __SEOF); /* If setting unbuffered mode, skip all the hard work. */ Index: vasprintf.c =================================================================== RCS file: /cvs/src/lib/libc/stdio/vasprintf.c,v retrieving revision 1.22 diff -u -p -r1.22 vasprintf.c --- vasprintf.c 17 Mar 2017 14:53:08 -0000 1.22 +++ vasprintf.c 26 Oct 2017 23:30:57 -0000 @@ -57,7 +57,7 @@ vasprintf(char **str, const char *fmt, _ return (ret); err: - free(f._bf._base); + freezero(f._bf._base, f._bf._size); f._bf._base = NULL; *str = NULL; errno = ENOMEM; Index: vfprintf.c =================================================================== RCS file: /cvs/src/lib/libc/stdio/vfprintf.c,v retrieving revision 1.77 diff -u -p -r1.77 vfprintf.c --- vfprintf.c 29 Aug 2016 12:20:57 -0000 1.77 +++ vfprintf.c 26 Oct 2017 23:30:57 -0000 @@ -159,7 +159,7 @@ __wcsconv(wchar_t *wcsarg, int prec) char buf[MB_LEN_MAX]; wchar_t *p; char *convbuf; - size_t clen, nbytes; + size_t clen, nbytes, end; /* Allocate space for the maximum number of bytes we could output. */ if (prec < 0) { @@ -197,12 +197,12 @@ __wcsconv(wchar_t *wcsarg, int prec) /* Fill the output buffer. */ p = wcsarg; memset(&mbs, 0, sizeof(mbs)); - if ((nbytes = wcsrtombs(convbuf, (const wchar_t **)&p, + if ((end = wcsrtombs(convbuf, (const wchar_t **)&p, nbytes, &mbs)) == (size_t)-1) { - free(convbuf); + freezero(convbuf, nbytes); return (NULL); } - convbuf[nbytes] = '\0'; + convbuf[end] = '\0'; return (convbuf); } #endif @@ -857,8 +857,10 @@ fp_common: if (flags & LONGINT) { wchar_t *wcp; - free(convbuf); - convbuf = NULL; + if (convbuf != NULL) { + freezero(convbuf, strlen(convbuf)); + convbuf = NULL; + } if ((wcp = GETARG(wchar_t *)) == NULL) { struct syslog_data sdata = SYSLOG_DATA_INIT; int save_errno = errno; @@ -1087,7 +1089,8 @@ overflow: finish: #ifdef PRINTF_WIDE_CHAR - free(convbuf); + if (convbuf != NULL) + freezero(convbuf, strlen(convbuf)); #endif #ifdef FLOATING_POINT if (dtoaresult) Index: vfwprintf.c =================================================================== RCS file: /cvs/src/lib/libc/stdio/vfwprintf.c,v retrieving revision 1.18 diff -u -p -r1.18 vfwprintf.c --- vfwprintf.c 15 Aug 2017 00:20:39 -0000 1.18 +++ vfwprintf.c 26 Oct 2017 23:30:57 -0000 @@ -169,7 +169,7 @@ __mbsconv(char *mbsarg, int prec) mbstate_t mbs; wchar_t *convbuf, *wcp; const char *p; - size_t insize, nchars, nconv; + size_t insize, osize, nchars, nconv; if (mbsarg == NULL) return (NULL); @@ -208,6 +208,7 @@ __mbsconv(char *mbsarg, int prec) convbuf = calloc(insize + 1, sizeof(*convbuf)); if (convbuf == NULL) return (NULL); + osize = insize; wcp = convbuf; p = mbsarg; bzero(&mbs, sizeof(mbs)); @@ -221,7 +222,7 @@ __mbsconv(char *mbsarg, int prec) insize -= nconv; } if (nconv == (size_t)-1 || nconv == (size_t)-2) { - free(convbuf); + freezero(convbuf, osize * sizeof(*convbuf)); return (NULL); } *wcp = '\0'; @@ -668,7 +669,8 @@ reswitch: switch (ch) { prec = dtoaend - dtoaresult; if (expt == INT_MAX) ox[1] = '\0'; - free(convbuf); + if (convbuf != NULL) + freezero(convbuf, strlen(convbuf)); cp = convbuf = __mbsconv(dtoaresult, -1); if (cp == NULL) goto error; @@ -717,7 +719,8 @@ fp_begin: if (expt == 9999) expt = INT_MAX; } - free(convbuf); + if (convbuf != NULL) + freezero(convbuf, strlen(convbuf)); cp = convbuf = __mbsconv(dtoaresult, -1); if (cp == NULL) goto error; @@ -839,7 +842,8 @@ fp_common: mbsarg = "(null)"; } - free(convbuf); + if (convbuf != NULL) + freezero(convbuf, strlen(convbuf)); convbuf = __mbsconv(mbsarg, prec); if (convbuf == NULL) { fp->_flags |= __SERR; @@ -1055,7 +1059,8 @@ overflow: ret = -1; finish: - free(convbuf); + if (convbuf != NULL) + freezero(convbuf, strlen(convbuf)); #ifdef FLOATING_POINT if (dtoaresult) __freedtoa(dtoaresult); Index: vswprintf.c =================================================================== RCS file: /cvs/src/lib/libc/stdio/vswprintf.c,v retrieving revision 1.6 diff -u -p -r1.6 vswprintf.c --- vswprintf.c 31 Aug 2015 02:53:57 -0000 1.6 +++ vswprintf.c 26 Oct 2017 23:30:57 -0000 @@ -64,13 +64,13 @@ vswprintf(wchar_t * __restrict s, size_t ret = __vfwprintf(&f, fmt, ap); if (ret < 0) { sverrno = errno; - free(f._bf._base); + freezero(f._bf._base, f._bf._size); errno = sverrno; return (-1); } if (ret == 0) { s[0] = L'\0'; - free(f._bf._base); + freezero(f._bf._base, f._bf._size); return (0); } *f._p = '\0'; @@ -81,7 +81,7 @@ vswprintf(wchar_t * __restrict s, size_t */ bzero(&mbs, sizeof(mbs)); nwc = mbsrtowcs(s, (const char **)&mbp, n, &mbs); - free(f._bf._base); + freezero(f._bf._base, f._bf._size); if (nwc == (size_t)-1) { errno = EILSEQ; return (-1); Index: vswscanf.c =================================================================== RCS file: /cvs/src/lib/libc/stdio/vswscanf.c,v retrieving revision 1.3 diff -u -p -r1.3 vswscanf.c --- vswscanf.c 31 Aug 2015 02:53:57 -0000 1.3 +++ vswscanf.c 26 Oct 2017 23:30:57 -0000 @@ -70,7 +70,7 @@ vswscanf(const wchar_t * __restrict str, bzero(&mbs, sizeof(mbs)); strp = str; if ((mlen = wcsrtombs(mbstr, &strp, len, &mbs)) == (size_t)-1) { - free(mbstr); + freezero(mbstr, len); return (EOF); } if (mlen == len) @@ -82,7 +82,7 @@ vswscanf(const wchar_t * __restrict str, f._read = eofread; f._lb._base = NULL; r = __vfwscanf(&f, fmt, ap); - free(mbstr); + freezero(mbstr, len); return (r); } Regards, kshe