This is an automated email from the ASF dual-hosted git repository. ardovm pushed a commit to branch trunk in repository https://gitbox.apache.org/repos/asf/openoffice.git
commit 8604ca21f9283f811f592bd95847a6002173ce6e Author: Peter Kovacs <[email protected]> AuthorDate: Sat Aug 1 12:53:44 2026 +0200 sw: ww8: validate PLCF length Add an inline WW8PLCF::IsValidLength() predicate and call it at the entry of both WW8PLCF::ReadPLCF and the WW8PLCFspecial constructor. Add GoogleTest_sw_ww8plcf covering the boundary values. Thanks to Yukihiro Nakamura ([email protected]) Co-authored-by: Yukihiro Nakamura ([email protected]) Co-Authored-By: Claude Opus 5 <[email protected]> --- main/sw/{Module_sw.mk => GoogleTest_sw_ww8plcf.mk} | 42 ++++++------ main/sw/Module_sw.mk | 1 + main/sw/source/filter/ww8/qa/ww8plcf_test.cxx | 78 ++++++++++++++++++++++ main/sw/source/filter/ww8/ww8scan.cxx | 15 +++++ main/sw/source/filter/ww8/ww8scan.hxx | 3 + 5 files changed, 116 insertions(+), 23 deletions(-) diff --git a/main/sw/Module_sw.mk b/main/sw/GoogleTest_sw_ww8plcf.mk similarity index 59% copy from main/sw/Module_sw.mk copy to main/sw/GoogleTest_sw_ww8plcf.mk index 5465500bca..5ffedcc35a 100644 --- a/main/sw/Module_sw.mk +++ b/main/sw/GoogleTest_sw_ww8plcf.mk @@ -20,34 +20,30 @@ #************************************************************** +$(eval $(call gb_GoogleTest_GoogleTest,sw_ww8plcf)) -$(eval $(call gb_Module_Module,sw)) - -$(eval $(call gb_Module_add_targets,sw,\ - AllLangResTarget_sw \ - Library_msword \ - Library_sw \ - Library_swd \ - Library_swui \ - Library_vbaswobj \ - Package_misc \ - Package_uiconfig \ - Package_xml \ +$(eval $(call gb_GoogleTest_add_exception_objects,sw_ww8plcf, \ + sw/source/filter/ww8/qa/ww8plcf_test \ )) - -ifeq ($(ENABLE_UNIT_TESTS),YES) -$(eval $(call gb_Module_add_check_targets,sw,\ - GoogleTest_sw_bigpointerarray \ +# WW8PLCF::IsValidLength is inline and references only compile-time constants, +# so the test compiles against the ww8 filter headers without linking msword. +$(eval $(call gb_GoogleTest_add_linked_libs,sw_ww8plcf, \ + sal \ + stl \ + sw \ + tl \ + $(gb_STDLIBS) \ )) -endif - -ifneq ($(OOO_JUNIT_JAR),) -$(eval $(call gb_Module_add_subsequentcheck_targets,sw,\ - JunitTest_sw_complex \ - JunitTest_sw_unoapi \ +$(eval $(call gb_GoogleTest_set_include,sw_ww8plcf,\ + $$(INCLUDE) \ + -I$(SRCDIR)/sw/inc \ + -I$(SRCDIR)/sw/inc/pch \ + -I$(SRCDIR)/sw/source/filter/inc \ + -I$(SRCDIR)/sw/source/filter/ww8 \ + -I$(OUTDIR)/inc/offuh \ + -I$(OUTDIR)/inc \ )) -endif # vim: set noet sw=4 ts=4: diff --git a/main/sw/Module_sw.mk b/main/sw/Module_sw.mk index 5465500bca..eda7a25d88 100644 --- a/main/sw/Module_sw.mk +++ b/main/sw/Module_sw.mk @@ -39,6 +39,7 @@ $(eval $(call gb_Module_add_targets,sw,\ ifeq ($(ENABLE_UNIT_TESTS),YES) $(eval $(call gb_Module_add_check_targets,sw,\ GoogleTest_sw_bigpointerarray \ + GoogleTest_sw_ww8plcf \ )) endif diff --git a/main/sw/source/filter/ww8/qa/ww8plcf_test.cxx b/main/sw/source/filter/ww8/qa/ww8plcf_test.cxx new file mode 100644 index 0000000000..c20a795e1a --- /dev/null +++ b/main/sw/source/filter/ww8/qa/ww8plcf_test.cxx @@ -0,0 +1,78 @@ +/************************************************************** + * + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + * + *************************************************************/ + +// Regression test for WW8PLCF::IsValidLength, the length guard shared by +// WW8PLCF::ReadPLCF and the WW8PLCFspecial constructor (ww8scan.cxx). + +#include "gtest/gtest.h" + +#include "ww8scan.hxx" // WW8PLCF::IsValidLength (inline, no filter link) +#include "ww8struc.hxx" // WW8_CP_MAX +#include <sal/types.h> + +// Non-positive count must be rejected. +TEST(WW8Plcf, IsValidLengthRejectsNegativeAndZero) +{ + EXPECT_FALSE( WW8PLCF::IsValidLength( -1 ) ); // 0xFFFFFFFF narrowed + EXPECT_FALSE( WW8PLCF::IsValidLength( 0 ) ); + EXPECT_FALSE( WW8PLCF::IsValidLength( -64 ) ); + EXPECT_FALSE( WW8PLCF::IsValidLength( SAL_MIN_INT32 ) ); +} + +// Lengths close to the maximum must be rejected too +TEST(WW8Plcf, IsValidLengthRejectsOverflowingUpperRange) +{ + EXPECT_FALSE( WW8PLCF::IsValidLength( WW8_CP_MAX ) ); + EXPECT_FALSE( WW8PLCF::IsValidLength( WW8_CP_MAX - 1 ) ); + EXPECT_FALSE( WW8PLCF::IsValidLength( WW8_CP_MAX - 3 ) ); +} + +// Genuine lengths are accepted +TEST(WW8Plcf, IsValidLengthAcceptsBenignLengths) +{ + EXPECT_TRUE( WW8PLCF::IsValidLength( 1 ) ); + EXPECT_TRUE( WW8PLCF::IsValidLength( 12 ) ); + EXPECT_TRUE( WW8PLCF::IsValidLength( 64 ) ); + EXPECT_TRUE( WW8PLCF::IsValidLength( WW8_CP_MAX - 4 ) ); // largest accepted +} + +// For every accepted length, the element count both readers allocate is +// large enough to hold the nPLCF bytes the subsequent Read copies in. +TEST(WW8Plcf, AcceptedLengthSizesBufferToHoldRead) +{ + const sal_Int32 aLens[] = { 1, 3, 4, 5, 12, 64, 4096, WW8_CP_MAX - 4 }; + for ( size_t i = 0; i < sizeof(aLens) / sizeof(aLens[0]); ++i ) + { + const sal_Int32 nPLCF = aLens[i]; + ASSERT_TRUE( WW8PLCF::IsValidLength( nPLCF ) ); + // Done in 64-bit to model the allocation without itself overflowing. + const sal_Int64 nElems = ( static_cast<sal_Int64>(nPLCF) + 3 ) / 4; + const sal_Int64 nCapacityBytes = nElems * 4; // sizeof(WW8_CP) == 4 + EXPECT_GT( nElems, 0 ); + EXPECT_GE( nCapacityBytes, static_cast<sal_Int64>(nPLCF) ); + } +} + +int main( int argc, char** argv ) +{ + ::testing::InitGoogleTest( &argc, argv ); + return RUN_ALL_TESTS(); +} diff --git a/main/sw/source/filter/ww8/ww8scan.cxx b/main/sw/source/filter/ww8/ww8scan.cxx index 250ca6f65b..40667c826d 100644 --- a/main/sw/source/filter/ww8/ww8scan.cxx +++ b/main/sw/source/filter/ww8/ww8scan.cxx @@ -2208,6 +2208,15 @@ WW8PLCFspecial::WW8PLCFspecial(SvStream* pSt, long nFilePos, long nPLCF, long nStruct, long nStartPos) : nIdx(0), nStru(nStruct) { + if (!WW8PLCF::IsValidLength(static_cast<sal_Int32>(nPLCF))) + { + nIMax = 0; + pPLCF_PosArray = new sal_Int32[1]; + pPLCF_PosArray[0] = WW8_CP_MAX; + pPLCF_Contents = 0; + return; + } + nIMax = ( nPLCF - 4 ) / ( 4 + nStruct ); // Pointer auf Pos- u. Struct-Array pPLCF_PosArray = new sal_Int32[ ( nPLCF + 3 ) / 4 ]; @@ -2382,6 +2391,12 @@ void WW8PLCF::ReadPLCF( SvStream* pSt, WW8_FC nFilePos, sal_Int32 nPLCF ) { bool failure = false; + if (!IsValidLength(nPLCF)) + { + MakeFailedPLCF(); + return; + } + // Pointer auf Pos-Array pPLCF_PosArray = new WW8_CP[ ( nPLCF + 3 ) / 4 ]; diff --git a/main/sw/source/filter/ww8/ww8scan.hxx b/main/sw/source/filter/ww8/ww8scan.hxx index 72f154623a..19eff0af3f 100644 --- a/main/sw/source/filter/ww8/ww8scan.hxx +++ b/main/sw/source/filter/ww8/ww8scan.hxx @@ -291,6 +291,9 @@ private: void MakeFailedPLCF(); public: + static bool IsValidLength( sal_Int32 nPLCF ) + { return nPLCF >= 1 && nPLCF <= ( WW8_CP_MAX - 4 ); } + WW8PLCF( SvStream* pSt, WW8_FC nFilePos, sal_Int32 nPLCF, int nStruct, WW8_CP nStartPos = -1 );
