Header bannerHeader banner
Advisory ID:
BRLY-LOGOFAIL-2023-009

[BRLY-LOGOFAIL-2023-009] Out-of-bounds Read in DXE driver

June 20, 2024
Severity:
Low
CVSS Score
3.2
Public Disclosure Date:
June 19, 2024

Summary

Binarly REsearch Team has discovered a OOB Read vulnerability in DXE driver. Improper loop exit condition will lead to OOB Read from ImagePtr during JPEG file processing in Insyde firmware.
Vendors Affected Icon

Vendors Affected

Lenovo
Insyde
Affected Products icon

Affected Products

Yoga 7 14IAL7

Potential Impact

This vulnerability will not lead to exploitation, however, it may lead to unexpected behaviour during GIF file processing.

Summary

Binarly REsearch Team has discovered a OOB Read vulnerability in DXE driver. Improper loop exit condition will lead to OOB Read from ImagePtr during JPEG file processing in Insyde firmware.

Vulnerability Information

     
  • BINARLY internal vulnerability identifier: BRLY-LOGOFAIL-2023-009  
  • Insyde PSIRT assigned CVE identifier: CVE-2023-40238  
  • CVSS v3.1: 3.2 Low AV:L/AC:L/PR:H/UI:N/S:C/C:N/I:L/A:N

Affected modules with confirmed impact by Binarly REsearch Team

Module name Module GUID Module SHA256
JpegDecoderDxe 2707e46d-dbd7-41c2-9c04-c9fdb8bad86c 2d84dc4c04ebb70719f86f8c9053cab57f4f537f23648192bebc83d397732e2e

Potential impact

This vulnerability will not lead to exploitation, however, it may lead to unexpected behaviour during GIF file processing.

Vulnerability description

The pseudocode of the vulnerable function is shown below:

__int64 __fastcall InitJfif(_BYTE *Image, __int64 ImageSize)
{
  UINT8 *ImagePtr; // rbx
  UINT8 *EndPtr; // rdi
  int v6; // eax
  _BYTE *v7; // r8
  unsigned int v8; // r9d
  int v9; // edx
  unsigned __int8 v10; // al
  __int64 v11; // rcx
  __int64 v12; // rdx
  int v13; // edx
  UINT8 v14; // r8
  __int64 result; // rax
  unsigned __int64 Skip; // rax

  sub_310(SOIPtr, 3064i64, 0i64);
  if ( *Image != 0xD8FF )
    return 1i64;
  ImagePtr = Image + 2;
  SOIPtr[0] = Image;
  EndPtr = &Image[ImageSize];
  
  // Vulnerability here: while (ImagePtr < (Image + ImageSize)
  // It is possible that *(ImagePtr + 2)/*(ImagePtr + 3) will exceed the buffer boundary
  // (when ImagePtr = Image + ImageSize - 3)
  // So we will have OOB read access here:

  // if ( ImagePtr[2] == 0xFF )
  //   Skip = 2i64;
  // else
  //   Skip = (ImagePtr[2] << 8) + ImagePtr[3] + 2i64;  
  if ( ImagePtr >= EndPtr )
    return 0i64;
  while ( 1 )
  {
    if ( *ImagePtr == 0xFF )
    {
      v6 = ImagePtr[1];
      if ( v6 )
        break;
    }
    Skip = 1i64;
LABEL_40:
    ImagePtr += Skip;
    if ( ImagePtr >= EndPtr )
      return 0i64;
  }
  if ( v6 > 0xC0u && v6 != 0xC4 && v6 <= 0xCFu )
    return 6i64;
  switch ( v6 )
  {
    case 0xC0:
      qword_2218 = ImagePtr;
      result = sub_62C(ImagePtr);
LABEL_35:
      if ( result )
        return result;
      goto LABEL_36;
    case 0xC4:
      result = sub_71C(ImagePtr);
      goto LABEL_35;
    case 0xDA:                                  // JPEG_SOS
      SOSPtr = ImagePtr;
      v12 = ImagePtr[3] + (ImagePtr[2] << 8);
      if ( ((ImagePtr[4] - 1) & 0xFD) != 0 || ImagePtr[(v12 - 1)] || ImagePtr[v12] != 63 || ImagePtr[(v12 + 1)] )
        return 5i64;
      v13 = 0;
      if ( ImagePtr[4] )
      {
        while ( ImagePtr[2 * v13 + 5] <= 3u )
        {
          v14 = ImagePtr[2 * v13 + 6];
          if ( (v14 & 0xF0u) > 0x10 || (v14 & 0xFu) > 1 )
            break;
          if ( ++v13 >= ImagePtr[4] )
            goto LABEL_36;
        }
        return 5i64;
      }
      goto LABEL_36;
  }
  if ( v6 != 219 )
  {
    switch ( v6 )
    {
      case 221:
        word_21E8 = ImagePtr[5] + (ImagePtr[4] << 8);
        break;
      case 224:
        qword_21C8 = ImagePtr;
        break;
      case 254:
        qword_21D8 = ImagePtr;
        break;
    }
    goto LABEL_36;
  }
  v7 = ImagePtr + 4;
  v8 = 0;
  v9 = (ImagePtr[3] - 2 + (ImagePtr[2] << 8)) / 65;
  if ( !v9 )
  {
LABEL_36:
    if ( ImagePtr[2] == 0xFF )
      Skip = 2i64;
    else
      Skip = (ImagePtr[2] << 8) + ImagePtr[3] + 2i64;
    goto LABEL_40;
  }
  while ( 1 )
  {
    v10 = *v7 & 0xF;
    if ( v10 > 3u || (*v7 & 0xF0) != 0 )
      return 3i64;
    v11 = (v7 + 1);
    v7 += 65;
    ++v8;
    SOIPtr[v10 + 6] = v11;
    if ( v8 >= v9 )
      goto LABEL_36;
  }
}

The following check is incomplete:

EndPtr = &Image[ImageSize];
if ( ImagePtr >= EndPtr ) { ... }

For example, if ImagePtr = EndPtr - 3 (and more), we will have OOB read here:

    if ( ImagePtr[2] == 0xFF )
      Skip = 2;
    else
      Skip = (ImagePtr[2] << 8) + ImagePtr[3] + 2;

Disclosure timeline

This bug is subject to a 90 day disclosure deadline. After 90 days elapsed or a patch has been made broadly available (whichever is earlier), the bug report will become visible to the public.

Disclosure Activity Date (YYYY-mm-dd)
Lenovo PSIRT is notified 2023-06-21
Lenovo ID (LEN-132940) is assigned 2023-06-22
CERT/CC is notified 2023-07-10
Insyde PSIRT confirmed reported issues 2023-09-10
Insyde PSIRT assigned CVE ID 2023-11-27
Insyde advisory release date 2023-12-06
BINARLY public disclosure date 2024-06-19

Acknowledgements

Binarly REsearch Team

Tags
Vulnerability
supply chain
FWHunt
See if you are impacted now with our Firmware Vulnerability Scanner