realpath() built with >=gcc-4.3 (where FORTIFY is enabled by default) and -Ox where x>0 cause application to abort. Test case: the following code built with gcc -O2: ========================================================================== #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/cdefs.h> #define PATH_MAX 1024 int main (int argc, char *argv[]) { int ret; char device_file_or_mount_point[PATH_MAX]; if (argc < 2 || strlen (argv[1]) == 0) { fprintf (stderr, "%s: pass relative path.\n", argv[0]); return 1; } realpath(argv[1], device_file_or_mount_point); return 0; } ========================================================================== produces: ./a.out /boot/ *** buffer overflow detected ***: ./a.out terminated ======= Backtrace: ========= /lib/libc.so.6(__fortify_fail+0x37)[0x7f1adb1c33a7] /lib/libc.so.6[0x7f1adb1c03d0] /lib/libc.so.6[0x7f1adb1c0a9b] ./a.out(main+0x55)[0x7f1adb6518c5] /lib/libc.so.6(__libc_start_main+0xe6)[0x7f1adb1015c6] ./a.out[0x7f1adb651789] ======= Memory map: ======== 7f1adaecc000-7f1adaee2000 r-xp 00000000 09:02 1124776 /lib64/libgcc_s.so.1 7f1adaee2000-7f1adb0e1000 ---p 00016000 09:02 1124776 /lib64/libgcc_s.so.1 7f1adb0e1000-7f1adb0e2000 r--p 00015000 09:02 1124776 /lib64/libgcc_s.so.1 7f1adb0e2000-7f1adb0e3000 rw-p 00016000 09:02 1124776 /lib64/libgcc_s.so.1 7f1adb0e3000-7f1adb229000 r-xp 00000000 09:02 1221130 /lib64/libc-2.9.so 7f1adb229000-7f1adb429000 ---p 00146000 09:02 1221130 /lib64/libc-2.9.so 7f1adb429000-7f1adb42d000 r--p 00146000 09:02 1221130 /lib64/libc-2.9.so 7f1adb42d000-7f1adb42e000 rw-p 0014a000 09:02 1221130 /lib64/libc-2.9.so 7f1adb42e000-7f1adb433000 rw-p 7f1adb42e000 00:00 0 7f1adb433000-7f1adb450000 r-xp 00000000 09:02 1220810 /lib64/ld-2.9.so 7f1adb643000-7f1adb645000 rw-p 7f1adb643000 00:00 0 7f1adb64d000-7f1adb64f000 rw-p 7f1adb64d000 00:00 0 7f1adb64f000-7f1adb650000 r--p 0001c000 09:02 1220810 /lib64/ld-2.9.so 7f1adb650000-7f1adb651000 rw-p 0001d000 09:02 1220810 /lib64/ld-2.9.so 7f1adb651000-7f1adb652000 r-xp 00000000 09:02 467215 /root/a.out 7f1adb851000-7f1adb852000 r--p 00000000 09:02 467215 /root/a.out 7f1adb852000-7f1adb853000 rw-p 00001000 09:02 467215 /root/a.out 7f1adc6d4000-7f1adc6f5000 rw-p 7f1adc6d4000 00:00 0 [heap] 7fff2a27c000-7fff2a291000 rw-p 7ffffffea000 00:00 0 [stack] 7fff2a3ff000-7fff2a400000 r-xp 7fff2a3ff000 00:00 0 [vdso] ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall] I found this bug with umount.hal helper which started to fail here after this commit: http://cgit.freedesktop.org/hal/commit/?id=6d8eed9015a6ca648fe1dad575621b6ea959a748 But probably other applications are affected too. At least I found similar issue with python reported here: https://bugs.launchpad.net/ubuntu/+source/gcc-defaults/+bug/286334 Also I found that scilab has 6a5321bddceaf0e4761f29a507bfad6e1f3a7b33 commit (googable) that basically modifies realpath(r,a) call to a=realpath(r,NULL).
Aha, as gcc devs pointed this is not a bug but feature of glibc. realpath manpage does not mentions this, but reading info libc it's explicitly stated: On systems which define `PATH_MAX' ... the buffer must be large enough for a pathname of this size. Since HAL_PATH_MAX=1024 is smaller then PATH_MAX=4096 this causes this abort. hal should be fixed here.
https://bugs.freedesktop.org/show_bug.cgi?id=25888
Finally this is fixed upstream: http://cgit.freedesktop.org/hal/commit/?id=a2c3dd5a04d79265772c09c4280606d5c2ed72c6 Please, grab the patch. And yes, it works here.
Fixed in 0.5.14-r1.
(In reply to comment #4) > Fixed in 0.5.14-r1. This appears to be a semi-valid fix, valid only until a new kernel revision changes PATH_MAX within /usr/include/linux/limits.h Also the dependency on -O appears to be strange behaviour. It stems from __USE_FORTIFY_LEVEL being defined differently on different optimization levels. With -O0 and sys-libs/glibc-2.11-r1, "__USE_FORTIFY_LEVEL > 0" evaluates to false in /usr/include/stdlib.h, 948 #if __USE_FORTIFY_LEVEL > 0 && defined __extern_always_inline 949 # include <bits/stdlib.h> 950 #endif while true with -O1, and this will then result in realpath_chk to be linked in. Here is a test program: #include <stdlib.h> #include <stdio.h> #if __USE_FORTIFY_LEVEL > 0 #warning "__USE_FORTIFIY_LEVEL > 0" #endif int main(int argc, char **argv) { char buffer[512]; printf("__bos(buffer)=%d\n",__bos(buffer)); const char *rp=realpath(argv[0],buffer); return rp!=NULL; } $ gcc -O0 test.c -o test0 $ gcc -O1 test.c -o test1 test.c:5:2: warning: #warning "__USE_FORTIFIY_LEVEL > 0" $ ./test0 __bos(buffer)=512 $ ./test1 __bos(buffer)=512 *** buffer overflow detected ***: test1 - terminated test1: buffer overflow attack in function <unknown> - terminated Report to http://bugs.gentoo.org/ Aborted (core dumped) So, is it correct for -Ox to change __USE_FORTIFY_LEVEL?
(In reply to comment #5) > This appears to be a semi-valid fix, valid only until a new kernel revision > changes PATH_MAX within /usr/include/linux/limits.h I had very same idea, but if you want this to change, report at upstream bug, please. > So, is it correct for -Ox to change __USE_FORTIFY_LEVEL? Check info gcc: NOTE: In Gentoo, `-D_FORTIFY_SOURCE=2' is set by default, and is activated when `-O' is set to 2 or higher. This enables additional compile-time and run-time checks for several libc functions. To disable, specify either `-U_FORTIFY_SOURCE' or `-D_FORTIFY_SOURCE=0'. So I guess this is Gentoo specific, is documented and easy to override.
This was the fix as applied upstream, so I'm going to leave it this way. I already have to carry enough divergent patches as it is.