[ advisories | exploits | discussions | news | conventions | security tools | texts & papers ]
 main menu
- feedback
- advertising
- privacy
- FightAIDS
- newsletter
- news
- read forum
- new topic
- search

- meetings list
- recent additions
- add your info
 top 100 sites
- visit top sites
- sign up now
- members

- add your url
- add domain
- search box
- link to us

- our projects
- free email
 m4d network
- security software
- secureroot
- m4d.com
Home : Advisories : catopen() may pose security risk for third party code

Title: catopen() may pose security risk for third party code
Released by: FreeBSD
Date: 27th September 2000
Printable version: Click here


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 

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 http://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 http://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 = '\0';

     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







(C) 1999-2000 All rights reserved.