Skip to content

heap overflow in SfxEntry::add when a cross-product prefix shortens the word below the suffix strip length #688

Description

@arshsmith1

aspell expand can overflow the heap when a word is expanded with a cross-product prefix followed by a cross-product suffix whose strip length is longer than the word left after the prefix.

SfxEntry::add (modules/speller/default/affix.cpp) checks the suffix conditions against orig_word but computes the copy length from word:

if ((orig_word.size > stripl) && (orig_word.size >= conds->num)) {
  ...
  if (cond < 0) {
    int alen = word.size - stripl;      // word, not orig_word
    if (alen >= limit) return EMPTY;
    char * newword = (char *)buf.alloc(alen + appndl + 1);
    memcpy(newword, word, alen);
    ...

When a cross-product prefix has already shortened the word, word can be shorter than orig_word. If word.size < stripl, the subtraction wraps (SimpleString::size is unsigned), alen becomes negative, the alen >= limit guard doesn't catch it, buf.alloc gets a tiny size, and memcpy(newword, word, alen) runs with a huge size_t.

Test case

Make a directory repro/ containing a copy of iso-8859-1.cset (from data/) plus these two files:

repro/xx.dat:

name xx
charset iso8859-1
special
soundslike none
affix xx

repro/xx_affix.dat:

SET iso8859-1
PFX A Y 1
PFX A aaaaa b aaaaa

SFX B Y 1
SFX B aaac x aaac

Then run:

echo 'aaaaac/AB' | ./prog/aspell --data-dir=repro --dict-dir=repro --lang=xx expand

With an ASan build this aborts:

AddressSanitizer: negative-size-param: (size=-2) in __asan_memcpy
    #0 __asan_memcpy
    #1 aspeller::SfxEntry::add          affix.cpp:1203
    #2 aspeller::AffixMgr::expand_suffix affix.cpp:939
    #3 aspeller::AffixMgr::expand        affix.cpp:917

Prefix A turns aaaaac into bc (size 2); suffix B has strip length 4; the conditions pass against orig_word aaaaac, so alen = 2 - 4 wraps to a large value.

PR #687 fixes it by bailing out with an empty result when word.size <= stripl, matching the guard PfxEntry::add and SfxEntry::applicable already use. After the patch the same command prints aaaaac bc aax and exits cleanly, and normal expansion (aaaaac/B -> aaaaac aax) is unaffected.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions