Skip to content
Permalink
master
Switch branches/tags

Name already in use

A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
Go to file
 
 
Cannot retrieve contributors at this time

Overview

libbpg is a library for the BPG graphics format. libbpg 0.9.7 may allow a crafted file to write out-of-bounds, which may lead to denial of service or arbitrary code execution.

Tested Versions

libbpg 0.9.7

Product URLs

http://bellard.org/bpg/

Details

In the build_msps function, two buffers(msps_buf and buf) will be malloced, and then in the while loop, with a crafted BPG image an attacker can controll the buf and cause an overflow in the heap, finally the vulnerability was triggered by av_free(msps_buf).

static int build_msps(uint8_t **pbuf, int *pbuf_len,
                      const uint8_t *input_data, int input_data_len1,
                      int width, int height, int chroma_format_idc,
                      int bit_depth)
{
    int input_data_len = input_data_len1;
    int idx, msps_len, ret, buf_len, i;
    uint32_t len;
    uint8_t *buf, *msps_buf;

    *pbuf = NULL;

    /* build the modified SPS header to please libavcodec */
    ret = get_ue(&len, input_data, input_data_len);
    int idx, msps_len, ret, buf_len, i;
    uint32_t len;
    uint8_t *buf, *msps_buf;

    *pbuf = NULL;

    /* build the modified SPS header to please libavcodec */
    ret = get_ue(&len, input_data, input_data_len);
    if (ret < 0)
        return -1;
    input_data += ret;
    input_data_len -= ret;

    if (len > input_data_len)
        return -1;

    msps_len = 1 + 4 + 4 + 1 + len;
    msps_buf = av_malloc(msps_len);
    idx = 0;
    msps_buf[idx++] = chroma_format_idc;
    msps_buf[idx++] = (width >> 24);
    msps_buf[idx++] = (width >> 16);
    msps_buf[idx++] = (width >> 8);
    msps_buf[idx++] = (width >> 0);
    msps_buf[idx++] = (height >> 24);
    msps_buf[idx++] = (height >> 16);
    msps_buf[idx++] = (height >> 8);
    msps_buf[idx++] = (height >> 0);
    msps_buf[idx++] = bit_depth - 8;
    memcpy(msps_buf + idx, input_data, len);
    idx += len;
    assert(idx == msps_len);
    input_data += len;
    input_data_len -= len;

    buf_len = 4 + 2 + msps_len * 2 + 4 + (input_data_len - len);
    buf = av_malloc(buf_len);

    idx = 0;
    /* NAL header */
    buf[idx++] = 0x00;
    buf[idx++] = 0x00;
    buf[idx++] = 0x00;
    buf[idx++] = 0x01;
    buf[idx++] = (48 << 1); /* application specific NAL unit type */
    buf[idx++] = 1;

    /* add the modified SPS with the correct escape codes */
    i = 0;
    while (i < msps_len) {
        if ((i + 1) < msps_len && msps_buf[i] == 0 && msps_buf[i + 1] == 0) {
            buf[idx++] = 0x00;
            buf[idx++] = 0x00;
            buf[idx++] = 0x03;
            i += 2;
        } else {
            buf[idx++] = msps_buf[i++];
        }
    }
    /* the last byte cannot be 0 */
    if (idx == 0 || buf[idx - 1] == 0x00)
        buf[idx++] = 0x80;
    av_free(msps_buf);

    *pbuf_len = idx;
    *pbuf = buf;
    return input_data_len1 - input_data_len;
}

Crash Information

The output of bpgdec with address sanitizer enabled

==37020==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x62300000de06 at pc 0x000000406730 bp 0x7fffffffe000 sp 0x7fffffffdff0
WRITE of size 1 at 0x62300000de06 thread T0
    #0 0x40672f in build_msps /root/libbpg-0.9.7/libbpg.c:256
    #1 0x40672f in hevc_decode_init1 /root/libbpg-0.9.7/libbpg.c:359

0x62300000de06 is located 0 bytes to the right of 6406-byte region [0x62300000c500,0x62300000de06)
allocated by thread T0 here:
    #0 0x7ffff6f02602 in malloc (/usr/lib/x86_64-linux-gnu/libasan.so.2+0x98602)
    #1 0x43b568 in av_malloc libavutil/mem.c:138

SUMMARY: AddressSanitizer: heap-buffer-overflow /root/libbpg-0.9.7/libbpg.c:256 build_msps
Shadow bytes around the buggy address:
  0x0c467fff9b70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c467fff9b80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c467fff9b90: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c467fff9ba0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c467fff9bb0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c467fff9bc0:[06]fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c467fff9bd0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c467fff9be0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c467fff9bf0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c467fff9c00: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c467fff9c10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07 
  Heap left redzone:       fa
  Heap right redzone:      fb
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack partial redzone:   f4
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
==37020==ABORTING

CREDIT

Zhao Liang, Huawei Weiran Labs