My previous report for col(1) was wrong.  I described a signed
integer overflow in the counting sort, but the actual bug is a
null pointer dereference in flush_lines().

Apologies for the confusion.  Corrected report follows.

The flush_lines() function dereferences a null pointer when
nflush exceeds the number of available lines.

At col.c:325-326:

  l = lines;
  lines = l->l_next;

A reverse line feed (vertical tab, \v) near the start of input
causes extra lines to be allocated before the first line.  When
these extra lines are later flushed, the line list is exhausted
before nflush reaches zero, leaving lines == NULL.

The 5-byte input "1\v2\n\n" reproduces the crash.

Confirmed with UBSan on OpenBSD 7.9/amd64 and 7.9/i386:

  ubsan: type-mismatch by 0x...
  Abort trap (core dumped)

Also confirmed with SIGSEGV on the system binary on OpenBSD
7.8/arm64, 7.9/i386, and 7.9/amd64.

Fix: check for NULL before dereferencing.

Found by AFL++ fuzzing.

Index: usr.bin/col/col.c
===================================================================
RCS file: /cvs/src/usr.bin/col/col.c,v
retrieving revision 1.20
diff -u -p -r1.20 col.c
--- usr.bin/col/col.c   4 Dec 2022 23:50:47 -0000       1.20
+++ usr.bin/col/col.c
@@ -322,7 +322,8 @@ flush_lines(int nflush)
        LINE *l;

        while (--nflush >= 0) {
-               l = lines;
+               if ((l = lines) == NULL)
+                       break;
                lines = l->l_next;
                if (l->l_line) {
                        flush_blanks();

Reply via email to