Blame libio/vtables.c

Packit 6c4009
/* libio vtable validation.
Packit 6c4009
   Copyright (C) 2016-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
Packit 6c4009
   The GNU C Library is free software; you can redistribute it and/or
Packit 6c4009
   modify it under the terms of the GNU Lesser General Public
Packit 6c4009
   License as published by the Free Software Foundation; either
Packit 6c4009
   version 2.1 of the License, or (at your option) any later version.
Packit 6c4009
Packit 6c4009
   The GNU C Library is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Packit 6c4009
   Lesser General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU Lesser General Public
Packit 6c4009
   License along with the GNU C Library; if not, see
Packit 6c4009
   <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#include <dlfcn.h>
Packit 6c4009
#include <libioP.h>
Packit 6c4009
#include <stdio.h>
Packit 6c4009
#include <ldsodefs.h>
Packit 6c4009
Packit 6c4009
#ifdef SHARED
Packit 6c4009
Packit 6c4009
void (*IO_accept_foreign_vtables) (void) attribute_hidden;
Packit 6c4009
Packit 6c4009
/* Used to detected multiple libcs.  */
Packit 6c4009
extern struct dl_open_hook *_dl_open_hook;
Packit 6c4009
libc_hidden_proto (_dl_open_hook);
Packit 6c4009
Packit 6c4009
#else  /* !SHARED */
Packit 6c4009
Packit 6c4009
/* Used to check whether static dlopen support is needed.  */
Packit 6c4009
# pragma weak __dlopen
Packit 6c4009
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
void attribute_hidden
Packit 6c4009
_IO_vtable_check (void)
Packit 6c4009
{
Packit 6c4009
#ifdef SHARED
Packit 6c4009
  /* Honor the compatibility flag.  */
Packit 6c4009
  void (*flag) (void) = atomic_load_relaxed (&IO_accept_foreign_vtables);
Packit 6c4009
#ifdef PTR_DEMANGLE
Packit 6c4009
  PTR_DEMANGLE (flag);
Packit 6c4009
#endif
Packit 6c4009
  if (flag == &_IO_vtable_check)
Packit 6c4009
    return;
Packit 6c4009
Packit 6c4009
  /* In case this libc copy is in a non-default namespace, we always
Packit 6c4009
     need to accept foreign vtables because there is always a
Packit 6c4009
     possibility that FILE * objects are passed across the linking
Packit 6c4009
     boundary.  */
Packit 6c4009
  {
Packit 6c4009
    Dl_info di;
Packit 6c4009
    struct link_map *l;
Packit 6c4009
    if (!rtld_active ()
Packit 6c4009
        || (_dl_addr (_IO_vtable_check, &di, &l, NULL) != 0
Packit 6c4009
            && l->l_ns != LM_ID_BASE))
Packit 6c4009
      return;
Packit 6c4009
  }
Packit 6c4009
Packit 6c4009
#else /* !SHARED */
Packit 6c4009
  /* We cannot perform vtable validation in the static dlopen case
Packit 6c4009
     because FILE * handles might be passed back and forth across the
Packit 6c4009
     boundary.  Therefore, we disable checking in this case.  */
Packit 6c4009
  if (__dlopen != NULL)
Packit 6c4009
    return;
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
  __libc_fatal ("Fatal error: glibc detected an invalid stdio handle\n");
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
/* Some variants of libstdc++ interpose _IO_2_1_stdin_ etc. and
Packit 6c4009
   install their own vtables directly, without calling _IO_init or
Packit 6c4009
   other functions.  Detect this by looking at the vtables values
Packit 6c4009
   during startup, and disable vtable validation in this case.  */
Packit 6c4009
#ifdef SHARED
Packit 6c4009
__attribute__ ((constructor))
Packit 6c4009
static void
Packit 6c4009
check_stdfiles_vtables (void)
Packit 6c4009
{
Packit 6c4009
  if (_IO_2_1_stdin_.vtable != &_IO_file_jumps
Packit 6c4009
      || _IO_2_1_stdout_.vtable != &_IO_file_jumps
Packit 6c4009
      || _IO_2_1_stderr_.vtable != &_IO_file_jumps)
Packit 6c4009
    IO_set_accept_foreign_vtables (&_IO_vtable_check);
Packit 6c4009
}
Packit 6c4009
#endif