On Wed, Oct 17, 2018 at 04:20:18PM +0200, ck...@pestilenz.org wrote: > >Synopsis: fmt(1) causes a trap with activated canaries > >Category: system > >Environment: > System : OpenBSD 6.3 > Details : OpenBSD 6.3 (GENERIC) #11: Thu Sep 20 15:53:36 CEST 2018 > > r...@syspatch-63-amd64.openbsd.org:/usr/src/sys/arch/amd64/compile/GENERIC > > Architecture: OpenBSD.amd64 > Machine : amd64 > >Description: > This problem has been found while using fmt(1) to reflow > mail in mutt. The test case has been found with afl. Without > any malloc.conf settings the free() call in fmt will not > cause a trap (of course). But with an activated canary in > malloc.conf it causes a trap. Other inputs may trigger > similar errors, this has been the smallest one I could find. > This has been tested on 6.3 and a -current snapshot of sep > 30th. > >How-To-Repeat: > Create a file t: > 0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 > 00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 > (100 '0's on one line followed by 101 '0's on the second) > > Set the C flag on malloc.conf. > ls -l /etc/malloc.conf > lrwxr-xr-x 1 root wheel 1 Oct 17 15:42 /etc/malloc.conf -> C > > Run 'fmt t' > fmt(39666) in realloc(): chunk canary corrupted 0xfc10db83780 0x64@0x64 > Abort trap > > >Fix: > I have not worked on a fix yet, since I don't know whether > this is a known problem. The error seems to lie in the > canary code, but I am not familiar with it.
The bug is in fmt. If len == length the buf[len] = '\0' statement is an overflow, which happens if the line is exactly 100 chars long. This fixes it, -Otto Index: fmt.c =================================================================== RCS file: /cvs/src/usr.bin/fmt/fmt.c,v retrieving revision 1.38 diff -u -p -r1.38 fmt.c --- fmt.c 20 Feb 2017 15:48:00 -0000 1.38 +++ fmt.c 17 Oct 2018 16:45:57 -0000 @@ -699,6 +699,10 @@ get_line(FILE *stream) } while (len > 0 && isspace((unsigned char)buf[len-1])) --len; + if (len >= length) { + length *= 2; + buf = xrealloc(buf, length); + } buf[len] = '\0'; return (len > 0 || ch != EOF) ? buf : NULL; }