AUSCERT External Security Bulletin Redistribution
                      ESB-2000.271 -- FreeBSD-SA-00:53
            catopen() may pose security risk for third party code
                              29 September 2000


	AusCERT Security Bulletin Summary

Product:                libc
Vendor:                 FreeBSD
Operating System:       FreeBSD
Impact:                 Execute Arbitrary Code/Commands
Access Required:        Local

- --------------------------BEGIN INCLUDED TEXT--------------------


FreeBSD-SA-00:53                                            Security Advisory
                                                                FreeBSD, Inc.

Topic:          catopen() may pose security risk for third party code

Category:       core
Module:         libc
Announced:      2000-09-27
Affects:        FreeBSD 5.0-CURRENT, 4.x and 3.x prior to the correction date.
Corrected:      Problem 1: 2000-08-06 (FreeBSD 5.0-CURRENT)
                           2000-08-22 (FreeBSD 4.1-STABLE)
                           2000-09-07 (FreeBSD 3.5-STABLE)
                Problem 2: 2000-09-08 (FreeBSD 5.0-CURRENT, 4.1-STABLE and
Credits:	Problem 1: Discovered during internal auditing
		Problem 2: Ivan Arce <iarce@core-sdi.com>
FreeBSD only:   NO

I.   Background

catopen() and setlocale() are functions which are used to display text
in a localized format, e.g. for international users.

II.  Problem Description

There are two problems addressed in this advisory:

1) The catopen() function did not correctly bounds-check an internal
buffer which could be indirectly overflowed by the setting of an
environment variable. A privileged application which uses catopen()
could be made to execute arbitrary code by an unprivileged local user.

2) The catopen() and setlocale() functions could be made to use an
arbitrary file as the source for localized data and message catalogs,
instead of one of the system files. An attacker could create a file
which is a valid locale file or message catalog but which contains
special formatting characters which may allow certain badly written
privileged applications to be exploited and execute arbitrary code as
the privileged user.

This second vulnerability is slightly different from the problem
originally discovered by Ivan Arce of Core-SDI which affects multiple
UNIX operating systems, which involved a different environment
variable and which FreeBSD is not susceptible to. However
Vulnerability 2 was discovered in FreeBSD after the publication the
Core-SDI advisory, and has the same effect on vulnerable applications.

NOTE that the FreeBSD base system is not believed to be vulnerable to
either of these problems, nor are any vulnerable third party programs
(including FreeBSD ports) currently known. Therefore the impact on the
majority of FreeBSD systems is expected to be nonexistent.

III. Impact

Certain setuid/setgid third-party software (including FreeBSD
ports/packages) may be vulnerable to a local exploit yielding
privileged access. No such software is however currently known.

It is believed that no program in the FreeBSD base system is
vulnerable to these bugs.

The problems were corrected prior to the release of FreeBSD 4.1.1.

IV.  Workaround

Vulnerability 1 described above is the more serious of the two, since
it does not require the application to contain a coding flaw in order
to exploit it. A scanning utility is provided to detect privileged
binaries which use the catopen() function (both statically and
dynamically linked binaries), which should be either rebuilt, or have
their privileges limited to minimize potential risk.

It is not feasible to detect binaries which are vulnerable to the
second vulnerability, however the provided utility will also report
statically linked binaries which use the setlocale() functions and
which *may* potentially be vulnerable. Most of the binaries reported
will not in fact be vulnerable, but should be recompiled anyway for
maximum assurance of security. Note that some FreeBSD system binaries
may be reported as possibly vulnerable by this script, however this
is not the case.

Statically linked binaries which are identified as vulnerable or
potentially vulnerable should be recompiled from source code after
patching and recompiling libc, if possible, in order to correct the
vulnerability. Dynamically linked binaries will be corrected by simply
patching and recompiling libc as described below.

As an interim measure, consider removing any identified setuid or
setgid binary, removing set[ug]id privileges from the file, or
limiting the file access permissions, as appropriate.

Of course, it is possible that some of the identified files may be
required for the correct operation of your local system, in which case
there is no clear workaround except for limiting the set of users who
may run the binaries, by an appropriate use of user groups and
removing the "o+x" file permission bit.

1) Download the 'scan_locale.sh' and 'test_locale.sh' scripts from


e.g. with the fetch(1) command:

# fetch ftp://ftp.freebsd.org/pub/FreeBSD/CERT/tools/SA-00:53/scan_locale.sh
Receiving scan_locale.sh (337 bytes): 100%
337 bytes transferred in 0.0 seconds (1.05 MBps)
# fetch ftp://ftp.freebsd.org/pub/FreeBSD/CERT/tools/SA-00:53/test_locale.sh
Receiving test_locale.sh (889 bytes): 100%
889 bytes transferred in 0.0 seconds (1.34 MBps)

2) Verify the md5 checksums and compare to the value below:

# /sbin/md5 scan_locale.sh
MD5 (scan_locale.sh) = efea80f74b05e7ddbc0261ef5211e453
# /sbin/md5 test_locale.sh
MD5 (test_locale.sh) = 2a485bf8171cc984dbc58b4d545668b4

3) Run the scan_locale.sh script against your system:

# sh scan_locale.sh ./test_locale.sh /

This will scan your entire system for setuid or setgid binaries which
make use of the exploitable function catopen(), or the potentially
exploitable function setlocale(). Each returned binary should be
examined (e.g. with 'ls -l' and/or other tools) to determine what
security risk it poses to your local environment, e.g. whether it can
be run by arbitrary local users who may be able to exploit it to gain

Note that this script reports setlocale() usage (i.e. vulnerability 2)
only in statically linked binaries, not dynamically linked binaries,
because of the high rate of false positives. It is likely that the
majority of such setlocale() binaries identified are not insecure and
their identification by this script should not be taken as evidence
that they are vulnerable, but they should be recompiled anyway for
maximum assurance of security.

4) Remove the binaries, or reduce their file permissions, as appropriate.

V.   Solution

Upgrade your vulnerable FreeBSD system to 4.1-STABLE or 3.5-STABLE
after the correction date, or patch your present system source code
and rebuild. Then run the scan_locale.sh script as instructed in
section IV and identify any statically-linked binaries as reported by
the script. These should either be removed, recompiled, or have
privileges restricted to secure them against this vulnerability (since
statically-linked binaries will not be affected by simply recompiling
the shared libc library).

To patch your present system: save the patch below into a file, and
execute the following commands as root:

cd /usr/src/lib/libc
patch < /path/to/patch/file
make all
make install

Patches for FreeBSD systems before the correction date:

    Index: msgcat.c
    RCS file: /usr2/ncvs//src/lib/libc/nls/msgcat.c,v
    retrieving revision 1.21
    retrieving revision 1.27
    diff -u -r1.21 -r1.27
    --- nls/msgcat.c	2000/01/27 23:06:33	1.21
    +++ nls/msgcat.c	2000/09/01 11:56:31	1.27
    @@ -91,8 +91,9 @@
         __const char *catpath = NULL;
         char        *nlspath;
         char	*lang;
    -    long	len;
         char	*base, *cptr, *pathP;
    +    int		spcleft;
    +    long	len;
         struct stat	sbuf;
         if (!name || !*name) {
    @@ -106,10 +107,10 @@
         } else {
     	if (type == NL_CAT_LOCALE)
     		lang = setlocale(LC_MESSAGES, NULL);
    -	else {
    -		if ((lang = (char *) getenv("LANG")) == NULL)
    -			lang = "C";
    -	}
    +	else
    +		lang = getenv("LANG");
    +	if (lang == NULL || strchr(lang, '/') != NULL)
    +		lang = "C";
     	if ((nlspath = (char *) getenv("NLSPATH")) == NULL
     #ifndef __NETBSD_SYSCALLS
     	    || issetugid()
    @@ -129,13 +130,22 @@
     		*cptr = '';
     		for (pathP = path; *nlspath; ++nlspath) {
     		    if (*nlspath == '%') {
    +		        spcleft = sizeof(path) - (pathP - path);
     			if (*(nlspath + 1) == 'L') {
    -			    strcpy(pathP, lang);
    +			    if (strlcpy(pathP, lang, spcleft) >= spcleft) {
    +				free(base);
    +				errno = ENAMETOOLONG;
    +				return(NLERR);
    +			    }
     			    pathP += strlen(lang);
     			} else if (*(nlspath + 1) == 'N') {
    -			    strcpy(pathP, name);
    +			    if (strlcpy(pathP, name, spcleft) >= spcleft) {
    +				free(base);
    +			        errno = ENAMETOOLONG;
    +				return(NLERR);
    +			    }
     			    pathP += strlen(name);
     			} else *(pathP++) = *nlspath;
     		    } else *(pathP++) = *nlspath;
    @@ -186,7 +196,7 @@
         MCSetT	*set;
         long	lo, hi, cur, dir;
    -    if (!cat || setId <= 0) return(NULL);
    +    if (cat == NULL || setId <= 0) return(NULL);
         lo = 0;
         if (setId - 1 < cat->numSets) {
    @@ -212,8 +222,8 @@
     	if (hi - lo == 1) cur += dir;
     	else cur += ((hi - lo) / 2) * dir;
    -    if (set->invalid)
    -	(void) loadSet(cat, set);
    +    if (set->invalid && loadSet(cat, set) <= 0)
    +	return(NULL);
    @@ -225,7 +235,7 @@
         MCMsgT	*msg;
         long	lo, hi, cur, dir;
    -    if (!set || set->invalid || msgId <= 0) return(NULL);
    +    if (set == NULL || set->invalid || msgId <= 0) return(NULL);
         lo = 0;
         if (msgId - 1 < set->numMsgs) {
    @@ -318,7 +328,7 @@
         off_t	nextSet;
         cat = (MCCatT *) malloc(sizeof(MCCatT));
    -    if (!cat) return(NLERR);
    +    if (cat == NULL) return(NLERR);
         cat->loadType = MCLoadBySet;
         if ((cat->fd = _open(catpath, O_RDONLY)) < 0) {
    @@ -351,7 +361,7 @@
         cat->numSets = header.numSets;
         cat->sets = (MCSetT *) malloc(sizeof(MCSetT) * header.numSets);
    -    if (!cat->sets) NOSPACE();
    +    if (cat->sets == NULL) NOSPACE();
         nextSet = header.firstSet;
         for (i = 0; i < cat->numSets; ++i) {
    Index: setlocale.c
    RCS file: /home/ncvs/src/lib/libc/locale/setlocale.c,v
    retrieving revision 1.27
    retrieving revision 1.28
    diff -u -r1.27 -r1.28
    --- locale/setlocale.c	2000/09/04 03:43:24	1.27
    +++ locale/setlocale.c	2000/09/08 07:29:48	1.28
    @@ -129,7 +129,7 @@
     		if (!env || !*env)
     			env = getenv("LANG");
    -		if (!env || !*env)
    +		if (!env || !*env || strchr(env, '/'))
     			env = "C";
     		(void) strncpy(new_categories[category], env, ENCODING_LEN);

Version: 2.6.2


- --------------------------END INCLUDED TEXT--------------------

This security bulletin is provided as a service to AusCERT's members.  As
AusCERT did not write the document quoted above, AusCERT has had no control
over its content.  The decision to use any or all of this information is
the responsibility of each user or organisation, and should be done so in
accordance with site policies and procedures.

NOTE: This is only the original release of the security bulletin.  It may
not be updated when updates to the original are made.  If downloading at
a later date, it is recommended that the bulletin is retrieved directly
from the original authors to ensure that the information is still current.

Contact information for the authors of the original document is included
in the Security Bulletin above.  If you have any questions or need further
information, please contact them directly.

Previous advisories and external security bulletins can be retrieved from:


If you believe that your system has been compromised, contact AusCERT or
your representative in FIRST (Forum of Incident Response and Security

Internet Email: auscert@auscert.org.au
Facsimile:	(07) 3365 7031
Telephone:	(07) 3365 4417 (International: +61 7 3365 4417)
		AusCERT personnel answer during Queensland business hours
		which are GMT+10:00 (AEST).
		On call after hours for emergencies.

Version: 2.6.3i
Charset: noconv
Comment: ftp://ftp.auscert.org.au/pub/auscert/AUSCERT_PGP.key