| Summary: | 4.9-STABLE libc locale support might contain buffer overflows (or stack corruption, or double free() problem), appearing on some configurations; fix and testcase attached | ||||||
|---|---|---|---|---|---|---|---|
| Product: | Base System | Reporter: | dotz <dotz> | ||||
| Component: | bin | Assignee: | freebsd-bugs (Nobody) <bugs> | ||||
| Status: | Closed FIXED | ||||||
| Severity: | Affects Only Me | ||||||
| Priority: | Normal | ||||||
| Version: | 4.9-STABLE | ||||||
| Hardware: | Any | ||||||
| OS: | Any | ||||||
| Attachments: |
|
||||||
State Changed From-To: open->closed This problem is believed to have been fixed in 4.10-R and -STABLE. |
***************************************************************** Disclaimer: I might be totally wrong here, but this case is worth looking at anyway. I have only partial knowledge about gcc, stack frames, buffer overflows and such stuff. ***************************************************************** After a few days of uptime, my fresh install of 4.9-RELEASE (from mini-iso) started to behave in a strange way. Whenever I used LC_ALL, LC_MESSAGES or LC_NUMERIC environment variables (they worked before!), standard FreeBSD programs from basesystem (like tcsh(1) or ls(1)) dumped core while start-up, no matter which locale was used. My RAM is tested; coredumps were repeatable; cvsup to -STABLE and buildworld/installworld performed a few times (CFLAGS=-O) did *not* change the situation. As it came out: - programs coredumped at line 69 of src/libc/locale/ldpart.c, then, after my patching, around line 125 (sorry, I don't have those backtraces saved, but look at the code -- it just asks for a coredump, not doing any NULL checking) - errors appeared, whenever __part_load_locale was called from: src/libc/locale files: lmessages.c, lnumeric.c and lmonetary.c. src/libc/stdtime/timelocale.c - errors appeared only with LC_ALL (or LC_* variables set to something else, than "" or "C") Below is the last gdb backtrace I took before squishing this bug: Core was generated by `ls'. Program terminated with signal 11, Segmentation fault. #0 0x8073551 in __part_load_locale (name=0x80a7860 "en_US.ISO8859-1", using_locale=0x80a9128, locale_buf=0x0, category_filename=0x809f153 "LC_TIME", locale_buf_size_max=58, locale_buf_size_min=58, dst_localebuf=0x80a9040) at /usr/src/lib/libc/../libc/locale/ldpart.c:136 136 *locale_buf = lbuf; (gdb) backtrace #0 0x8073551 in __part_load_locale (name=0x80a7860 "en_US.ISO8859-1", using_locale=0x80a9128, locale_buf=0x0, category_filename=0x809f153 "LC_TIME", locale_buf_size_max=58, locale_buf_size_min=58, dst_localebuf=0x80a9040) at /usr/src/lib/libc/../libc/locale/ldpart.c:136 #1 0x8061d1b in __time_load_locale (name=0x80a7860 "en_US.ISO8859-1") at /usr/src/lib/libc/../libc/stdtime/timelocal.c:113 #2 0x805cff4 in loadlocale (category=5) at /usr/src/lib/libc/../libc/locale/setlocale.c:317 #3 0x805cc5d in setlocale (category=0, locale=0x80908e9 "") at /usr/src/lib/libc/../libc/locale/setlocale.c:205 #4 0x804839c in main (argc=1, argv=0xbfbffb8c) at /usr/src/bin/ls/ls.c:145 The question is: did the bug occur because those programs were static-linked? No idea. My pkgsrc-compiled (www.pkgsrc.org) pkgsrc/editors/jed worked without problems (but hey, it didn't use any LOCALE settings, I suppose). But -- on the other hand -- pkgsrc/databases/postgresql did coredumped. The just error started to appear and there was no way to stop this. I know, sounds silly and unbeliveable. But I have my RAM tested, I have backtrace, hah -- I even have a patch, which fixed it. Please read on. Fix: I have only partial knowledge about the calling proces in ldpart.c, so those patches might be only a walk-around and not a fix. Please remember about it. How-To-Repeat: This is the best part: I totally have no damn clue, what did I do on the system. This problem occurs on my machine on 4-STABLE rebuilt (few times) and cvsupped around Tue Dec 23 22:58:01 CET 2003. Anyway, here is promised testcase. I made it look as similar to code found in the files I mentioned in "Full description". Of course this can not be explictly compared to locale in libc (many factors are different). Compiling this with AFTER_MY_PATCH set to 0 issues a warning, which is not present in warnings generated by libc compile (even with -Wall). This might be because of the way __part_load_locale is called. Remember, that I have not tested if libc enters __part_load_locale with the same arguments only one time or many times; I have just found something, that looks like a serious bug to me -- and created patches, that get rid of it. I have no more time for testing this (I have work to do, who hasn't) -- but if you find this situation interesting, feel free to e-mail me, I will help with tracking of this bug to the extent of shell account on my machine. testcase.c: #include <stdio.h> #include <stdlib.h> /* * AFTER_MY_PATCH: * * when defined to "0", segfaults on my setup, which is: * FreeBSD mainframe.w.lub.pl 4.9-STABLE FreeBSD 4.9-STABLE #0: Tue Dec 23 20:45:53 CET 2003 root@mainframe.w.lub.pl:/usr/obj/usr/src/sys/MP-UX i386 * (a stripped GENERIC) * * doc@mainframe:~> gcc --version * 2.95.4 * doc@mainframe:~> ld --version * GNU ld version 2.12.1 [FreeBSD] 2002-07-20 */ #define AFTER_MY_PATCH 1 static char *_whatever_locale_buf; FAKE__part_load_locale(char **foo) { static char *a = "worked"; #if AFTER_MY_PATCH == 1 puts("here"); if (_whatever_locale_buf != NULL) { puts("and here!"); if (*_whatever_locale_buf != NULL) { puts("still here!"); if (strcmp("worked", _whatever_locale_buf)==0) { puts("I was already used. This is okay."); exit(0); } } } puts("after here!"); #else puts("before checking"); if (*_whatever_locale_buf != NULL && strcmp("worked", *_whatever_locale_buf)==0) { puts("I was already used. This is okay."); exit(0); } puts("after checking"); #endif puts("about to set variable"); *foo = a; puts("did it! returning!"); } main(){ FAKE__part_load_locale(&_whatever_locale_buf); puts(_whatever_locale_buf); /* should output "worked" */ FAKE__part_load_locale(&_whatever_locale_buf); /* should output "already used" and exit */ }