Bug 107506

Summary: iconv stuff seem to access freed memory
Product: [Retired] Red Hat Linux Reporter: Frediano Ziglio <freddyz77>
Component: ElectricFenceAssignee: Jakub Jelinek <jakub>
Status: CLOSED RAWHIDE QA Contact: David Lawrence <dkl>
Severity: medium Docs Contact:
Priority: medium    
Version: 9   
Target Milestone: ---   
Target Release: ---   
Hardware: i686   
OS: Linux   
Whiteboard:
Fixed In Version: Doc Type: Bug Fix
Doc Text:
Story Points: ---
Clone Of: Environment:
Last Closed: 2004-10-16 17:20:32 UTC Type: ---
Regression: --- Mount Type: ---
Documentation: --- CRM:
Verified Versions: Category: ---
oVirt Team: --- RHEL 7.3 requirements from Atomic Host:
Cloudforms Team: --- Target Upstream Version:
Embargoed:
Attachments:
Description Flags
Output of libSegfault.so attached
none
Output of strace
none
Updated ElectricFence package to fix free bug none

Description Frediano Ziglio 2003-10-19 17:33:08 UTC
From Bugzilla Helper:
User-Agent: Mozilla/5.0 Galeon/1.2.7 (X11; Linux i686; U;) Gecko/20030131

Description of problem:
Trying to debug FreeTDS library glibc seem to crash using ElectricFence as
memory debugger. iconv seem to access to freed memory. I simplyfied my test
program until I get a simple C program that depend only on glibc and still crash.


Version-Release number of selected component (if applicable):
glibc-2.3.2-27.9

How reproducible:
Always

Steps to Reproduce:
1. Write a C file as
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include <iconv.h>
#include <pwd.h>
#include <string.h>
 
static char *
tds_get_homedir2(void)
{
        struct passwd *pw, bpw;
        char buf[1024];
 
        if (getpwuid_r(getuid(), &bpw, buf, sizeof(buf), &pw))
                return NULL;
        return strdup(pw->pw_dir);
}
 
int
main(int argc, char **argv)
{
        iconv_t cd;
                                                                                
        void *c = malloc(100);
                                                                                
        printf("line %d\n", __LINE__);
                                                                                
        tds_get_homedir2();
                                                                                
        cd = iconv_open("ISO-8859-1", "UTF-8");
        iconv_close(cd);
                                                                                
        printf("line %d\n", __LINE__);
        free(c);
        printf("line %d\n", __LINE__);
        return 0;
}

2. compile with (you must have ElectricFence installed)
gcc -O2 -Wall -lefence -o iconvbug iconvbug.c
3. enable freed memory protection
export EF_PROTECT_FREE=1
4. launch it 
./iconvbug

    

Actual Results:  A core is reported

  Electric Fence 2.2.0 Copyright (C) 1987-1999 Bruce Perens <bruce>
line 28
line 35
line 37
Segmentation fault (core dumped)

gdb ./iconvbug core.3681

(gdb) bt
#0  0x40031fb4 in gconv () from /usr/lib/gconv/ISO8859-1.so
#1  0x42029d40 in exit () from /lib/tls/libc.so.6
#2  0x42015708 in __libc_start_main () from /lib/tls/libc.so.6

Expected Results:  It should not crash

Additional info:

Commenting iconv calls or getpwuid_r call program do not crash.

Comment 1 Ulrich Drepper 2003-10-27 08:34:21 UTC
This is no glibc problem, there is something wrong with ElectricFence.  Not
surprising actually, a lot of the functionality it implements is fragile at best.

What happens is that it somehow gets confused about the blocks it allocated. 
This is an excerpt from the strace run:

mmap2(NULL, 1048576, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
0xbf45b000
mprotect(0xbf45c000, 1044480, PROT_NONE) = 0
mprotect(0xbf45b000, 4096, PROT_READ|PROT_WRITE) = 0
mprotect(0xbf45c000, 4096, PROT_READ|PROT_WRITE) = 0
munmap(0xbf45d000, 4096)                = 0
mprotect(0xbf45b000, 4096, PROT_NONE)   = 0

The 0xbf45c000 allocation seems to be done in response to the malloc(100) call.
 The page at 0xbf45b000 seems to be some kind of administrative patch.  Next
comes this:

mmap2(NULL, 4096, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) =
0xbf45d000

This is a mmap call made directly by libc, not EF.  It's the allocation of the
buffer for stdout.  Not that it directly follows the already allocated block.

Before the code crashes this can be seen:

write(1, "line 34\n", 8)                = 8
mprotect(0xbf45b000, 4096, PROT_READ|PROT_WRITE) = 0
munmap(0xbf45c000, 8192)                = 0
mprotect(0xbf45b000, 4096, PROT_NONE)   = 0

The munmap call is made in response to the free() call.  Then the program
crashes since the buffer for stdout at address 0xbf45d000 has also been freed. 
Incorrectly so.


The problem seems to be that initial munmap() call above.  Why did EF create
this 4096 byte hole in mapping?  It's probably meant to be some kind of
protection for the block allocate just below and maybe this should actually be a
mprotect() call.

Anyway, reassigning to EF.


Comment 2 Ulrich Drepper 2003-10-27 08:37:08 UTC
Created attachment 95507 [details]
Output of libSegfault.so attached

The failing access is using %ecx

Comment 3 Ulrich Drepper 2003-10-27 08:38:43 UTC
Created attachment 95508 [details]
Output of strace

Output of strace for the very same run.  The end of the strace output shows
libSegFault at work.

I used

strace -o STRACE-OUT -E EF_PROTECT_FREE=1 -E LD_PRELOAD=debug/libSegFault.so
./i

Comment 4 Frediano Ziglio 2003-10-29 14:32:46 UTC
Created attachment 95575 [details]
Updated ElectricFence package to fix free bug

I updated RawHide version.

freddy77

Comment 5 Jakub Jelinek 2004-10-16 17:20:32 UTC
Should be fixed in ElectricFence-2.2.2-19 in rawhide.
I actually took a different approach, calling Page_Delete for the
guard pages (and in free) always, not just when EF_PROTECT_FREE
and changing Page_Delete, so that it does Page_DenyAccess (== mprotect PROT_NONE)
and madvise MADV_DONTNEED.