Signed-off-by: Nikolay Sivov nsivov@codeweavers.com --- dlls/ole32/stg_prop.c | 194 +++++++++++++++++++++++++++++++----------- 1 file changed, 144 insertions(+), 50 deletions(-)
diff --git a/dlls/ole32/stg_prop.c b/dlls/ole32/stg_prop.c index 54904a581b..00ba5ade29 100644 --- a/dlls/ole32/stg_prop.c +++ b/dlls/ole32/stg_prop.c @@ -1229,19 +1229,80 @@ static void* WINAPI Allocate_CoTaskMemAlloc(void *this, ULONG size) return CoTaskMemAlloc(size); }
-/* FIXME: there isn't any checking whether the read property extends past the - * end of the buffer. - */ -static HRESULT PropertyStorage_ReadProperty(PROPVARIANT *prop, const BYTE *data, - UINT codepage, void* (WINAPI *allocate)(void *this, ULONG size), void *allocate_data) +struct read_buffer { - HRESULT hr = S_OK; + BYTE *data; + size_t size; +}; + +static HRESULT buffer_test_offset(const struct read_buffer *buffer, size_t offset, size_t len) +{ + return len > buffer->size || offset > buffer->size - len ? STG_E_READFAULT : S_OK; +} + +static HRESULT buffer_read_uint64(const struct read_buffer *buffer, size_t offset, ULARGE_INTEGER *data) +{ + HRESULT hr; + + if (SUCCEEDED(hr = buffer_test_offset(buffer, offset, sizeof(*data)))) + StorageUtl_ReadULargeInteger(buffer->data, offset, data); + + return hr; +} + +static HRESULT buffer_read_dword(const struct read_buffer *buffer, size_t offset, DWORD *data) +{ + HRESULT hr; + + if (SUCCEEDED(hr = buffer_test_offset(buffer, offset, sizeof(*data)))) + StorageUtl_ReadDWord(buffer->data, offset, data); + + return hr; +} + +static HRESULT buffer_read_word(const struct read_buffer *buffer, size_t offset, WORD *data) +{ + HRESULT hr; + + if (SUCCEEDED(hr = buffer_test_offset(buffer, offset, sizeof(*data)))) + StorageUtl_ReadWord(buffer->data, offset, data); + + return hr; +} + +static HRESULT buffer_read_byte(const struct read_buffer *buffer, size_t offset, BYTE *data) +{ + HRESULT hr; + + if (SUCCEEDED(hr = buffer_test_offset(buffer, offset, sizeof(*data)))) + *data = *(buffer->data + offset); + + return hr; +} + +static HRESULT buffer_read_len(const struct read_buffer *buffer, size_t offset, void *dest, size_t len) +{ + HRESULT hr; + + if (SUCCEEDED(hr = buffer_test_offset(buffer, offset, len))) + memcpy(dest, buffer->data + offset, len); + + return hr; +} + +static HRESULT PropertyStorage_ReadProperty(PROPVARIANT *prop, const struct read_buffer *buffer, + size_t offset, UINT codepage, void* (WINAPI *allocate)(void *this, ULONG size), void *allocate_data) +{ + HRESULT hr; DWORD vt;
assert(prop); - assert(data); - StorageUtl_ReadDWord(data, 0, &vt); - data += sizeof(DWORD); + assert(buffer->data); + + if (FAILED(hr = buffer_read_dword(buffer, offset, &vt))) + return hr; + + offset += sizeof(DWORD); prop->vt = vt; switch (prop->vt) { @@ -1249,53 +1310,57 @@ static HRESULT PropertyStorage_ReadProperty(PROPVARIANT *prop, const BYTE *data, case VT_NULL: break; case VT_I1: - prop->u.cVal = *(const char *)data; + hr = buffer_read_byte(buffer, offset, (BYTE *)&prop->u.cVal); TRACE("Read char 0x%x ('%c')\n", prop->u.cVal, prop->u.cVal); break; case VT_UI1: - prop->u.bVal = *data; + hr = buffer_read_byte(buffer, offset, &prop->u.bVal); TRACE("Read byte 0x%x\n", prop->u.bVal); break; case VT_BOOL: - StorageUtl_ReadWord(data, 0, (WORD*)&prop->u.boolVal); + hr = buffer_read_word(buffer, offset, (WORD *)&prop->u.boolVal); TRACE("Read bool %d\n", prop->u.boolVal); break; case VT_I2: - StorageUtl_ReadWord(data, 0, (WORD*)&prop->u.iVal); + hr = buffer_read_word(buffer, offset, (WORD *)&prop->u.iVal); TRACE("Read short %d\n", prop->u.iVal); break; case VT_UI2: - StorageUtl_ReadWord(data, 0, &prop->u.uiVal); + hr = buffer_read_word(buffer, offset, &prop->u.uiVal); TRACE("Read ushort %d\n", prop->u.uiVal); break; case VT_INT: case VT_I4: - StorageUtl_ReadDWord(data, 0, (DWORD*)&prop->u.lVal); + hr = buffer_read_dword(buffer, offset, (DWORD *)&prop->u.lVal); TRACE("Read long %d\n", prop->u.lVal); break; case VT_UINT: case VT_UI4: - StorageUtl_ReadDWord(data, 0, &prop->u.ulVal); + hr = buffer_read_dword(buffer, offset, &prop->u.ulVal); TRACE("Read ulong %d\n", prop->u.ulVal); break; case VT_I8: - StorageUtl_ReadULargeInteger(data, 0, (ULARGE_INTEGER *)&prop->u.hVal); + hr = buffer_read_uint64(buffer, offset, (ULARGE_INTEGER *)&prop->u.hVal); TRACE("Read long long %s\n", wine_dbgstr_longlong(prop->u.hVal.QuadPart)); break; case VT_UI8: - StorageUtl_ReadULargeInteger(data, 0, &prop->u.uhVal); + hr = buffer_read_uint64(buffer, offset, &prop->u.uhVal); TRACE("Read ulong long %s\n", wine_dbgstr_longlong(prop->u.uhVal.QuadPart)); break; case VT_R8: - memcpy(&prop->u.dblVal, data, sizeof(double)); + hr = buffer_read_len(buffer, offset, &prop->u.dblVal, sizeof(prop->u.dblVal)); TRACE("Read double %f\n", prop->u.dblVal); break; case VT_LPSTR: { DWORD count; - - StorageUtl_ReadDWord(data, 0, &count); - if (codepage == CP_UNICODE && count % 2) + + if (FAILED(hr = buffer_read_dword(buffer, offset, &count))) + break; + + offset += sizeof(DWORD); + + if (codepage == CP_UNICODE && count % sizeof(WCHAR)) { WARN("Unicode string has odd number of bytes\n"); hr = STG_E_INVALIDHEADER; @@ -1305,7 +1370,9 @@ static HRESULT PropertyStorage_ReadProperty(PROPVARIANT *prop, const BYTE *data, prop->u.pszVal = allocate(allocate_data, count); if (prop->u.pszVal) { - memcpy(prop->u.pszVal, data + sizeof(DWORD), count); + if (FAILED(hr = buffer_read_len(buffer, offset, prop->u.pszVal, count))) + break; + /* This is stored in the code page specified in codepage. * Don't convert it, the caller will just store it as-is. */ @@ -1332,8 +1399,12 @@ static HRESULT PropertyStorage_ReadProperty(PROPVARIANT *prop, const BYTE *data, { DWORD count, wcount;
- StorageUtl_ReadDWord(data, 0, &count); - if (codepage == CP_UNICODE && count % 2) + if (FAILED(hr = buffer_read_dword(buffer, offset, &count))) + break; + + offset += sizeof(DWORD); + + if (codepage == CP_UNICODE && count % sizeof(WCHAR)) { WARN("Unicode string has odd number of bytes\n"); hr = STG_E_INVALIDHEADER; @@ -1341,18 +1412,22 @@ static HRESULT PropertyStorage_ReadProperty(PROPVARIANT *prop, const BYTE *data, else { if (codepage == CP_UNICODE) - wcount = count / 2; + wcount = count / sizeof(WCHAR); else - wcount = MultiByteToWideChar(codepage, 0, (LPCSTR)(data + sizeof(DWORD)), count, NULL, 0); + { + if (FAILED(hr = buffer_test_offset(buffer, offset, count))) + break; + wcount = MultiByteToWideChar(codepage, 0, (LPCSTR)(buffer->data + offset), count, NULL, 0); + }
prop->u.bstrVal = SysAllocStringLen(NULL, wcount); /* FIXME: use allocator? */
if (prop->u.bstrVal) { if (codepage == CP_UNICODE) - memcpy(prop->u.bstrVal, data + sizeof(DWORD), count); + hr = buffer_read_len(buffer, offset, prop->u.bstrVal, count); else - MultiByteToWideChar(codepage, 0, (LPCSTR)(data + sizeof(DWORD)), count, prop->u.bstrVal, wcount); + MultiByteToWideChar(codepage, 0, (LPCSTR)(buffer->data + offset), count, prop->u.bstrVal, wcount);
prop->u.bstrVal[wcount - 1] = '\0'; TRACE("Read string value %s\n", debugstr_w(prop->u.bstrVal)); @@ -1366,12 +1441,16 @@ static HRESULT PropertyStorage_ReadProperty(PROPVARIANT *prop, const BYTE *data, { DWORD count;
- StorageUtl_ReadDWord(data, 0, &count); + if (FAILED(hr = buffer_read_dword(buffer, offset, &count))) + break; + + offset += sizeof(DWORD); + prop->u.blob.cbSize = count; prop->u.blob.pBlobData = allocate(allocate_data, count); if (prop->u.blob.pBlobData) { - memcpy(prop->u.blob.pBlobData, data + sizeof(DWORD), count); + hr = buffer_read_len(buffer, offset, prop->u.blob.pBlobData, count); TRACE("Read blob value of size %d\n", count); } else @@ -1382,31 +1461,40 @@ static HRESULT PropertyStorage_ReadProperty(PROPVARIANT *prop, const BYTE *data, { DWORD count;
- StorageUtl_ReadDWord(data, 0, &count); + if (FAILED(hr = buffer_read_dword(buffer, offset, &count))) + break; + + offset += sizeof(DWORD); + prop->u.pwszVal = allocate(allocate_data, count * sizeof(WCHAR)); if (prop->u.pwszVal) { - memcpy(prop->u.pwszVal, data + sizeof(DWORD), - count * sizeof(WCHAR)); - /* make sure string is NULL-terminated */ - prop->u.pwszVal[count - 1] = '\0'; - PropertyStorage_ByteSwapString(prop->u.pwszVal, count); - TRACE("Read string value %s\n", debugstr_w(prop->u.pwszVal)); + if (SUCCEEDED(hr = buffer_read_len(buffer, offset, prop->u.pwszVal, count * sizeof(WCHAR)))) + { + /* make sure string is NULL-terminated */ + prop->u.pwszVal[count - 1] = '\0'; + PropertyStorage_ByteSwapString(prop->u.pwszVal, count); + TRACE("Read string value %s\n", debugstr_w(prop->u.pwszVal)); + } } else hr = STG_E_INSUFFICIENTMEMORY; break; } case VT_FILETIME: - StorageUtl_ReadULargeInteger(data, 0, - (ULARGE_INTEGER *)&prop->u.filetime); + hr = buffer_read_uint64(buffer, offset, (ULARGE_INTEGER *)&prop->u.filetime); break; case VT_CF: { DWORD len = 0, tag = 0;
- StorageUtl_ReadDWord(data, 0, &len); - StorageUtl_ReadDWord(data, 4, &tag); + if (SUCCEEDED(hr = buffer_read_dword(buffer, offset, &len))) + hr = buffer_read_dword(buffer, offset + sizeof(DWORD), &tag); + if (FAILED(hr)) + break; + + offset += 2 * sizeof(DWORD); + if (len > 8) { len -= 8; @@ -1414,7 +1502,7 @@ static HRESULT PropertyStorage_ReadProperty(PROPVARIANT *prop, const BYTE *data, prop->u.pclipdata->cbSize = len; prop->u.pclipdata->ulClipFmt = tag; prop->u.pclipdata->pClipData = allocate(allocate_data, len - sizeof(prop->u.pclipdata->ulClipFmt)); - memcpy(prop->u.pclipdata->pClipData, data+8, len - sizeof(prop->u.pclipdata->ulClipFmt)); + hr = buffer_read_len(buffer, offset, prop->u.pclipdata->pClipData, len - sizeof(prop->u.pclipdata->ulClipFmt)); } else hr = STG_E_INVALIDPARAMETER; @@ -1522,6 +1610,7 @@ static HRESULT PropertyStorage_ReadSectionHeaderFromStream(IStream *stm,
static HRESULT PropertyStorage_ReadFromStream(PropertyStorage_impl *This) { + struct read_buffer read_buffer; PROPERTYSETHEADER hdr; FORMATIDOFFSET fmtOffset; PROPERTYSECTIONHEADER sectionHdr; @@ -1617,14 +1706,16 @@ static HRESULT PropertyStorage_ReadFromStream(PropertyStorage_impl *This) hr = STG_E_INSUFFICIENTMEMORY; goto end; } - hr = IStream_Read(This->stm, buf, sectionHdr.cbSection - - sizeof(PROPERTYSECTIONHEADER), &count); + read_buffer.data = buf; + read_buffer.size = sectionHdr.cbSection - sizeof(sectionHdr); + + hr = IStream_Read(This->stm, read_buffer.data, read_buffer.size, &count); if (FAILED(hr)) goto end; TRACE("Reading %d properties:\n", sectionHdr.cProperties); for (i = 0; SUCCEEDED(hr) && i < sectionHdr.cProperties; i++) { - PROPERTYIDOFFSET *idOffset = (PROPERTYIDOFFSET *)(buf + + PROPERTYIDOFFSET *idOffset = (PROPERTYIDOFFSET *)(read_buffer.data + i * sizeof(PROPERTYIDOFFSET));
if (idOffset->dwOffset < sizeof(PROPERTYSECTIONHEADER) || @@ -1650,9 +1741,9 @@ static HRESULT PropertyStorage_ReadFromStream(PropertyStorage_impl *This) PROPVARIANT prop;
PropVariantInit(&prop); - if (SUCCEEDED(PropertyStorage_ReadProperty(&prop, - buf + idOffset->dwOffset - sizeof(PROPERTYSECTIONHEADER), - This->codePage, Allocate_CoTaskMemAlloc, NULL))) + if (SUCCEEDED(PropertyStorage_ReadProperty(&prop, &read_buffer, + idOffset->dwOffset - sizeof(PROPERTYSECTIONHEADER), This->codePage, + Allocate_CoTaskMemAlloc, NULL))) { TRACE("Read property with ID 0x%08x, type %d\n", idOffset->propid, prop.vt); @@ -2960,9 +3051,12 @@ static void* WINAPI Allocate_PMemoryAllocator(void *this, ULONG cbSize) BOOLEAN WINAPI StgConvertPropertyToVariant(const SERIALIZEDPROPERTYVALUE* prop, USHORT CodePage, PROPVARIANT* pvar, void* pma) { + struct read_buffer read_buffer; HRESULT hr;
- hr = PropertyStorage_ReadProperty(pvar, (const BYTE*)prop, CodePage, Allocate_PMemoryAllocator, pma); + read_buffer.data = (BYTE *)prop; + read_buffer.size = ~(size_t)0; + hr = PropertyStorage_ReadProperty(pvar, &read_buffer, 0, CodePage, Allocate_PMemoryAllocator, pma);
if (FAILED(hr)) {