Pavel Kankovsky
1998-May-26 12:42 UTC
Re: [linux-security] Beware of dangerous enviroment (Re: Overflows in minicom)
On Sat, 23 May 1998, Torkil Zachariassen wrote:> >I have browsed various versions of libc and found a handful of weak points > >where the value of an enviroment variable is trusted more than necessary. >[1]> Could you explain to programming novices on linux-security - people like > myself 8) - hwo this could affect security on a firewall (proxy and/or > IP-router, with/without othert services like a webserver, lpd and alike) > running Linux (of course)?[2]> And what could proper precautions be and how could we monitor this part > of the security?[To the moderator: I have no idea whether all this stuff belongs to the list. It is up to you to decide. :) ] ad [1] This means if the attacker could make some privileged (*) program execute with any of those (**) variables set to certain values, the program would be coaxed to read (or write) any file on the system if it uses any affected libc subsystem. How does it affect your firewall? First of all, it is quite unlikely the bug is remotely exploitable (but it is certainly possible: for instance, the telnet protocol allows the client to set arbitrary enviroment variables, and some old versions of telnetd honored the settings carelessly). Second, the bugs (save from LD_PROFILE_OUTPUT which is much more dangerous) can be abused to crash the system (read /dev/flaky_device), annihilate kernel messages (read /dev/kmsg), or corrupt open data streams (read /proc/1234/fd/0), one can hardly steal data or modify them in any predictible way. ad [2]: The proper precaution is to fix libc, of course. Ulrich Drepper posted a fix for glibc2.[01], I myself have made a rather simpleminded (thus overly paranoid) fix for libc 5.4.44 recently. I am enclosing it. (***) Hmmm... perhaps the even more proper precaution would be to separate "vital" (syscalls, string routines) and "user convenience" (NLS, time conversion) parts of libc, undertake an exhaustive audit of the "vital" part (the whole libc is too huge), and avoid linking privileged programs with anything but the audited library. Unfortunately, many programs would have to be split into an unprivileged "front-end" and a privileged "back-end". How to monitor? This a hard question. An attempt to abuse such a hole could probably be detected if you audited enviroment variable settings of security sensitive programs, and unusual directory lookups crossing ".." entries. AFAIK, syscall auditing is a part of Linux-privs project and is going to be merged into 2.3. --Pavel Kankovsky aka Peak [ Boycott Microsoft--http://www.vcnet.com/bms ] (*) for a non-user, any program is privileged (**) the actual meaning of "those" depends on the version of libc (***) voila, I patched more getenv()s than I reported in my post: MALLOC_*, NIS_*; I have to admit I do know whether I did it because I found they were harmful or because I was too lazy to verify they were safe... <<<patch for 5.4.44>>> --- libc-5.4.44/libc/dl-malloc/malloc.c.secenv Sun Nov 2 03:48:44 1997 +++ libc-5.4.44/libc/dl-malloc/malloc.c Sat May 16 15:28:14 1998 @@ -257,6 +257,8 @@ #include <stdio.h> /* needed for malloc_stats */ +extern char *__libc_secure_getenv(const char *); + /* Compile-time options @@ -3365,15 +3367,15 @@ if(__libc_malloc_initialized) return; __libc_malloc_initialized = 1; - if((s = getenv("MALLOC_TRIM_THRESHOLD_"))) + if((s = __libc_secure_getenv("MALLOC_TRIM_THRESHOLD_"))) mALLOPt(M_TRIM_THRESHOLD, atoi(s)); - if((s = getenv("MALLOC_TOP_PAD_"))) + if((s = __libc_secure_getenv("MALLOC_TOP_PAD_"))) mALLOPt(M_TOP_PAD, atoi(s)); - if((s = getenv("MALLOC_MMAP_THRESHOLD_"))) + if((s = __libc_secure_getenv("MALLOC_MMAP_THRESHOLD_"))) mALLOPt(M_MMAP_THRESHOLD, atoi(s)); - if((s = getenv("MALLOC_MMAP_MAX_"))) + if((s = __libc_secure_getenv("MALLOC_MMAP_MAX_"))) mALLOPt(M_MMAP_MAX, atoi(s)); - s = getenv("MALLOC_CHECK_"); + s = __libc_secure_getenv("MALLOC_CHECK_"); if(s) { if(s[0]) mALLOPt(M_CHECK_ACTION, (int)(s[0] - ''0'')); __malloc_check_init(); --- libc-5.4.44/libc/locale/findlocale.c.secenv Sat Oct 5 00:53:01 1996 +++ libc-5.4.44/libc/locale/findlocale.c Sat May 16 15:32:10 1998 @@ -35,6 +35,8 @@ const struct locale_data *_nl_find_locale (const char *, size_t, int, char **); +extern char *__libc_secure_getenv(const char *); + static inline char * copy (const char *string) @@ -73,11 +75,11 @@ { /* The user decides which locale to use by setting environment variables. */ - *name = getenv ("LC_ALL"); + *name = __libc_secure_getenv ("LC_ALL"); if (*name == NULL || (*name)[0] == ''\0'') - *name = getenv (_nl_category_names[category]); + *name = __libc_secure_getenv (_nl_category_names[category]); if (*name == NULL || (*name)[0] == ''\0'') - *name = getenv ("LANG"); + *name = __libc_secure_getenv ("LANG"); if (*name == NULL || (*name)[0] == ''\0'') *name = (char *) _nl_C_name; } --- libc-5.4.44/libc/nls/msgcat.c.secenv Thu Aug 28 04:59:19 1997 +++ libc-5.4.44/libc/nls/msgcat.c Sat May 16 16:45:42 1998 @@ -124,6 +124,8 @@ #include <sys/mman.h> #endif +extern char *__libc_secure_getenv(const char *); + nl_catd catopen( const char *name, int type ) { @@ -141,13 +143,13 @@ if (stat(catpath, &sbuf)) return(NLERR); } else { #if BROKEN_SETLOCALE - if ((lang = (char *) getenv ("LANG")) == NULL) lang = "C"; + if ((lang = (char *) __libc_secure_getenv ("LANG")) == NULL) lang = "C"; #else /* Query the locale from the previous setlocale call in msgcat-libc.c*/ if ((lang = (char *) setlocale(LC_MESSAGES,(char *) NULL)) == NULL) lang="C"; #endif - if ((nlspath = (char *) getenv ("NLSPATH")) == NULL) { + if ((nlspath = (char *) __libc_secure_getenv ("NLSPATH")) == NULL) { #if OLD_NLS_PATHS nlspath = "/nlslib/%L/%N.cat:/nlslib/%N/%L"; #else @@ -187,6 +189,7 @@ ++nlspath; strcpy(pathP, lang); pathP = tmp; + continue; } else if (*(nlspath + 1) == ''N'') { char * tmp = pathP + strlen(name); if (tmp > path + sizeof (path)) @@ -197,15 +200,14 @@ ++nlspath; strcpy(pathP, name); pathP = tmp; - } else *(pathP++) = *nlspath; - } else - { - if (pathP >= path + sizeof (path)) - { - goto error; + continue; } - *(pathP++) = *nlspath; } + if (pathP >= path + sizeof (path)) + { + goto error; + } + *(pathP++) = *nlspath; } *pathP = ''\0''; if (stat(path, &sbuf) == 0 && S_ISREG (sbuf.st_mode)) { --- libc-5.4.44/libc/nys/nis/src/nis_names.c.secenv Mon Oct 21 06:40:17 1996 +++ libc-5.4.44/libc/nys/nis/src/nis_names.c Sat May 16 15:46:52 1998 @@ -29,6 +29,8 @@ #include "nis_conf.h" #include "xalloc.h" +extern char *__libc_secure_getenv(const char *); + nis_name nis_local_directory(void) { @@ -152,7 +154,7 @@ static char default_group[NIS_MAXNAMELEN]; char *cptr; - if ((cptr=getenv("NIS_GROUP"))==NULL) + if ((cptr=__libc_secure_getenv("NIS_GROUP"))==NULL) return ""; if (strlen(cptr) >= sizeof(default_group)) @@ -317,7 +319,7 @@ return rnames; } - path = getenv("NIS_PATH"); + path = __libc_secure_getenv("NIS_PATH"); if (path == NULL) path = "$"; --- libc-5.4.44/libc/time/bsdtime.c.secenv Mon Oct 21 06:40:22 1996 +++ libc-5.4.44/libc/time/bsdtime.c Sat May 16 17:02:38 1998 @@ -1015,6 +1015,8 @@ (void) tzparse(GMT, sp, TRUE); } +extern char *__libc_secure_getenv(const char *); + #ifdef __STDC__ void tzset(void) @@ -1026,7 +1028,7 @@ register const char * name; void tzsetwall(void); - name = getenv("TZ"); + name = __libc_secure_getenv("TZ"); if (name == NULL) { tzsetwall(); return; <<<end of the patch>>>