COMMAND crt0.c SYSTEMS AFFECTED FreeBSD 2.1.5, 2.1.6 PROBLEM Thomas Ptacek and Michael Scher reported that there is a critically important security problem in FreeBSD 2.1.5's C runtime support library that will enable anyone with control of the environment of a process to cause it to execute arbitrary code. All executable SUID programs on the system are vulnerable to this problem. The issue is that FreeBSD 2.1.5's crt0.c start() routine, which calls the "main()" entry point function in the program that is starting, will under some circumstances call routines that set the "locale" of the program. The routines that do this are heavily dependant on environment variables, which are in some circumstances copied directly into local character buffers on the stack of the locale routines. An immediately exploitable problem is evident in "startup_setrunelocale()", which, if certain environment variables are set, will copy the value of "PATH_LOCALE" directly into a 1024 byte buffer on the routine's stack. An attacker simply needs to insert machine code and virtual memory addresses into the "PATH_LOCALE" variable, enable startup locale processing, and run an SUID program. On FreeBSD 2.1.5, startup locale processing is enabled by setting the environment variable "ENABLE_STARTUP_LOCALE". "startup_setrunelocale()" is called if the environment variable "LC_CTYPE" is set as well. SOLUTION FreeBSD 2.2-BETA, as well as OpenBSD, seem to have this problem resolved. FreeBSD's crt0 start() function does not process locales and is thus not vulnerable to this problem. Dan Cross gave untested patch which SHOULD fix the problem, though: ----- Begin startup_setlocale.diff *** startup_setlocale.c 1997/02/03 07:40:46 1.1 --- startup_setlocale.c 1997/02/03 07:41:47 *************** *** 174,183 **** return(0); } ! (void) strcpy(name, PathLocale); ! (void) strcat(name, "/"); ! (void) strcat(name, encoding); ! (void) strcat(name, "/LC_CTYPE"); if ((fp = fopen(name, "r")) == NULL) return(ENOENT); --- 174,181 ---- return(0); } ! (void) snprintf(name, ! PATH_MAX, "%s/%s/LC_CTYPE", PathLocale, encoding); if ((fp = fopen(name, "r")) == NULL) return(ENOENT); ----- End of startup_setlocale.diff