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