Bug 512689 - gcc sigabort flexible array mebers in union with fortify source
Summary: gcc sigabort flexible array mebers in union with fortify source
Keywords:
Status: CLOSED NOTABUG
Alias: None
Product: Fedora
Classification: Fedora
Component: gcc
Version: rawhide
Hardware: All
OS: Linux
high
medium
Target Milestone: ---
Assignee: Jakub Jelinek
QA Contact: Fedora Extras Quality Assurance
URL:
Whiteboard:
Depends On:
Blocks: 511520
TreeView+ depends on / blocked
 
Reported: 2009-07-20 11:54 UTC by Nikola Pajkovsky
Modified: 2014-02-02 22:13 UTC (History)
3 users (show)

Fixed In Version:
Doc Type: Bug Fix
Doc Text:
Clone Of:
Environment:
Last Closed: 2009-08-05 12:43:24 UTC
Type: ---


Attachments (Terms of Use)

Description Nikola Pajkovsky 2009-07-20 11:54:15 UTC
gcc with FORTIFY_SOURCES think that code can be exploited by buffer overflow.
But that not true. This piece of code is known as Flexible Array Members. It's extension in gcc and without FORTIFY_SOURCE is everything fine. You can try valgrind. No memory leak and even overwriting memory.

Version:
gcc version 4.4.0 20090623 (Red Hat 4.4.0-10) (GCC)


Steps to Reproduce:
1. make new file with this code
$ cat fam.c 
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    int n;
    union {
        int d;
        char string[1];
    }u;
}fam_t;

int main( void )
{

    char test_string[] = "Toto je testovaci string.";


    size_t size = 0;
    size = sizeof( fam_t ) + (strlen(test_string)-1)*sizeof(char);

    fam_t* fam = NULL;
    fam = (fam_t*)malloc(size);
    strcpy( fam->u.string, test_string );
    fam->n = size;
    printf("%i\t%s\n", fam->n, fam->u.string);

    free(fam);

    return 0;
}
2. compile
$ gcc -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -o fam fam.c

3. run it
  
Actual results:
*** buffer overflow detected ***: ./fam terminated
======= Backtrace: =========
/lib64/libc.so.6(__fortify_fail+0x37)[0x3ffb4f7537]
/lib64/libc.so.6[0x3ffb4f5590]
./fam[0x4006fa]
/lib64/libc.so.6(__libc_start_main+0xfd)[0x3ffb41ea2d]
./fam[0x400579]
======= Memory map: ========
00400000-00401000 r-xp 00000000 08:02 5959039                            /home/npajkovs/src/flexible-array-members/fam
00600000-00601000 rw-p 00000000 08:02 5959039                            /home/npajkovs/src/flexible-array-members/fam
01c79000-01c9a000 rw-p 00000000 00:00 0                                  [heap]
32f3000000-32f301a000 r-xp 00000000 08:01 3068191                        /lib64/libgcc_s-4.4.0-20090623.so.1
32f301a000-32f3219000 ---p 0001a000 08:01 3068191                        /lib64/libgcc_s-4.4.0-20090623.so.1
32f3219000-32f321a000 rw-p 00019000 08:01 3068191                        /lib64/libgcc_s-4.4.0-20090623.so.1
3ffb000000-3ffb01f000 r-xp 00000000 08:01 3068302                        /lib64/ld-2.10.1.so
3ffb21e000-3ffb21f000 r--p 0001e000 08:01 3068302                        /lib64/ld-2.10.1.so
3ffb21f000-3ffb220000 rw-p 0001f000 08:01 3068302                        /lib64/ld-2.10.1.so
3ffb400000-3ffb564000 r-xp 00000000 08:01 3068629                        /lib64/libc-2.10.1.so
3ffb564000-3ffb764000 ---p 00164000 08:01 3068629                        /lib64/libc-2.10.1.so
3ffb764000-3ffb768000 r--p 00164000 08:01 3068629                        /lib64/libc-2.10.1.so
3ffb768000-3ffb769000 rw-p 00168000 08:01 3068629                        /lib64/libc-2.10.1.so
3ffb769000-3ffb76e000 rw-p 00000000 00:00 0 
7fb68e72c000-7fb68e72e000 rw-p 00000000 00:00 0 
7fb68e74b000-7fb68e74d000 rw-p 00000000 00:00 0 
7fff313ac000-7fff313c1000 rw-p 00000000 00:00 0                          [stack]
7fff313ff000-7fff31400000 r-xp 00000000 00:00 0                          [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0                  [vsyscall]
Neúspěšně ukončen (SIGABRT)


Expected results:
print on stdout message:
59	This is a testing string for flexible array members.

Comment 1 Jakub Jelinek 2009-07-24 09:32:38 UTC
gcc-4.4.0-15 and later in rawhide should allow this.

Comment 2 Adam Goode 2009-08-05 01:03:05 UTC
This is still failing for htmldoc. Here is a modified fam.c, with a structure that is failing in htmldoc (from ps-pdf.cxx):


#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct render_str		/**** Render entity structure ****/
{
  struct render_str	*prev;		/* Previous rendering entity */
  struct render_str	*next;		/* Next rendering entity */
  int	type;				/* Type of entity */
  float	x,				/* Position in points */
	y,				/* ... */
	width,				/* Size in points */
	height;				/* ... */
  union
  {
    struct
    {
      int	typeface,		/* Typeface for text */
		style;			/* Style of text */
      float	size;			/* Size of text in points */
      float	spacing;		/* Inter-character spacing */
      float	rgb[3];			/* Color of text */
      unsigned char	buffer[1];		/* String buffer */
    }   	text;
    void	*image;			/* Image pointer */
    float	box[3];			/* Box color */
    unsigned char	link[1];		/* Link URL */
  }	data;
} fam_t;

int main( void )
{

    char test_string[] = "Toto je testovaci string.";


    size_t size = 0;
    size = sizeof( fam_t ) + (strlen(test_string)-1)*sizeof(char);

    fam_t* fam = NULL;
    fam = (fam_t*)malloc(size);
    strcpy( fam->data.text.buffer, test_string );
    printf("%s\n", fam->data.text.buffer);

    free(fam);

    return 0;
}

Comment 3 Jakub Jelinek 2009-08-05 07:15:17 UTC
That's nested too much, sorry, this isn't going to work with -D_FORTIFY_SOURCE=2.
Either build with -D_FORTIFY_SOURCE=1, or rearrange the struct.

Comment 4 Jakub Jelinek 2009-08-05 07:24:31 UTC
Or use memcpy instead of strcpy.

Comment 5 Nikola Pajkovsky 2009-08-05 12:37:06 UTC
Another bug/problem/nasty thing with flexible array member. It seems that code is work perfectly. Valgrind said there isn't any memory leaks. Give only echo if it will be fixed. Easy solution is use memcpy.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


typedef int *ClientData;


typedef struct VarTrace {
    ClientData clientData;	/* Argument to pass to proc. */
    int flags;			/* What events the trace procedure is
				 * interested in: OR-ed combination of
				 * TCL_TRACE_READS, TCL_TRACE_WRITES,
				 * TCL_TRACE_UNSETS and TCL_TRACE_ARRAY. */
    struct VarTrace *nextPtr;	/* Next in list of traces associated with a
				 * particular variable. */
} VarTrace;

typedef struct {
    int flags;			/* Operations for which Tcl command is to be
				 * invoked. */
    size_t length;		/* Number of non-NUL chars. in command. */
    char command[4];		/* Space for Tcl command to invoke. Actual
				 * size will be as large as necessary to hold
				 * command. This field must be the last in the
				 * structure, so that it can be larger than 4
				 * bytes. */
} TraceVarInfo;

typedef struct {
    VarTrace traceInfo;
    TraceVarInfo traceCmdInfo;
} CombinedTraceVarInfo;


int main( void )
{

    char test_string[] = "This is testing string for flexible member array";

    CombinedTraceVarInfo* ctvi;
    size_t size = sizeof( CombinedTraceVarInfo) + strlen(test_string) +1 - sizeof( ctvi->traceCmdInfo.command);
    ctvi = malloc( size );
//    strcpy( ctvi->traceCmdInfo.command, test_string );
    memcpy(ctvi->traceCmdInfo.command, test_string, sizeof(test_string ));
    printf("%s\n", ctvi->traceCmdInfo.command);
    free(ctvi);

    return 0;
}

Comment 6 Jakub Jelinek 2009-08-05 12:43:24 UTC
That's definitely nothing close to the standard flexible array member definition.
Fix up the code.  Easy fix is to put what is meant to be a flexible array member as a flexible array member (i.e. as last, array, field into CombinedTraceVarInfo).


Note You need to log in before you can comment on or make changes to this bug.