public inbox for glibc-bugs@sourceware.org
help / color / mirror / Atom feed
* [Bug libc/4977] New: SEGV in strlen() of string argument of vsnprintf call on RHEL WS3/64-bit
@ 2007-08-29 15:29 timp at pulsic dot com
  2007-08-29 15:40 ` [Bug libc/4977] " jakub at redhat dot com
                   ` (4 more replies)
  0 siblings, 5 replies; 6+ messages in thread
From: timp at pulsic dot com @ 2007-08-29 15:29 UTC (permalink / raw)
  To: glibc-bugs

As per summary, a call to vsnprintf such as

vsnprintf( buf, nchar, fmt, ap )

where the va_list 'ap' has a C string argument is causing a SEGV in the strlen.
Typical stack

Program received signal SIGSEGV, Segmentation fault.
0x0000002a95707290 in strlen () from /lib64/tls/libc.so.6
(gdb) bt
#0  0x0000002a95707290 in strlen () from /lib64/tls/libc.so.6
#1  0x0000002a956d45b0 in vfprintf () from /lib64/tls/libc.so.6
#2  0x0000002a956f8949 in vsnprintf () from /lib64/tls/libc.so.6

Source code for a trivial reproducible case below, compiled on (uname -a)

Linux hpopteron 2.4.21-50.ELsmp #1 SMP Tue May 8 17:10:20 EDT 2007 x86_64 x86_64
x86_64 GNU/Linux

with

gcc --std=c9x -Wall -pedantic -g -o vsn vsn.c

using

gcc (GCC) 3.2.3 20030502 (Red Hat Linux 3.2.3-59)
GNU C Library stable release version 2.3.2, by Roland McGrath et al.

Run as

./vsn "foo"

Code follows 

---------------------%<------------------------
#include <stdio.h>
#include <stdarg.h>
#include <malloc.h>

int vssprintf
(
 char **	userBufPtr,
 const char *	format,
 va_list 	ap
)
{
    if( userBufPtr )
    {
	/* see how many formatted characters there are to process,
	 * this should work even if the format is "" or equivalent
	 * eg. ( "%s", "" ) */
	int nchar = vsnprintf( NULL, 0, format, ap ) + 1;
	char * bufPtr = (char *)malloc( nchar );

	nchar = vsnprintf( bufPtr, nchar, format, ap );

	*userBufPtr = bufPtr ; 
	return( nchar );
    }
    /* IO errors in system ..printf() funtions should normally trigger the
     * return of a negative number (e.g. in ANSI / ISO C) - do the same here */
    return -1 ;
}

int ssprintf
(
 char **	userBufPtr,
 const char *	format,
 ... 
)
{
    int	nchar = -1 ;
    if( userBufPtr )
    {
	va_list	ap;

	/* Unravel the format, args, ... into a buffer */
	va_start( ap, format );

	nchar = vssprintf( userBufPtr, format, ap );

	/* Clean up */
	va_end(ap);
    }

    return( nchar );
}


int main( int argc, char *argv[] )
{
    int n = 0 ;
    if( argc > 1 )
    {
	char * buf ;
	n = ssprintf( &buf, "Hello %s !\n", argv[1] );
	fprintf( stderr, "Printed %d characters from va_list\n", n ) ;
	n = printf( "%s\n", buf ) ;
    }
    return n ;
}
---------------------%<------------------------

Under Valgrind I get the following stack

--2099-- Reading syms from
/usr/local/lib/valgrind/amd64-linux/vgpreload_memcheck.so (0x4A17000)
--2099-- REDIR: 0x40101A0 (index) redirected to 0x4A1A7E0 (index)
--2099-- REDIR: 0x4010350 (strcmp) redirected to 0x4A1AC80 (strcmp)
--2099-- REDIR: 0x4010380 (strlen) redirected to 0x4A1AA10 (strlen)
--2099-- Reading syms from /lib64/tls/libc-2.3.2.so (0x4B1D000)
--2099-- REDIR: 0x4B9B620 (rindex) redirected to 0x4A1A700 (rindex)
--2099-- REDIR: 0x4B9B280 (strlen) redirected to 0x4A1A9D0 (strlen)
--2099-- REDIR: 0x4B93540 (malloc) redirected to 0x4A18C6F (malloc)
==2099== Invalid read of size 1
==2099==    at 0x4A1A9D2: strlen (mac_replace_strmem.c:243)
==2099==    by 0x4B685AF: vfprintf (in /lib64/tls/libc-2.3.2.so)
==2099==    by 0x4B8C948: vsnprintf (in /lib64/tls/libc-2.3.2.so)
==2099==    by 0x400600: vssprintf (vsn.c:20)
==2099==    by 0x40070A: ssprintf (vsn.c:45)
==2099==    by 0x400752: main (vsn.c:61)
==2099==  Address 0x2 is not stack'd, malloc'd or (recently) free'd
==2099== 
==2099== Process terminating with default action of signal 11 (SIGSEGV)
==2099==  Access not within mapped region at address 0x2
==2099==    at 0x4A1A9D2: strlen (mac_replace_strmem.c:243)
==2099==    by 0x4B685AF: vfprintf (in /lib64/tls/libc-2.3.2.so)
==2099==    by 0x4B8C948: vsnprintf (in /lib64/tls/libc-2.3.2.so)
==2099==    by 0x400600: vssprintf (vsn.c:20)
==2099==    by 0x40070A: ssprintf (vsn.c:45)
==2099==    by 0x400752: main (vsn.c:61)
--2099-- REDIR: 0x4B93710 (free) redirected to 0x4A197E1 (free)
--2099-- REDIR: 0x4B9CEA0 (memset) redirected to 0x4A1B140 (memset)
==2099== 
==2099== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 3 from 2)
==2099== 
==2099== 1 errors in context 1 of 1:
==2099== Invalid read of size 1
==2099==    at 0x4A1A9D2: strlen (mac_replace_strmem.c:243)
==2099==    by 0x4B685AF: vfprintf (in /lib64/tls/libc-2.3.2.so)
==2099==    by 0x4B8C948: vsnprintf (in /lib64/tls/libc-2.3.2.so)
==2099==    by 0x400600: vssprintf (vsn.c:20)
==2099==    by 0x40070A: ssprintf (vsn.c:45)
==2099==    by 0x400752: main (vsn.c:61)
==2099==  Address 0x2 is not stack'd, malloc'd or (recently) free'd
--2099-- 
--2099-- supp:    1 strlen-not-intercepted-early-enough-HACK-5
--2099-- supp:    2 dl_relocate_object
==2099== 
==2099== IN SUMMARY: 1 errors from 1 contexts (suppressed: 3 from 2)
==2099== 
==2099== malloc/free: in use at exit: 13 bytes in 1 blocks.
==2099== malloc/free: 1 allocs, 0 frees, 13 bytes allocated.
==2099== 

.............

Looks like strlen() is being given duff info. Quick Google reveals similar
bug/stack seen reported under Nessus, gnash and Firefly forums this year.
Reproduced on

- SuSE 10.1 / 64-bit platform (no details)

- RHEL WS4/64
gcc (GCC) 3.4.6 20060404 (Red Hat 3.4.6-3)
Linux tornado 2.6.9-42.EL #1 Tue Aug 15 09:30:48 BST 2006 x86_64 x86_64 x86_64
GNU/Linux
GNU C Library stable release version 2.3.4, by Roland McGrath et al.


Cheers
Tim

-- 
           Summary: SEGV in strlen() of string argument of vsnprintf call on
                    RHEL WS3/64-bit
           Product: glibc
           Version: unspecified
            Status: NEW
          Severity: critical
          Priority: P2
         Component: libc
        AssignedTo: drepper at redhat dot com
        ReportedBy: timp at pulsic dot com
                CC: glibc-bugs at sources dot redhat dot com


http://sourceware.org/bugzilla/show_bug.cgi?id=4977

------- You are receiving this mail because: -------
You are on the CC list for the bug, or are watching someone who is.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Bug libc/4977] SEGV in strlen() of string argument of vsnprintf call on RHEL WS3/64-bit
  2007-08-29 15:29 [Bug libc/4977] New: SEGV in strlen() of string argument of vsnprintf call on RHEL WS3/64-bit timp at pulsic dot com
@ 2007-08-29 15:40 ` jakub at redhat dot com
  2007-08-29 15:58 ` timp at pulsic dot com
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: jakub at redhat dot com @ 2007-08-29 15:40 UTC (permalink / raw)
  To: glibc-bugs


------- Additional Comments From jakub at redhat dot com  2007-08-29 15:40 -------
The testcase is invalid.
Please read http://www.opengroup.org/onlinepubs/009695399/basedefs/stdarg.h.html
carefully.
Particularly you are missing va_copy and another va_end.

-- 
           What    |Removed                     |Added
----------------------------------------------------------------------------
             Status|NEW                         |RESOLVED
         Resolution|                            |INVALID


http://sourceware.org/bugzilla/show_bug.cgi?id=4977

------- You are receiving this mail because: -------
You are on the CC list for the bug, or are watching someone who is.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Bug libc/4977] SEGV in strlen() of string argument of vsnprintf call on RHEL WS3/64-bit
  2007-08-29 15:29 [Bug libc/4977] New: SEGV in strlen() of string argument of vsnprintf call on RHEL WS3/64-bit timp at pulsic dot com
  2007-08-29 15:40 ` [Bug libc/4977] " jakub at redhat dot com
@ 2007-08-29 15:58 ` timp at pulsic dot com
  2007-08-29 16:10 ` jakub at redhat dot com
                   ` (2 subsequent siblings)
  4 siblings, 0 replies; 6+ messages in thread
From: timp at pulsic dot com @ 2007-08-29 15:58 UTC (permalink / raw)
  To: glibc-bugs


------- Additional Comments From timp at pulsic dot com  2007-08-29 15:58 -------
(In reply to comment #1)
> The testcase is invalid.
> Please read http://www.opengroup.org/onlinepubs/009695399/basedefs/stdarg.h.html
> carefully.

Agh - stupidity hits. Thanks for the link - I guess this means passing the
va_list as a function parameter is highly implementation specific and will
potentially be unavailable on some systems (e.g. HP-UX 11i even with recent
compilers has no va_copy) or with no c9x compliant compilers.

> Particularly you are missing va_copy and another va_end.

yep - on C99 systems. That went past a few of us, should have realised.

Cheers
tim


-- 


http://sourceware.org/bugzilla/show_bug.cgi?id=4977

------- You are receiving this mail because: -------
You are on the CC list for the bug, or are watching someone who is.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Bug libc/4977] SEGV in strlen() of string argument of vsnprintf call on RHEL WS3/64-bit
  2007-08-29 15:29 [Bug libc/4977] New: SEGV in strlen() of string argument of vsnprintf call on RHEL WS3/64-bit timp at pulsic dot com
  2007-08-29 15:40 ` [Bug libc/4977] " jakub at redhat dot com
  2007-08-29 15:58 ` timp at pulsic dot com
@ 2007-08-29 16:10 ` jakub at redhat dot com
  2007-08-29 16:34 ` timp at pulsic dot com
  2007-08-29 16:41 ` jakub at redhat dot com
  4 siblings, 0 replies; 6+ messages in thread
From: jakub at redhat dot com @ 2007-08-29 16:10 UTC (permalink / raw)
  To: glibc-bugs


------- Additional Comments From jakub at redhat dot com  2007-08-29 16:10 -------
Passing it once to some function is just fine.  What your testcase does
wrong is passing the same va_list object to another function, while the standards
say that if you pass it to some function and that function uses va_arg on it,
then the object can be only passed to va_end, nothing else.
On some architectures it can work even multiple times, that's mainly
architectures which define va_list as a pointer (e.g. i386), but note
that doing so is highly unportable.  On other architectures, va_list as is
a one element array containing some structure (e.g. x86_64).  If you pass
that to some function, you just pass its address to it, the object actually
resides in the function which invoked va_start or va_copy, if their argument
is an automatic va_list variable.  So, the first vsnprintf will modify that
va_list object to point after all arguments it consumed and when you call
vsnprintf again with the same va_list (== the same address of some automatic
struct), it will start looking at garbage.

-- 


http://sourceware.org/bugzilla/show_bug.cgi?id=4977

------- You are receiving this mail because: -------
You are on the CC list for the bug, or are watching someone who is.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Bug libc/4977] SEGV in strlen() of string argument of vsnprintf call on RHEL WS3/64-bit
  2007-08-29 15:29 [Bug libc/4977] New: SEGV in strlen() of string argument of vsnprintf call on RHEL WS3/64-bit timp at pulsic dot com
                   ` (2 preceding siblings ...)
  2007-08-29 16:10 ` jakub at redhat dot com
@ 2007-08-29 16:34 ` timp at pulsic dot com
  2007-08-29 16:41 ` jakub at redhat dot com
  4 siblings, 0 replies; 6+ messages in thread
From: timp at pulsic dot com @ 2007-08-29 16:34 UTC (permalink / raw)
  To: glibc-bugs


------- Additional Comments From timp at pulsic dot com  2007-08-29 16:34 -------
(In reply to comment #3)
> Passing it once to some function is just fine.  What your testcase does
> wrong is passing the same va_list object to another function, while the standards
> say that if you pass it to some function and that function uses va_arg on it,
> then the object can be only passed to va_end, nothing else.
> On some architectures it can work even multiple times, 

yep - that's what I was alluding too - poor language on my part 

> that's mainly
> architectures which define va_list as a pointer (e.g. i386), but note
> that doing so is highly unportable.  

indeed - it's one thing that I hadn't fully appreciated until now

> On other architectures, va_list as is
> a one element array containing some structure (e.g. x86_64).  If you pass
> that to some function, you just pass its address to it, the object actually
> resides in the function which invoked va_start or va_copy, if their argument
> is an automatic va_list variable.  So, the first vsnprintf will modify that
> va_list object to point after all arguments it consumed and when you call
> vsnprintf again with the same va_list (== the same address of some automatic
> struct), it will start looking at garbage.

ah - I've just realised that I missed the requirement for the va_end after the
first vsnprintf() from my reading of the specification - thanks for the
clarification. As with many things, now that it's been pointed out to me, it
does seem  obvious :)

I sit enlightened.
Cheers Jakub

Tim


-- 


http://sourceware.org/bugzilla/show_bug.cgi?id=4977

------- You are receiving this mail because: -------
You are on the CC list for the bug, or are watching someone who is.


^ permalink raw reply	[flat|nested] 6+ messages in thread

* [Bug libc/4977] SEGV in strlen() of string argument of vsnprintf call on RHEL WS3/64-bit
  2007-08-29 15:29 [Bug libc/4977] New: SEGV in strlen() of string argument of vsnprintf call on RHEL WS3/64-bit timp at pulsic dot com
                   ` (3 preceding siblings ...)
  2007-08-29 16:34 ` timp at pulsic dot com
@ 2007-08-29 16:41 ` jakub at redhat dot com
  4 siblings, 0 replies; 6+ messages in thread
From: jakub at redhat dot com @ 2007-08-29 16:41 UTC (permalink / raw)
  To: glibc-bugs


------- Additional Comments From jakub at redhat dot com  2007-08-29 16:40 -------
Last note:
Each invocation of the va_start() and va_copy() macros shall be matched by a
corresponding invocation of the va_end() macro in the same function.
just to be sure.
The current va_end() is fine, all you need to add
va_list ap2;
va_copy (ap2, ap);
before the first vsnprintf call, change second (or first, doesn't matter which
one if just one) vsnprintf call to use ap2 instead and add
va_end (ap2);
after that call.

-- 


http://sourceware.org/bugzilla/show_bug.cgi?id=4977

------- You are receiving this mail because: -------
You are on the CC list for the bug, or are watching someone who is.


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2007-08-29 16:41 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2007-08-29 15:29 [Bug libc/4977] New: SEGV in strlen() of string argument of vsnprintf call on RHEL WS3/64-bit timp at pulsic dot com
2007-08-29 15:40 ` [Bug libc/4977] " jakub at redhat dot com
2007-08-29 15:58 ` timp at pulsic dot com
2007-08-29 16:10 ` jakub at redhat dot com
2007-08-29 16:34 ` timp at pulsic dot com
2007-08-29 16:41 ` jakub at redhat dot com

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).