broken configuration test with fortify source

Bug #601030 reported by Matthias Klose on 2010-07-02
14
This bug affects 2 people
Affects Status Importance Assigned to Milestone
GLibC
Fix Released
Medium
Linaro GCC
Invalid
Undecided
Unassigned
Linaro Toolchain Miscellanies
Fix Released
High
Chung-Lin Tang
eglibc (Ubuntu)
High
Unassigned
Lucid
Medium
Unassigned
Maverick
High
Unassigned
gawk (Ubuntu)
Undecided
Canonical Foundations Team
Lucid
Undecided
Unassigned
Maverick
Undecided
Canonical Foundations Team

Bug Description

Binary package hint: gcc-4.4

gcc-4.4 -g -O2 -U_FORTIFY_SOURCE -Wall conftest.c && ./a.out
works
while
gcc-4.4 -g -O2 -Wall conftest.c && ./a.out
does not (hangs). 4.3 and 4.5 do work, -O1 as well.

Related branches

Matthias Klose (doko) wrote :
Matthias Klose (doko) wrote :

seen on amd64

Changed in gcc-4.4 (Ubuntu Maverick):
importance: Undecided → High
milestone: none → maverick-alpha-3
status: New → Confirmed
Matthias Klose (doko) wrote :

breaks the gawk build on amd64

Changed in gawk (Ubuntu Maverick):
importance: Undecided → High
milestone: none → maverick-alpha-3
status: New → Confirmed
Martin Pitt (pitti) on 2010-08-04
Changed in gawk (Ubuntu Maverick):
milestone: maverick-alpha-3 → ubuntu-10.10-beta
Changed in gcc-4.4 (Ubuntu Maverick):
milestone: maverick-alpha-3 → ubuntu-10.10-beta
Changed in gcc-4.4 (Ubuntu Maverick):
assignee: nobody → Canonical Foundations Team (canonical-foundations)
Changed in gawk (Ubuntu Maverick):
assignee: nobody → Canonical Foundations Team (canonical-foundations)
Colin Watson (cjwatson) wrote :

I can't seem to reproduce this in current Maverick; gawk builds fine.

Matthias Klose (doko) wrote :

still reproducible for me on maverick, note that on Debian/sid, it does work:

gcc-4.4 -g -O2 -fstack-protector -D_FORTIFY_SOURCE -Wall conftest.c && ./a.out

Matthias Klose (doko) wrote :

the test succeeds with gcc-4.4 in maverick built without the Linaro patchset.

Colin Watson (cjwatson) wrote :

Confirmed in ronne's maverick amd64 chroot. Attached conftest.c and preprocessed source. strace shows:

...
setrlimit(RLIMIT_STACK, {rlim_cur=1024*1024, rlim_max=1024*1024}) = 0
sigaltstack({ss_sp=0x7fffd7df0130, ss_flags=0, ss_size=8192}, NULL) = 0
rt_sigaction(SIGSEGV, {0x4008d0, [], SA_RESTORER|SA_STACK, 0x7f6373fe0c20}, NULL, 8) = 0
rt_sigaction(SIGBUS, {0x4008d0, [], SA_RESTORER|SA_STACK, 0x7f6373fe0c20}, NULL, 8) = 0
rt_sigprocmask(SIG_BLOCK, [], [], 8) = 0
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
sigaltstack(NULL, {ss_sp=0x7fffd7df0130, ss_flags=SS_ONSTACK, ss_size=8192}) = 0
--- SIGSEGV (Segmentation fault) @ 0 (0) ---
rt_sigprocmask(SIG_SETMASK, [], NULL, 8) = 0
sigaltstack(NULL, {ss_sp=0x7fffd7df0130, ss_flags=SS_ONSTACK, ss_size=8192}) = 0
[repeats]

Colin Watson (cjwatson) wrote :
Colin Watson (cjwatson) wrote :

It seems to go into the same infinite loop under strace both with -O2 and -O1, although -O1 exits normally and immediately without strace.

Colin Watson (cjwatson) wrote :

I went through all the optimisations that are in -O2 but not -O1 (-falign-functions -falign-jumps -falign-labels -fcaller-saves -fcrossjumping -fcse-follow-jumps -fdelete-null-pointer-checks -fexpensive-optimizations -fforward-propagate -fgcse -finline-small-functions -fipa-cp -foptimize-register-move -foptimize-sibling-calls -fpeephole2 -fregmove -freorder-blocks -freorder-functions -frerun-cse-after-loop -fschedule-insns2 -fstrict-aliasing -fthread-jumps -ftree-builtin-call-dce -ftree-pre -ftree-switch-conversion -ftree-vrp). Not a single one of them produces this effect reliably, but the bulk of them produce it sometimes.

Loïc Minier (lool) on 2010-09-01
tags: added: amd64
Michael Hope (michaelh1) wrote :

The fault occurs as the 'pass' value given to longjmp() gets corrupted before use by setjmp(), causing the 'setjmp() < 2' test to fail and the system to loop forever. The only assembler level fortify/non-fortify difference is a call to longjmp_chk instead of longjmp.

Note that shifting 'mystack' off the stack and into static memory also works around the problem.

(Tested using gcc 4.4.4-9ubuntu1)

Michael Hope (michaelh1) wrote :

eglibc-2.11.1/sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S is broken. It saves the value of 'pass' in ecx for later use but ecx is trashed by a syscall.

The syscall is used to bring in the signal stack so that the fortify code can print an error message if needed. The problem goes away with -U_FORTIFY_SOURCE as no such syscall is used.

Michael Hope (michaelh1) on 2010-09-01
Changed in gcc-linaro:
status: New → Invalid
Changed in linaro-toolchain-misc:
importance: Undecided → High
assignee: nobody → Chung-Lin Tang (cltang)
status: New → Confirmed
Kees Cook (kees) wrote :

FWIW, this is broken on Lucid too. I've attached a slightly more minimal testcase that disables stack randomization and adds an alarm call to make the loop more obvious.

Kees Cook (kees) wrote :
Kees Cook (kees) wrote :

Oh, and it fails for me with gcc-4.3 and gcc-4.5 as well. I think the differences in failure modes was due to stack randomization somehow.

Since 2.11 and later, it seems that longjmp will fail on x86_64 when
_FORTIFY_SOURCE is enabled.

Works on x86_32, and 2.10 and earlier.

https://launchpad.net/bugs/601030

Created attachment 4962
reproducer

Here is the reproducer. This dies on alarm on Ubuntu x86_64 (eglibc 2.11 and
2.12) and Fedora x86_64 (2.12) when using more recent glibc:

$ gcc -O2 -fno-stack-protector -D_FORTIFY_SOURCE=2 -Wall minimal.c -o minimal
/tmp
$ ./minimal
Alarm Clock

It doesn't always fail, and I tried to mitigate this by disabling ASLR.

Michael Hope noticed:

"The fault occurs as the 'pass' value given to longjmp() gets corrupted before
use by setjmp(), causing the 'setjmp() < 2' test to fail and the system to loop
forever. The only assembler level fortify/non-fortify difference is a call to
longjmp_chk instead of longjmp.

Note that shifting 'mystack' off the stack and into static memory also works
around the problem.

glibc-2.11.1/sysdeps/unix/sysv/linux/x86_64/____longjmp_chk.S is broken. It
saves the value of 'pass' in ecx for later use but ecx is trashed by a syscall.

The syscall is used to bring in the signal stack so that the fortify code can
print an error message if needed. The problem goes away with -U_FORTIFY_SOURCE
as no such syscall is used."

affects: gcc-4.4 (Ubuntu Maverick) → eglibc (Ubuntu Maverick)
Changed in gawk (Ubuntu Maverick):
status: Confirmed → Invalid
importance: High → Undecided
Kees Cook (kees) on 2010-09-02
Changed in eglibc (Ubuntu Lucid):
status: New → Confirmed
Changed in gawk (Ubuntu Lucid):
status: New → Invalid
Changed in eglibc (Ubuntu Lucid):
importance: Undecided → Medium
Changed in glibc:
status: Unknown → Confirmed

Fixed in git.

Matthias Klose (doko) on 2010-09-09
Changed in eglibc (Ubuntu Maverick):
assignee: Canonical Foundations Team (canonical-foundations) → nobody
milestone: ubuntu-10.10-beta → ubuntu-10.10
status: Confirmed → In Progress
tags: added: patch
Matthias Klose (doko) wrote :

fixed in maverick, and gawk built

Changed in eglibc (Ubuntu Maverick):
status: In Progress → Fix Released
Changed in gawk (Ubuntu Maverick):
milestone: ubuntu-10.10-beta → none
status: Invalid → Fix Released
Changed in glibc:
importance: Unknown → Medium
status: Confirmed → Fix Released
Changed in linaro-toolchain-misc:
status: Confirmed → Fix Released
Rolf Leggewie (r0lf) wrote :

lucid has seen the end of its life and is no longer receiving any updates. Marking the lucid task for this ticket as "Won't Fix".

Changed in eglibc (Ubuntu Lucid):
status: Confirmed → Won't Fix
To post a comment you must log in.
This report contains Public information  Edit
Everyone can see this information.

Other bug subscribers

Remote bug watches

Bug watches keep track of this bug in other bug trackers.