1st Jan 1996 [SBWID-156]
COMMAND
setlocale()
SYSTEMS AFFECTED
FreeBSD 2.1.x, 2.2 (prior to December 1996)
PROBLEM
Thomas H. Ptacek reported that anyone who installed FreeBSD 2.2
prior to December of 1996 is vulnerable to locale routine problems
similar to the one that afflicts crt0 start() in FreeBSD 2.1.x
(take a look at crt0 bug on this page).
Specifically, You are able to cause a shell to be executed from
any program that calls setlocale() in FreeBSD 2.2. Thomas tested
this out with dmesg, which promptly gave him an SGID "kmem" shell.
Note that programs that shed privilege using saved-set UIDs are
vulnerable to this problem as well, as the machine code used to
take over the affected programs can easily restore privilege.
The setlocale() call contains a number of potential exploits
through string overflows during environment variable expansion.
Because the 2.1.6 and earlier versions of FreeBSD called
setlocale() in the C runtime code, the problem is especially
acute there in that it essentially effects all binaries on the
system. In FreeBSD 2.2 BETA and later releases, the setlocale()
call was removed from crt0.c and the exploit closed through
additional checks.
The setlocale() library function looks for the environment
variable "PATH_LOCALE" in the current process's environment, and
if it exists, later copies the contents of this variable to a
stack buffer without doing proper bounds checking. If the
environment variable was specially initialized with the proper
amount and type of data prior to running a setuid program, it is
possible to cause the program to overflow its stack and execute
arbitrary code which could allow the user to become root. Any
binary linked on a system with setlocale() built into crt0.c or
which calls setlocale() directly has the buffer overrun
vulnerability. If this binary has the setuid or setgid bits set,
or is called by another setuid/setgid binary (even if that other
setuid/setgid binary does not have this vulnerability),
unauthorized access may be allowed.
Update (18 september 2002)
======
Beleive it or not, but this issue existed until now in NetBSD too. From
NetBSD security advisory [2002-012: buffer overrun in setlocale] :
The setlocale (or its subcontractor, __setlocale) function, defined in
lib/libc/locale/setlocale.c, is used to change the locale of each
locale category. setlocale() function switches the locale of the
category specified by the first argument to the second argument. The
special category LC_ALL can be used to change all locale categories at
the same time. In this case, the NetBSD implementation of setlocale
allows a special form of the second argument string to specify
individual locales per category.
In this form, each locale is given in a single string separated by
slashes ('/'), as "A/B/C/D/E/F". Here, each element corresponds to
categories LC_COLLATE, LC_CTYPE, LC_MONETARY, LC_NUMERIC, LC_TIME and
LC_MESSAGES, respectively. The setlocale() function attempts to
decomposit these elements into an array object named new_categories
locally defined in lib/libc/locale/setlocale.c. However, the code to
check the array boundary was lacking and thus this decomposition code
could destroy data segment if a string having over six elements was
given.
If the program which has set[ug]id bit or which is called from
set[ug]id program calls setlocale() with LC_ALL as the first argument
and with the string derived from user-given data (e.g.
setlocale(LC_ALL, getenv("FOO")) ) as the second argument, then such
program could be exploitable. DefaultLanguageProc function of X Toolkit
Intrinsics (Xt) is a example of such usage. DefaultLanguageProc calls
setlocale as "setlocale(LC_ALL, xnl)". Here, xnl variable is null
string ("") by default, but can be overriden by user via - -xnllanguage
option. Most Xt programs, including xterm, use this language procedure.
xterm is a setuid root program and thus any local user could illegally
acquire root account by using this problem.
On the other hand, the frequently used special form, setlocale(LC_ALL,
""), does not have this problem because the decomposition code is never
executed in this form, although user-given LC_ALL environment variable
is similarly referred.
SOLUTION
The locale routines were patched at the end of 1996 to cause
PATH_LOCALE (the environment variable who's contents are trampling
all over the stack frames of locale routines) to be ignored if the
euid doesn't match the uid; the patch also avoids the stack
overrun by allocating space for the variable on the heap with
strdup().
People running FreeBSD revisions that don't have this patch will
want to make sure they've applied these patches as soon as
possible. Vulnerability can easily be assessed by setting
LC_CTYPE, filling PATH_LOCALE with 2000 random characters, and
attempting to run /sbin/dmesg (which will segfault if the problem
exists).
FreeBSD recommends recompiling libc with the following patches
and then recompiling all staticly linked binaries (all in /sbin
and /bin as well as chflags, gunzip, gzcat, gzip, ld, tar and
zcat in /usr/bin) eliminates this vulnerability in FreeBSD 2.1.6
and earlier releases:
However, a full solution may require a re-link of all
setuid/setgid local binaries or all local binaries likely to
be called from another setuid/setgid program that were
originally linked statically under one of the affected OSs.
Dynamically linked executables will benefit directly from
this patch once libc is rebuilt and reinstalled and do not
need to be relinked.
Because of the severity of this security hole, a full update
release for FreeBSD 2.1.6 will also be released very shortly,
that release being provisionally assigned the version number of
2.1.7. Patch for this can be found at following address:
ftp://freebsd.org/pub/CERT/patches/SA-97:01/
NetBSD
======
Updates available, check : http://www.NetBSD.ORG/Security/
TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2025 AOH