From: Tim Cadogan-Cowper Date: Sun, 18 Jul 2010 19:39:06 +1000 Subject: mmio: Ensure FOURCC string conversions are always null-terminated. Three TRACE debug calls in the mmioDescend function of mmio.c attempt to print FOURCC data, by directly casting it to LPCSTR. This is dangerous as: (i) FOURCC data types are DWORDs, i.e. four bytes (one for each char), with no null terminating byte (see http://msdn.microsoft.com/en-us/library/dd375802%28VS.85%29.aspx); and (ii) it assumes the byte order on the host architecture is little endian. Because the LPCSTR casts are not necessarily null-terminated there will occasionally be buffer overflows in mmio's TRACE debug strings, with a consequent crash to desktop and debug output beginning with 'wine_dbg_vprintf: debugstr buffer overflow...' For a consistent and predictable case where this occurs, see Bug 10280 "Oblivion: Horse Armour Crash" (http://bugs.winehq.org/show_bug.cgi?id=10280). This patch fixes the problem (and any crashes caused by it) by using a new internal function in mmio - mmioFOURCCToString - which converts FOURCC data to strings that are correctly null-terminated and respect byte order. I have tested with Oblivion and can confirm it fixes Bug 10280 on my machine (ubuntu 10.04). Furthermore the patch will ensure that chunk IDs and fourccTypes are correctly printed in the mmio debug channel (at the moment they are not). --- dlls/winmm/mmio.c | 46 ++++++++++++++++++++++++++++++++++++++-------- 1 files changed, 38 insertions(+), 8 deletions(-) diff --git a/dlls/winmm/mmio.c b/dlls/winmm/mmio.c index a6e06b5..0c87058 100644 --- a/dlls/winmm/mmio.c +++ b/dlls/winmm/mmio.c @@ -48,6 +48,26 @@ WINE_DEFAULT_DEBUG_CHANNEL(mmio); static WINE_MMIO *MMIOList; /************************************************************************** + * mmioFOURCCToString [internal] + */ +static void mmioFOURCCToString(FOURCC fcc, char* s) +{ +/* Caller must ensure that s has at least 5 bytes */ +#ifdef WORDS_BIGENDIAN + s[0]=(fcc >> 24) & 0xFF; + s[1]=(fcc >> 16) & 0xFF; + s[2]=(fcc >> 8) & 0xFF; + s[3]=(fcc ) & 0xFF; +#else + s[0]=(fcc ) & 0xFF; + s[1]=(fcc >> 8) & 0xFF; + s[2]=(fcc >> 16) & 0xFF; + s[3]=(fcc >> 24) & 0xFF; +#endif + s[4]=0; +} + +/************************************************************************** * mmioDosIOProc [internal] */ static LRESULT CALLBACK mmioDosIOProc(LPMMIOINFO lpmmioinfo, UINT uMessage, @@ -1130,6 +1150,8 @@ MMRESULT WINAPI mmioDescend(HMMIO hmmio, LPMMCKINFO lpck, DWORD dwOldPos; FOURCC srchCkId; FOURCC srchType; + char szCkId[5]; + char szFCCType[5]; TRACE("(%p, %p, %p, %04X);\n", hmmio, lpck, lpckParent, uFlags); @@ -1173,8 +1195,10 @@ MMRESULT WINAPI mmioDescend(HMMIO hmmio, LPMMCKINFO lpck, srchType = lpck->fccType; } - TRACE("searching for %4.4s.%4.4s\n", - (LPCSTR)&srchCkId, srchType ? (LPCSTR)&srchType : "any"); + mmioFOURCCToString((DWORD)srchCkId, szCkId); + mmioFOURCCToString((DWORD)srchType, szFCCType); + TRACE("searching for chkID=%08X('%s'), fccType=%08X('%s')\n", + (DWORD)srchCkId, szCkId, (DWORD)srchType, szFCCType); while (TRUE) { @@ -1189,10 +1213,12 @@ MMRESULT WINAPI mmioDescend(HMMIO hmmio, LPMMCKINFO lpck, } lpck->dwDataOffset = dwOldPos + 2 * sizeof(DWORD); - TRACE("ckid=%4.4s fcc=%4.4s cksize=%08X !\n", - (LPCSTR)&lpck->ckid, - srchType ? (LPCSTR)&lpck->fccType:"", + mmioFOURCCToString((DWORD)lpck->ckid, szCkId); + mmioFOURCCToString((DWORD)lpck->fccType, szFCCType); + TRACE("ckid=%08X('%s') fcc=%08X('%s') cksize=%u\n", + (DWORD)lpck->ckid, szCkId, (DWORD)lpck->fccType, szFCCType, lpck->cksize); + if ( (!srchCkId || (srchCkId == lpck->ckid)) && (!srchType || (srchType == lpck->fccType)) ) break; @@ -1213,9 +1239,13 @@ MMRESULT WINAPI mmioDescend(HMMIO hmmio, LPMMCKINFO lpck, mmioSeek(hmmio, lpck->dwDataOffset, SEEK_SET); lpck->fccType = 0; } - TRACE("lpck: ckid=%.4s, cksize=%d, dwDataOffset=%d fccType=%08X (%.4s)!\n", - (LPSTR)&lpck->ckid, lpck->cksize, lpck->dwDataOffset, - lpck->fccType, srchType?(LPSTR)&lpck->fccType:""); + + mmioFOURCCToString((DWORD)lpck->ckid, szCkId); + mmioFOURCCToString((DWORD)lpck->fccType, szFCCType); + TRACE("lpck: ckid=%08X('%s'), cksize=%u, dwDataOffset=%u fccType=%08X('%s')\n", + (DWORD)lpck->ckid, szCkId, lpck->cksize, lpck->dwDataOffset, + (DWORD)lpck->fccType, szFCCType); + return MMSYSERR_NOERROR; } -- 1.7.0.4