Project: liblouis (liblouis/liblouis), language: c++
Vulnerability instance: liblouis.cve-2023-26767
Sanitizer: address

================= Bug Report (1/1) ==================
## Source: GitHub Issue
## URL: https://github.com/liblouis/liblouis/issues/1292
## Description:
Issue: liblouis/liblouis#1292
Title: global-buffer-overflow in lou_setDataPath() when long path is given
State: closed
Created by: Marsman1996
Created at: 2023-02-04 14:23:04+00:00
Labels: bug, memory error

Issue Body:
When long path is given to API `lou_setDataPath()`, there will be a global-buffer-overflow.

Similar to #1291, because liblouis does not check the input length.

https://github.com/liblouis/liblouis/blob/63722f0428cd4e98d7446658162fb71732d892bb/liblouis/compileTranslationTable.c#L58-L62

## Test Environment
Ubuntu 16.04.3 LTS
liblouis (master, 6223f21)

## How to trigger
1. Compile liblouis with AddressSanitizer
2. Compile the [fuzz driver](https://raw.githubusercontent.com/Marsman1996/pocs/master/liblouis/driver-API-6223f21-lou_setDataPath-BO.c) and [poc file](https://raw.githubusercontent.com/Marsman1996/pocs/master/liblouis/poc-API-6223f21-lou_setDataPath-BO)
3. Compile the fuzz driver: `$ clang -g -fsanitize=address,fuzzer ./driver-API-6223f21-lou_setDataPath-BO.c ./bin_asan/lib/liblouis.a -I ./bin_asan/include/liblouis/ -o driver-API-6223f21-lou_setDataPath-BO`
4. run the compiled driver: `$ ./driver-API-6223f21-lou_setDataPath-BO poc-API-6223f21-lou_setDataPath-BO`

## ASAN report
```
$ ./driver-API-6223f21-lou_setDataPath-BO poc-API-6223f21-lou_setDataPath-BO
Minimum size is 0
INFO: Running with entropic power schedule (0xFF, 100).
INFO: Seed: 1537783897
INFO: Loaded 1 modules   (2848 inline 8-bit counters): 2848 [0x80bf40, 0x80ca60), 
INFO: Loaded 1 PC tables (2848 PCs): 2848 [0x5b9668,0x5c4868), 
./driver-API-6223f21-lou_setDataPath-BO: Running 1 inputs 1 time(s) each.
Running: poc-API-6223f21-lou_setDataPath-BO
=================================================================
==29969==ERROR: AddressSanitizer: global-buffer-overflow on address 0x0000010e85a0 at pc 0x00000050dc38 bp 0x7ffed6135f90 sp 0x7ffed6135750
WRITE of size 4098 at 0x0000010e85a0 thread T0
    #0 0x50dc37 in strcpy /local/mnt/workspace/bcain_clang_vm-bcain-aus_3184/final/llvm-project/compiler-rt/lib/asan/asan_interceptors.cpp:423:5
    #1 0x553af6 in lou_setDataPath /opt/disk/marsman/liblouis/6223f21/build_asan/liblouis/../../code/liblouis/compileTranslationTable.c:62:2
    #2 0x553674 in AFG_func /opt/disk/marsman/liblouis/6223f21/./driver-API-6223f21-lou_setDataPath-BO.c:16:2
    #3 0x553890 in LLVMFuzzerTestOneInput /opt/disk/marsman/liblouis/6223f21/./driver-API-6223f21-lou_setDataPath-BO.c:43:2
    #4 0x459951 in fuzzer::Fuzzer::ExecuteCallback(unsigned char const*, unsigned long) /local/mnt/workspace/bcain_clang_vm-bcain-aus_3184/final/llvm-project/compiler-rt/lib/fuzzer/FuzzerLoop.cpp:599:15
    #5 0x443612 in fuzzer::RunOneTest(fuzzer::Fuzzer*, char const*, unsigned long) /local/mnt/workspace/bcain_clang_vm-bcain-aus_3184/final/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:323:6
    #6 0x449980 in fuzzer::FuzzerDriver(int*, char***, int (*)(unsigned char const*, unsigned long)) /local/mnt/workspace/bcain_clang_vm-bcain-aus_3184/final/llvm-project/compiler-rt/lib/fuzzer/FuzzerDriver.cpp:856:9
    #7 0x473902 in main /local/mnt/workspace/bcain_clang_vm-bcain-aus_3184/final/llvm-project/compiler-rt/lib/fuzzer/FuzzerMain.cpp:20:10
    #8 0x7fdb3926383f in __libc_start_main /build/glibc-S7Ft5T/glibc-2.23/csu/../csu/libc-start.c:291
    #9 0x41e118 in _start (/opt/disk/marsman/liblouis/6223f21/driver-API-6223f21-lou_setDataPath-BO+0x41e118)

0x0000010e85a0 is located 0 bytes to the right of global variable 'dataPath' defined in '../../code/liblouis/compileTranslationTable.c:59:14' (0x10e7da0) of size 2048
SUMMARY: AddressSanitizer: global-buffer-overflow /local/mnt/workspace/bcain_clang_vm-bcain-aus_3184/final/llvm-project/compiler-rt/lib/asan/asan_interceptors.cpp:423:5 in strcpy
Shadow bytes around the buggy address:
  0x000080215060: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x000080215070: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x000080215080: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x000080215090: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0000802150a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0000802150b0: 00 00 00 00[f9]f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
  0x0000802150c0: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
  0x0000802150d0: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
  0x0000802150e0: f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9 f9
  0x0000802150f0: f9 f9 f9 f9 00 f9 f9 f9 f9 f9 f9 f9 04 f9 f9 f9
  0x000080215100: f9 f9 f9 f9 00 00 00 00 00 00 00 00 00 00 00 00
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
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  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
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==29969==ABORTING
```


Comments:
Comment by bertfrees on 2023-02-04 17:34:21+00:00:
Thanks for the report. I think we should consider dropping lou_setDataPath as it seems redundant.

Commit References:
63722f0428cd4e98d7446658162fb71732d892bb

Build script:
#!/bin/bash
# Default build script template for C/C++ projects
set -eu

# Define configuration options
CONFIG_OPTS="--disable-shared"
CMAKE_OPTS="-DCMAKE_BUILD_TYPE=Debug"
MAKE_OPTS="-j$(nproc)"
BUILD_DIR="build"

# 1. Run build preparation scripts if they exist
for prep_script in buildconf autogen.sh bootstrap; do
  if [ -x "$prep_script" ]; then
    echo "Running $prep_script..."
    ./$prep_script
    break
  elif [ -f "$prep_script" ]; then
    echo "Found $prep_script but it's not executable, setting permissions..."
    chmod +x $prep_script
    ./$prep_script
    break
  fi
done

# 2. Handle different build systems
if [ -f "configure" ]; then
  echo "Found configure script, running with options: $CONFIG_OPTS"
  ./configure $CONFIG_OPTS

  echo "Building with make $MAKE_OPTS"
  make $MAKE_OPTS
elif [ -f "CMakeLists.txt" ]; then
  echo "Found CMakeLists.txt, using CMake build system"
  mkdir -p $BUILD_DIR
  cd $BUILD_DIR
  cmake $CMAKE_OPTS ..
  make $MAKE_OPTS
elif [ -f "Makefile" ] || [ -f "makefile" ]; then
  echo "Found Makefile, building with make $MAKE_OPTS"
  make $MAKE_OPTS
elif [ -f "meson.build" ]; then
  echo "Found meson.build, using Meson build system"
  mkdir -p $BUILD_DIR
  meson setup $BUILD_DIR .
  cd $BUILD_DIR
  ninja
elif [ -f "GNUmakefile" ]; then
  echo "Found GNUmakefile, building with make $MAKE_OPTS"
  make $MAKE_OPTS
elif [ -d ".git" ] && [ -f "Makefile.am" ]; then
  echo "Found Makefile.am, running autoreconf"
  autoreconf -i
  ./configure $CONFIG_OPTS
  make $MAKE_OPTS
else
  echo "WARNING: No recognized build system found!"
  echo "Trying generic approach:"
  
  # Try to detect common source patterns and compile them
  if ls *.c >/dev/null 2>&1 || ls *.cpp >/dev/null 2>&1 || ls *.cc >/dev/null 2>&1; then
    echo "Found C/C++ source files, attempting direct compilation"
    if ls *.cpp >/dev/null 2>&1 || ls *.cc >/dev/null 2>&1; then
      CXX=${CXX:-g++}
      echo "Compiling C++ sources with $CXX"
      $CXX -g -O1 -fsanitize=address -fno-omit-frame-pointer -o main *.cpp *.cc 2>/dev/null || true
    elif ls *.c >/dev/null 2>&1; then
      CC=${CC:-gcc}
      echo "Compiling C sources with $CC"
      $CC -g -O1 -fsanitize=address -fno-omit-frame-pointer -o main *.c 2>/dev/null || true
    fi
  fi
fi

Dockerfile:
FROM hwiwonlee/secb.base:latest
RUN apt-get update && apt-get install -y make autoconf automake libtool pkg-config zlib1g-dev libpci-dev
RUN git clone https://github.com/liblouis/liblouis liblouis
RUN git -C liblouis checkout f628d16ab5fb82160e92b07fe4d9ed96fbab325e
WORKDIR $SRC/liblouis
COPY build.sh $SRC/

Additional files: