Project: libredwg (libredwg/libredwg), language: c++
Vulnerability instance: libredwg.cve-2022-35164
Sanitizer: address

================= Bug Report (1/1) ==================
## Source: GitHub Issue
## URL: https://github.com/LibreDWG/libredwg/issues/497
## Description:
Issue: LibreDWG/libredwg#497
Title: Heap use-after-free still exists in the bit_copy_chain
State: closed
Created by: 0xdd96
Created at: 2022-06-17 12:04:26+00:00
Labels: bug, fuzzing

Issue Body:
# Vulnerability description
version: [0.12.4.4608](https://github.com/LibreDWG/libredwg/releases/tag/0.12.4.4608) & latest  commit [f2dea29](https://github.com/LibreDWG/libredwg/commit/f2dea296a0a3bb16afdae8d2ca16749a617a4383)
poc: [poc](https://github.com/0xdd96/PoC/raw/main/libredwg/UAF-bit_copy_chain)
command: ./dwgrewrite poc

**_This is similar to issue #364 and others, but it seems that the patch https://github.com/LibreDWG/libredwg/commit/e95cc1eea8744c40e298208679eda14039b9b5d3 has not fully fixed them._**

Here is the trace reported by ASAN:
```
==28024==ERROR: AddressSanitizer: heap-use-after-free on address 0x7ffff3b65800 at pc 0x5555564f67f6 bp 0x7fffffff6760 sp 0x7fffffff6750
READ of size 1 at 0x7ffff3b65800 thread T0
    #0 0x5555564f67f5 in bit_read_RC libredwg/src/bits.c:317
    #1 0x5555564f67f5 in bit_copy_chain libredwg/src/bits.c:3352
    #2 0x555556105ec6 in obj_flush_hdlstream libredwg/src/encode.c:833
    #3 0x555556105ec6 in dwg_encode_PLANESURFACE_private libredwg/src/dwg.spec:9150
    #4 0x5555563a57df in dwg_encode_PLANESURFACE libredwg/src/dwg.spec:9136
    #5 0x5555563a57df in dwg_encode_variable_type libredwg/src/classes.inc:247
    #6 0x5555563ab3d0 in dwg_encode_add_object libredwg/src/encode.c:4432
    #7 0x5555563c914c in dwg_encode libredwg/src/encode.c:2769
    #8 0x55555575ca00 in dwg_write_file libredwg/src/dwg.c:429
    #9 0x555555758a3f in main libredwg/programs/dwgrewrite.c:350
    #10 0x7ffff726f0b2 in __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x240b2)
    #11 0x55555575924d in _start (libredwg/build-ASAN/dwgrewrite+0x20524d)

0x7ffff3b65800 is located 0 bytes inside of 208896-byte region [0x7ffff3b65800,0x7ffff3b98800)
freed by thread T0 here:
    #0 0x7ffff7699ffe in __interceptor_realloc (/lib/x86_64-linux-gnu/libasan.so.5+0x10dffe)
    #1 0x5555564f532c in bit_chain_alloc_size libredwg/src/bits.c:3046
    #2 0x5555564f532c in bit_chain_alloc libredwg/src/bits.c:3062
    #3 0x5555564f532c in bit_copy_chain libredwg/src/bits.c:3339
    #4 0x1900000105  (<unknown module>)

previously allocated by thread T0 here:
    #0 0x7ffff7699ffe in __interceptor_realloc (/lib/x86_64-linux-gnu/libasan.so.5+0x10dffe)
    #1 0x5555564f396f in bit_chain_alloc_size libredwg/src/bits.c:3046
    #2 0x5555564f396f in bit_chain_alloc libredwg/src/bits.c:3062
    #3 0x31fff  (<unknown module>)
```

# Vulnerability analysis

When running to `bit_copy_chain`, both `dat->chain` and `tmp_dat->chain` point to `0x7ffff3b65800` (see the gdb output below). 

This will lead to use-after-free, since line 3339 calls `realloc`, which frees the chunk `0x7ffff3b65800`, and line 3352 ties to read from the freed chunk. 

Also note that the comment says `bit_copy_chain` *Copy the whole content of tmp_data to dat, and reset tmp_dat*, so why `dat->chain = tmp_dat->chain` in this PoC should be further investigated.

https://github.com/LibreDWG/libredwg/blob/f2dea296a0a3bb16afdae8d2ca16749a617a4383/src/bits.c#L3333-L3360

```
pwndbg> p *dat
$6 = {
  chain = 0x7ffff3b65800,
  size = 208896,
  byte = 204890,
  bit = 6 '\006',
  opts = 1 '\001',
  version = R_2000,
  from_version = R_2004,
  fh = 0x0
}

pwndbg> p *tmp_dat
$10 = {
  chain = 0x7ffff3b65800,
  size = 208896,
  byte = 204882,
  bit = 6 '\006',
  opts = 1 '\001',
  version = R_2000,
  from_version = R_2004,
  fh = 0x0
}
```



Comments:
Comment by rurban on 2022-08-15 08:46:46+00:00:
I think I found some thinkos in the obj_flush_hdlstream logic


---

Comment by rurban on 2023-06-27 10:19:27+00:00:
Fixed with commit 69dcecd2157b467ddffb94c0d01b6d6e0c1b3b62
Author: Reini Urban <rurban@cpan.org>
Date:   Tue Jun 27 11:25:27 2023 +0200

    ACTION_3DSOLID: fix double-free
    
    do not flush the hdlstream 2x. Fixes GH #497

Commit References:
f2dea296a0a3bb16afdae8d2ca16749a617a4383
69dcecd2157b467ddffb94c0d01b6d6e0c1b3b62
e95cc1eea8744c40e298208679eda14039b9b5d3

Build script:
#!/bin/bash -eu
# Minimized build script with only core build commands
set -eu
sh ./autogen.sh
./configure --disable-shared --disable-bindings --enable-release
make -j$(nproc)

Dockerfile:
FROM hwiwonlee/secb.base:latest
RUN apt-get update && apt-get install -y autoconf libtool texinfo
RUN git clone https://github.com/libredwg/libredwg libredwg
RUN git -C libredwg checkout 89c4fa63a01e854eace1855c3d4e33f591df9d16
WORKDIR $SRC/libredwg
COPY build.sh $SRC/

Additional files:
filename: llvmfuzz.options
content: [libfuzzer]
detect_leaks=0