CVE-2021-33035: Buffer Copy without Checking Size of Input ('Classic Buffer Overflow') (CWE-120)
value: Apache OpenOffice opens dBase/DBF documents and shows the contents as spreadsheets. DBF are database files with data organized in fields. When reading DBF data the size of certain fields is not checked: the data is just copied into local variables. A carefully crafted document could overflow the allocated space, leading to the execution of arbitrary code by altering the contents of the program stack. This issue affects Apache OpenOffice up to and including version 4.1.10
CWE description: The product copies an input buffer to an output buffer without verifying that the size of the input buffer is less than the size of the output buffer, leading to a buffer overflow.
CVSS v3 base score: 7.8
Published: 2021-09-23T08:15Z
Repository: https://github.com/apache/openoffice
Language: Other
Files changed: main/connectivity/source/drivers/dbase/DTable.cxx
Commit date: 2021-06-26 09:46:32 +0200
Commit message: add useful checks

Diff: diff --git a/main/connectivity/source/drivers/dbase/DTable.cxx b/main/connectivity/source/drivers/dbase/DTable.cxx
index 2400e8f9e0..8e6dc676e2 100644
--- a/main/connectivity/source/drivers/dbase/DTable.cxx
+++ b/main/connectivity/source/drivers/dbase/DTable.cxx
@@ -894,10 +894,14 @@ sal_Bool ODbaseTable::fetchRow(OValueRefRow& _rRow,const OSQLColumns & _rCols, s
 			pData[nLen] = cLast;
 		} // if (nType == DataType::CHAR || nType == DataType::VARCHAR)
         else if ( DataType::TIMESTAMP == nType )
         {
             sal_Int32 nDate = 0,nTime = 0;
+            OSL_ENSURE(nLen == 8, "Invalid length for date field");
+            if (nLen != 8) {
+                return false;
+            }
 			memcpy(&nDate, pData, 4);
             memcpy(&nTime, pData+ 4, 4);
             if ( !nDate && !nTime )
             {
                 (_rRow->get())[i]->setNull();
@@ -909,17 +913,25 @@ sal_Bool ODbaseTable::fetchRow(OValueRefRow& _rRow,const OSQLColumns & _rCols, s
                 *(_rRow->get())[i] = aDateTime;
             }
         }
         else if ( DataType::INTEGER == nType )
         {
+            OSL_ENSURE(nLen == 4, "Invalid length for integer field");
+            if (nLen != 4) {
+                return false;
+            }
             sal_Int32 nValue = 0;
 			memcpy(&nValue, pData, nLen);
             *(_rRow->get())[i] = nValue;
         }
         else if ( DataType::DOUBLE == nType )
         {
             double d = 0.0;
+            OSL_ENSURE(nLen == 8, "Invalid length for double field");
+            if (nLen != 8) {
+                return false;
+            }
             if (getBOOL((*aIter)->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))) // Currency wird gesondert behandelt
             {
                 sal_Int64 nValue = 0;
 			    memcpy(&nValue, pData, nLen);
             
@@ -957,10 +969,14 @@ sal_Bool ODbaseTable::fetchRow(OValueRefRow& _rRow,const OSQLColumns & _rCols, s
 
 			switch (nType)
 			{
 				case DataType::DATE:
 				{
+                    OSL_ENSURE(nLen == 8, "Invalid length for date field");
+                    if (nLen != 8) {
+                        return false;
+                    }
 					if (aStr.Len() != nLen)
 					{
 						(_rRow->get())[i]->setNull();
 						break;
 					}
@@ -976,10 +992,14 @@ sal_Bool ODbaseTable::fetchRow(OValueRefRow& _rRow,const OSQLColumns & _rCols, s
 					*(_rRow->get())[i] = ORowSetValue(aStr);
 					//	pVal->setDouble(SdbTools::ToDouble(aStr));
 				break;
 				case DataType::BIT:
 				{
+                    OSL_ENSURE(nLen == 1, "Invalid length for bit field");
+                    if (nLen != 1) {
+                        return false;
+                    }
 					sal_Bool b;
 					switch (* ((const char *)pData))
 					{
 						case 'T':
 						case 'Y':
@@ -1871,19 +1891,29 @@ sal_Bool ODbaseTable::UpdateBuffer(OValueRefVector& rRow, OValueRefRow pOrgRow,c
 		{
 			switch (nType)
 			{
                 case DataType::TIMESTAMP:
                     {
+                        OSL_ENSURE(nLen == 8, "Invalid length for timestamp field");
+                        if (nLen != 8) {
+                            bHadError = true;
+                            break;
+                        }
                         sal_Int32 nJulianDate = 0, nJulianTime = 0;
                         lcl_CalcJulDate(nJulianDate,nJulianTime,rRow.get()[nPos]->getValue());
                         // Genau 8 Byte kopieren:
 					    memcpy(pData,&nJulianDate,4);
                         memcpy(pData+4,&nJulianTime,4);
                     }
                     break;
 				case DataType::DATE:
 				{
+                    OSL_ENSURE(nLen == 8, "Invalid length for date field");
+                    if (nLen != 8) {
+                        bHadError = true;
+                        break;
+                    }
 					::com::sun::star::util::Date aDate;
 					if(rRow.get()[nPos]->getValue().getTypeKind() == DataType::DOUBLE)
 						aDate = ::dbtools::DBTypeConversion::toDate(rRow.get()[nPos]->getValue().getDouble());
 					else
 						aDate = rRow.get()[nPos]->getValue();
@@ -1898,16 +1928,26 @@ sal_Bool ODbaseTable::UpdateBuffer(OValueRefVector& rRow, OValueRefRow pOrgRow,c
 					// Genau 8 Byte kopieren:
 					strncpy(pData,s,sizeof s - 1);
 				} break;
                 case DataType::INTEGER:
                     {
+                        OSL_ENSURE(nLen == 4, "Invalid length for integer field");
+                        if (nLen != 4) {
+                            bHadError = true;
+                            break;
+                        }
                         sal_Int32 nValue = rRow.get()[nPos]->getValue();
                         memcpy(pData,&nValue,nLen);
                     }
                     break;
                 case DataType::DOUBLE:
                     {
+                        OSL_ENSURE(nLen == 8, "Invalid length for double field");
+                        if (nLen != 8) {
+                            bHadError = true;
+                            break;
+                        }
                         const double d = rRow.get()[nPos]->getValue();
                         m_pColumns->getByIndex(i) >>= xCol;
                         
                         if (getBOOL(xCol->getPropertyValue(OMetaConnection::getPropMap().getNameByIndex(PROPERTY_ID_ISCURRENCY)))) // Currency wird gesondert behandelt
                         {
@@ -1956,10 +1996,15 @@ sal_Bool ODbaseTable::UpdateBuffer(OValueRefVector& rRow, OValueRefRow pOrgRow,c
                              ) );
                         ::dbtools::throwGenericSQLException( sError, *this );
 					}
 				} break;
 				case DataType::BIT:
+                    OSL_ENSURE(nLen == 1, "Invalid length for bit field");
+                    if (nLen != 1) {
+                        bHadError = true;
+                        break;
+                    }
 					*pData = rRow.get()[nPos]->getValue().getBool() ? 'T' : 'F';
 					break;
                 case DataType::LONGVARBINARY:
 				case DataType::LONGVARCHAR:
 				{

Fixed code:             OSL_ENSURE(nLen == 8, "Invalid length for date field");
            if (nLen != 8) {
                return false;
            }
            OSL_ENSURE(nLen == 4, "Invalid length for integer field");
            if (nLen != 4) {
                return false;
            }
            OSL_ENSURE(nLen == 8, "Invalid length for double field");
            if (nLen != 8) {
                return false;
            }
                    OSL_ENSURE(nLen == 8, "Invalid length for date field");
                    if (nLen != 8) {
                        return false;
                    }
                    OSL_ENSURE(nLen == 1, "Invalid length for bit field");
                    if (nLen != 1) {
                        return false;
                    }
                        OSL_ENSURE(nLen == 8, "Invalid length for timestamp field");
                        if (nLen != 8) {
                            bHadError = true;
                            break;
                        }
                    OSL_ENSURE(nLen == 8, "Invalid length for date field");
                    if (nLen != 8) {
                        bHadError = true;
                        break;
                    }
                        OSL_ENSURE(nLen == 4, "Invalid length for integer field");
                        if (nLen != 4) {
                            bHadError = true;
                            break;
                        }
                        OSL_ENSURE(nLen == 8, "Invalid length for double field");
                        if (nLen != 8) {
                            bHadError = true;
                            break;
                        }
                    OSL_ENSURE(nLen == 1, "Invalid length for bit field");
                    if (nLen != 1) {
                        bHadError = true;
                        break;
                    }