Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SEGV; heap-buffer-overflow](lou_checkyaml): index pos out of range (input->chars[pos]) #1532

Open
benehalo opened this issue Mar 15, 2024 · 0 comments
Labels
bug Bug in the code (not in a table) memory error Buffer overflow, use after free, memory leak, ...

Comments

@benehalo
Copy link
Contributor

Dear All,

This bug was found on Ubuntu 20.04 64-bit & liblouis was checked out from master branch of GitHub repository. Its commit is 607d015 (Thu Mar 14 09:14:22 2024 +0100).

liblouis was built with ASAN using clang-14. The compile command was:

cd $BUILD
export FLAGS='-DFORTIFY_SOURCE -fstack-protector-all -fsanitize=address -g'
CC=clang CXX=clang++ CFLAGS=$FLAGS  CXXFLAGS=$FLAGS $PROJ/configure --disable-shared --with-yaml
make -j

To reproduce:
Download and unzip the attached zip archive, and get POCs

$BUILD/tools/lou_checkyaml [poc]

Bug Analysis

The cause of the bug is the lack of proper range checking for the index pos when it is used or obtained. This allows pos to potentially be

An out-of-bounds array index pos might leads to SEGV / heap-buffer-overflow

GDB Analysis

pos < 0

Program received signal SIGSEGV, Segmentation fault.
0x00000000004226d7 in translatePass (table=0x45f1c0, currentPass=2, input=0x7fffffffc8c8, output=0x7fffffffc8b0, posMapping=0x4701f0, realInlen=0x7fffffffc7fc, cursorPosition=0x7fffffffc864, cursorStatus=0x7fffffffc860, mode=0) at ../../liblouis/liblouis/lou_translateString.c:1085
1085                            output->chars[output->length++] = input->chars[pos++];
(gdb) bt
#0  0x00000000004226d7 in translatePass (table=0x45f1c0, currentPass=2, input=0x7fffffffc8c8, output=0x7fffffffc8b0, posMapping=0x4701f0, realInlen=0x7fffffffc7fc, cursorPosition=0x7fffffffc864, cursorStatus=0x7fffffffc860, mode=0) at ../../liblouis/liblouis/lou_translateString.c:1085
#1  0x000000000041f94a in _lou_translate (tableList=0x46e990 "checkyaml_inline_table_at_line_5", displayTableList=0x45a9b0 "checkyaml_inline_table_at_line_3", inbufx=0x45a1c0, inlen=0x7fffffffca10, outbuf=0x45f040, outlen=0x7fffffffca08, typeform=0x0, spacing=0x0, outputPos=0x0, inputPos=0x0, cursorPos=0x7fffffffc9e4, mode=0, rules=0x0, rulesLen=0x0) at ../../liblouis/liblouis/lou_translateString.c:1289
#2  0x000000000041d395 in check_base (tableList=0x46e990 "checkyaml_inline_table_at_line_5", input=0x45a950 "b", expected=0x45a170 "bm\toraeay\tevskcow\t]'ctt", in=...) at ../../liblouis/tools/brl_checks.c:178
#3  0x00000000004050d7 in check_translation (event=..., table=0x46e990 "checkyaml_inline_table_at_line_5", word=0x45a950 "b", translation=0x45a170 "bm\toraeay\tevskcow\t]'ctt", display_table=0x45a9b0 "checkyaml_inline_table_at_line_3", description=0x0, typeform=0x0, mode=(unknown: 0), expected_inputPos=0x0, expected_outputPos=0x0, cursorPos=-1, expected_cursorPos=-1, max_outlen=-1, real_inlen=-1, direction=0, xfail=0) at ../../liblouis/tools/lou_checkyaml.c:783
#4  0x0000000000404855 in read_test (parser=0x7fffffffdbb0, tables=0x7fffffffce60, display_table=0x45a9b0 "checkyaml_inline_table_at_line_3", testmode=2) at ../../liblouis/tools/lou_checkyaml.c:893
#5  0x0000000000403e47 in read_tests (parser=0x7fffffffdbb0, tables=0x7fffffffce60, display_table=0x45a9b0 "checkyaml_inline_table_at_line_3", testmode=2) at ../../liblouis/tools/lou_checkyaml.c:933
#6  0x0000000000402cb8 in main (argc=2, argv=0x7fffffffdea8) at ../../liblouis/tools/lou_checkyaml.c:1129
(gdb) p pos
$14 = -2147479982

pos > input->length

Breakpoint 22, translateString (table=0x630000000400, mode=0, currentPass=1, input=0x7fffffffab20, output=0x7fffffffab60, posMapping=0x627000000100, 
    typebuf=0x623000001d00, srcSpacing=0x0, destSpacing=0x0, wordBuffer=0x621000006500, emphasisBuffer=0x625000007900, haveEmphasis=0, realInlen=0x7fffffffac40, 
    cursorPosition=0x7fffffffaba0, cursorStatus=0x7fffffffabb0, compbrlStart=-1, compbrlEnd=-1) at ../../liblouis/liblouis/lou_translateString.c:3882
3882                                            pos++;
(gdb) list
3877                            } else {
3878                                    for (k = 0; k < transCharslen; k++) {
3879                                            if (!putCharacter(input->chars[pos], table, pos, input, output,
3880                                                                    posMapping, cursorPosition, cursorStatus, mode))
3881                                                    goto failure;
3882                                            pos++;
3883                                    }
3884                            }
3885                            break;
3886                    }
(gdb) p pos
$49 = 396
(gdb) p input->length 
$50 = 397
(gdb) n
3878                                    for (k = 0; k < transCharslen; k++) {
(gdb) p pos
$51 = 397
(gdb) n
3879                                            if (!putCharacter(input->chars[pos], table, pos, input, output,
(gdb) n
=================================================================
==1902934==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61800000079a at pc 0x00000056757d bp 0x7fffffff96f0 sp 0x7fffffff96e8
READ of size 2 at 0x61800000079a thread T0
[Detaching after fork from child process 2262048]
    #0 0x56757c in translateString /data/symccgo/bug/liblouis/obj-asan-dbg/liblouis/../../liblouis/liblouis/lou_translateString.c:3879:24

ASAN says

There are too many different ASAN reports relevant to this bug, here are only two typical reports

AddressSanitizer:DEADLYSIGNAL
=================================================================
==2896314==ERROR: AddressSanitizer: SEGV on unknown address 0x61cfffff5c92 (pc 0x000000571117 bp 0x7ffc96a5bed0 sp 0x7ffc96a5b480 T0)
==2896314==The signal is caused by a READ memory access.
    #0 0x571117 in passDoTest /data/symccgo/bug/liblouis/obj-asan-dbg/liblouis/../../liblouis/liblouis/lou_translateString.c:807:9
    #1 0x56f234 in findForPassRule /data/symccgo/bug/liblouis/obj-asan-dbg/liblouis/../../liblouis/liblouis/lou_translateString.c:211:7
    #2 0x57ebc9 in passSelectRule /data/symccgo/bug/liblouis/obj-asan-dbg/liblouis/../../liblouis/liblouis/lou_translateString.c:1029:7
    #3 0x56b158 in translatePass /data/symccgo/bug/liblouis/obj-asan-dbg/liblouis/../../liblouis/liblouis/lou_translateString.c:1059:4
    #4 0x55ccc8 in _lou_translate /data/symccgo/bug/liblouis/obj-asan-dbg/liblouis/../../liblouis/liblouis/lou_translateString.c:1289:16
    #5 0x55517a in check_base /data/symccgo/bug/liblouis/obj-asan-dbg/tools/../../liblouis/tools/brl_checks.c:178:17
    #6 0x501600 in check_translation /data/symccgo/bug/liblouis/obj-asan-dbg/tools/../../liblouis/tools/lou_checkyaml.c:783:6
    #7 0x4ff8af in read_test /data/symccgo/bug/liblouis/obj-asan-dbg/tools/../../liblouis/tools/lou_checkyaml.c:893:4
    #8 0x4fd2c1 in read_tests /data/symccgo/bug/liblouis/obj-asan-dbg/tools/../../liblouis/tools/lou_checkyaml.c:933:4
    #9 0x4f9ed2 in main /data/symccgo/bug/liblouis/obj-asan-dbg/tools/../../liblouis/tools/lou_checkyaml.c:1129:5
    #10 0x7fbd882ed082 in __libc_start_main /build/glibc-SzIz7B/glibc-2.31/csu/../csu/libc-start.c:308:16
    #11 0x41c3bd in _start (/data/symccgo/bug/liblouis/obj-asan-dbg/tools/lou_checkyaml+0x41c3bd)

AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV /data/symccgo/bug/liblouis/obj-asan-dbg/liblouis/../../liblouis/liblouis/lou_translateString.c:807:9 in passDoTest
==2896314==ABORTING
=================================================================
==1902934==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x61800000079a at pc 0x00000056757d bp 0x7fffffff96f0 sp 0x7fffffff96e8
READ of size 2 at 0x61800000079a thread T0
[Detaching after fork from child process 2262048]
    #0 0x56757c in translateString /data/symccgo/bug/liblouis/obj-asan-dbg/liblouis/../../liblouis/liblouis/lou_translateString.c:3879:24
    #1 0x55cc42 in _lou_translate /data/symccgo/bug/liblouis/obj-asan-dbg/liblouis/../../liblouis/liblouis/lou_translateString.c:1282:16
    #2 0x55517a in check_base /data/symccgo/bug/liblouis/obj-asan-dbg/tools/../../liblouis/tools/brl_checks.c:178:17
    #3 0x501600 in check_translation /data/symccgo/bug/liblouis/obj-asan-dbg/tools/../../liblouis/tools/lou_checkyaml.c:783:6
    #4 0x4ff8af in read_test /data/symccgo/bug/liblouis/obj-asan-dbg/tools/../../liblouis/tools/lou_checkyaml.c:893:4
    #5 0x4fd2c1 in read_tests /data/symccgo/bug/liblouis/obj-asan-dbg/tools/../../liblouis/tools/lou_checkyaml.c:933:4
    #6 0x4f9ed2 in main /data/symccgo/bug/liblouis/obj-asan-dbg/tools/../../liblouis/tools/lou_checkyaml.c:1129:5
    #7 0x7ffff7c2e082 in __libc_start_main /build/glibc-SzIz7B/glibc-2.31/csu/../csu/libc-start.c:308:16
    #8 0x41c3bd in _start (/data/symccgo/bug/liblouis/obj-asan-dbg/tools/lou_checkyaml+0x41c3bd)

0x61800000079a is located 0 bytes to the right of 794-byte region [0x618000000480,0x61800000079a)
allocated by thread T0 here:
    #0 0x4c1f2f in malloc /llvm-project/compiler-rt/lib/asan/asan_malloc_linux.cpp:145:3
    #1 0x55480f in check_base /data/symccgo/bug/liblouis/obj-asan-dbg/tools/../../liblouis/tools/brl_checks.c:136:10
    #2 0x501600 in check_translation /data/symccgo/bug/liblouis/obj-asan-dbg/tools/../../liblouis/tools/lou_checkyaml.c:783:6
    #3 0x4ff8af in read_test /data/symccgo/bug/liblouis/obj-asan-dbg/tools/../../liblouis/tools/lou_checkyaml.c:893:4
    #4 0x4fd2c1 in read_tests /data/symccgo/bug/liblouis/obj-asan-dbg/tools/../../liblouis/tools/lou_checkyaml.c:933:4
    #5 0x4f9ed2 in main /data/symccgo/bug/liblouis/obj-asan-dbg/tools/../../liblouis/tools/lou_checkyaml.c:1129:5
    #6 0x7ffff7c2e082 in __libc_start_main /build/glibc-SzIz7B/glibc-2.31/csu/../csu/libc-start.c:308:16

SUMMARY: AddressSanitizer: heap-buffer-overflow /data/symccgo/bug/liblouis/obj-asan-dbg/liblouis/../../liblouis/liblouis/lou_translateString.c:3879:24 in translateString
Shadow bytes around the buggy address:
  0x0c307fff80a0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c307fff80b0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c307fff80c0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c307fff80d0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x0c307fff80e0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x0c307fff80f0: 00 00 00[02]fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c307fff8100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c307fff8110: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c307fff8120: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c307fff8130: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
  0x0c307fff8140: 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
  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
==1902934==ABORTING

POC

attached zip archive

@egli egli added bug Bug in the code (not in a table) memory error Buffer overflow, use after free, memory leak, ... labels Mar 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Bug in the code (not in a table) memory error Buffer overflow, use after free, memory leak, ...
Projects
None yet
Development

No branches or pull requests

2 participants