[Bug other/83520] New: format string bug in libvtv

2017-12-20 Thread charo.ctf at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83520

Bug ID: 83520
   Summary: format string bug in libvtv
   Product: gcc
   Version: unknown
Status: UNCONFIRMED
  Severity: normal
  Priority: P3
 Component: other
  Assignee: unassigned at gcc dot gnu.org
  Reporter: charo.ctf at gmail dot com
  Target Milestone: ---

Description:
  On startup of a program compiled with "-fvtable-verify=std" or
  "-fvtable-verify=preinit", argv[0] is directly passed as the
  third argument of snprintf.
  This would cause memory corruption if argv[0] contains format
  specifiers like %n.

Affected version:
  gcc>=4.9 configured with --enable-vtable-verify

Technical description:
  The code below is taken from gcc-5-20171003/libvtv/vtv_rts.cc

  ==vtv_rts.cc (line 832-856)==
  static int
  dl_iterate_phdr_callback (struct dl_phdr_info *info, size_t, void *data)
  {
int * mprotect_flags = (int *) data;
off_t map_sect_offset = 0;
ElfW (Word) map_sect_len = 0;
char buffer[1024];
char program_name[1024];
const char *map_sect_name = VTV_PROTECTED_VARS_SECTION;

/* Check to see if this is the record for the Linux Virtual Dynamic
   Shared Object (linux-vdso.so.1), which exists only in memory (and
   therefore cannot be read from disk).  */

if (strcmp (info->dlpi_name, "linux-vdso.so.1") == 0)
  return 0;

if (strlen (info->dlpi_name) == 0
&& info->dlpi_addr != 0)
  return 0;

/* Get the name of the main executable.  This may or may not include
   arguments passed to the program.  Find the first space, assume it
   is the start of the argument list, and change it to a '\0'. */
snprintf (program_name, sizeof (program_name), program_invocation_name);
  =

  As we can see, there is a format string bug at the last line of
  the code above.

  According to the manpage of program_invocation_name,
  program_invocation_name is the same as the value of argv[0] of
  main(), which means that this value is user supplied.

  There is another format string bug with the same situation as
  above in read_section_offset_and_length function (line 576).

===PoC===
$ g++-vtv -v
Using built-in specs.
COLLECT_GCC=g++-vtv
COLLECT_LTO_WRAPPER=/usr/local/libexec/gcc/x86_64-linux-gnu/5.4.1/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../gcc-5-20171003/configure -v --enable-languages=c,c++
--program-suffix=-vtv --disable-multilib --enable-libstdcxx-threads
--enable-vtable-verify --build=x86_64-linux-gnu --host=x86_64-linux-gnu
--target=x86_64-linux-gnu
Thread model: posix
gcc version 5.4.1 20171003 (GCC)
$ cat victim.cpp
#include 
int main(){
puts("Hello world");
}
$ g++-vtv -o victim -fvtable-verify=std victim.cpp
$ ./victim
Hello world
$ ln -s ./victim ./%n
$ ./%n
Segmentation fault (core dumped)
=

[Bug other/83520] format string bug in libvtv

2017-12-24 Thread charo.ctf at gmail dot com
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=83520

--- Comment #3 from Touma Hatano  ---
Sorry for misleading.
My point was that if we can replace
  snprintf (program_name, sizeof (program_name), program_invocation_name);
with
  snprintf (program_name, sizeof (program_name), "%s",
program_invocation_name);
, the program won't crash when program_invocation_name contains format
specifiers.

How do you think?