# Sanitize the environment in a paranoid way. diff -upk.orig glibc-2.3.5.orig/argp/argp-help.c glibc-2.3.5/argp/argp-help.c --- glibc-2.3.5.orig/argp/argp-help.c 2004-06-01 22:15:24 +0000 +++ glibc-2.3.5/argp/argp-help.c 2005-05-17 13:53:18 +0000 @@ -166,7 +166,7 @@ static const struct uparam_name uparam_n static void fill_in_uparams (const struct argp_state *state) { - const char *var = getenv ("ARGP_HELP_FMT"); + const char *var = __secure_getenv ("ARGP_HELP_FMT"); #define SKIPWS(p) do { while (isspace (*p)) p++; } while (0); diff -upk.orig glibc-2.3.5.orig/catgets/catgets.c glibc-2.3.5/catgets/catgets.c --- glibc-2.3.5.orig/catgets/catgets.c 2002-05-15 03:46:42 +0000 +++ glibc-2.3.5/catgets/catgets.c 2005-05-17 13:53:18 +0000 @@ -50,7 +50,7 @@ catopen (const char *cat_name, int flag) || (__libc_enable_secure && strchr (env_var, '/') != NULL)) env_var = "C"; - nlspath = getenv ("NLSPATH"); + nlspath = __secure_getenv ("NLSPATH"); if (nlspath != NULL && *nlspath != '\0') { /* Append the system dependent directory. */ diff -upk.orig glibc-2.3.5.orig/debug/pcprofile.c glibc-2.3.5/debug/pcprofile.c --- glibc-2.3.5.orig/debug/pcprofile.c 2001-07-06 04:54:45 +0000 +++ glibc-2.3.5/debug/pcprofile.c 2005-05-17 13:53:18 +0000 @@ -38,7 +38,7 @@ install (void) { /* See whether the environment variable `PCPROFILE_OUTPUT' is defined. If yes, it should name a FIFO. We open it and mark ourself as active. */ - const char *outfile = getenv ("PCPROFILE_OUTPUT"); + const char *outfile = __secure_getenv ("PCPROFILE_OUTPUT"); if (outfile != NULL && *outfile != '\0') { diff -upk.orig glibc-2.3.5.orig/elf/dl-support.c glibc-2.3.5/elf/dl-support.c --- glibc-2.3.5.orig/elf/dl-support.c 2004-11-06 00:24:49 +0000 +++ glibc-2.3.5/elf/dl-support.c 2005-05-23 02:18:40 +0000 @@ -159,6 +159,7 @@ void internal_function _dl_aux_init (ElfW(auxv_t) *av) { + int security_mask = 0; int seen = 0; uid_t uid = 0; gid_t gid = 0; @@ -192,30 +193,34 @@ _dl_aux_init (ElfW(auxv_t) *av) break; #endif case AT_UID: + if (seen & 1) break; uid ^= av->a_un.a_val; seen |= 1; break; case AT_EUID: + if (seen & 2) break; uid ^= av->a_un.a_val; seen |= 2; break; case AT_GID: + if (seen & 4) break; gid ^= av->a_un.a_val; seen |= 4; break; case AT_EGID: + if (seen & 8) break; gid ^= av->a_un.a_val; seen |= 8; break; case AT_SECURE: - seen = -1; - __libc_enable_secure = av->a_un.a_val; - __libc_enable_secure_decided = 1; + security_mask |= av->a_un.a_val != 0; break; } if (seen == 0xf) { - __libc_enable_secure = uid != 0 || gid != 0; + security_mask |= ((uid != 0) << 1) | ((gid != 0) << 2); + __libc_security_mask = security_mask; + __libc_enable_secure = __libc_security_mask != 0; __libc_enable_secure_decided = 1; } } @@ -232,19 +237,19 @@ _dl_non_dynamic_init (void) if (!_dl_pagesize) _dl_pagesize = __getpagesize (); - _dl_verbose = *(getenv ("LD_WARN") ?: "") == '\0' ? 0 : 1; + _dl_verbose = *(__secure_getenv ("LD_WARN") ?: "") == '\0' ? 0 : 1; /* Initialize the data structures for the search paths for shared objects. */ - _dl_init_paths (getenv ("LD_LIBRARY_PATH")); + _dl_init_paths (__secure_getenv ("LD_LIBRARY_PATH")); - _dl_lazy = *(getenv ("LD_BIND_NOW") ?: "") == '\0'; + _dl_lazy = *(__secure_getenv ("LD_BIND_NOW") ?: "") == '\0'; - _dl_bind_not = *(getenv ("LD_BIND_NOT") ?: "") != '\0'; + _dl_bind_not = *(__secure_getenv ("LD_BIND_NOT") ?: "") != '\0'; - _dl_dynamic_weak = *(getenv ("LD_DYNAMIC_WEAK") ?: "") == '\0'; + _dl_dynamic_weak = *(__secure_getenv ("LD_DYNAMIC_WEAK") ?: "") == '\0'; - _dl_profile_output = getenv ("LD_PROFILE_OUTPUT"); + _dl_profile_output = __secure_getenv ("LD_PROFILE_OUTPUT"); if (_dl_profile_output == NULL || _dl_profile_output[0] == '\0') _dl_profile_output = &"/var/tmp\0/var/profile"[__libc_enable_secure ? 9 : 0]; @@ -257,6 +262,8 @@ _dl_non_dynamic_init (void) EXTRA_UNSECURE_ENVVARS #endif ; + static const char restricted_envvars[] = + RESTRICTED_ENVVARS; const char *cp = unsecure_envvars; while (cp < unsecure_envvars + sizeof (unsecure_envvars)) @@ -265,8 +272,31 @@ _dl_non_dynamic_init (void) cp = (const char *) __rawmemchr (cp, '\0') + 1; } - if (__access ("/etc/suid-debug", F_OK) != 0) - __unsetenv ("MALLOC_CHECK_"); + if (__libc_security_mask & 2) + { + static const char unsecure_uid_envvars[] = + UNSECURE_UID_ENVVARS; + + cp = unsecure_uid_envvars; + while (cp < unsecure_uid_envvars + sizeof (unsecure_uid_envvars)) + { + __unsetenv (cp); + cp = (const char *) __rawmemchr (cp, '\0') + 1; + } + } + + /* This loop is buggy: it will only check the first occurrence of each + variable (but will correctly remove all in case of a match). This + may be a problem if the list is later re-ordered or accessed by an + application with something other than the glibc getenv(). */ + cp = restricted_envvars; + while (cp < restricted_envvars + sizeof (restricted_envvars)) + { + const char *value = getenv (cp); + if (value && (value[0] == '.' || strchr(value, '/'))) + __unsetenv (cp); + cp = (const char *) __rawmemchr (cp, '\0') + 1; + } } #ifdef DL_PLATFORM_INIT diff -upk.orig glibc-2.3.5.orig/elf/rtld.c glibc-2.3.5/elf/rtld.c --- glibc-2.3.5.orig/elf/rtld.c 2005-04-06 02:49:51 +0000 +++ glibc-2.3.5/elf/rtld.c 2005-05-23 01:53:37 +0000 @@ -2093,6 +2093,7 @@ process_envvars (enum mode *modep) GLRO(dl_profile_output) = &"/var/tmp\0/var/profile"[INTUSE(__libc_enable_secure) ? 9 : 0]; + if (__builtin_expect (!INTUSE(__libc_enable_secure), 1)) while ((envline = _dl_next_ld_env_entry (&runp)) != NULL) { size_t len = 0; @@ -2154,8 +2155,7 @@ process_envvars (enum mode *modep) case 9: /* Test whether we want to see the content of the auxiliary array passed up from the kernel. */ - if (!INTUSE(__libc_enable_secure) - && memcmp (envline, "SHOW_AUXV", 9) == 0) + if (memcmp (envline, "SHOW_AUXV", 9) == 0) _dl_show_auxv (); break; @@ -2168,8 +2168,7 @@ process_envvars (enum mode *modep) case 11: /* Path where the binary is found. */ - if (!INTUSE(__libc_enable_secure) - && memcmp (envline, "ORIGIN_PATH", 11) == 0) + if (memcmp (envline, "ORIGIN_PATH", 11) == 0) GLRO(dl_origin_path) = &envline[12]; break; @@ -2188,8 +2187,7 @@ process_envvars (enum mode *modep) break; } - if (!INTUSE(__libc_enable_secure) - && memcmp (envline, "DYNAMIC_WEAK", 12) == 0) + if (memcmp (envline, "DYNAMIC_WEAK", 12) == 0) GLRO(dl_dynamic_weak) = 1; break; @@ -2199,15 +2197,13 @@ process_envvars (enum mode *modep) #ifdef EXTRA_LD_ENVVARS_13 EXTRA_LD_ENVVARS_13 #endif - if (!INTUSE(__libc_enable_secure) - && memcmp (envline, "USE_LOAD_BIAS", 13) == 0) + if (memcmp (envline, "USE_LOAD_BIAS", 13) == 0) GLRO(dl_use_load_bias) = envline[14] == '1' ? -1 : 0; break; case 14: /* Where to place the profiling data file. */ - if (!INTUSE(__libc_enable_secure) - && memcmp (envline, "PROFILE_OUTPUT", 14) == 0 + if (memcmp (envline, "PROFILE_OUTPUT", 14) == 0 && envline[15] != '\0') GLRO(dl_profile_output) = &envline[15]; break; @@ -2251,16 +2247,39 @@ process_envvars (enum mode *modep) EXTRA_UNSECURE_ENVVARS #endif UNSECURE_ENVVARS; + static const char restricted_envvars[] = + RESTRICTED_ENVVARS; const char *nextp; - nextp = unsecure_envvars; - do + for (nextp = unsecure_envvars; *nextp != '\0'; + nextp = (char *) rawmemchr (nextp, '\0') + 1) { unsetenv (nextp); - /* We could use rawmemchr but this need not be fast. */ - nextp = (char *) (strchr) (nextp, '\0') + 1; } - while (*nextp != '\0'); + + if (__builtin_expect (INTUSE(__libc_security_mask) & 2, 0)) + { + static const char unsecure_uid_envvars[] = + UNSECURE_UID_ENVVARS; + + for (nextp = unsecure_uid_envvars; *nextp != '\0'; + nextp = (char *) rawmemchr (nextp, '\0') + 1) + { + unsetenv (nextp); + } + } + + /* This loop is buggy: it will only check the first occurrence of each + variable (but will correctly remove all in case of a match). This + may be a problem if the list is later re-ordered or accessed by an + application with something other than the glibc getenv(). */ + for (nextp = restricted_envvars; *nextp != '\0'; + nextp = (char *) rawmemchr (nextp, '\0') + 1) + { + const char *value = getenv (nextp); + if (value && (value[0] == '.' || strchr(value, '/'))) + unsetenv (nextp); + } if (__access ("/etc/suid-debug", F_OK) != 0) { diff -upk.orig glibc-2.3.5.orig/elf/Versions glibc-2.3.5/elf/Versions --- glibc-2.3.5.orig/elf/Versions 2004-10-19 22:20:33 +0000 +++ glibc-2.3.5/elf/Versions 2005-05-23 01:53:37 +0000 @@ -56,5 +56,6 @@ ld { _dl_make_stack_executable; # Only here for gdb while a better method is developed. _dl_debug_state; + __libc_security_mask; } } diff -upk.orig glibc-2.3.5.orig/gmon/gmon.c glibc-2.3.5/gmon/gmon.c --- glibc-2.3.5.orig/gmon/gmon.c 2004-09-14 04:24:43 +0000 +++ glibc-2.3.5/gmon/gmon.c 2005-05-17 13:53:18 +0000 @@ -326,8 +326,8 @@ write_gmon (void) # define O_NOFOLLOW 0 #endif - env = getenv ("GMON_OUT_PREFIX"); - if (env != NULL && !__libc_enable_secure) + env = __secure_getenv ("GMON_OUT_PREFIX"); + if (env != NULL) { size_t len = strlen (env); char buf[len + 20]; diff -upk.orig glibc-2.3.5.orig/iconv/gconv_cache.c glibc-2.3.5/iconv/gconv_cache.c --- glibc-2.3.5.orig/iconv/gconv_cache.c 2003-06-11 21:38:47 +0000 +++ glibc-2.3.5/iconv/gconv_cache.c 2005-05-17 13:53:18 +0000 @@ -55,7 +55,7 @@ __gconv_load_cache (void) /* We cannot use the cache if the GCONV_PATH environment variable is set. */ - __gconv_path_envvar = getenv ("GCONV_PATH"); + __gconv_path_envvar = __secure_getenv ("GCONV_PATH"); if (__gconv_path_envvar != NULL) return -1; diff -upk.orig glibc-2.3.5.orig/include/unistd.h glibc-2.3.5/include/unistd.h --- glibc-2.3.5.orig/include/unistd.h 2004-06-30 07:35:39 +0000 +++ glibc-2.3.5/include/unistd.h 2005-05-23 02:16:28 +0000 @@ -141,10 +141,12 @@ libc_hidden_proto (__sbrk) and some functions contained in the C library ignore various environment variables that normally affect them. */ extern int __libc_enable_secure attribute_relro; +extern int __libc_security_mask attribute_relro; extern int __libc_enable_secure_decided; #ifdef IS_IN_rtld /* XXX The #ifdef should go. */ extern int __libc_enable_secure_internal attribute_relro attribute_hidden; +extern int __libc_security_mask_internal attribute_relro attribute_hidden; #endif diff -upk.orig glibc-2.3.5.orig/intl/loadmsgcat.c glibc-2.3.5/intl/loadmsgcat.c --- glibc-2.3.5.orig/intl/loadmsgcat.c 2004-09-26 05:06:56 +0000 +++ glibc-2.3.5/intl/loadmsgcat.c 2005-05-17 13:53:18 +0000 @@ -816,7 +816,7 @@ _nl_init_domain_conv (domain_file, domai outcharset = domainbinding->codeset; else { - outcharset = getenv ("OUTPUT_CHARSET"); + outcharset = __secure_getenv ("OUTPUT_CHARSET"); if (outcharset == NULL || outcharset[0] == '\0') { # ifdef _LIBC diff -upk.orig glibc-2.3.5.orig/io/getdirname.c glibc-2.3.5/io/getdirname.c --- glibc-2.3.5.orig/io/getdirname.c 2001-07-06 04:54:53 +0000 +++ glibc-2.3.5/io/getdirname.c 2005-05-17 13:53:18 +0000 @@ -31,7 +31,7 @@ get_current_dir_name (void) char *pwd; struct stat64 dotstat, pwdstat; - pwd = getenv ("PWD"); + pwd = __secure_getenv ("PWD"); if (pwd != NULL && stat64 (".", &dotstat) == 0 && stat64 (pwd, &pwdstat) == 0 diff -upk.orig glibc-2.3.5.orig/libidn/toutf8.c glibc-2.3.5/libidn/toutf8.c --- glibc-2.3.5.orig/libidn/toutf8.c 2004-03-08 20:52:56 +0000 +++ glibc-2.3.5/libidn/toutf8.c 2005-05-17 13:53:18 +0000 @@ -71,7 +71,7 @@ const char * stringprep_locale_charset (void) { - const char *charset = getenv ("CHARSET"); /* flawfinder: ignore */ + const char *charset = __secure_getenv ("CHARSET"); /* flawfinder: ignore */ if (charset && *charset) return charset; diff -upk.orig glibc-2.3.5.orig/locale/newlocale.c glibc-2.3.5/locale/newlocale.c --- glibc-2.3.5.orig/locale/newlocale.c 2004-07-16 19:05:49 +0000 +++ glibc-2.3.5/locale/newlocale.c 2005-05-17 13:53:18 +0000 @@ -104,7 +104,7 @@ __newlocale (int category_mask, const ch locale_path = NULL; locale_path_len = 0; - locpath_var = getenv ("LOCPATH"); + locpath_var = __secure_getenv ("LOCPATH"); if (locpath_var != NULL && locpath_var[0] != '\0') { if (__argz_create_sep (locpath_var, ':', diff -upk.orig glibc-2.3.5.orig/locale/setlocale.c glibc-2.3.5/locale/setlocale.c --- glibc-2.3.5.orig/locale/setlocale.c 2004-08-04 21:55:05 +0000 +++ glibc-2.3.5/locale/setlocale.c 2005-05-17 13:53:18 +0000 @@ -237,7 +237,7 @@ setlocale (int category, const char *loc locale_path = NULL; locale_path_len = 0; - locpath_var = getenv ("LOCPATH"); + locpath_var = __secure_getenv ("LOCPATH"); if (locpath_var != NULL && locpath_var[0] != '\0') { if (__argz_create_sep (locpath_var, ':', diff -upk.orig glibc-2.3.5.orig/malloc/arena.c glibc-2.3.5/malloc/arena.c --- glibc-2.3.5.orig/malloc/arena.c 2005-03-07 22:46:24 +0000 +++ glibc-2.3.5/malloc/arena.c 2005-05-17 13:53:18 +0000 @@ -456,10 +456,10 @@ ptmalloc_init (void) # undef NO_STARTER # endif #endif + s = NULL; #ifdef _LIBC secure = __libc_enable_secure; - s = NULL; - if (__builtin_expect (_environ != NULL, 1)) + if (! secure && __builtin_expect (_environ != NULL, 1)) { char **runp = _environ; char *envline; @@ -482,15 +482,14 @@ ptmalloc_init (void) s = &envline[7]; break; case 8: - if (! secure && memcmp (envline, "TOP_PAD_", 8) == 0) + if (memcmp (envline, "TOP_PAD_", 8) == 0) mALLOPt(M_TOP_PAD, atoi(&envline[9])); break; case 9: - if (! secure && memcmp (envline, "MMAP_MAX_", 9) == 0) + if (memcmp (envline, "MMAP_MAX_", 9) == 0) mALLOPt(M_MMAP_MAX, atoi(&envline[10])); break; case 15: - if (! secure) { if (memcmp (envline, "TRIM_THRESHOLD_", 15) == 0) mALLOPt(M_TRIM_THRESHOLD, atoi(&envline[16])); diff -upk.orig glibc-2.3.5.orig/malloc/memusage.c glibc-2.3.5/malloc/memusage.c --- glibc-2.3.5.orig/malloc/memusage.c 2004-08-10 04:11:50 +0000 +++ glibc-2.3.5/malloc/memusage.c 2005-05-17 13:53:18 +0000 @@ -193,7 +193,7 @@ int_handler (int signo) static void me (void) { - const char *env = getenv ("MEMUSAGE_PROG_NAME"); + const char *env = __secure_getenv ("MEMUSAGE_PROG_NAME"); size_t prog_len = strlen (__progname); initialized = -1; @@ -229,7 +229,7 @@ me (void) if (!start_sp) start_sp = GETSP (); - outname = getenv ("MEMUSAGE_OUTPUT"); + outname = __secure_getenv ("MEMUSAGE_OUTPUT"); if (outname != NULL && outname[0] != '\0' && (access (outname, R_OK | W_OK) == 0 || errno == ENOENT)) { @@ -251,7 +251,7 @@ me (void) /* Determine the buffer size. We use the default if the environment variable is not present. */ buffer_size = DEFAULT_BUFFER_SIZE; - if (getenv ("MEMUSAGE_BUFFER_SIZE") != NULL) + if (__secure_getenv ("MEMUSAGE_BUFFER_SIZE") != NULL) { buffer_size = atoi (getenv ("MEMUSAGE_BUFFER_SIZE")); if (buffer_size == 0 || buffer_size > DEFAULT_BUFFER_SIZE) @@ -259,7 +259,7 @@ me (void) } /* Possibly enable timer-based stack pointer retrieval. */ - if (getenv ("MEMUSAGE_NO_TIMER") == NULL) + if (__secure_getenv ("MEMUSAGE_NO_TIMER") == NULL) { struct sigaction act; @@ -280,7 +280,7 @@ me (void) } } - if (!not_me && getenv ("MEMUSAGE_TRACE_MMAP") != NULL) + if (!not_me && __secure_getenv ("MEMUSAGE_TRACE_MMAP") != NULL) trace_mmap = true; } } diff -upk.orig glibc-2.3.5.orig/nis/nis_defaults.c glibc-2.3.5/nis/nis_defaults.c --- glibc-2.3.5.orig/nis/nis_defaults.c 2004-10-24 20:28:28 +0000 +++ glibc-2.3.5/nis/nis_defaults.c 2005-05-17 13:53:18 +0000 @@ -379,7 +379,7 @@ __nis_default_owner (char *defaults) } else { - cptr = getenv ("NIS_DEFAULTS"); + cptr = __secure_getenv ("NIS_DEFAULTS"); if (cptr != NULL) { dptr = strstr (cptr, "owner="); @@ -419,7 +419,7 @@ __nis_default_group (char *defaults) } else { - cptr = getenv ("NIS_DEFAULTS"); + cptr = __secure_getenv ("NIS_DEFAULTS"); if (cptr != NULL) { dptr = strstr (cptr, "group="); @@ -450,7 +450,7 @@ __nis_default_ttl (char *defaults) return searchttl (defaults); } - cptr = getenv ("NIS_DEFAULTS"); + cptr = __secure_getenv ("NIS_DEFAULTS"); if (cptr == NULL) return DEFAULT_TTL; @@ -478,9 +478,9 @@ __nis_default_access (char *param, unsig result = searchaccess (param, result); else { - cptr = getenv ("NIS_DEFAULTS"); + cptr = __secure_getenv ("NIS_DEFAULTS"); if (cptr != NULL && strstr (cptr, "access=") != NULL) - result = searchaccess (getenv ("NIS_DEFAULTS"), result); + result = searchaccess (cptr, result); } return result; diff -upk.orig glibc-2.3.5.orig/nis/nis_local_names.c glibc-2.3.5/nis/nis_local_names.c --- glibc-2.3.5.orig/nis/nis_local_names.c 2004-10-24 20:28:28 +0000 +++ glibc-2.3.5/nis/nis_local_names.c 2005-05-17 13:53:18 +0000 @@ -30,7 +30,7 @@ nis_local_group (void) char *cptr; if (__nisgroup[0] == '\0' - && (cptr = getenv ("NIS_GROUP")) != NULL + && (cptr = __secure_getenv ("NIS_GROUP")) != NULL && strlen (cptr) < NIS_MAXNAMELEN) { char *cp = stpcpy (__nisgroup, cptr); diff -upk.orig glibc-2.3.5.orig/nis/nis_subr.c glibc-2.3.5/nis/nis_subr.c --- glibc-2.3.5.orig/nis/nis_subr.c 2004-10-24 20:28:28 +0000 +++ glibc-2.3.5/nis/nis_subr.c 2005-05-17 13:53:18 +0000 @@ -152,7 +152,7 @@ nis_getnames (const_nis_name name) } /* Get the search path, where we have to search "name" */ - path = getenv ("NIS_PATH"); + path = __secure_getenv ("NIS_PATH"); if (path == NULL) path = strdupa ("$"); else diff -upk.orig glibc-2.3.5.orig/posix/execvp.c glibc-2.3.5/posix/execvp.c --- glibc-2.3.5.orig/posix/execvp.c 2005-02-26 01:02:17 +0000 +++ glibc-2.3.5/posix/execvp.c 2005-05-23 01:53:37 +0000 @@ -87,19 +87,18 @@ execvp (file, argv) } else { - char *path = getenv ("PATH"); + char *path = __secure_getenv ("PATH"); bool path_malloc = false; if (path == NULL) { /* There is no `PATH' in the environment. - The default search path is the current directory - followed by the path `confstr' returns for `_CS_PATH'. */ + The default search path is what `confstr' returns + for `_CS_PATH'. */ size_t len = confstr (_CS_PATH, (char *) NULL, 0); - path = (char *) malloc (1 + len); + path = (char *) malloc (len); if (path == NULL) return -1; - path[0] = ':'; - (void) confstr (_CS_PATH, path + 1, len); + (void) confstr (_CS_PATH, path, len); path_malloc = true; } diff -upk.orig glibc-2.3.5.orig/resolv/res_hconf.c glibc-2.3.5/resolv/res_hconf.c --- glibc-2.3.5.orig/resolv/res_hconf.c 2004-06-01 22:17:39 +0000 +++ glibc-2.3.5/resolv/res_hconf.c 2005-05-17 13:53:18 +0000 @@ -431,7 +431,7 @@ do_init (void) memset (&_res_hconf, '\0', sizeof (_res_hconf)); - hconf_name = getenv (ENV_HOSTCONF); + hconf_name = __secure_getenv (ENV_HOSTCONF); if (hconf_name == NULL) hconf_name = _PATH_HOSTCONF; @@ -453,30 +453,30 @@ do_init (void) fclose (fp); } - envval = getenv (ENV_SERVORDER); + envval = __secure_getenv (ENV_SERVORDER); if (envval) { _res_hconf.num_services = 0; arg_service_list (ENV_SERVORDER, 1, envval, 0); } - envval = getenv (ENV_SPOOF); + envval = __secure_getenv (ENV_SPOOF); if (envval) arg_spoof (ENV_SPOOF, 1, envval, 0); - envval = getenv (ENV_MULTI); + envval = __secure_getenv (ENV_MULTI); if (envval) arg_bool (ENV_MULTI, 1, envval, HCONF_FLAG_MULTI); - envval = getenv (ENV_REORDER); + envval = __secure_getenv (ENV_REORDER); if (envval) arg_bool (ENV_REORDER, 1, envval, HCONF_FLAG_REORDER); - envval = getenv (ENV_TRIM_ADD); + envval = __secure_getenv (ENV_TRIM_ADD); if (envval) arg_trimdomain_list (ENV_TRIM_ADD, 1, envval, 0); - envval = getenv (ENV_TRIM_OVERR); + envval = __secure_getenv (ENV_TRIM_OVERR); if (envval) { _res_hconf.num_trimdomains = 0; diff -upk.orig glibc-2.3.5.orig/resolv/res_init.c glibc-2.3.5/resolv/res_init.c --- glibc-2.3.5.orig/resolv/res_init.c 2004-10-11 20:49:25 +0000 +++ glibc-2.3.5/resolv/res_init.c 2005-05-23 01:53:37 +0000 @@ -201,7 +201,7 @@ __res_vinit(res_state statp, int preinit #endif /* Allow user to override the local domain definition */ - if ((cp = getenv("LOCALDOMAIN")) != NULL) { + if ((cp = __secure_getenv("LOCALDOMAIN")) != NULL) { (void)strncpy(statp->defdname, cp, sizeof(statp->defdname) - 1); statp->defdname[sizeof(statp->defdname) - 1] = '\0'; haveenv++; @@ -441,7 +441,7 @@ __res_vinit(res_state statp, int preinit #endif /* !RFC1535 */ } - if ((cp = getenv("RES_OPTIONS")) != NULL) + if ((cp = __secure_getenv("RES_OPTIONS")) != NULL) res_setoptions(statp, cp, "env"); statp->options |= RES_INIT; return (0); diff -upk.orig glibc-2.3.5.orig/resolv/res_query.c glibc-2.3.5/resolv/res_query.c --- glibc-2.3.5.orig/resolv/res_query.c 2004-10-18 05:09:59 +0000 +++ glibc-2.3.5/resolv/res_query.c 2005-05-17 13:53:18 +0000 @@ -453,7 +453,7 @@ res_hostalias(const res_state statp, con if (statp->options & RES_NOALIASES) return (NULL); - file = getenv("HOSTALIASES"); + file = __secure_getenv("HOSTALIASES"); if (file == NULL || (fp = fopen(file, "r")) == NULL) return (NULL); setbuf(fp, NULL); diff -upk.orig glibc-2.3.5.orig/stdlib/fmtmsg.c glibc-2.3.5/stdlib/fmtmsg.c --- glibc-2.3.5.orig/stdlib/fmtmsg.c 2005-02-16 10:37:10 +0000 +++ glibc-2.3.5/stdlib/fmtmsg.c 2005-05-17 13:53:18 +0000 @@ -226,8 +226,8 @@ fmtmsg (long int classification, const c static void init (void) { - const char *msgverb_var = getenv ("MSGVERB"); - const char *sevlevel_var = getenv ("SEV_LEVEL"); + const char *msgverb_var = __secure_getenv ("MSGVERB"); + const char *sevlevel_var = __secure_getenv ("SEV_LEVEL"); if (msgverb_var != NULL && msgverb_var[0] != '\0') { diff -upk.orig glibc-2.3.5.orig/sunrpc/rpc_svcout.c glibc-2.3.5/sunrpc/rpc_svcout.c --- glibc-2.3.5.orig/sunrpc/rpc_svcout.c 2004-10-17 14:59:39 +0000 +++ glibc-2.3.5/sunrpc/rpc_svcout.c 2005-05-17 13:53:18 +0000 @@ -901,7 +901,7 @@ write_pm_most (const char *infile, int n f_print (fout, "\t\t_rpcpmstart = 1;\n"); if (logflag) open_log_file (infile, "\t\t"); - f_print (fout, "\t\tif ((netid = getenv(\"NLSPROVIDER\")) == NULL) {\n"); + f_print (fout, "\t\tif ((netid = __secure_getenv(\"NLSPROVIDER\")) == NULL) {\n"); sprintf (_errbuf, "cannot get transport name"); print_err_message ("\t\t\t"); f_print (fout, "\t\t} else if ((nconf = getnetconfigent(netid)) == NULL) {\n"); diff -upk.orig glibc-2.3.5.orig/sysdeps/generic/dl-sysdep.c glibc-2.3.5/sysdeps/generic/dl-sysdep.c --- glibc-2.3.5.orig/sysdeps/generic/dl-sysdep.c 2004-11-06 00:24:47 +0000 +++ glibc-2.3.5/sysdeps/generic/dl-sysdep.c 2005-05-23 02:19:02 +0000 @@ -48,8 +48,10 @@ extern void __libc_check_standard_fds (v #ifdef NEED_DL_BASE_ADDR ElfW(Addr) _dl_base_addr; #endif -int __libc_enable_secure attribute_relro = 0; +int __libc_enable_secure attribute_relro = 1; INTVARDEF(__libc_enable_secure) +int __libc_security_mask attribute_relro = 0x7fffffff; +INTVARDEF(__libc_security_mask) int __libc_multiple_libcs = 0; /* Defining this here avoids the inclusion of init-first. */ /* This variable contains the lowest stack address ever used. */ @@ -74,6 +76,10 @@ static ElfW(auxv_t) *_dl_auxv attribute_ # define DL_STACK_END(cookie) ((void *) (cookie)) #endif +#ifdef HAVE_AUX_XID +#undef HAVE_AUX_XID +#endif + ElfW(Addr) _dl_sysdep_start (void **start_argptr, void (*dl_main) (const ElfW(Phdr) *phdr, ElfW(Word) phnum, @@ -83,19 +89,19 @@ _dl_sysdep_start (void **start_argptr, ElfW(Word) phnum = 0; ElfW(Addr) user_entry; ElfW(auxv_t) *av; -#ifdef HAVE_AUX_SECURE + int security_mask = 0; +#if 0 # define set_seen(tag) (tag) /* Evaluate for the side effects. */ -# define set_seen_secure() ((void) 0) #else uid_t uid = 0; gid_t gid = 0; unsigned int seen = 0; -# define set_seen_secure() (seen = -1) # ifdef HAVE_AUX_XID # define set_seen(tag) (tag) /* Evaluate for the side effects. */ # else # define M(type) (1 << (type)) # define set_seen(tag) seen |= M ((tag)->a_type) +# define is_seen(tag) seen & M ((tag)->a_type) # endif #endif #ifdef NEED_DL_SYSINFO @@ -129,21 +135,18 @@ _dl_sysdep_start (void **start_argptr, _dl_base_addr = av->a_un.a_val; break; #endif -#ifndef HAVE_AUX_SECURE case AT_UID: case AT_EUID: + if (is_seen (av)) break; uid ^= av->a_un.a_val; break; case AT_GID: case AT_EGID: + if (is_seen (av)) break; gid ^= av->a_un.a_val; break; -#endif case AT_SECURE: -#ifndef HAVE_AUX_SECURE - seen = -1; -#endif - INTUSE(__libc_enable_secure) = av->a_un.a_val; + security_mask |= av->a_un.a_val != 0; break; case AT_PLATFORM: GLRO(dl_platform) = av->a_un.a_ptr; @@ -176,8 +179,6 @@ _dl_sysdep_start (void **start_argptr, DL_SYSDEP_OSCHECK (dl_fatal); #endif -#ifndef HAVE_AUX_SECURE - if (seen != -1) { /* Fill in the values we have not gotten from the kernel through the auxiliary vector. */ @@ -189,12 +190,12 @@ _dl_sysdep_start (void **start_argptr, SEE (GID, gid, gid); SEE (EGID, gid, egid); # endif - - /* If one of the two pairs of IDs does not match this is a setuid - or setgid run. */ - INTUSE(__libc_enable_secure) = uid | gid; } -#endif + /* If one of the two pairs of IDs does not match + this is a setuid or setgid run. */ + security_mask |= ((uid != 0) << 1) | ((gid != 0) << 2); + INTUSE(__libc_security_mask) = security_mask; + INTUSE(__libc_enable_secure) = security_mask != 0; #ifndef HAVE_AUX_PAGESIZE if (GLRO(dl_pagesize) == 0) diff -upk.orig glibc-2.3.5.orig/sysdeps/generic/enbl-secure.c glibc-2.3.5/sysdeps/generic/enbl-secure.c --- glibc-2.3.5.orig/sysdeps/generic/enbl-secure.c 2003-05-06 06:33:13 +0000 +++ glibc-2.3.5/sysdeps/generic/enbl-secure.c 2005-05-23 02:21:09 +0000 @@ -27,11 +27,17 @@ int __libc_enable_secure_decided; /* Safest assumption, if somehow the initializer isn't run. */ int __libc_enable_secure = 1; +int __libc_security_mask = 0x7fffffff; void __libc_init_secure (void) { if (__libc_enable_secure_decided == 0) - __libc_enable_secure = (__geteuid () != __getuid () - || __getegid () != __getgid ()); + { + __libc_security_mask = + ((__geteuid () != __getuid ()) << 1) | + ((__getegid () != __getgid ()) << 2); + __libc_enable_secure = __libc_security_mask != 0; + __libc_security_mask |= __libc_enable_secure; + } } diff -upk.orig glibc-2.3.5.orig/sysdeps/generic/glob.c glibc-2.3.5/sysdeps/generic/glob.c --- glibc-2.3.5.orig/sysdeps/generic/glob.c 2004-10-27 18:21:02 +0000 +++ glibc-2.3.5/sysdeps/generic/glob.c 2005-05-23 01:53:37 +0000 @@ -171,7 +171,7 @@ extern int errno; # define ANSI_STRING #else /* No standard headers. */ -extern char *getenv (); +extern char *__secure_getenv (); # ifdef HAVE_STRING_H # include @@ -693,7 +693,7 @@ glob (pattern, flags, errfunc, pglob) if (dirname[1] == '\0' || dirname[1] == '/') { /* Look up home directory. */ - const char *home_dir = getenv ("HOME"); + const char *home_dir = __secure_getenv ("HOME"); # ifdef _AMIGA if (home_dir == NULL || home_dir[0] == '\0') home_dir = "SYS:"; diff -upk.orig glibc-2.3.5.orig/sysdeps/generic/segfault.c glibc-2.3.5/sysdeps/generic/segfault.c --- glibc-2.3.5.orig/sysdeps/generic/segfault.c 2004-10-14 02:22:13 +0000 +++ glibc-2.3.5/sysdeps/generic/segfault.c 2005-05-17 13:53:18 +0000 @@ -149,7 +149,7 @@ __attribute__ ((constructor)) install_handler (void) { struct sigaction sa; - const char *sigs = getenv ("SEGFAULT_SIGNALS"); + const char *sigs = __secure_getenv ("SEGFAULT_SIGNALS"); const char *name; sa.sa_handler = (void *) catch_segfault; @@ -157,7 +157,7 @@ install_handler (void) sa.sa_flags = SA_RESTART; /* Maybe we are expected to use an alternative stack. */ - if (getenv ("SEGFAULT_USE_ALTSTACK") != 0) + if (__secure_getenv ("SEGFAULT_USE_ALTSTACK") != 0) { void *stack_mem = malloc (2 * SIGSTKSZ); struct sigaltstack ss; @@ -203,7 +203,7 @@ install_handler (void) } /* Preserve the output file name if there is any given. */ - name = getenv ("SEGFAULT_OUTPUT_NAME"); + name = __secure_getenv ("SEGFAULT_OUTPUT_NAME"); if (name != NULL && name[0] != '\0') { int ret = access (name, R_OK | W_OK); diff -upk.orig glibc-2.3.5.orig/sysdeps/generic/unsecvars.h glibc-2.3.5/sysdeps/generic/unsecvars.h --- glibc-2.3.5.orig/sysdeps/generic/unsecvars.h 2004-12-07 06:54:31 +0000 +++ glibc-2.3.5/sysdeps/generic/unsecvars.h 2005-05-17 13:53:18 +0000 @@ -2,23 +2,82 @@ all stuffed in a single string which means they have to be terminated with a '\0' explicitly. */ #define UNSECURE_ENVVARS \ - "LD_PRELOAD\0" \ - "LD_LIBRARY_PATH\0" \ - "LD_ORIGIN_PATH\0" \ - "LD_DEBUG\0" \ - "LD_DEBUG_OUTPUT\0" \ - "LD_PROFILE\0" \ - "LD_USE_LOAD_BIAS\0" \ - "LD_DYNAMIC_WEAK\0" \ - "LD_SHOW_AUXV\0" \ - "GCONV_PATH\0" \ - "GETCONF_DIR\0" \ - "HOSTALIASES\0" \ - "LOCALDOMAIN\0" \ - "LOCPATH\0" \ - "MALLOC_TRACE\0" \ - "NLSPATH\0" \ - "RESOLV_HOST_CONF\0" \ - "RES_OPTIONS\0" \ - "TMPDIR\0" \ + "ARGP_HELP_FMT\0" \ + "DATEMSK\0" \ + "GCONV_PATH\0" \ + "GETCONF_DIR\0" \ + "GMON_OUT_PREFIX\0" \ + "HESIOD_CONFIG\0" \ + "HES_DOMAIN\0" \ + "HOSTALIASES\0" \ + "LD_BIND_NOT\0" \ + "LD_BIND_NOW\0" \ + "LD_DEBUG\0" \ + "LD_DEBUG_OUTPUT\0" \ + "LD_DYNAMIC_WEAK\0" \ + "LD_HWCAP_MASK\0" \ + "LD_LIBRARY_PATH\0" \ + "LD_ORIGIN_PATH\0" \ + "LD_PRELOAD\0" \ + "LD_PROFILE\0" \ + "LD_PROFILE_OUTPUT\0" \ + "LD_SHOW_AUXV\0" \ + "LD_TRACE_LOADED_OBJECTS\0" \ + "LD_USE_LOAD_BIAS\0" \ + "LD_WARN\0" \ + "LOCALDOMAIN\0" \ + "LOCPATH\0" \ + "MALLOC_CHECK_\0" \ + "MALLOC_MMAP_MAX_\0" \ + "MALLOC_MMAP_THRESHOLD_\0" \ + "MALLOC_TOP_PAD_\0" \ + "MALLOC_TRACE\0" \ + "MALLOC_TRIM_THRESHOLD_\0" \ + "MEMUSAGE_BUFFER_SIZE\0" \ + "MEMUSAGE_NO_TIMER\0" \ + "MEMUSAGE_OUTPUT\0" \ + "MEMUSAGE_PROG_NAME\0" \ + "MEMUSAGE_TRACE_MMAP\0" \ + "MSGVERB\0" \ + "NIS_DEFAULTS\0" \ + "NIS_GROUP\0" \ + "NIS_PATH\0" \ + "NLSPATH\0" \ + "PCPROFILE_OUTPUT\0" \ + "POSIXLY_CORRECT\0" \ + "PWD\0" \ + "RESOLV_ADD_TRIM_DOMAINS\0" \ + "RESOLV_HOST_CONF\0" \ + "RESOLV_MULTI\0" \ + "RESOLV_OVERRIDE_TRIM_DOMAINS\0" \ + "RESOLV_REORDER\0" \ + "RESOLV_SERV_ORDER\0" \ + "RESOLV_SPOOF_CHECK\0" \ + "RES_OPTIONS\0" \ + "SEGFAULT_OUTPUT_NAME\0" \ + "SEGFAULT_SIGNALS\0" \ + "SEGFAULT_USE_ALTSTACK\0" \ + "SEV_LEVEL\0" \ + "TZ\0" \ "TZDIR\0" + +#define UNSECURE_UID_ENVVARS \ + "TMPDIR\0" + +#define RESTRICTED_ENVVARS \ + "LANG\0" \ + "LANGUAGE\0" \ + "LC_ADDRESS\0" \ + "LC_ALL\0" \ + "LC_COLLATE\0" \ + "LC_CTYPE\0" \ + "LC_IDENTIFICATION\0" \ + "LC_MEASUREMENT\0" \ + "LC_MESSAGES\0" \ + "LC_MONETARY\0" \ + "LC_NAME\0" \ + "LC_NUMERIC\0" \ + "LC_PAPER\0" \ + "LC_TELEPHONE\0" \ + "LC_TIME\0" \ + "LC_XXX\0" diff -upk.orig glibc-2.3.5.orig/sysdeps/generic/wordexp.c glibc-2.3.5/sysdeps/generic/wordexp.c --- glibc-2.3.5.orig/sysdeps/generic/wordexp.c 2005-02-16 10:56:31 +0000 +++ glibc-2.3.5/sysdeps/generic/wordexp.c 2005-05-17 13:53:18 +0000 @@ -315,7 +315,7 @@ parse_tilde (char **word, size_t *word_l results are unspecified. We do a lookup on the uid if HOME is unset. */ - home = getenv ("HOME"); + home = __secure_getenv ("HOME"); if (home != NULL) { *word = w_addstr (*word, word_length, max_length, home); @@ -1491,7 +1491,7 @@ envsubst: } } else - value = getenv (env); + value = __secure_getenv (env); if (value == NULL && (flags & WRDE_UNDEF)) { @@ -2268,7 +2268,7 @@ wordexp (const char *words, wordexp_t *p /* Find out what the field separators are. * There are two types: whitespace and non-whitespace. */ - ifs = getenv ("IFS"); + ifs = __secure_getenv ("IFS"); if (!ifs) /* IFS unset - use . */ diff -upk.orig glibc-2.3.5.orig/sysdeps/posix/spawni.c glibc-2.3.5/sysdeps/posix/spawni.c --- glibc-2.3.5.orig/sysdeps/posix/spawni.c 2004-09-12 18:05:00 +0000 +++ glibc-2.3.5/sysdeps/posix/spawni.c 2005-05-17 13:53:18 +0000 @@ -216,16 +216,15 @@ __spawni (pid_t *pid, const char *file, } /* We have to search for FILE on the path. */ - path = getenv ("PATH"); + path = __secure_getenv ("PATH"); if (path == NULL) { /* There is no `PATH' in the environment. - The default search path is the current directory - followed by the path `confstr' returns for `_CS_PATH'. */ + The default search path is ehat `confstr' returns + for `_CS_PATH'. */ len = confstr (_CS_PATH, (char *) NULL, 0); - path = (char *) __alloca (1 + len); - path[0] = ':'; - (void) confstr (_CS_PATH, path + 1, len); + path = (char *) __alloca (len); + (void) confstr (_CS_PATH, path, len); } len = strlen (file) + 1; diff -upk.orig glibc-2.3.5.orig/sysdeps/unix/sysv/linux/dl-librecon.h glibc-2.3.5/sysdeps/unix/sysv/linux/dl-librecon.h --- glibc-2.3.5.orig/sysdeps/unix/sysv/linux/dl-librecon.h 2004-03-05 10:14:48 +0000 +++ glibc-2.3.5/sysdeps/unix/sysv/linux/dl-librecon.h 2005-05-23 01:53:37 +0000 @@ -53,7 +53,7 @@ _dl_osversion_init (char *assume_kernel) #define DL_OSVERSION_INIT \ do { \ - char *assume_kernel = getenv ("LD_ASSUME_KERNEL"); \ + char *assume_kernel = __secure_getenv ("LD_ASSUME_KERNEL"); \ if (assume_kernel) \ _dl_osversion_init (assume_kernel); \ } while (0) diff -upk.orig glibc-2.3.5.orig/sysdeps/unix/sysv/linux/i386/dl-librecon.h glibc-2.3.5/sysdeps/unix/sysv/linux/i386/dl-librecon.h --- glibc-2.3.5.orig/sysdeps/unix/sysv/linux/i386/dl-librecon.h 2004-10-14 01:53:55 +0000 +++ glibc-2.3.5/sysdeps/unix/sysv/linux/i386/dl-librecon.h 2005-05-17 13:53:18 +0000 @@ -57,6 +57,7 @@ /* Extra unsecure variables. The names are all stuffed in a single string which means they have to be terminated with a '\0' explicitly. */ #define EXTRA_UNSECURE_ENVVARS \ + "LD_LIBRARY_VERSION\0" \ "LD_AOUT_LIBRARY_PATH\0" \ "LD_AOUT_PRELOAD\0" diff -upk.orig glibc-2.3.5.orig/time/getdate.c glibc-2.3.5/time/getdate.c --- glibc-2.3.5.orig/time/getdate.c 2003-09-04 08:25:11 +0000 +++ glibc-2.3.5/time/getdate.c 2005-05-17 13:53:18 +0000 @@ -115,7 +115,7 @@ __getdate_r (const char *string, struct struct stat64 st; int mday_ok = 0; - datemsk = getenv ("DATEMSK"); + datemsk = __secure_getenv ("DATEMSK"); if (datemsk == NULL || *datemsk == '\0') return 1; diff -upk.orig glibc-2.3.5.orig/time/tzfile.c glibc-2.3.5/time/tzfile.c --- glibc-2.3.5.orig/time/tzfile.c 2004-11-20 20:23:03 +0000 +++ glibc-2.3.5/time/tzfile.c 2005-05-17 13:53:18 +0000 @@ -133,7 +133,7 @@ __tzfile_read (const char *file, size_t unsigned int len, tzdir_len; char *new, *tmp; - tzdir = getenv ("TZDIR"); + tzdir = __secure_getenv ("TZDIR"); if (tzdir == NULL || *tzdir == '\0') { tzdir = default_tzdir; diff -upk.orig glibc-2.3.5.orig/time/tzset.c glibc-2.3.5/time/tzset.c --- glibc-2.3.5.orig/time/tzset.c 2004-12-06 22:50:41 +0000 +++ glibc-2.3.5/time/tzset.c 2005-05-17 13:53:18 +0000 @@ -158,8 +158,11 @@ tzset_internal (always, explicit) return; is_initialized = 1; - /* Examine the TZ environment variable. */ - tz = getenv ("TZ"); + /* Examine the TZ environment variable. This doesn't really have to be + a __secure_getenv() call as __tzfile_read() tries to only read files + found under a trusted directory, but this helps reduce the amount of + security-critical code. */ + tz = __secure_getenv ("TZ"); if (tz == NULL && !explicit) /* Use the site-wide default. This is a file name which means we would not see changes to the file if we compare only the file