[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#669154: freopen() can crash due to incomplete stream version detection



Package: libc6
Version: 2.13-27
Severity: important
Tags: upstream

   The i386 version of eglibc provides two versions of fopen() and
fclose(), version GLIBC_2.0 and GLIBC2.1. However, they only provide
one version of freopen(), version GLIBC_2.0.

   This shouldn't be a problem because freopen() does a version check,
found in freopen.c:

#if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
  if (&_IO_stdin_used == NULL)
    {
        /* (call _IO_old_file_fopen instead of _IO_file_fopen) */

   So if the current binary was built with an older version of the libc,
&_IO_stdin_used will be NULL and the older version of the builtin fopen
will be called.

   However, it may happen that the file was opened with the old version
but the _IO_stdin_used symbol from the new library be present anyway.
For instance, when the application gets the address of freopen using
dlsym(). Here is a simple test case:

#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>

static FILE * (*my_fopen)   (const char *, const char *);
static FILE * (*my_freopen) (const char *, const char *, FILE *);
static int    (*my_fclose)  (FILE *);

int main(void)
{
    my_fopen = dlsym(RTLD_NEXT, "fopen");
    my_freopen = dlsym(RTLD_NEXT, "freopen");
    my_fclose = dlsym(RTLD_NEXT, "fclose");

    FILE * s = my_fopen("/dev/null", "w+t");
    s = my_freopen("/dev/null", "w+t", s);
    my_fclose(s);

    return 0;
}

   This program will crash on Debian i386, because 1) my_freopen()
will call _IO_file_fopen() from the new libio, but 2) the symbol for
fclose() will be "fopen@GLIBC_2.0" from the old libio, causing a memory
corruption.

   There might be a way for freopen() to better check which version of
libio was used. Maybe upstream has an opinion on this. Or maybe they
believe it's not a problem; however, note that there is no way to use
dlsym() with a libc6 symbol and ensure we get a version compatible with
the current running binary. There is dlvsym() but it requires to know
the version string beforehands.

   I hope I'm being clear enough!


-- System Information:
Debian Release: wheezy/sid
  APT prefers stable
  APT policy: (500, 'stable')
Architecture: amd64 (x86_64)

Kernel: Linux 3.2.0-2-amd64 (SMP w/4 CPU cores)
Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/dash

Versions of packages libc6 depends on:
ii  libc-bin  2.13-27
ii  libgcc1   1:4.7.0-2

libc6 recommends no packages.

Versions of packages libc6 suggests:
ii  debconf [debconf-2.0]  1.5.42
ii  glibc-doc              <none>
ii  locales                2.13-27

-- debconf information:
  glibc/upgrade: true
  glibc/disable-screensaver:
  glibc/restart-failed:
* glibc/restart-services: postfix cups cron atd
  libraries/restart-without-asking: false



Reply to: