Skip to content

Missing Negative Length Validation in _lou_backTranslate Leading to negative-size-param Crash #1984

@FuzzAnything-ORG

Description

@FuzzAnything-ORG

Missing Negative Length Validation in _lou_backTranslate Leading to negative-size-param Crash

Summary

_lou_backTranslate does not validate that *outlen is non-negative before using it in a memset call, causing an AddressSanitizer negative-size-param abort. The symmetric forward-translation function _lou_translate contains the exact guard that is missing here.

Version

$ git describe
v3.34.0-383-g040cc859

Description

In liblouis/lou_backTranslateString.c, the function _lou_backTranslate validates only that pointers are non-NULL (line 212) and that the table loads successfully (line 217). It never checks whether *inlen or *outlen are negative. Execution then reaches line 257:

// lou_backTranslateString.c

/* line 212 – only NULL-pointer check, no value check */
if (tableList == NULL || inbuf == NULL || inlen == NULL || outbuf == NULL ||
        outlen == NULL)
    return 0;
if (displayTableList == NULL) displayTableList = tableList;
_lou_getTable(tableList, displayTableList, &table, &displayTable);
if (table == NULL) return 0;          /* line 217 – no *inlen/*outlen guard here */

/* ... setup code ... */

typebuf = (unsigned char *)typeform;
/* line 257 – crash: *outlen is negative, but passed as size_t to memset */
if (typebuf != NULL) memset(typebuf, 0, *outlen * sizeof(formtype));

When *outlen is a large negative int (e.g. -210865563), the expression *outlen * sizeof(formtype) is evaluated as (int) × (size_t). C integer promotion converts the int to size_t, yielding a huge positive value (-210865563 * 2 = 0xFFFFFFFF974E5F0A on 64-bit), triggering ASAN's negative-size-param detector.

A secondary issue is that getStringBuffer(*outlen) on line 243 is also called with the negative value before the memset is reached, which can corrupt the internal string buffer pool.

The fix already exists in the forward-translation path (lou_translateString.c, line 1198):

/* _lou_translate – has the guard that _lou_backTranslate is missing */
if (table == NULL || *inlen < 0 || *outlen < 0) return 0;  // line 1198

PoC Code

#include <cstddef>
#include <cstdint>
#include "liblouis.h"

static void avoid_log(logLevels level, const char *msg) {
    (void)level;
    (void)msg;
}

static void __attribute__((destructor)) free_resources(void) {
    lou_free();
}

extern "C" int LLVMFuzzerTestOneInput(const uint8_t * /*data*/, size_t /*size*/) {
    lou_registerLogCallback(avoid_log);
    lou_setDataPath("/root/FuzzAgent/output/liblouis/build/sanitizer/share/liblouis/tables");

    const int BUF_SIZE = 256;
    widechar inbuf[BUF_SIZE]      = {};
    widechar outbuf[BUF_SIZE]     = {};
    formtype typeform[BUF_SIZE]   = {};

    for (int i = 0; i < BUF_SIZE; i++)
        inbuf[i] = (widechar)(i % 256);

    // Negative outlen triggers: memset(typebuf, 0, *outlen * sizeof(formtype))
    // with a negative size → AddressSanitizer: negative-size-param
    int inlen  = BUF_SIZE;
    int outlen = -210865563;

    lou_backTranslateString("bg.ctb", inbuf, &inlen, outbuf, &outlen,
                            typeform, nullptr, 0);
    return 0;
}

Reproduction Steps

# You need to modify the lou data path in poc.cpp
clang++ -g -O0 -fsanitize=address,undefined,fuzzer \
    -I<build>/include poc.cpp -o poc \
    -Wl,--start-group <build>/lib/lib*.a -Wl,--end-group

./poc 

Stack Trace

==487961==ERROR: AddressSanitizer: negative-size-param: (size=-421731126)
    #0 0x5c106fba4c6c in __asan_memset (/root/FuzzAgent/output/liblouis/crash_reports/crash_004/poc+0x15ec6c) (BuildId: e5ade6ea74e866ae6f88ce10ff400dbf5ec9c40d)
    #1 0x5c106fc49be7 in _lou_backTranslate /tmp/build_tmp/liblouis/lou_backTranslateString.c:257:23
    #2 0x5c106fc485ce in lou_backTranslate /tmp/build_tmp/liblouis/lou_backTranslateString.c:179:9
    #3 0x5c106fc48520 in lou_backTranslateString /tmp/build_tmp/liblouis/lou_backTranslateString.c:171:9
    #4 0x5c106fbeca0e in LLVMFuzzerTestOneInput /root/FuzzAgent/output/liblouis/crash_reports/crash_004/poc.cpp:37:5

Address 0x7526aac004a0 is located in stack of thread T0 at offset 1184 in frame
    #0 0x5c106fbec407 in LLVMFuzzerTestOneInput /root/FuzzAgent/output/liblouis/crash_reports/crash_004/poc.cpp:20

Suggested Fix

Add the same negative-value guard that already exists in _lou_translate (lou_translateString.c:1198):

--- a/liblouis/lou_backTranslateString.c
+++ b/liblouis/lou_backTranslateString.c
@@ -217,6 +217,7 @@ _lou_backTranslate(...)
 	_lou_getTable(tableList, displayTableList, &table, &displayTable);
 	if (table == NULL) return 0;
+	if (*inlen < 0 || *outlen < 0) return 0;
 
 	if (!_lou_isValidMode(mode))

Signed-off-by: FuzzAnything fuzzanything@gmail.com

Metadata

Metadata

Assignees

No one assigned

    Labels

    memory errorBuffer overflow, use after free, memory leak, ...

    Type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions