On Wed, Oct 17, 2018 at 04:20:18PM +0200, [email protected] 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
>
> [email protected]:/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;
}