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/>
next in thread | raw e-mail | index | archive | help
https://bugs.freebsd.org/bugzilla/show_bug.cgi?id=3D206770 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 centr= al point is __vfprintf and what it does/calls for such "string output" routine= s. 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 involve= d. To start the description I note the actual, low-level failure point: #0 0x419a89c8 in memcpy (dst0=3D0xffffd734, src0=3D<optimized out>, length=3D<optimized out>) at /usr/src/lib/libc/string/bcopy.c:124 124 TLOOP1(*--dst =3D *--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 =3D FAKE_FILE; . . . va_start(ap, fmt); f._flags =3D __SWR | __SSTR; f._bf._base =3D f._p =3D (unsigned char *)str; f._bf._size =3D f._w =3D n; ret =3D __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 =3D iop->iov; iop->uio.uio_resid =3D 0; iop->uio.uio_iovcnt =3D 0; iop->fp =3D 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 t= o. 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_ba= se (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.*=3D" /usr/src/lib/libc/stdio/* /usr/src/lib/libc/stdio/fputs.c: iov.iov_base =3D (void *)s; /usr/src/lib/libc/stdio/fputws.c: iov.iov_base =3D buf; /usr/src/lib/libc/stdio/fwrite.c: iov.iov_base =3D (void *)buf; /usr/src/lib/libc/stdio/perror.c: v->iov_base =3D (char *)s; /usr/src/lib/libc/stdio/perror.c: v->iov_base =3D ": "; /usr/src/lib/libc/stdio/perror.c: v->iov_base =3D msgbuf; /usr/src/lib/libc/stdio/perror.c: v->iov_base =3D "\n"; /usr/src/lib/libc/stdio/printfcommon.h: iop->iov[iop->uio.uio_iovcnt].iov_b= ase =3D (char *)ptr; /usr/src/lib/libc/stdio/puts.c: iov[0].iov_base =3D (void *)s; /usr/src/lib/libc/stdio/puts.c: iov[1].iov_base =3D "\n"; /usr/src/lib/libc/stdio/putw.c: iov.iov_base =3D &w; /usr/src/lib/libc/stdio/vfwprintf.c: iov.iov_base =3D buf; /usr/src/lib/libc/stdio/xprintf.c: io->iovp->iov_base =3D __DECONST(vo= id *, 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 fil= e 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 assign= ment 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 =3D (char *)ptr; iop->iov[iop->uio.uio_iovcnt].iov_len =3D len; iop->uio.uio_resid +=3D len; . . . In other words: The segmentation violation is for dereferencing of __vfprin= tf'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 =3D __sfvwrite(fp, uio); and __sfvwrite(FILE *fp, struct __suio *uio) does: p =3D iov->iov_base; len =3D iov->iov_len; where iov->iov_base is another name for __vfprintf's io.uio.uio_iov->iov_b= ase . __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 ).=20 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. --=20 You are receiving this mail because: You are the assignee for the bug.=
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?bug-206770-8>
