Bug 1943408 - CVE-2021-32490 djvulibre: Out of bounds write in function DJVU::filter_bv() via crafted djvu file [fedora-all]
Summary: CVE-2021-32490 djvulibre: Out of bounds write in function DJVU::filter_bv() ...
Keywords:
Status: ASSIGNED
Alias: None
Product: Fedora
Classification: Fedora
Component: djvulibre
Version: 33
Hardware: x86_64
OS: Linux
medium
medium
Target Milestone: ---
Assignee: Marek Kašík
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks: CVE-2021-32490
TreeView+ depends on / blocked
 
Reported: 2021-03-26 02:02 UTC by 1vanChen
Modified: 2021-05-10 17:07 UTC (History)
4 users (show)

Fixed In Version:
Doc Type: If docs needed, set a value
Doc Text:
Clone Of:
Environment:
Last Closed:
Type: Bug


Attachments (Terms of Use)
pocfile (596 bytes, application/octet-stream)
2021-03-26 02:02 UTC, 1vanChen
no flags Details
Check size of image for 0 (658 bytes, patch)
2021-04-08 09:22 UTC, Marek Kašík
no flags Details | Diff

Description 1vanChen 2021-03-26 02:02:28 UTC
Created attachment 1766464 [details]
pocfile

To Reproduce

```shell
./ddjvu ./poc.djvu
```

Debug Info

```shell
# ./ddjvu ./poc.djvu
AddressSanitizer:DEADLYSIGNAL
=================================================================
==27444==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x00000080286b bp 0x7ffff2865320 sp 0x7ffff2865140 T2)
==27444==The signal is caused by a WRITE memory access.
==27444==Hint: address points to the zero page.
    #0 0x80286b in DJVU::filter_bv(short*, int, int, int, int) /src/djvulibre-ddjvu/libdjvu/IW44Image.cpp:309:24
    #1 0x7e7da2 in DJVU::IW44Image::Transform::Decode::backward(short*, int, int, int, int, int) /src/djvulibre-ddjvu/libdjvu/IW44Image.cpp:1883:7
    #2 0x7e62af in DJVU::IW44Image::Map::image(signed char*, int, int, int) /src/djvulibre-ddjvu/libdjvu/IW44Image.cpp:714:7
    #3 0x7fbd6d in DJVU::IWPixmap::get_pixmap() /src/djvulibre-ddjvu/libdjvu/IW44Image.cpp:1656:9
    #4 0x621319 in DJVU::DjVuFile::decode_chunk(DJVU::GUTF8String const&, DJVU::GP<DJVU::ByteStream> const&, bool, bool, bool) /src/djvulibre-ddjvu/libdjvu/DjVuFile.cpp:984:15
    #5 0x61835b in DJVU::DjVuFile::decode(DJVU::GP<DJVU::ByteStream> const&) /src/djvulibre-ddjvu/libdjvu/DjVuFile.cpp:1255:25
    #6 0x616b2d in DJVU::DjVuFile::decode_func() /src/djvulibre-ddjvu/libdjvu/DjVuFile.cpp:484:5
    #7 0x61689b in DJVU::DjVuFile::static_decode_func(void*) /src/djvulibre-ddjvu/libdjvu/DjVuFile.cpp:464:9
    #8 0x77b07a in DJVU::GThread::start(void*) /src/djvulibre-ddjvu/libdjvu/GThreads.cpp:392:11
    #9 0x7ffff6ceb6b9 in start_thread /build/glibc-e6zv40/glibc-2.23/nptl/pthread_create.c:333
    #10 0x7ffff66014dc in clone /build/glibc-e6zv40/glibc-2.23/misc/../sysdeps/unix/sysv/linux/x86_64/clone.S:109

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /src/djvulibre-ddjvu/libdjvu/IW44Image.cpp:309:24 in DJVU::filter_bv(short*, int, int, int, int)
Thread T2 created by T0 here:
    #0 0x4838ba in pthread_create /local/mnt/workspace/tmp/final/llvm-project/compiler-rt/lib/asan/asan_interceptors.cpp:214:3
    #1 0x77b5a0 in DJVU::GThread::create(void (*)(void*), void*) /src/djvulibre-ddjvu/libdjvu/GThreads.cpp:440:13
    #2 0x62552c in DJVU::DjVuFile::start_decode() /src/djvulibre-ddjvu/libdjvu/DjVuFile.cpp:1341:22
    #3 0x62499b in DJVU::DjVuFile::resume_decode(bool) /src/djvulibre-ddjvu/libdjvu/DjVuFile.cpp:1366:7
    #4 0x5fa9dd in DJVU::DjVuDocument::get_page(int, bool, DJVU::DjVuPort*) const /src/djvulibre-ddjvu/libdjvu/DjVuDocument.cpp:1070:12
    #5 0x569f7a in DJVU::DjVuDocument::get_page(int, bool, DJVU::DjVuPort*) /src/djvulibre-ddjvu/libdjvu/./DjVuDocument.h:604:53
    #6 0x5363cd in ddjvu_page_create(DJVU::ddjvu_document_s*, DJVU::ddjvu_job_s*, char const*, int) /src/djvulibre-ddjvu/libdjvu/ddjvuapi.cpp:1580:23
    #7 0x4d33f6 in dopage(int) /src/djvulibre-ddjvu/tools/ddjvu.cpp:733:17
    #8 0x4d4717 in parse_pagespec(char const*, int, void (*)(int)) /src/djvulibre-ddjvu/tools/ddjvu.cpp:825:11
    #9 0x4df19b in main /src/djvulibre-ddjvu/tools/ddjvu.cpp:1214:3
    #10 0x7ffff651a83f in __libc_start_main /build/glibc-e6zv40/glibc-2.23/csu/../csu/libc-start.c:291

==27444==ABORTING
```

I think  unchecked variables data16 is the root cause of this vulnerability:

```c

void
IW44Image::Map::image(signed char *img8, int rowsize, int pixsep, int fast)
{
  // Allocate reconstruction buffer
  short *data16;
  size_t sz = bw * bh;
  if (sz / (size_t)bw != (size_t)bh) // multiplication overflow
    G_THROW("IW44Image: image size exceeds maximum (corrupted file?)");
  GPBuffer<short> gdata16(data16,sz);
  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  ...
  if (fast)
    {
      IW44Image::Transform::Decode::backward(data16, iw, ih, bw, 32, 2);
      p = data16;
      for (i=0; i<bh; i+=2,p+=bw)
        for (int jj=0; jj<bw; jj+=2,p+=2)
          p[bw] = p[bw+1] = p[1] = p[0];
    }
  else
    {
      IW44Image::Transform::Decode::backward(data16, iw, ih, bw, 32, 1);
    }
```





Environment:

- version : djvulibre master (ee314b880c926e884be77d53ee459d9850c9c7f0)
- OS: Ubuntu 16.04
- clang version: 11



Credit: 1vanChen of NSFOCUS Security Team

Comment 1 Marek Kašík 2021-04-08 09:22:40 UTC
Created attachment 1770184 [details]
Check size of image for 0

This simple patch which checks image size for 0 fixes this issue for me. It also checks whether the data were actually allocated.

Comment 2 1vanChen 2021-04-11 12:59:39 UTC
(In reply to Marek Kašík from comment #1)
> Created attachment 1770184 [details]
> Check size of image for 0
> 
> This simple patch which checks image size for 0 fixes this issue for me. It
> also checks whether the data were actually allocated.

This patch looks great! I cannot reproduce this bug after applying this patch.


Note You need to log in before you can comment on or make changes to this bug.