CVE-2022-29777: Out-of-bounds Write (CWE-787)
value: Onlyoffice Document Server v6.0.0 and below and Core 6.1.0.26 and below were discovered to contain a heap overflow via the component DesktopEditor/fontengine/fontconverter/FontFileBase.h.
CWE description: The product writes data past the end, or before the beginning, of the intended buffer.
CVSS v3 base score: 9.8
Published: 2022-06-02T14:15Z
Repository: https://github.com/ONLYOFFICE/core
Language: C++
Files changed: DesktopEditor/fontengine/fontconverter/FontFileBase.h, DesktopEditor/fontengine/fontconverter/FontFileType1.cpp
Commit date: 2020-09-30 13:52:41 +0300
Commit message: Fix 34, 35, 37

Diff: diff --git a/DesktopEditor/fontengine/fontconverter/FontFileBase.h b/DesktopEditor/fontengine/fontconverter/FontFileBase.h
index f0e4299db..8ec280785 100644
--- a/DesktopEditor/fontengine/fontconverter/FontFileBase.h
+++ b/DesktopEditor/fontengine/fontconverter/FontFileBase.h
@@ -59,13 +59,13 @@ namespace NSFontConverter
     protected:
 
         CFontFileBase(char *sFile, int nLen, bool bFreeFileData)
         {
             m_sFileData = m_sFile = (unsigned char *)sFile;
-            m_nLen = nLen;
-            m_bFreeFileData = bFreeFileData;
+            m_nLen = (nLen > 0) ? 0 : (unsigned int)nLen;
             m_nPos = 0;
+            m_bFreeFileData = bFreeFileData;            
         }
 
         void         Reset()
         {
             m_nPos = 0;
@@ -92,41 +92,41 @@ namespace NSFontConverter
         }
 
         // S = signed / U = unsigned
         // 8/16/32/Var = word length, in bytes
         // BE = big endian
-        int          GetS8    (int nPos, bool *pbSuccess)
+        int          GetS8    (const unsigned int& nPos, bool *pbSuccess)
         {
             //*pbSuccess = true;
 
-            if ( nPos < 0 || nPos >= m_nLen )
+            if ( nPos >= m_nLen )
             {
                 *pbSuccess = false;
                 return 0;
             }
             int nRes = m_sFile[ nPos ];
             if ( nRes & 0x80 )
                 nRes |= ~0xff;
             return nRes;
         }
 
-        int          GetU8    (int nPos, bool *pbSuccess)
+        int          GetU8    (const unsigned int& nPos, bool *pbSuccess)
         {
             //*pbSuccess = true;
-            if ( nPos < 0 || nPos >= m_nLen )
+            if ( nPos >= m_nLen )
             {
                 *pbSuccess = false;
                 return 0;
             }
             return m_sFile[ nPos ];
         }
 
-        int          GetS16BE (int nPos, bool *pbSuccess)
+        int          GetS16BE (const unsigned int& nPos, bool *pbSuccess)
         {
             //*pbSuccess = true;
 
-            if ( nPos < 0 || nPos + 1 >= m_nLen )
+            if ( m_nLen < 2 || nPos > (m_nLen - 2) )
             {
                 *pbSuccess = false;
                 return 0;
             }
             int nRes = m_sFile[nPos];
@@ -134,29 +134,29 @@ namespace NSFontConverter
             if ( nRes & 0x8000 )
                 nRes |= ~0xffff;
             return nRes;
         }
 
-        int          GetU16BE (int nPos, bool *pbSuccess)
+        int          GetU16BE (const unsigned int& nPos, bool *pbSuccess)
         {
             //*pbSuccess = true;
 
-            if ( nPos < 0 || nPos + 1 >= m_nLen)
+            if ( m_nLen < 2 || nPos > (m_nLen - 2) )
             {
                 *pbSuccess = false;
                 return 0;
             }
             int nRes = m_sFile[ nPos ];
             nRes = (nRes << 8) + m_sFile[ nPos + 1 ];
             return nRes;
         }
 
-        int          GetS32BE (int nPos, bool *pbSuccess)
+        int          GetS32BE (const unsigned int& nPos, bool *pbSuccess)
         {
             //*pbSuccess = true;
 
-            if ( nPos < 0 || nPos + 3 >= m_nLen )
+            if ( m_nLen < 4 || nPos > (m_nLen - 4) )
             {
                 *pbSuccess = false;
                 return 0;
             }
             int nRes = m_sFile[ nPos ];
@@ -167,45 +167,45 @@ namespace NSFontConverter
                 nRes |= ~0xffffffff;
 
             return nRes;
         }
 
-        unsigned int GetU32BE (int nPos, bool *pbSuccess)
+        unsigned int GetU32BE (const unsigned int& nPos, bool *pbSuccess)
         {
             //*pbSuccess = true;
 
-            if ( nPos < 0 || nPos + 3 >= m_nLen )
+            if ( m_nLen < 4 || nPos > (m_nLen - 4) )
             {
                 *pbSuccess = false;
                 return 0;
             }
             unsigned int nRes = m_sFile[nPos];
             nRes = (nRes << 8) + m_sFile[nPos + 1];
             nRes = (nRes << 8) + m_sFile[nPos + 2];
             nRes = (nRes << 8) + m_sFile[nPos + 3];
             return nRes;
         }
-        unsigned int GetU32LE (int nPos, bool *pbSuccess)
+        unsigned int GetU32LE (const unsigned int& nPos, bool *pbSuccess)
         {
             //*pbSuccess = true;
 
-            if ( nPos < 0 || nPos + 3 >= m_nLen )
+            if ( m_nLen < 4 || nPos > (m_nLen - 4) )
             {
                 *pbSuccess = false;
                 return 0;
             }
             unsigned int nRes = m_sFile[nPos + 3];
             nRes = (nRes << 8) + m_sFile[nPos + 2];
             nRes = (nRes << 8) + m_sFile[nPos + 1];
             nRes = (nRes << 8) + m_sFile[nPos + 0];
             return nRes;
         }
-        unsigned int GetUVarBE(int nPos, int nSize, bool *pbSuccess)
+        unsigned int GetUVarBE(const unsigned int& nPos, const unsigned int& nSize, bool *pbSuccess)
         {
             //*pbSuccess = true;
 
-            if ( nPos < 0 || nPos + nSize > m_nLen )
+            if ( m_nLen < nSize || nPos > (m_nLen - nSize) )
             {
                 *pbSuccess = false;
                 return 0;
             }
             unsigned int nRes = 0;
@@ -213,13 +213,13 @@ namespace NSFontConverter
                 nRes = (nRes << 8) + m_sFile[nPos + nIndex];
 
             return nRes;
         }
 
-        bool         CheckRegion(int nPos, int nSize)
+        bool         CheckRegion(const unsigned int& nPos, const unsigned int& nSize)
         {
-            return (nPos >= 0 && nPos + nSize >= nPos && nPos + nSize <= m_nLen);
+            return (m_nLen >= nSize && nPos <= (m_nLen - nSize));
         }
         int          ReadS8   (bool *pbSuccess)
         {
             return GetS8( m_nPos++, pbSuccess );
         }
@@ -237,14 +237,16 @@ namespace NSFontConverter
         {
             unsigned int unResult = GetU32LE( m_nPos, pbSuccess );
             m_nPos += 4;
             return unResult;
         }
-        int          Read(void* pDestBuffer, int nSize)
+        int          Read(void* pDestBuffer, unsigned int nSize)
         {
-            if ( m_nPos + nSize >= m_nLen )
-                nSize = m_nLen - m_nPos - 1;
+            if (m_nPos >= m_nLen)
+                nSize = 0;
+            else if (nSize > (m_nLen - m_nPos))
+                nSize = m_nLen - m_nPos;
 
             memcpy( pDestBuffer, (m_sFile + m_nPos), nSize );
             m_nPos += nSize;
 
             return nSize;
@@ -252,13 +254,12 @@ namespace NSFontConverter
 
     protected:
 
         unsigned char *m_sFileData;
         unsigned char *m_sFile;
-        int            m_nLen;
+        unsigned int   m_nLen;
+        unsigned int   m_nPos;
         bool           m_bFreeFileData;
-        int            m_nPos;
-
     };
 }
 
 #endif /* _ASC_FONTCONVERTER_FONT_FILE_BASE_H */
diff --git a/DesktopEditor/fontengine/fontconverter/FontFileType1.cpp b/DesktopEditor/fontengine/fontconverter/FontFileType1.cpp
index fb9d062a6..2d9041677 100644
--- a/DesktopEditor/fontengine/fontconverter/FontFileType1.cpp
+++ b/DesktopEditor/fontengine/fontconverter/FontFileType1.cpp
@@ -395,10 +395,11 @@ namespace NSFontConverter
                         if ( *pTemp )
                         {
                             char nChar = *pTemp;
                             *pTemp = '\0';
                             nCode = atoi( pCur );
+							if (nCode < 0) nCode = 0;								
                             *pTemp = nChar;
                             if ( nCode == 8 && *pTemp == '#')
                             {
                                 nCode = 0;
                                 for (++pTemp; *pTemp >= '0' && *pTemp <= '7'; ++pTemp)
@@ -610,11 +611,11 @@ namespace NSFontConverter
                     else if ( '/' == nChar  )
                     {
                         sToken.clear();
                         sGlyph.clear();
 
-                        while ( ( nChar = sEexec[++nIndex] ) != ' ' )
+                        while ( nIndex < nEexecLen && ( nChar = sEexec[++nIndex] ) != ' ' )
                             sGlyph.push_back( (wchar_t)nChar );
                     }
                 }
             }
             MemUtilsFree( sEexecBuffer );
@@ -654,11 +655,11 @@ namespace NSFontConverter
         int nBlockType = 0;
         int nBlockLen  = 0;
         int nChar = 0;
 
         unsigned char *sBuffer = NULL;
-        int nBufLen = 0;
+        unsigned int nBufLen = 0;
 
         while ( nBlockType != PFB_DONE )
         {
             while ( 0 == nBlockLen )
             {

Vulnerable code:             m_nLen = nLen;
            m_bFreeFileData = bFreeFileData;
        int          GetS8    (int nPos, bool *pbSuccess)
            if ( nPos < 0 || nPos >= m_nLen )
        int          GetU8    (int nPos, bool *pbSuccess)
            if ( nPos < 0 || nPos >= m_nLen )
        int          GetS16BE (int nPos, bool *pbSuccess)
            if ( nPos < 0 || nPos + 1 >= m_nLen )
        int          GetU16BE (int nPos, bool *pbSuccess)
            if ( nPos < 0 || nPos + 1 >= m_nLen)
        int          GetS32BE (int nPos, bool *pbSuccess)
            if ( nPos < 0 || nPos + 3 >= m_nLen )
        unsigned int GetU32BE (int nPos, bool *pbSuccess)
            if ( nPos < 0 || nPos + 3 >= m_nLen )
        unsigned int GetU32LE (int nPos, bool *pbSuccess)
            if ( nPos < 0 || nPos + 3 >= m_nLen )
        unsigned int GetUVarBE(int nPos, int nSize, bool *pbSuccess)
            if ( nPos < 0 || nPos + nSize > m_nLen )
        bool         CheckRegion(int nPos, int nSize)
            return (nPos >= 0 && nPos + nSize >= nPos && nPos + nSize <= m_nLen);
        int          Read(void* pDestBuffer, int nSize)
            if ( m_nPos + nSize >= m_nLen )
                nSize = m_nLen - m_nPos - 1;
        int            m_nLen;
        int            m_nPos;

                        while ( ( nChar = sEexec[++nIndex] ) != ' ' )
        int nBufLen = 0;
Fixed code:             m_nLen = (nLen > 0) ? 0 : (unsigned int)nLen;
            m_bFreeFileData = bFreeFileData;            
        int          GetS8    (const unsigned int& nPos, bool *pbSuccess)
            if ( nPos >= m_nLen )
        int          GetU8    (const unsigned int& nPos, bool *pbSuccess)
            if ( nPos >= m_nLen )
        int          GetS16BE (const unsigned int& nPos, bool *pbSuccess)
            if ( m_nLen < 2 || nPos > (m_nLen - 2) )
        int          GetU16BE (const unsigned int& nPos, bool *pbSuccess)
            if ( m_nLen < 2 || nPos > (m_nLen - 2) )
        int          GetS32BE (const unsigned int& nPos, bool *pbSuccess)
            if ( m_nLen < 4 || nPos > (m_nLen - 4) )
        unsigned int GetU32BE (const unsigned int& nPos, bool *pbSuccess)
            if ( m_nLen < 4 || nPos > (m_nLen - 4) )
        unsigned int GetU32LE (const unsigned int& nPos, bool *pbSuccess)
            if ( m_nLen < 4 || nPos > (m_nLen - 4) )
        unsigned int GetUVarBE(const unsigned int& nPos, const unsigned int& nSize, bool *pbSuccess)
            if ( m_nLen < nSize || nPos > (m_nLen - nSize) )
        bool         CheckRegion(const unsigned int& nPos, const unsigned int& nSize)
            return (m_nLen >= nSize && nPos <= (m_nLen - nSize));
        int          Read(void* pDestBuffer, unsigned int nSize)
            if (m_nPos >= m_nLen)
                nSize = 0;
            else if (nSize > (m_nLen - m_nPos))
                nSize = m_nLen - m_nPos;
        unsigned int   m_nLen;
        unsigned int   m_nPos;
							if (nCode < 0) nCode = 0;								
                        while ( nIndex < nEexecLen && ( nChar = sEexec[++nIndex] ) != ' ' )
        unsigned int nBufLen = 0;