Summary: | sys-devel/gcc: files compiled with -fstack-protector -fPIE refer to hidden symbol __stack_chk_fail_local on 32-bit x86 and ppc | ||
---|---|---|---|
Product: | Gentoo Linux | Reporter: | Anthony Basile <blueness> |
Component: | Hardened | Assignee: | The Gentoo Linux Hardened Team <hardened> |
Status: | RESOLVED INVALID | ||
Severity: | normal | CC: | aballier, toolchain |
Priority: | High | ||
Version: | unspecified | ||
Hardware: | x86 | ||
OS: | Linux | ||
Whiteboard: | |||
Package list: | Runtime testing required: | --- | |
Bug Depends on: | 747346 | ||
Bug Blocks: | 325849 |
Description
Anthony Basile
2010-06-30 09:42:31 UTC
Here's the symbol table for x86: # nm test1.o U __stack_chk_fail_local 00000000 T doit1 # ld -shared -o libtest.so test1.o test2.o test1.o: In function `doit1': test1.c:(.text+0x1e): undefined reference to `__stack_chk_fail_local' test2.o: In function `doit2': test2.c:(.text+0x1e): undefined reference to `__stack_chk_fail_local' ld: libtest.so: hidden symbol `__stack_chk_fail_local' isn't defined ld: final link failed: Nonrepresentable section on output # gcc -Xlinker -shared -o libtest.so test1.o test2.o # nm libtest.so 00001ef4 a _DYNAMIC 00001fd4 a _GLOBAL_OFFSET_TABLE_ 000006b8 R _IO_stdin_used w _Jv_RegisterClasses 00001eec D __DTOR_END__ 00002008 A __bss_start w __cxa_finalize@@GLIBC_2.1.3 00002000 D __data_start 00002004 D __dso_handle w __gmon_start__ 00000577 T __i686.get_pc_thunk.bx 00001ee0 d __init_array_end 00001ee0 d __init_array_start 000005d0 T __libc_csu_fini 000005e0 T __libc_csu_init U __libc_start_main@@GLIBC_2.0 U __stack_chk_fail@@GLIBC_2.4 00000640 T __stack_chk_fail_local 00002008 A _edata 00002010 A _end 00000698 T _fini 000006b4 R _fp_hw 000003f0 T _init 00000460 T _start 00002000 W data_start 0000057c T doit1 000005a0 T doit2 U main Here's the symbol table for amd64: # nm test1.o U _GLOBAL_OFFSET_TABLE_ U __stack_chk_fail 0000000000000000 T doit1 # ld -shared -o libtest.so test1.o test2.o # nm libtest.so 0000000000200ee8 a _DYNAMIC 0000000000200fe8 a _GLOBAL_OFFSET_TABLE_ 0000000000201008 A __bss_start U __stack_chk_fail 0000000000201008 A _edata 0000000000201008 A _end 0000000000000330 T doit1 0000000000000360 T doit2 # rm libtest.so # gcc -Xlinker -shared -o libtest.so test1.o test2.o # nm libtest.so 0000000000200de0 a _DYNAMIC 0000000000200fa0 a _GLOBAL_OFFSET_TABLE_ 00000000000008f8 R _IO_stdin_used w _Jv_RegisterClasses 0000000000200dd0 D __DTOR_END__ 0000000000201010 A __bss_start w __cxa_finalize@@GLIBC_2.2.5 0000000000201000 D __data_start 0000000000201008 D __dso_handle w __gmon_start__ 0000000000200db4 d __init_array_end 0000000000200db4 d __init_array_start 0000000000000810 T __libc_csu_fini 0000000000000820 T __libc_csu_init U __libc_start_main@@GLIBC_2.2.5 U __stack_chk_fail@@GLIBC_2.4 0000000000201010 A _edata 0000000000201020 A _end 00000000000008e8 T _fini 0000000000000650 T _init 00000000000006b0 T _start 0000000000201000 W data_start 00000000000007ac T doit1 00000000000007dc T doit2 U main # nm test1.o U __stack_chk_fail_local 00000000 T doit1 # ld -shared -o libtest.so test1.o test2.o test1.o: In function `doit1': test1.c:(.text+0x4c): undefined reference to `__stack_chk_fail_local' test2.o: In function `doit2': test2.c:(.text+0x4c): undefined reference to `__stack_chk_fail_local' ld: libtest.so: hidden symbol `__stack_chk_fail_local' isn't defined ld: final link failed: Nonrepresentable section on output # gcc -Xlinker -shared -o libtest.so test1.o test2.o # nm libtest.so 00000920 t 00000000.plt_pic32.__gmon_start__ 00000930 t 00000000.plt_pic32.__libc_start_main@@GLIBC_2.0 00000950 t 00008000.got2.plt_pic32.__cxa_finalize@@GLIBC_2.1.3 00000940 t 00008000.got2.plt_pic32.__stack_chk_fail@@GLIBC_2.4 00010ef8 a _DYNAMIC 00010fe4 a _GLOBAL_OFFSET_TABLE_ 000009e8 R _IO_stdin_used w _Jv_RegisterClasses 00019018 D _SDA_BASE_ 00010ec4 D __DTOR_END__ 00011018 A __bss_start w __cxa_finalize@@GLIBC_2.1.3 00011010 D __data_start 00011014 D __dso_handle 00000960 t __glink 00000970 t __glink_PLTresolve w __gmon_start__ 00010eb8 d __init_array_end 00010eb8 d __init_array_start 000007bc T __libc_csu_fini 000007c0 T __libc_csu_init U __libc_start_main@@GLIBC_2.0 U __stack_chk_fail@@GLIBC_2.4 00000874 T __stack_chk_fail_local 00011018 A _edata 00011020 A _end 000009b0 T _fini 000004e4 T _init 00000510 T _start 00011010 W data_start 000006e4 T doit1 00000750 T doit2 U main It should be obvious from the symbol table, but I forgot to say this is for 32-bit ppc. (In reply to comment #3) > # nm test1.o > U __stack_chk_fail_local > 00000000 T doit1 > > # ld -shared -o libtest.so test1.o test2.o > test1.o: In function `doit1': > test1.c:(.text+0x4c): undefined reference to `__stack_chk_fail_local' > test2.o: In function `doit2': > test2.c:(.text+0x4c): undefined reference to `__stack_chk_fail_local' > ld: libtest.so: hidden symbol `__stack_chk_fail_local' isn't defined > ld: final link failed: Nonrepresentable section on output > > # gcc -Xlinker -shared -o libtest.so test1.o test2.o > # nm libtest.so > 00000920 t 00000000.plt_pic32.__gmon_start__ > 00000930 t 00000000.plt_pic32.__libc_start_main@@GLIBC_2.0 > 00000950 t 00008000.got2.plt_pic32.__cxa_finalize@@GLIBC_2.1.3 > 00000940 t 00008000.got2.plt_pic32.__stack_chk_fail@@GLIBC_2.4 > 00010ef8 a _DYNAMIC > 00010fe4 a _GLOBAL_OFFSET_TABLE_ > 000009e8 R _IO_stdin_used > w _Jv_RegisterClasses > 00019018 D _SDA_BASE_ > 00010ec4 D __DTOR_END__ > 00011018 A __bss_start > w __cxa_finalize@@GLIBC_2.1.3 > 00011010 D __data_start > 00011014 D __dso_handle > 00000960 t __glink > 00000970 t __glink_PLTresolve > w __gmon_start__ > 00010eb8 d __init_array_end > 00010eb8 d __init_array_start > 000007bc T __libc_csu_fini > 000007c0 T __libc_csu_init > U __libc_start_main@@GLIBC_2.0 > U __stack_chk_fail@@GLIBC_2.4 > 00000874 T __stack_chk_fail_local > 00011018 A _edata > 00011020 A _end > 000009b0 T _fini > 000004e4 T _init > 00000510 T _start > 00011010 W data_start > 000006e4 T doit1 > 00000750 T doit2 > U main > Here's the symbol table for ppc64: # nm test1.o U __stack_chk_fail 0000000000000000 D doit1 # ld -shared -o libtest.so test1.o test2.o # nm libtest.so 0000000000000350 t 00000010.plt_call.__stack_chk_fail+0 0000000000010ec0 a _DYNAMIC 0000000000011038 A __bss_start 0000000000000430 t __glink_PLTresolve U __stack_chk_fail 0000000000011038 A _edata 0000000000011068 A _end 0000000000011000 D doit1 0000000000011018 D doit2 # gcc -Xlinker -shared -o libtest.so test1.o test2.o # nm libtest.so 0000000000000910 t 00000011.plt_call.__cxa_finalize@@GLIBC_2.3+0 00000000000008f8 t 00000011.plt_call.__libc_start_main@@GLIBC_2.3+0 00000000000008e0 t 00000011.plt_call.__stack_chk_fail@@GLIBC_2.4+0 0000000000010e30 a _DYNAMIC 0000000000000d50 R _IO_stdin_used w _Jv_RegisterClasses 0000000000010e00 D __DTOR_END__ 0000000000011188 A __bss_start w __cxa_finalize@@GLIBC_2.3 0000000000011000 D __data_start 0000000000011008 D __dso_handle 0000000000000cd8 t __glink_PLTresolve w __gmon_start__ 0000000000010de4 d __init_array_end 0000000000010de4 d __init_array_start 00000000000110d0 D __libc_csu_fini 00000000000110e8 D __libc_csu_init U __libc_start_main@@GLIBC_2.3 U __stack_chk_fail@@GLIBC_2.4 0000000000011188 A _edata 00000000000111f8 A _end 0000000000011058 D _fini 0000000000011040 D _init 0000000000011010 D _start 0000000000011000 W data_start 00000000000110a0 D doit1 00000000000110b8 D doit2 U main This bug results from an analysis of bug #325849 but seems to be a bigger issue. I've made them dependent/blocker, but its not a hard block because you can always work around using gcc -Xlinker on the 32-bit archs. Okay Zorry and I have narrowed this down and it doesn't seem to be a hardened issues. Using i686-pc-linux-gnu-4.4.3 we can reproduce the problem. Here are the steps: echo "void doit1() { char buff[256] ; }" > test1.c echo "void doit2() { char buff[256] ; }" > test2.c gcc -c -fstack-protector -fPIE test1.c gcc -c -fstack-protector -fPIE test2.c ld -shared -o libtest.so test1.o test2.o #FAIL test1.o: In function `doit1': test1.c:(.text+0x21): undefined reference to `__stack_chk_fail_local' test2.o: In function `doit2': test2.c:(.text+0x21): undefined reference to `__stack_chk_fail_local' ld: libtest.so: hidden symbol `__stack_chk_fail_local' isn't defined ld: final link failed: Nonrepresentable section on output nm test1.o U __stack_chk_fail_local 00000000 T doit1 (In reply to comment #7) emerge --info for that system is Portage 2.1.8.3 (default/linux/x86/10.0, gcc-4.4.3, glibc-2.11.2-r0, 2.6.32-gentoo-r7 i686) ================================================================= System uname: Linux-2.6.32-gentoo-r7-i686-Intel-R-_Core-TM-_i7_CPU_920_@_2.67GHz-with-gentoo-1.12.13 Timestamp of tree: Wed, 30 Jun 2010 07:00:01 +0000 app-shells/bash: 4.0_p37 dev-lang/python: 2.6.5-r2, 3.1.2-r3 sys-apps/baselayout: 1.12.13 sys-apps/sandbox: 1.6-r2 sys-devel/autoconf: 2.13, 2.65 sys-devel/automake: 1.10.3, 1.11.1 sys-devel/binutils: 2.20.1-r1 sys-devel/gcc: 4.3.4, 4.4.3-r2 sys-devel/gcc-config: 1.4.1 sys-devel/libtool: 2.2.6b virtual/os-headers: 2.6.30-r1 ACCEPT_KEYWORDS="x86" ACCEPT_LICENSE="* -@EULA" CBUILD="i686-pc-linux-gnu" CFLAGS="-O2 -march=i686 -pipe" CHOST="i686-pc-linux-gnu" CONFIG_PROTECT="/etc" CONFIG_PROTECT_MASK="/etc/ca-certificates.conf /etc/env.d /etc/gconf /etc/revdep-rebuild /etc/sandbox.d /etc/terminfo" CXXFLAGS="-O2 -march=i686 -pipe" DISTDIR="/usr/portage/distfiles" FEATURES="assume-digests distlocks fixpackages news parallel-fetch protect-owned sandbox sfperms strict unmerge-logs unmerge-orphans userfetch" GENTOO_MIRRORS="ftp://192.168.100.9/pub/gentoo" LDFLAGS="-Wl,-O1" MAKEOPTS="-j3" PKGDIR="/usr/portage/packages" PORTAGE_CONFIGROOT="/" PORTAGE_RSYNC_OPTS="--recursive --links --safe-links --perms --times --compress --force --whole-file --delete --stats --timeout=180 --exclude=/distfiles --exclude=/local --exclude=/packages" PORTAGE_TMPDIR="/var/tmp" PORTDIR="/usr/portage" PORTDIR_OVERLAY="/usr/local/portage" SYNC="rsync://192.168.100.7/portage" USE="acl berkdb bzip2 cli cracklib crypt cups cxx dri fortran gdbm gpm iconv ipv6 modules mudflap ncurses nls nptl nptlonly openmp pam pcre perl pppd python readline reflection session spl ssl sysfs tcpd unicode x86 xorg zlib" ALSA_CARDS="ali5451 als4000 atiixp atiixp-modem bt87x ca0106 cmipci emu10k1 emu10k1x ens1370 ens1371 es1938 es1968 fm801 hda-intel intel8x0 intel8x0m maestro3 trident usb-audio via82xx via82xx-modem ymfpci" ALSA_PCM_PLUGINS="adpcm alaw asym copy dmix dshare dsnoop empty extplug file hooks iec958 ioplug ladspa lfloat linear meter mmap_emul mulaw multi null plug rate route share shm softvol" APACHE2_MODULES="actions alias auth_basic authn_alias authn_anon authn_dbm authn_default authn_file authz_dbm authz_default authz_groupfile authz_host authz_owner authz_user autoindex cache dav dav_fs dav_lock deflate dir disk_cache env expires ext_filter file_cache filter headers include info log_config logio mem_cache mime mime_magic negotiation rewrite setenvif speling status unique_id userdir usertrack vhost_alias" ELIBC="glibc" INPUT_DEVICES="keyboard mouse evdev" KERNEL="linux" LCD_DEVICES="bayrad cfontz cfontz633 glk hd44780 lb216 lcdm001 mtxorb ncurses text" RUBY_TARGETS="ruby18" USERLAND="GNU" VIDEO_CARDS="fbdev glint intel mach64 mga neomagic nv r128 radeon savage sis tdfx trident vesa via vmware voodoo" XTABLES_ADDONS="quota2 psd pknock lscan length2 ipv4options ipset ipp2p iface geoip fuzzy condition tee tarpit sysrq steal rawnat logmark ipmark dhcpmac delude chaos account" Unset: CPPFLAGS, CTARGET, EMERGE_DEFAULT_OPTS, FFLAGS, INSTALL_MASK, LANG, LC_ALL, LINGUAS, PORTAGE_COMPRESS, PORTAGE_COMPRESS_FLAGS, PORTAGE_RSYNC_EXTRA_OPTS To be complete, this also happens with -fPIC instead of PIE. Using the test code from Comment #7, we get gcc -c -fstack-protector -fPIC test1.c gcc -c -fstack-protector -fPIC test2.c ld -shared -o libtest.so test1.o test2.o test1.o: In function `doit1': test1.c:(.text+0x21): undefined reference to `__stack_chk_fail_local' test2.o: In function `doit2': test2.c:(.text+0x21): undefined reference to `__stack_chk_fail_local' ld: libtest.so: hidden symbol `__stack_chk_fail_local' isn't defined ld: final link failed: Nonrepresentable section on output nm test1.o U __stack_chk_fail_local 00000000 T doit1 4.3.4 works fine with the same test code. I've now tested gcc-4.5.0 on both 32 and 64 bits. Here's a summary of where the test code fails. On x86: [1] i686-pc-linux-gnu-4.3.4 # works [2] i686-pc-linux-gnu-4.4.3 # fails [3] i686-pc-linux-gnu-4.5.0 # fails On x86_64: [1] x86_64-pc-linux-gnu-4.3.4 # works [2] x86_64-pc-linux-gnu-4.4.3 # works [3] x86_64-pc-linux-gnu-4.5.0 # works So the problem seems to be for 32-bit >= gcc-4.4 i dont see that. looks to me like gcc has always behaved this way. every version from 4.1.0 to 4.5.0 on my system certainly does. $ gcc-4.1.2 -c -fstack-protector -fPIE test1.c -m32 $ readelf -s test1.o | grep stack 8: 00000000 0 NOTYPE GLOBAL DEFAULT UND __stack_chk_fail_local it also seems to be doing this on purpose. look at targhooks.c:default_hidden_stack_protect_fail() and how config/rs6000/rs6000.c and config/i386/i386.c call this for 32bit targets. running the linker directly is wrong. use gcc so that it adds all the internal glibc files such as /usr/lib32/libc_nonshared.a which does provide __stack_chk_fail_local. if you do wish to run the linker directly, do it right. (In reply to comment #13) > running the linker directly is wrong. use gcc so that it adds all the internal > glibc files such as /usr/lib32/libc_nonshared.a which does provide > __stack_chk_fail_local. > > if you do wish to run the linker directly, do it right. > what is the "right" way of doing it ? how can one guess if it needs to link to libc_nonshared.a or not considering one has no control on the specs/cflags used at compile time ? wont that fail in the same way with gcc -nostdlib instead of ld ? when dealing with anything beyond machine code generation, the compiler output is highly tied to the C library. so if you break the gcc/link process by invoking the linker directly, it's on your head to do it right. the only supported linking method is via `gcc`. this is especially true for anything coming out of the hardened toolchain with the heavy ssp usage. (In reply to comment #15) > when dealing with anything beyond machine code generation, the compiler output > is highly tied to the C library. Actually this bug is a case in point. We were confused because the object code produced on each of the four arches looked so different. And yet, if you link via gcc, it all worked in the end. "How can one guess?" Best not to guess at what needs to be linked in, and just use gcc. Lesson learned :) |