Bug#1144169: nec2c: stack buffer overflow reading a card line longer than 81 characters

ch <[email protected]>
Newsgroups gmane.linux.debian.devel.ham
Message-ID <1786485872.648631.4190619.nullmailer__1116.89902130223$1786486647$gmane$org@murgatroid.com>
Package: nec2c
Version: 1.3.1-3
Severity: important
Tags: upstream security

main() reads deck lines into an 81-byte buffer, while load_line() fills a
caller's buffer with up to LINE_LEN (132) characters plus a terminator:

  main.c:41   char ain[3], line_buf[81];
  nec2c.h:81  #define LINE_LEN 132
  misc.c      while( num_chr < LINE_LEN ) { buff[num_chr++] = (char)chr; ... }
              buff[num_chr] = '\0';

A card line longer than 81 characters therefore overflows line_buf by up to 52
bytes. A NEC-2 comment card is 80 columns plus its "CM ", so ordinary input
reaches it; no malformed or hostile deck is required.

Reproducer -- a deck whose second CM card is 100 characters. It must not be
the first line, which is read on a different path:

  {
    echo "CM first"
    echo "CM $(printf 'A%.0s' {1..100})"
    echo "CE"
    echo "GW 1 9 0 0 0 0 0 1 0.001"
    echo "GE 0"
    echo "EK"
    echo "EX 0 1 5 0 1.0 0.0"
    echo "FR 0 1 0 0 145.9 0"
    echo "RP 0 3 1 1000 0 0 30 0"
    echo "EN"
  } > t.nec
  nec2c -i t.nec -o t.out

Built from the 1.3.1-3 source with gcc -O0 -g -fsanitize=address:

  ERROR: AddressSanitizer: stack-buffer-overflow
  WRITE of size 1
    #0 load_line misc.c:154
    #1 main      main.c:269
  [1920, 2001) 'line_buf' (line 41) <== Memory access at offset 2001
    overflows this variable

The packaged binary usually does not crash, because main()'s infile[81] and
otfile[81] are adjacent to line_buf and absorb the overrun rather than the
stack canary. That makes it quiet, not harmless: it is an out-of-bounds write
whose length is controlled by the input file.

Severity: this is a local command-line tool reading a file the user chose, so
I have not filed it as a security issue. It would deserve one for any workflow
that feeds it decks from an untrusted source.

Upstream status: upstream git (https://github.com/KJ7LNW/nec2c) widened the
buffer to LINE_LEN in 3d8c230, before tagging v1.3.1. That reduces the
overflow to a single byte but does not remove it -- load_line() still writes
buff[LINE_LEN] into a char[LINE_LEN] -- and I have reported that separately.
There is therefore no released upstream version to upgrade to yet.

Suggested fix, which is sufficient on its own against the 1.3.1-3 source:

  --- a/main.c
  +++ b/main.c
  @@
  -  char ain[3], line_buf[81];
  +  char ain[3], line_buf[LINE_LEN+1];

With that applied, ASan is clean on the reproducer and an over-long line is
rejected rather than corrupting memory.
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.