Bug 23521

Summary: NULL pointer write in vfprintf code
Product: Base System Reporter: luddes <luddes>
Component: miscAssignee: freebsd-bugs (Nobody) <bugs>
Status: Closed FIXED    
Severity: Affects Only Me    
Priority: Normal    
Version: Unspecified   
Hardware: Any   
OS: Any   

Description luddes 2000-12-13 13:20:01 UTC
This code crashes because of a NULL pointer write inside the vfprintf code.
It should print the 8th argument as an integer.
printf("%8$d", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);

GDB output:
0x280d49e0 in vfprintf () from /usr/lib/libc.so.4
(gdb) x/i $eip
0x280d49e0 <vfprintf+10028>:    mov    %eax,(%edx)
(gdb) info reg edx
edx            0x0      0

Fix: 

Perhaps the memory allocation failure is at:
if (tablemax >= STATIC_ARG_TBL_SIZE) {
        *argtable = (void **)
                malloc (sizeof (void *) * (tablemax + 1));
}
How-To-Repeat: Compile a C program with this contents:
int main() {
    printf("%8$d", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
}
and run it
Comment 1 Peter Pentchev 2000-12-14 15:16:05 UTC
On Wed, Dec 13, 2000 at 05:19:51AM -0800, luddes@hotmail.com wrote:
> 
> >Number:         23521
> >Category:       misc
> >Synopsis:       NULL pointer write in vfprintf code
> >Originator:     Ludde
> >Release:        4.1.1
> >Environment:
> FreeBSD matchbox.dumle.nu 4.1.1-RELEASE FreeBSD 4.1.1-RELEASE #3: Wed Dec  6 19:34:33 CET 2000     root@matchbox.dumle.nu:/usr/src/sys/compile/MATCHBOX  i386
> >Description:
> This code crashes because of a NULL pointer write inside the vfprintf code.
> It should print the 8th argument as an integer.
> printf("%8$d", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
> 
> GDB output:
> 0x280d49e0 in vfprintf () from /usr/lib/libc.so.4
> (gdb) x/i $eip
> 0x280d49e0 <vfprintf+10028>:    mov    %eax,(%edx)
> (gdb) info reg edx
> edx            0x0      0
> >How-To-Repeat:
> Compile a C program with this contents:
> int main() {
>     printf("%8$d", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
> }
> and run it
> >Fix:
> Perhaps the memory allocation failure is at:
> if (tablemax >= STATIC_ARG_TBL_SIZE) {
>         *argtable = (void **)
>                 malloc (sizeof (void *) * (tablemax + 1));
> }

For the record, I can 'reliably' duplicate this.  It always happens on
%8$ or above; up to 7 works fine.  The following test program:

#include <stdio.h>

int main(void) {

  printf("%5$d\n", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14);
  printf("%6$d\n", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14);
  printf("%7$d\n", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14);
  printf("%8$d\n", 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14);
  /* notreached :( */
  return 0;
}

..produces the following result:

[roam@ringworld:v4 ~/c/misc/foo]$ ./foo
5
6
7
Segmentation fault (core dumped)
[roam@ringworld:v4 ~/c/misc/foo]$

..no matter what combination of -g*, -O* and -f* options I compile it with.
  
I've tested this on RELENG_4 and -current, both as of Dec 11, and the result
was identical.

G'luck,
Peter

-- 
What would this sentence be like if pi were 3?
Comment 2 Mark Peek 2000-12-19 15:53:44 UTC
The bug is due to code in __grow_type_table() trashing the stack from
calling memset() with the wrong address. The patch below should fix the
problem.

Note: it was interesting that the original vfprintf() code didn't crash
when compiled with just "-g" but "-g -O" crashed it just fine.

Mark


Index: vfprintf.c
===================================================================
RCS file: /cvs/freebsd/src/lib/libc/stdio/vfprintf.c,v
retrieving revision 1.22
diff -u -r1.22 vfprintf.c
--- vfprintf.c	1999/08/28 00:01:20	1.22
+++ vfprintf.c	2000/12/18 03:50:48
@@ -1191,7 +1191,7 @@
 		    reallocf (typetable, sizeof (unsigned char) * newsize);

 	}
-	memset (&typetable [*tablesize], T_UNUSED, (newsize - *tablesize));
+	memset (*typetable + *tablesize, T_UNUSED, (newsize - *tablesize));

 	*tablesize = newsize;
 }
Comment 3 Archie Cobbs freebsd_committer freebsd_triage 2001-01-10 17:40:54 UTC
State Changed
From-To: open->closed

Fixed in versions 1.23 (HEAD) and 1.22.2.1 (RELENG_4).