Date: Sun, 31 Jan 2016 01:50:55 +0000 From: bugzilla-noreply@freebsd.org To: freebsd-bugs@FreeBSD.org Subject: [Bug 206770] 11.0-CURRENT/clang380-import: libc/stdio uninitialized pointer use (exposed via powerpc 32-bit context) Message-ID: <bug-206770-8@https.bugs.freebsd.org/bugzilla/>
index | next in thread | raw e-mail
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=206770 Bug ID: 206770 Summary: 11.0-CURRENT/clang380-import: libc/stdio uninitialized pointer use (exposed via powerpc 32-bit context) Product: Base System Version: 11.0-CURRENT Hardware: Any OS: Any Status: New Severity: Affects Only Me Priority: --- Component: bin Assignee: freebsd-bugs@FreeBSD.org Reporter: markmi@dsl-only.net Using projects/clang380-import (-r294962 currently) I've been experimenting with a clang based powerpc (32-bit) buildworld (mixed with a gcc421 based buildkernel). Things boot and much operates but I ran into signals getting segmentation violations during signal handlers. It turn out the ones that I've looked at so far are using routines similar to snprinf in the signal handlers and I've found that the call chains involved have an uninitialized pointer in use. The following uses snprintf as a starting context but the more common central point is __vfprintf and what it does/calls for such "string output" routines. Unfortunately the reason is spread out in the code so it takes a bit to describe the context for the uninitialized pointer that I expect is involved. To start the description I note the actual, low-level failure point: #0 0x419a89c8 in memcpy (dst0=0xffffd734, src0=<optimized out>, length=<optimized out>) at /usr/src/lib/libc/string/bcopy.c:124 124 TLOOP1(*--dst = *--src); In the assembler code for this is the the *--src access that gets the segmentation violation. I do not justify that claim here but use that fact later. So what leads up to that? Going the other way, starting from the use of snprintf. . . snprintf(char * __restrict str, size_t n, char const * __restrict fmt, ...) sets up its __vfprintf(FILE *fp, locale_t locale, const char *fmt0, va_list ap) use via: va_list ap; FILE f = FAKE_FILE; . . . va_start(ap, fmt); f._flags = __SWR | __SSTR; f._bf._base = f._p = (unsigned char *)str; f._bf._size = f._w = n; ret = __vfprintf(&f, __get_locale(), fmt, ap); so at the __vfprintf call f._p reference the buffer that __vfprintf's str references. __vfprintf in turn does (in part): struct io_state io; /* I/O buffering state */ . . . io_init(&io, fp); where io is on-stack (not implicitly initialized). The io_init does: #define NIOV 8 struct io_state { FILE *fp; struct __suio uio; /* output information: summary */ struct __siov iov[NIOV];/* ... and individual io vectors */ }; static inline void io_init(struct io_state *iop, FILE *fp) { iop->uio.uio_iov = iop->iov; iop->uio.uio_resid = 0; iop->uio.uio_iovcnt = 0; iop->fp = fp; } where (on stack as part of __vfprintf's io): struct __siov { void *iov_base; size_t iov_len; }; struct __suio { struct __siov *uio_iov; int uio_iovcnt; int uio_resid; }; So via __vfprintf's io.fp->_p the str buffer is accessible for outputting to. But in none of this or other code that I've looked at for this snprintf use case have I found code that initializes the involved io.uio.uio_iov->iov_base (i.e., io.iov[0].iov_base) to point to anything specific. (Nor is iov_base's matching iov_len initialized.) Here is a stab at finding all the initializations of iov_base fields: # grep "iov_base.*=" /usr/src/lib/libc/stdio/* /usr/src/lib/libc/stdio/fputs.c: iov.iov_base = (void *)s; /usr/src/lib/libc/stdio/fputws.c: iov.iov_base = buf; /usr/src/lib/libc/stdio/fwrite.c: iov.iov_base = (void *)buf; /usr/src/lib/libc/stdio/perror.c: v->iov_base = (char *)s; /usr/src/lib/libc/stdio/perror.c: v->iov_base = ": "; /usr/src/lib/libc/stdio/perror.c: v->iov_base = msgbuf; /usr/src/lib/libc/stdio/perror.c: v->iov_base = "\n"; /usr/src/lib/libc/stdio/printfcommon.h: iop->iov[iop->uio.uio_iovcnt].iov_base = (char *)ptr; /usr/src/lib/libc/stdio/puts.c: iov[0].iov_base = (void *)s; /usr/src/lib/libc/stdio/puts.c: iov[1].iov_base = "\n"; /usr/src/lib/libc/stdio/putw.c: iov.iov_base = &w; /usr/src/lib/libc/stdio/vfwprintf.c: iov.iov_base = buf; /usr/src/lib/libc/stdio/xprintf.c: io->iovp->iov_base = __DECONST(void *, ptr); The only file above involved in common for this context turns out to be: /usr/src/lib/libc/stdio/printfcommon.h and the above assignment in that file is in io_print(struct io_state *iop, const CHAR * __restrict ptr, int len, locale_t locale), which is not in use for this context. Here is that assignment anyway (just for reference): static inline int io_print(struct io_state *iop, const CHAR * __restrict ptr, int len, locale_t locale) { iop->iov[iop->uio.uio_iovcnt].iov_base = (char *)ptr; iop->iov[iop->uio.uio_iovcnt].iov_len = len; iop->uio.uio_resid += len; . . . In other words: The segmentation violation is for dereferencing of __vfprintf's uninitialized io.uio.uio_iov->iov_base . Returning to tracing the actually used code for this context to support that claim some more. . . The __vfprintf (FILE *fp, locale_t locale, const char *fmt0, va_list ap) eventually does: if (io_flush(&io, locale)) and io_flush(struct io_state *iop, locale_t locale) does: return (__sprint(iop->fp, &iop->uio, locale)); and _sprintf(FILE *fp, struct __suio *uio, locale_t locale) does: err = __sfvwrite(fp, uio); and __sfvwrite(FILE *fp, struct __suio *uio) does: p = iov->iov_base; len = iov->iov_len; where iov->iov_base is another name for __vfprintf's io.uio.uio_iov->iov_base . __sfvwrite then uses: #define COPY(n) (void)memcpy((void *)fp->_p, (void *)p, (size_t)(n)) which fails dereferencing p (i.e., dereferencing __vfprintf's io.uio.uio_iov->iov_base ). In other words (again): The segmentation violation is for dereferencing of the uninitialized __vfprintf io.uio.uio_iov->iov_base unless I've missed some initialization some place in the executing code for these sorts of "string output" contexts. -- You are receiving this mail because: You are the assignee for the bug.help
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?bug-206770-8>
