https://gcc.gnu.org/bugzilla/show_bug.cgi?id=94158
Bug ID: 94158 Summary: Expanded strlen causes out-of-bounds read on AMD64 target Product: gcc Version: 9.2.1 Status: UNCONFIRMED Severity: normal Priority: P3 Component: target Assignee: unassigned at gcc dot gnu.org Reporter: par...@cyber-itl.org Target Milestone: --- On AMD64/Linux, When strlen() is expanded, if the argument to strlen comes from a source like strdup() or other functions returning allocator generated pointers, the expanded strlen() makes an assumption about the alignment of the char array. Expanded strlen(): callq 0x4011e0 <strdup> mov %rax,%rsi mov %rax,%rdx mov (%rdx),%ecx add $0x4,%rdx lea -0x1010101(%rcx),%eax not %ecx and %ecx,%eax and $0x80808080,%eax je 0x40109a <main+58> If the input argument is not 4-byte aligned, the "mov (%rdx),%ecx" can read up to 3 bytes off the end of the allocated array. Testing with GCC 9.2.1 this expanding behavior can be trigger with -O2 and -O3. On git HEAD (c56871dd15a258c8775740194e6ed960a1f3d850) it requires the '-minline-all-stringops' flag and -O2 / -O3. Reproduction: #include <stdio.h> #include <sys/mman.h> #define PAGE_SIZE 4096 #define ALIGN_SIZE(x) (((x) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) char *strdup(const char *str) { size_t size = __builtin_strlen(str) + 1; size_t len = ALIGN_SIZE(size); char *ptr = (char *) mmap(NULL, len + PAGE_SIZE, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, 0, 0); munmap(&ptr[len], PAGE_SIZE); char *dest = ptr + PAGE_SIZE - size; __builtin_memcpy(dest, str, size); return dest; } int main(int argc, char **argv) { char blah[] = "AAAABBBBCCCCDD"; char *dest = strdup(blah); __builtin_printf("%s %ld\n", dest, __builtin_strlen(dest)); return 0; } Newer than 9.2.1: gcc -minline-all-stringops -O2 -o strlen-crash ./strlen-crash.c 9.2.1 and below: gcc -O2 -o strlen-crash ./strlen-crash.c ./strlen-crash # Should SIGSEGV on the 'mov (%rdx),%ecx' instruction, if expanded. GCC -v output: Using built-in specs. COLLECT_GCC=gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-pc-linux-gnu/9.2.1/lto-wrapper Target: x86_64-pc-linux-gnu Configured with: /build/gcc/src/gcc/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --with-pkgversion='Arch Linux 9.2.1+20200130-2' --with-bugurl=https://bugs.archlinux.org/ --enable-languages=c,c++,ada,fortran,go,lto,objc,obj-c++,d --enable-shared --enable-threads=posix --with-system-zlib --with-isl --enable-__cxa_atexit --disable-libunwind-exceptions --enable-clocale=gnu --disable-libstdcxx-pch --disable-libssp --enable-gnu-unique-object --enable-linker-build-id --enable-lto --enable-plugin --enable-install-libiberty --with-linker-hash-style=gnu --enable-gnu-indirect-function --enable-multilib --disable-werror --enable-checking=release --enable-default-pie --enable-default-ssp --enable-cet=auto gdc_include_dir=/usr/include/dlang/gdc Thread model: posix gcc version 9.2.1 20200130 (Arch Linux 9.2.1+20200130-2) GCC -v from git HEAD (c56871dd15a258c8775740194e6ed960a1f3d850): Using built-in specs. COLLECT_GCC=./bin/gcc COLLECT_LTO_WRAPPER=/tmp/gcc/build-bins/libexec/gcc/x86_64-pc-linux-gnu/10.0.1/lto-wrapper Target: x86_64-pc-linux-gnu Configured with: ../configure --prefix=/tmp/gcc/build-bins/ --enable-languages=c,c++ --disable-bootstrap --disable-multilib Thread model: posix Supported LTO compression algorithms: zlib zstd gcc version 10.0.1 20200312 (experimental) (GCC)