Kaydet (Commit) db39370e authored tarafından Stephan Bergmann's avatar Stephan Bergmann Kaydeden (comit) Caolán McNamara

Handle non-aligned FFNs

...as found by UBSan in CppunitTest_sw_filters_test (see below), and at the same
time limit reads within the pA array to its bounds.

> Testing file:///.../sw/qa/core/data/ww6/pass/crash-2.doc:
> sw/source/filter/ww8/ww8scan.cxx:6473:32: runtime error: upcast of misaligned address 0x6200000e70e7 for type 'WW8_FFN_Ver6', which requires 2 byte alignment
> 0x6200000e70e7: note: pointer points here
>  00 00 00 00 00  00 00 00 00 00 00 00 00  00 00 00 0e 00 00 6a 00  00 00 00 0e 00 00 6a 00  00 00 6a
>              ^
>  WW8Fonts::WW8Fonts(SvStream&, WW8Fib&) sw/source/filter/ww8/ww8scan.cxx:6473:32
>  SwWW8ImplReader::CoreLoad(WW8Glossary*, SwPosition const&) sw/source/filter/ww8/ww8par.cxx:4961:20
>  SwWW8ImplReader::LoadThroughDecryption(SwPaM&, WW8Glossary*) sw/source/filter/ww8/ww8par.cxx:5767:19
>  SwWW8ImplReader::LoadDoc(SwPaM&, WW8Glossary*) sw/source/filter/ww8/ww8par.cxx:6039:19
>  WW8Reader::Read(SwDoc&, rtl::OUString const&, SwPaM&, rtl::OUString const&) sw/source/filter/ww8/ww8par.cxx:6157:20
>  SwReader::Read(Reader const&) sw/source/filter/basflt/shellio.cxx:175:18
>  SwDocShell::ConvertFrom(SfxMedium&) sw/source/uibase/app/docsh.cxx:258:22
>  SfxObjectShell::DoLoad(SfxMedium*) sfx2/source/doc/objstor.cxx:790:23
>  SwFiltersTest::filter(rtl::OUString const&, rtl::OUString const&, rtl::OUString const&, SfxFilterFlags, SotClipboardFormatId, unsigned int, bool) sw/qa/core/filters-test.cxx:112:20
>  SwFiltersTest::load(rtl::OUString const&, rtl::OUString const&, rtl::OUString const&, SfxFilterFlags, SotClipboardFormatId, unsigned int) sw/qa/core/filters-test.cxx:71:12
>  test::FiltersTest::recursiveScan(test::filterStatus, rtl::OUString const&, rtl::OUString const&, rtl::OUString const&, SfxFilterFlags, SotClipboardFormatId, unsigned int, bool) unotest/source/cpp/filters-test.cxx:129:20
>  test::FiltersTest::testDir(rtl::OUString const&, rtl::OUString const&, rtl::OUString const&, SfxFilterFlags, SotClipboardFormatId, unsigned int, bool) unotest/source/cpp/filters-test.cxx:154:5
>  SwFiltersTest::testCVEs() sw/qa/core/filters-test.cxx:154:5

(cherry picked from commit 63738868)

Change-Id: I31ac8dc11d985745785c9dda1cec8a11a41098bb
Reviewed-on: https://gerrit.libreoffice.org/17985Reviewed-by: 's avatarCaolán McNamara <caolanm@redhat.com>
Tested-by: 's avatarCaolán McNamara <caolanm@redhat.com>
üst 3a0ca274
...@@ -20,10 +20,12 @@ ...@@ -20,10 +20,12 @@
#include "ww8scan.hxx" #include "ww8scan.hxx"
#include "ww8par.hxx" #include "ww8par.hxx"
#include <cassert>
#include <cstddef>
#include <cstring>
#include <functional> #include <functional>
#include <algorithm> #include <algorithm>
#include <string.h>
#include <i18nlangtag/mslangid.hxx> #include <i18nlangtag/mslangid.hxx>
#include <sprmids.hxx> #include <sprmids.hxx>
#include <rtl/tencinfo.h> #include <rtl/tencinfo.h>
...@@ -6357,10 +6359,15 @@ WW8_STD* WW8Style::Read1Style( short& rSkip, OUString* pString, short* pcbStd ) ...@@ -6357,10 +6359,15 @@ WW8_STD* WW8Style::Read1Style( short& rSkip, OUString* pString, short* pcbStd )
return pStd; return pStd;
} }
struct WW8_FFN_Ver6 : public WW8_FFN_BASE namespace {
const sal_uInt16 maxStrSize = 65;
}
struct WW8_FFN_Ver6
{ {
// ab Ver6 WW8_FFN_BASE base;
sal_Char szFfn[65]; // 0x6 bzw. 0x40 ab Ver8 zero terminated string that // from Ver6
sal_Char szFfn[maxStrSize]; // 0x6 bzw. 0x40 ab Ver8 zero terminated string that
// records name of font. // records name of font.
// Maximal size of szFfn is 65 characters. // Maximal size of szFfn is 65 characters.
// Vorsicht: Dieses Array kann auch kleiner sein!!! // Vorsicht: Dieses Array kann auch kleiner sein!!!
...@@ -6439,6 +6446,50 @@ namespace ...@@ -6439,6 +6446,50 @@ namespace
} }
return nMax; return nMax;
} }
template<typename T> bool readU8(
sal_uInt8 const * p, std::size_t offset, sal_uInt8 const * pEnd,
T * value)
{
assert(p <= pEnd);
assert(value != nullptr);
if (offset >= static_cast<std::size_t>(pEnd - p)) {
return false;
}
*value = p[offset];
return true;
}
bool readS16(
sal_uInt8 const * p, std::size_t offset, sal_uInt8 const * pEnd,
short * value)
{
assert(p <= pEnd);
assert(value != nullptr);
if (offset > static_cast<std::size_t>(pEnd - p)
|| static_cast<std::size_t>(pEnd - p) - offset < 2)
{
return false;
}
*value = unsigned(p[offset]) + (unsigned(p[offset + 1]) << 8);
return true;
}
sal_Int32 getStringLength(
sal_uInt8 const * p, std::size_t offset, sal_uInt8 const * pEnd)
{
assert(p <= pEnd);
assert(pEnd - p <= SAL_MAX_INT32);
if (offset >= static_cast<std::size_t>(pEnd - p)) {
return -1;
}
void const * p2 = std::memchr(
p + offset, 0, static_cast<std::size_t>(pEnd - p) - offset);
if (p2 == nullptr) {
return -1;
}
return static_cast<sal_uInt8 const *>(p2) - (p + offset);
}
} }
WW8Fonts::WW8Fonts( SvStream& rSt, WW8Fib& rFib ) WW8Fonts::WW8Fonts( SvStream& rSt, WW8Fib& rFib )
...@@ -6476,6 +6527,7 @@ WW8Fonts::WW8Fonts( SvStream& rSt, WW8Fib& rFib ) ...@@ -6476,6 +6527,7 @@ WW8Fonts::WW8Fonts( SvStream& rSt, WW8Fib& rFib )
// read all font information // read all font information
nFFn = rSt.Read(pA, nFFn); nFFn = rSt.Read(pA, nFFn);
sal_uInt8 * const pEnd = pA + nFFn;
const sal_uInt16 nCalcMax = calcMaxFonts(pA, nFFn); const sal_uInt16 nCalcMax = calcMaxFonts(pA, nFFn);
if (eVersion < ww::eWW8) if (eVersion < ww::eWW8)
...@@ -6495,17 +6547,26 @@ WW8Fonts::WW8Fonts( SvStream& rSt, WW8Fib& rFib ) ...@@ -6495,17 +6547,26 @@ WW8Fonts::WW8Fonts( SvStream& rSt, WW8Fib& rFib )
if( eVersion <= ww::eWW2 ) if( eVersion <= ww::eWW2 )
{ {
WW8_FFN_BASE* pVer2 = reinterpret_cast<WW8_FFN_BASE*>(pA); sal_uInt8 const * pVer2 = pA;
for(sal_uInt16 i=0; i<nMax; ++i, ++p) sal_uInt16 i = 0;
for(; i<nMax; ++i, ++p)
{ {
p->cbFfnM1 = pVer2->cbFfnM1; if (!readU8(
pVer2, offsetof(WW8_FFN_BASE, cbFfnM1), pEnd,
&p->cbFfnM1))
{
break;
}
p->prg = 0; p->prg = 0;
p->fTrueType = 0; p->fTrueType = 0;
p->ff = 0; p->ff = 0;
p->wWeight = ( *(reinterpret_cast<sal_uInt8*>(pVer2) + 1) ); if (!(readU8(pVer2, 1, pEnd, &p->wWeight)
p->chs = ( *(reinterpret_cast<sal_uInt8*>(pVer2) + 2) ); && readU8(pVer2, 2, pEnd, &p->chs)))
{
break;
}
/* /*
#i8726# 7- seems to encode the name in the same encoding as #i8726# 7- seems to encode the name in the same encoding as
the font, e.g load the doc in 97 and save to see the unicode the font, e.g load the doc in 97 and save to see the unicode
...@@ -6515,27 +6576,49 @@ WW8Fonts::WW8Fonts( SvStream& rSt, WW8Fib& rFib ) ...@@ -6515,27 +6576,49 @@ WW8Fonts::WW8Fonts( SvStream& rSt, WW8Fib& rFib )
if ((eEnc == RTL_TEXTENCODING_SYMBOL) || (eEnc == RTL_TEXTENCODING_DONTKNOW)) if ((eEnc == RTL_TEXTENCODING_SYMBOL) || (eEnc == RTL_TEXTENCODING_DONTKNOW))
eEnc = RTL_TEXTENCODING_MS_1252; eEnc = RTL_TEXTENCODING_MS_1252;
p->sFontname = OUString ( (reinterpret_cast<char*>(pVer2) + 1 + 2), strlen((reinterpret_cast<char*>(pVer2) + 1 + 2)), eEnc); sal_Int32 n = getStringLength(pVer2, 1 + 2, pEnd);
pVer2 = reinterpret_cast<WW8_FFN_BASE*>( reinterpret_cast<sal_uInt8*>(pVer2) + pVer2->cbFfnM1 + 1 ); if (n == -1) {
break;
}
p->sFontname = OUString(
reinterpret_cast<char const *>(pVer2 + 1 + 2), n, eEnc);
pVer2 = pVer2 + p->cbFfnM1 + 1;
} }
nMax = i;
} }
else if( eVersion < ww::eWW8 ) else if( eVersion < ww::eWW8 )
{ {
WW8_FFN_Ver6* pVer6 = reinterpret_cast<WW8_FFN_Ver6*>(pA); sal_uInt8 const * pVer6 = pA;
sal_uInt8 c2; sal_uInt16 i = 0;
for(sal_uInt16 i=0; i<nMax; ++i, ++p) for(; i<nMax; ++i, ++p)
{ {
p->cbFfnM1 = pVer6->cbFfnM1; if (!readU8(
c2 = *(reinterpret_cast<sal_uInt8*>(pVer6) + 1); pVer6, offsetof(WW8_FFN_BASE, cbFfnM1), pEnd,
&p->cbFfnM1))
{
break;
}
sal_uInt8 c2;
if (!readU8(pVer6, 1, pEnd, &c2)) {
break;
}
p->prg = c2 & 0x02; p->prg = c2 & 0x02;
p->fTrueType = (c2 & 0x04) >> 2; p->fTrueType = (c2 & 0x04) >> 2;
// ein Reserve-Bit ueberspringen // ein Reserve-Bit ueberspringen
p->ff = (c2 & 0x70) >> 4; p->ff = (c2 & 0x70) >> 4;
p->wWeight = SVBT16ToShort( *reinterpret_cast<SVBT16*>(&pVer6->wWeight) ); if (!(readS16(
p->chs = pVer6->chs; pVer6, offsetof(WW8_FFN_BASE, wWeight), pEnd,
p->ibszAlt = pVer6->ibszAlt; &p->wWeight)
&& readU8(
pVer6, offsetof(WW8_FFN_BASE, chs), pEnd, &p->chs)
&& readU8(
pVer6, offsetof(WW8_FFN_BASE, ibszAlt), pEnd,
&p->ibszAlt)))
{
break;
}
/* /*
#i8726# 7- seems to encode the name in the same encoding as #i8726# 7- seems to encode the name in the same encoding as
the font, e.g load the doc in 97 and save to see the unicode the font, e.g load the doc in 97 and save to see the unicode
...@@ -6544,12 +6627,27 @@ WW8Fonts::WW8Fonts( SvStream& rSt, WW8Fib& rFib ) ...@@ -6544,12 +6627,27 @@ WW8Fonts::WW8Fonts( SvStream& rSt, WW8Fib& rFib )
rtl_TextEncoding eEnc = WW8Fib::GetFIBCharset(p->chs, rFib.lid); rtl_TextEncoding eEnc = WW8Fib::GetFIBCharset(p->chs, rFib.lid);
if ((eEnc == RTL_TEXTENCODING_SYMBOL) || (eEnc == RTL_TEXTENCODING_DONTKNOW)) if ((eEnc == RTL_TEXTENCODING_SYMBOL) || (eEnc == RTL_TEXTENCODING_DONTKNOW))
eEnc = RTL_TEXTENCODING_MS_1252; eEnc = RTL_TEXTENCODING_MS_1252;
p->sFontname = OUString(pVer6->szFfn, rtl_str_getLength(pVer6->szFfn), eEnc); sal_Int32 n = getStringLength(
const sal_uInt16 maxStrSize = sizeof (pVer6->szFfn) / sizeof (pVer6->szFfn[0]); pVer6, offsetof(WW8_FFN_Ver6, szFfn), pEnd);
if (n == -1) {
break;
}
p->sFontname = OUString(
reinterpret_cast<char const *>(
pVer6 + offsetof(WW8_FFN_Ver6, szFfn)),
n, eEnc);
if (p->ibszAlt && p->ibszAlt < maxStrSize) //don't start after end of string if (p->ibszAlt && p->ibszAlt < maxStrSize) //don't start after end of string
{ {
const sal_Char *pAlt = pVer6->szFfn+p->ibszAlt; n = getStringLength(
p->sFontname += ";" + OUString(pAlt, rtl_str_getLength(pAlt), eEnc); pVer6, offsetof(WW8_FFN_Ver6, szFfn) + p->ibszAlt,
pEnd);
if (n == -1) {
break;
}
p->sFontname += ";" + OUString(
reinterpret_cast<char const *>(
pVer6 + offsetof(WW8_FFN_Ver6, szFfn) + p->ibszAlt),
n, eEnc);
} }
else else
{ {
...@@ -6562,8 +6660,9 @@ WW8Fonts::WW8Fonts( SvStream& rSt, WW8Fib& rFib ) ...@@ -6562,8 +6660,9 @@ WW8Fonts::WW8Fonts( SvStream& rSt, WW8Fib& rFib )
p->sFontname += ";Symbol"; p->sFontname += ";Symbol";
} }
} }
pVer6 = reinterpret_cast<WW8_FFN_Ver6*>( reinterpret_cast<sal_uInt8*>(pVer6) + pVer6->cbFfnM1 + 1 ); pVer6 = pVer6 + p->cbFfnM1 + 1;
} }
nMax = i;
} }
else else
{ {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment