Date: Sun, 13 Dec 2015 21:55:25 +1100 (EST) From: Bruce Evans <brde@optusnet.com.au> To: Garrett Cooper <ngie@freebsd.org> Cc: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: Re: svn commit: r292153 - head/lib/libc/regex/grot Message-ID: <20151213202334.G997@besplex.bde.org> In-Reply-To: <201512130633.tBD6XqrN024958@repo.freebsd.org> References: <201512130633.tBD6XqrN024958@repo.freebsd.org>
next in thread | previous in thread | raw e-mail | index | archive | help
On Sun, 13 Dec 2015, Garrett Cooper wrote: > Log: > Add -static to CFLAGS to unbreak the tests by using a libc.a with > the xlocale private symbols exposed which aren't exposed publicly > via the DSO This is an interesting hack. I think there are some bad bugs in static libraries from exposing public private (sic) symbols in them, and from using private public (sic) symbols. Or perhaps the reverse. A public private symbol is one that is public (extern) in C but not exported from the shared library. A private public symbol is one that is public (extern) in C and is also exported by the shared library, but is a weak symbol so it is sort of private for both. An example of the latter is 'open' or syslog. Both are in the user namespace for Standard C. syslog is in the user namespace for some versions of POSIX. libc is supposed to use renamed versions so that it never uses a user version. It mostly does this for _open. open is a weak symbol so that sloppy parts of libc and POSIX applications can see it. Non-POSIX applications can see it too unless they replace it. According to nm on libc.a, the only thing in the library with a sloppy reference to open is citrus_mmap.o. It also references close, fstat, mmap and munmap. This is probably OK since it is an extension of POSIX. There is the following thicket of complications in names for what should be the simple open syscall: open.o: X U __libc_interposing X U __stack_chk_fail X U __stack_chk_guard X 0000000000000000 W open _open.o: X U .cerror X 0000000000000000 T __sys_open X 0000000000000000 W _open Even _open is a weak symbol. That makes no sense. Similarly for all syscalls except ones like _exit whose primary syscall name has the single underscore. I think it is just a bug in the PSEUDO macro in SYS.h. Functions like syslog() are not handled so carefully. They are never renamed. This was not a problem, since they were not called much from other parts of libc. Perhaps never for syslog(), or just from associated parts with the closure of the parts being entirely inside or entirely outside APIs that have syslog(). But this was broken by the stack protector code. The stack protector code is not called from all over the library, e.g., for open as shown above. This turns the careful renaming for open into just an obfuscation (except the obfuscations also give pessimizations). Test program for this. X #include <fcntl.h> X #include <stdio.h> X X #ifndef NO_DEBLOAT X void X openlog(void) X { X puts("opensyslog() is not in the Standard C library()"); X } X X void X syslog(void) X { X puts("syslog() is not in the Standard C library()"); X /* I am careful not to call this, but stack_protector.c isn't. */ X // system("rm -rf /"); X } X X void X vsyslog(void) X { X puts("vsyslog() is not even in POSIX"); X } X X void X closelog(void) X { X puts("opensyslog() is not in the Standard C library()"); X } X X off_t X lseek(int fd, off_t offset, int whence) X { X puts("lseek() is not in the Standard C library()"); X return -1; X } X #endif X X int X main(void) X { X #ifdef FORCE_USE X openlog(); X vsyslog(); X closelog(); X #else X open("/dev/null", 0); /* warm up for debugging */ X open("/dev/null", 0); /* try to get it to call us */ X #endif X puts("hello world is bloated"); X } This must be run under gdb. Manually corrupt the stack so that __stack_chk_fail is called. Then the private syslog() is called iff the linkage is static. The other functions are normally not called since __stack_chk_fail kills the program with SIGABRT after calling syslog(). Debugging this shows another bug (bogusness at least): _open uses the open syscall, but open uses the openat syscall. Debugging this is especially difficult when it is dynamically linked. Then the __libc_interposing, __stack_chk_fail and __stack_chk_guard symbols are so private that even the debugger can't see them, at least with the library not compiled with -g. With static linkage, they are normal public symbols. This program was originally for testing reduction of library bloat. The bloat is so large that the null program main(){} now links to syslog and might even call it if the stack gets corrupted. So the null program now has size more than 460KB on amd64 (more than 4 times larger than /bin/sh in FreeBSD-1). Bruce
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20151213202334.G997>