Source: autofs Version: 5.0.8-1 Severity: important Tags: security upstream patch
Hi, the following vulnerability was published for autofs. CVE-2014-8169[0]: priv escalation via interpreter load path for program based automount maps If you fix the vulnerability please also make sure to include the CVE (Common Vulnerabilities & Exposures) id in your changelog entry. For further information see: [0] https://security-tracker.debian.org/tracker/CVE-2014-8169 [1] https://bugzilla.redhat.com/show_bug.cgi?id=1192565 Attached are the backported patches for 5.0.8, lightly tested but a second pair of eyes to review would be welcome. Regards, Salvatore
diff -Nru autofs-5.0.8/debian/changelog autofs-5.0.8/debian/changelog --- autofs-5.0.8/debian/changelog 2014-03-07 05:16:25.000000000 +0100 +++ autofs-5.0.8/debian/changelog 2015-02-28 23:11:25.000000000 +0100 @@ -1,3 +1,21 @@ +autofs (5.0.8-1.1) unstable; urgency=high + + * Non-maintainer upload by the Security Team. + * Add patches for CVE-2014-8169. + When a program map uses an interpreted languages like python it is + possible to load and execute arbitray code from a user home directory. + This is because the standard environment variables are used to locate + and load modules when using these languages. To avoid that we need to + add a prefix to these environment names so they aren't used for this + purpose. The prefix used is "AUTOFS_" and is not configurable. + Additionally a configuration option to force the use of program map + standard environment variables is added + (FORCE_STANDARD_PROGRAM_MAP_ENV). + * Refresh remove-kernel-mount.nfs-version-check.patch patch + * Refresh manpages-hyphen.patch patch + + -- Salvatore Bonaccorso <[email protected]> Sat, 28 Feb 2015 20:23:20 +0100 + autofs (5.0.8-1) unstable; urgency=low * New upstream release [October 2013] (Closes: #729023). diff -Nru autofs-5.0.8/debian/patches/CVE-2014-8169-add-a-prefix-to-program-map-stdvars.patch autofs-5.0.8/debian/patches/CVE-2014-8169-add-a-prefix-to-program-map-stdvars.patch --- autofs-5.0.8/debian/patches/CVE-2014-8169-add-a-prefix-to-program-map-stdvars.patch 1970-01-01 01:00:00.000000000 +0100 +++ autofs-5.0.8/debian/patches/CVE-2014-8169-add-a-prefix-to-program-map-stdvars.patch 2015-02-28 23:11:25.000000000 +0100 @@ -0,0 +1,200 @@ +Description: add a prefix to program map stdvars + When a program map uses an interpreted languages like python it is + possible to load and execute arbitrary code from a user home directory. + This is because the standard environment variables are used to locate + and load modules when using these languages. (CVE-2014-8169) + . + To avoid that we need to add a prefix to these environment names so + they aren't used for this purpose. The prefix used is "AUTOFS_" and + is not configurable. +Origin: vendor +Author: Ian Kent <[email protected]> +Reviewed-by: Salvatore Bonaccorso <[email protected]> +Last-Update: 2015-02-28 +--- +--- a/include/mounts.h ++++ b/include/mounts.h +@@ -85,8 +85,8 @@ unsigned int linux_version_code(void); + int check_nfs_mount_version(struct nfs_mount_vers *, struct nfs_mount_vers *); + extern unsigned int nfs_mount_uses_string_options; + +-struct substvar *addstdenv(struct substvar *sv); +-struct substvar *removestdenv(struct substvar *sv); ++struct substvar *addstdenv(struct substvar *sv, const char *prefix); ++struct substvar *removestdenv(struct substvar *sv, const char *prefix); + + unsigned int query_kproto_ver(void); + unsigned int get_kver_major(void); +--- a/lib/mounts.c ++++ b/lib/mounts.c +@@ -31,6 +31,7 @@ + + #define MAX_OPTIONS_LEN 80 + #define MAX_MNT_NAME_LEN 30 ++#define MAX_ENV_NAME 15 + + #define EBUFSIZ 1024 + +@@ -303,7 +304,61 @@ int check_nfs_mount_version(struct nfs_m + } + #endif + +-struct substvar *addstdenv(struct substvar *sv) ++static char *set_env_name(const char *prefix, const char *name, char *buf) ++{ ++ size_t len; ++ ++ len = strlen(name); ++ if (prefix) ++ len += strlen(prefix); ++ len++; ++ ++ if (len > MAX_ENV_NAME) ++ return NULL; ++ ++ if (!prefix) ++ strcpy(buf, name); ++ else { ++ strcpy(buf, prefix); ++ strcat(buf, name); ++ } ++ return buf; ++} ++ ++static struct substvar *do_macro_addvar(struct substvar *list, ++ const char *prefix, ++ const char *name, ++ const char *val) ++{ ++ char buf[MAX_ENV_NAME + 1]; ++ char *new; ++ size_t len; ++ ++ new = set_env_name(prefix, name, buf); ++ if (new) { ++ len = strlen(new); ++ list = macro_addvar(list, new, len, val); ++ } ++ return list; ++} ++ ++static struct substvar *do_macro_removevar(struct substvar *list, ++ const char *prefix, ++ const char *name) ++{ ++ char buf[MAX_ENV_NAME + 1]; ++ char *new; ++ size_t len; ++ ++ new = set_env_name(prefix, name, buf); ++ if (new) { ++ len = strlen(new); ++ list = macro_removevar(list, new, len); ++ } ++ return list; ++} ++ ++struct substvar *addstdenv(struct substvar *sv, const char *prefix) + { + struct substvar *list = sv; + struct thread_stdenv_vars *tsv; +@@ -318,14 +373,14 @@ struct substvar *addstdenv(struct substv + num = (long) tsv->uid; + ret = sprintf(numbuf, "%ld", num); + if (ret > 0) +- list = macro_addvar(list, "UID", 3, numbuf); ++ list = do_macro_addvar(list, prefix, "UID", numbuf); + num = (long) tsv->gid; + ret = sprintf(numbuf, "%ld", num); + if (ret > 0) +- list = macro_addvar(list, "GID", 3, numbuf); +- list = macro_addvar(list, "USER", 4, tsv->user); +- list = macro_addvar(list, "GROUP", 5, tsv->group); +- list = macro_addvar(list, "HOME", 4, tsv->home); ++ list = do_macro_addvar(list, prefix, "GID", numbuf); ++ list = do_macro_addvar(list, prefix, "USER", tsv->user); ++ list = do_macro_addvar(list, prefix, "GROUP", tsv->group); ++ list = do_macro_addvar(list, prefix, "HOME", tsv->home); + mv = macro_findvar(list, "HOST", 4); + if (mv) { + char *shost = strdup(mv->val); +@@ -333,7 +388,8 @@ struct substvar *addstdenv(struct substv + char *dot = strchr(shost, '.'); + if (dot) + *dot = '\0'; +- list = macro_addvar(list, "SHOST", 5, shost); ++ list = do_macro_addvar(list, ++ prefix, "SHOST", shost); + free(shost); + } + } +@@ -341,16 +397,16 @@ struct substvar *addstdenv(struct substv + return list; + } + +-struct substvar *removestdenv(struct substvar *sv) ++struct substvar *removestdenv(struct substvar *sv, const char *prefix) + { + struct substvar *list = sv; + +- list = macro_removevar(list, "UID", 3); +- list = macro_removevar(list, "USER", 4); +- list = macro_removevar(list, "HOME", 4); +- list = macro_removevar(list, "GID", 3); +- list = macro_removevar(list, "GROUP", 5); +- list = macro_removevar(list, "SHOST", 5); ++ list = do_macro_removevar(list, prefix, "UID"); ++ list = do_macro_removevar(list, prefix, "USER"); ++ list = do_macro_removevar(list, prefix, "HOME"); ++ list = do_macro_removevar(list, prefix, "GID"); ++ list = do_macro_removevar(list, prefix, "GROUP"); ++ list = do_macro_removevar(list, prefix, "SHOST"); + return list; + } + +--- a/modules/lookup_program.c ++++ b/modules/lookup_program.c +@@ -272,7 +272,7 @@ int lookup_mount(struct autofs_point *ap + if (ctxt->mapfmt && strcmp(ctxt->mapfmt, "MAPFMT_DEFAULT")) { + struct parse_context *pctxt = (struct parse_context *) ctxt->parse->context; + /* Add standard environment as seen by sun map parser */ +- pctxt->subst = addstdenv(pctxt->subst); ++ pctxt->subst = addstdenv(pctxt->subst, "AUTOFS_"); + macro_setenv(pctxt->subst); + } + execl(ctxt->mapname, ctxt->mapname, name, NULL); +--- a/modules/parse_sun.c ++++ b/modules/parse_sun.c +@@ -1223,12 +1223,12 @@ int parse_mount(struct autofs_point *ap, + pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); + macro_lock(); + +- ctxt->subst = addstdenv(ctxt->subst); ++ ctxt->subst = addstdenv(ctxt->subst, NULL); + + mapent_len = expandsunent(mapent, NULL, name, ctxt->subst, slashify); + if (mapent_len == 0) { + error(ap->logopt, MODPREFIX "failed to expand map entry"); +- ctxt->subst = removestdenv(ctxt->subst); ++ ctxt->subst = removestdenv(ctxt->subst, NULL); + macro_unlock(); + pthread_setcancelstate(cur_state, NULL); + return 1; +@@ -1238,7 +1238,7 @@ int parse_mount(struct autofs_point *ap, + if (!pmapent) { + char *estr = strerror_r(errno, buf, MAX_ERR_BUF); + logerr(MODPREFIX "alloca: %s", estr); +- ctxt->subst = removestdenv(ctxt->subst); ++ ctxt->subst = removestdenv(ctxt->subst, NULL); + macro_unlock(); + pthread_setcancelstate(cur_state, NULL); + return 1; +@@ -1246,7 +1246,7 @@ int parse_mount(struct autofs_point *ap, + pmapent[mapent_len] = '\0'; + + expandsunent(mapent, pmapent, name, ctxt->subst, slashify); +- ctxt->subst = removestdenv(ctxt->subst); ++ ctxt->subst = removestdenv(ctxt->subst, NULL); + + macro_unlock(); + pthread_setcancelstate(cur_state, NULL); diff -Nru autofs-5.0.8/debian/patches/CVE-2014-8169-add-config-option-to-force-use-of-program-map-stdvars.patch autofs-5.0.8/debian/patches/CVE-2014-8169-add-config-option-to-force-use-of-program-map-stdvars.patch --- autofs-5.0.8/debian/patches/CVE-2014-8169-add-config-option-to-force-use-of-program-map-stdvars.patch 1970-01-01 01:00:00.000000000 +0100 +++ autofs-5.0.8/debian/patches/CVE-2014-8169-add-config-option-to-force-use-of-program-map-stdvars.patch 2015-02-28 23:11:25.000000000 +0100 @@ -0,0 +1,137 @@ +Description: add config option to force use of program map stdvars + Enabling the extended environment (including $HOME, for example) for + program maps opens automount(8) to a privilege escalation. + . + Rather than just removing the entended environment a configuration + option is added to disable it by default so that those who wish to + use it can do so if they wish. +Origin: vendor +Author: Ian Kent <[email protected]> +Author: Salvatore Bonaccorso <[email protected]> +Last-Update: 2015-02-28 +--- +--- a/include/defaults.h ++++ b/include/defaults.h +@@ -28,6 +28,7 @@ + #define DEFAULT_UMOUNT_WAIT 12 + #define DEFAULT_BROWSE_MODE 1 + #define DEFAULT_LOGGING 0 ++#define DEFAULT_FORCE_STD_PROG_MAP_ENV 0 + + #define DEFAULT_LDAP_TIMEOUT -1 + #define DEFAULT_LDAP_NETWORK_TIMEOUT 8 +@@ -62,6 +63,7 @@ unsigned int defaults_get_timeout(void); + unsigned int defaults_get_negative_timeout(void); + unsigned int defaults_get_browse_mode(void); + unsigned int defaults_get_logging(void); ++unsigned int defaults_force_std_prog_map_env(void); + const char *defaults_get_ldap_server(void); + unsigned int defaults_get_ldap_timeout(void); + unsigned int defaults_get_ldap_network_timeout(void); +--- a/lib/defaults.c ++++ b/lib/defaults.c +@@ -35,6 +35,7 @@ + #define ENV_NAME_NEGATIVE_TIMEOUT "NEGATIVE_TIMEOUT" + #define ENV_NAME_BROWSE_MODE "BROWSE_MODE" + #define ENV_NAME_LOGGING "LOGGING" ++#define ENV_NAME_FORCE_STD_PROG_MAP_ENV "FORCE_STANDARD_PROGRAM_MAP_ENV" + + #define LDAP_URI "LDAP_URI" + #define ENV_LDAP_TIMEOUT "LDAP_TIMEOUT" +@@ -519,6 +520,7 @@ unsigned int defaults_read_config(unsign + check_set_config_value(key, ENV_NAME_NEGATIVE_TIMEOUT, value, to_syslog) || + check_set_config_value(key, ENV_NAME_BROWSE_MODE, value, to_syslog) || + check_set_config_value(key, ENV_NAME_LOGGING, value, to_syslog) || ++ check_set_config_value(key, ENV_NAME_FORCE_STD_PROG_MAP_ENV, value, to_syslog) || + check_set_config_value(key, ENV_LDAP_TIMEOUT, value, to_syslog) || + check_set_config_value(key, ENV_LDAP_NETWORK_TIMEOUT, value, to_syslog) || + check_set_config_value(key, ENV_NAME_MAP_OBJ_CLASS, value, to_syslog) || +@@ -629,6 +631,17 @@ unsigned int defaults_get_logging(void) + return logging; + } + ++unsigned int defaults_force_std_prog_map_env(void) ++{ ++ int res; ++ ++ res = get_env_yesno(ENV_NAME_FORCE_STD_PROG_MAP_ENV); ++ if (res < 0) ++ res = DEFAULT_FORCE_STD_PROG_MAP_ENV; ++ ++ return res; ++} ++ + unsigned int defaults_get_ldap_timeout(void) + { + int res; +--- a/man/autofs.5 ++++ b/man/autofs.5 +@@ -174,6 +174,11 @@ SHOST Short hostname (domain part remove + .fi + .RE + .sp ++If a program map is used these standard environment variables will have ++a prefix of "AUTOFS_" to prevent interpreted languages like python from ++being able to load and execute arbitray code from a user home directory. ++.RE ++.sp + Additional entries can be defined with the -Dvariable=Value map-option to + .BR automount (8). + .SS Executable Maps +--- a/modules/lookup_program.c ++++ b/modules/lookup_program.c +@@ -132,6 +132,7 @@ int lookup_mount(struct autofs_point *ap + int ret = 1; + int distance; + int alloci = 1; ++ char *prefix; + + source = ap->entry->current; + ap->entry->current = NULL; +@@ -265,6 +266,17 @@ int lookup_mount(struct autofs_point *ap + warn(ap->logopt, + MODPREFIX "failed to set PWD to %s for map %s", + ap->path, ctxt->mapname); ++ ++ /* ++ * By default use a prefix with standard environment ++ * variables to prevent system subversion by interpreted ++ * languages. ++ */ ++ if (defaults_force_std_prog_map_env()) ++ prefix = NULL; ++ else ++ prefix = "AUTOFS_"; ++ + /* + * MAPFMT_DEFAULT must be "sun" for ->parse_init() to have setup + * the macro table. +@@ -272,7 +284,7 @@ int lookup_mount(struct autofs_point *ap + if (ctxt->mapfmt && strcmp(ctxt->mapfmt, "MAPFMT_DEFAULT")) { + struct parse_context *pctxt = (struct parse_context *) ctxt->parse->context; + /* Add standard environment as seen by sun map parser */ +- pctxt->subst = addstdenv(pctxt->subst, "AUTOFS_"); ++ pctxt->subst = addstdenv(pctxt->subst, prefix); + macro_setenv(pctxt->subst); + } + execl(ctxt->mapname, ctxt->mapname, name, NULL); +--- a/samples/autofs.conf.default.in ++++ b/samples/autofs.conf.default.in +@@ -80,6 +80,17 @@ BROWSE_MODE="no" + # + #LDAP_NETWORK_TIMEOUT=8 + # ++# FORCE_STANDARD_PROGRAM_MAP_ENV - disable the use of the "AUTOFS_" ++# prefix for standard environment variables when ++# executing a program map. Since program maps ++# are run as the privileded user this opens ++# automount(8) to potential user privilege ++# escalation when the program map is written ++# in a language that can load components from, ++# for example, a user home directory. ++# ++#FORCE_STANDARD_PROGRAM_MAP_ENV="no" ++# + # Define base dn for map dn lookup. + # + # SEARCH_BASE - base dn to use for searching for map search dn. diff -Nru autofs-5.0.8/debian/patches/manpages-hyphen.patch autofs-5.0.8/debian/patches/manpages-hyphen.patch --- autofs-5.0.8/debian/patches/manpages-hyphen.patch 2014-03-07 05:16:07.000000000 +0100 +++ autofs-5.0.8/debian/patches/manpages-hyphen.patch 2015-02-28 23:11:25.000000000 +0100 @@ -5,8 +5,7 @@ --- a/man/autofs.5 +++ b/man/autofs.5 -@@ -21,9 +21,9 @@ - This is a description of the text file format. Other methods of specifying +@@ -22,7 +22,7 @@ This is a description of the text file f these files may exist. All empty lines or lines beginning with # are ignored. The basic format of one line in such maps is: .P @@ -15,9 +14,7 @@ .SS key For indirect mounts this is the part of the path name between the mount point - and the path into the filesystem when it is mounted. Usually you can think about the -@@ -39,22 +39,22 @@ - from SunOS). The options are a list of comma separated options as +@@ -40,20 +40,20 @@ from SunOS). The options are a list of customary for the .BR mount (8) command. There are two special options @@ -42,9 +39,7 @@ can be used to negate the option if it is present in the master map entry for the map but is not wanted for the given mount. - .SS location -@@ -71,15 +71,15 @@ - .sp +@@ -72,13 +72,13 @@ Indirect map: .RS +.2i .ta 1.0i 3.0i .nf @@ -65,9 +60,7 @@ /usr myserver.me.org:/usr \\ /home myserver.me.org:/home .fi - .RE -@@ -103,9 +103,9 @@ - .sp +@@ -104,7 +104,7 @@ example entry for an autofs map: .RS +.2i .ta 1.0i 3.0i .nf @@ -76,9 +69,7 @@ .fi .RE .sp - Direct map: -@@ -149,14 +149,14 @@ - .sp +@@ -150,12 +150,12 @@ scripts (Curly braces can be used to sep .RS +.2i .ta 1.5i .nf @@ -96,10 +87,8 @@ .fi .RE .sp - autofs provides additional variables that are set based on the -@@ -173,9 +173,9 @@ - SHOST Short hostname (domain part removed if present) - .fi +@@ -179,7 +179,7 @@ a prefix of "AUTOFS_" to prevent interpr + being able to load and execute arbitray code from a user home directory. .RE .sp -Additional entries can be defined with the -Dvariable=Value map-option to @@ -107,11 +96,9 @@ .BR automount (8). .SS Executable Maps A map can be marked as executable. A - .B program --- a/man/auto.master.5.in +++ b/man/auto.master.5.in -@@ -249,19 +249,19 @@ - options replace the global options (program default "yes", append options). +@@ -250,8 +250,8 @@ options replace the global options (prog .TP .B LOGGING set default log level "none", "verbose" or "debug" (program default "none"). @@ -122,8 +109,7 @@ which corresponds to a hostname will allow access to the exports of that host. The hosts map cannot be dynamically updated and requires a HUP signal to be sent to the daemon for it to check hosts for an update. Due to possible - hierarchic dependencies within a mount tree, it might not be completely - updated during the HUP signal processing. +@@ -260,7 +260,7 @@ updated during the HUP signal processing .P For example, with an entry in the master map of .nh @@ -132,4 +118,3 @@ .hy accessing /net/myserver will mount exports from myserver on directories below /net/myserver. - .P diff -Nru autofs-5.0.8/debian/patches/remove-kernel-mount.nfs-version-check.patch autofs-5.0.8/debian/patches/remove-kernel-mount.nfs-version-check.patch --- autofs-5.0.8/debian/patches/remove-kernel-mount.nfs-version-check.patch 2014-03-07 05:16:07.000000000 +0100 +++ autofs-5.0.8/debian/patches/remove-kernel-mount.nfs-version-check.patch 2015-02-28 23:11:25.000000000 +0100 @@ -22,8 +22,7 @@ --- a/daemon/automount.c +++ b/daemon/automount.c -@@ -50,11 +50,8 @@ - const char *libdir = AUTOFS_LIB_DIR; /* Location of library modules */ +@@ -51,9 +51,6 @@ const char *libdir = AUTOFS_LIB_DIR; /* const char *mapdir = AUTOFS_MAP_DIR; /* Location of mount maps */ const char *confdir = AUTOFS_CONF_DIR; /* Location of autofs config file */ @@ -33,9 +32,7 @@ /* autofs fifo name prefix */ const char *fifodir = AUTOFS_FIFO_DIR "/autofs.fifo"; - const char *global_options; /* Global option, from command line */ -@@ -1284,10 +1281,8 @@ - status = pthread_mutex_lock(&mrc.mutex); +@@ -1285,8 +1282,6 @@ static int do_hup_signal(struct master * if (status) fatal(status); @@ -44,9 +41,7 @@ master_mutex_lock(); /* Already doing a map read or shutdown or no mounts */ if (master->reading) { - status = pthread_mutex_unlock(&mrc.mutex); -@@ -1951,10 +1946,8 @@ - program = argv[0]; +@@ -1952,8 +1947,6 @@ int main(int argc, char *argv[]) defaults_read_config(0); @@ -55,11 +50,9 @@ kpkt_len = get_kpkt_len(); timeout = defaults_get_timeout(); ghost = defaults_get_browse_mode(); - logging = defaults_get_logging(); --- a/include/mounts.h +++ b/include/mounts.h -@@ -75,16 +75,9 @@ - struct list_head ordered; +@@ -76,14 +76,7 @@ struct mnt_list { }; @@ -72,13 +65,11 @@ -int check_nfs_mount_version(struct nfs_mount_vers *, struct nfs_mount_vers *); -extern unsigned int nfs_mount_uses_string_options; - struct substvar *addstdenv(struct substvar *sv); - struct substvar *removestdenv(struct substvar *sv); - + struct substvar *addstdenv(struct substvar *sv, const char *prefix); + struct substvar *removestdenv(struct substvar *sv, const char *prefix); --- a/modules/replicated.c +++ b/modules/replicated.c -@@ -885,11 +885,10 @@ - * greater than 2.6.22 and mount.nfs version is greater than 1.1.1. +@@ -886,9 +886,8 @@ int prune_host_list(unsigned logopt, str * But also allow the MOUNT_WAIT configuration parameter to override * the probing. */ @@ -90,11 +81,9 @@ if (!this) return 1; } else { - if (!this || !this->next) --- a/lib/mounts.c +++ b/lib/mounts.c -@@ -163,8 +163,9 @@ - { +@@ -165,6 +165,7 @@ unsigned int get_kver_minor(void) return kver.minor; } @@ -102,14 +91,11 @@ #ifdef HAVE_MOUNT_NFS static int extract_version(char *start, struct nfs_mount_vers *vers) { - char *s_ver = strchr(start, ' '); -@@ -301,8 +302,9 @@ - { +@@ -303,6 +304,7 @@ int check_nfs_mount_version(struct nfs_m return 0; } #endif +#endif - struct substvar *addstdenv(struct substvar *sv) + static char *set_env_name(const char *prefix, const char *name, char *buf) { - struct substvar *list = sv; diff -Nru autofs-5.0.8/debian/patches/series autofs-5.0.8/debian/patches/series --- autofs-5.0.8/debian/patches/series 2014-03-07 05:16:07.000000000 +0100 +++ autofs-5.0.8/debian/patches/series 2015-02-28 23:11:25.000000000 +0100 @@ -1,4 +1,8 @@ # +# CVE-2014-8169 +CVE-2014-8169-add-a-prefix-to-program-map-stdvars.patch +CVE-2014-8169-add-config-option-to-force-use-of-program-map-stdvars.patch +# # bugfixes forwarded to upstream filagdir.patch # @@ -15,3 +19,4 @@ link-daemon-with-lpthread.patch fix-ldflags.patch remove-kernel-mount.nfs-version-check.patch +
Description: add a prefix to program map stdvars When a program map uses an interpreted languages like python it is possible to load and execute arbitrary code from a user home directory. This is because the standard environment variables are used to locate and load modules when using these languages. (CVE-2014-8169) . To avoid that we need to add a prefix to these environment names so they aren't used for this purpose. The prefix used is "AUTOFS_" and is not configurable. Origin: vendor Author: Ian Kent <[email protected]> Reviewed-by: Salvatore Bonaccorso <[email protected]> Last-Update: 2015-02-28 --- --- a/include/mounts.h +++ b/include/mounts.h @@ -85,8 +85,8 @@ unsigned int linux_version_code(void); int check_nfs_mount_version(struct nfs_mount_vers *, struct nfs_mount_vers *); extern unsigned int nfs_mount_uses_string_options; -struct substvar *addstdenv(struct substvar *sv); -struct substvar *removestdenv(struct substvar *sv); +struct substvar *addstdenv(struct substvar *sv, const char *prefix); +struct substvar *removestdenv(struct substvar *sv, const char *prefix); unsigned int query_kproto_ver(void); unsigned int get_kver_major(void); --- a/lib/mounts.c +++ b/lib/mounts.c @@ -31,6 +31,7 @@ #define MAX_OPTIONS_LEN 80 #define MAX_MNT_NAME_LEN 30 +#define MAX_ENV_NAME 15 #define EBUFSIZ 1024 @@ -303,7 +304,61 @@ int check_nfs_mount_version(struct nfs_m } #endif -struct substvar *addstdenv(struct substvar *sv) +static char *set_env_name(const char *prefix, const char *name, char *buf) +{ + size_t len; + + len = strlen(name); + if (prefix) + len += strlen(prefix); + len++; + + if (len > MAX_ENV_NAME) + return NULL; + + if (!prefix) + strcpy(buf, name); + else { + strcpy(buf, prefix); + strcat(buf, name); + } + return buf; +} + +static struct substvar *do_macro_addvar(struct substvar *list, + const char *prefix, + const char *name, + const char *val) +{ + char buf[MAX_ENV_NAME + 1]; + char *new; + size_t len; + + new = set_env_name(prefix, name, buf); + if (new) { + len = strlen(new); + list = macro_addvar(list, new, len, val); + } + return list; +} + +static struct substvar *do_macro_removevar(struct substvar *list, + const char *prefix, + const char *name) +{ + char buf[MAX_ENV_NAME + 1]; + char *new; + size_t len; + + new = set_env_name(prefix, name, buf); + if (new) { + len = strlen(new); + list = macro_removevar(list, new, len); + } + return list; +} + +struct substvar *addstdenv(struct substvar *sv, const char *prefix) { struct substvar *list = sv; struct thread_stdenv_vars *tsv; @@ -318,14 +373,14 @@ struct substvar *addstdenv(struct substv num = (long) tsv->uid; ret = sprintf(numbuf, "%ld", num); if (ret > 0) - list = macro_addvar(list, "UID", 3, numbuf); + list = do_macro_addvar(list, prefix, "UID", numbuf); num = (long) tsv->gid; ret = sprintf(numbuf, "%ld", num); if (ret > 0) - list = macro_addvar(list, "GID", 3, numbuf); - list = macro_addvar(list, "USER", 4, tsv->user); - list = macro_addvar(list, "GROUP", 5, tsv->group); - list = macro_addvar(list, "HOME", 4, tsv->home); + list = do_macro_addvar(list, prefix, "GID", numbuf); + list = do_macro_addvar(list, prefix, "USER", tsv->user); + list = do_macro_addvar(list, prefix, "GROUP", tsv->group); + list = do_macro_addvar(list, prefix, "HOME", tsv->home); mv = macro_findvar(list, "HOST", 4); if (mv) { char *shost = strdup(mv->val); @@ -333,7 +388,8 @@ struct substvar *addstdenv(struct substv char *dot = strchr(shost, '.'); if (dot) *dot = '\0'; - list = macro_addvar(list, "SHOST", 5, shost); + list = do_macro_addvar(list, + prefix, "SHOST", shost); free(shost); } } @@ -341,16 +397,16 @@ struct substvar *addstdenv(struct substv return list; } -struct substvar *removestdenv(struct substvar *sv) +struct substvar *removestdenv(struct substvar *sv, const char *prefix) { struct substvar *list = sv; - list = macro_removevar(list, "UID", 3); - list = macro_removevar(list, "USER", 4); - list = macro_removevar(list, "HOME", 4); - list = macro_removevar(list, "GID", 3); - list = macro_removevar(list, "GROUP", 5); - list = macro_removevar(list, "SHOST", 5); + list = do_macro_removevar(list, prefix, "UID"); + list = do_macro_removevar(list, prefix, "USER"); + list = do_macro_removevar(list, prefix, "HOME"); + list = do_macro_removevar(list, prefix, "GID"); + list = do_macro_removevar(list, prefix, "GROUP"); + list = do_macro_removevar(list, prefix, "SHOST"); return list; } --- a/modules/lookup_program.c +++ b/modules/lookup_program.c @@ -272,7 +272,7 @@ int lookup_mount(struct autofs_point *ap if (ctxt->mapfmt && strcmp(ctxt->mapfmt, "MAPFMT_DEFAULT")) { struct parse_context *pctxt = (struct parse_context *) ctxt->parse->context; /* Add standard environment as seen by sun map parser */ - pctxt->subst = addstdenv(pctxt->subst); + pctxt->subst = addstdenv(pctxt->subst, "AUTOFS_"); macro_setenv(pctxt->subst); } execl(ctxt->mapname, ctxt->mapname, name, NULL); --- a/modules/parse_sun.c +++ b/modules/parse_sun.c @@ -1223,12 +1223,12 @@ int parse_mount(struct autofs_point *ap, pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cur_state); macro_lock(); - ctxt->subst = addstdenv(ctxt->subst); + ctxt->subst = addstdenv(ctxt->subst, NULL); mapent_len = expandsunent(mapent, NULL, name, ctxt->subst, slashify); if (mapent_len == 0) { error(ap->logopt, MODPREFIX "failed to expand map entry"); - ctxt->subst = removestdenv(ctxt->subst); + ctxt->subst = removestdenv(ctxt->subst, NULL); macro_unlock(); pthread_setcancelstate(cur_state, NULL); return 1; @@ -1238,7 +1238,7 @@ int parse_mount(struct autofs_point *ap, if (!pmapent) { char *estr = strerror_r(errno, buf, MAX_ERR_BUF); logerr(MODPREFIX "alloca: %s", estr); - ctxt->subst = removestdenv(ctxt->subst); + ctxt->subst = removestdenv(ctxt->subst, NULL); macro_unlock(); pthread_setcancelstate(cur_state, NULL); return 1; @@ -1246,7 +1246,7 @@ int parse_mount(struct autofs_point *ap, pmapent[mapent_len] = '\0'; expandsunent(mapent, pmapent, name, ctxt->subst, slashify); - ctxt->subst = removestdenv(ctxt->subst); + ctxt->subst = removestdenv(ctxt->subst, NULL); macro_unlock(); pthread_setcancelstate(cur_state, NULL);
Description: add config option to force use of program map stdvars Enabling the extended environment (including $HOME, for example) for program maps opens automount(8) to a privilege escalation. . Rather than just removing the entended environment a configuration option is added to disable it by default so that those who wish to use it can do so if they wish. Origin: vendor Author: Ian Kent <[email protected]> Author: Salvatore Bonaccorso <[email protected]> Last-Update: 2015-02-28 --- --- a/include/defaults.h +++ b/include/defaults.h @@ -28,6 +28,7 @@ #define DEFAULT_UMOUNT_WAIT 12 #define DEFAULT_BROWSE_MODE 1 #define DEFAULT_LOGGING 0 +#define DEFAULT_FORCE_STD_PROG_MAP_ENV 0 #define DEFAULT_LDAP_TIMEOUT -1 #define DEFAULT_LDAP_NETWORK_TIMEOUT 8 @@ -62,6 +63,7 @@ unsigned int defaults_get_timeout(void); unsigned int defaults_get_negative_timeout(void); unsigned int defaults_get_browse_mode(void); unsigned int defaults_get_logging(void); +unsigned int defaults_force_std_prog_map_env(void); const char *defaults_get_ldap_server(void); unsigned int defaults_get_ldap_timeout(void); unsigned int defaults_get_ldap_network_timeout(void); --- a/lib/defaults.c +++ b/lib/defaults.c @@ -35,6 +35,7 @@ #define ENV_NAME_NEGATIVE_TIMEOUT "NEGATIVE_TIMEOUT" #define ENV_NAME_BROWSE_MODE "BROWSE_MODE" #define ENV_NAME_LOGGING "LOGGING" +#define ENV_NAME_FORCE_STD_PROG_MAP_ENV "FORCE_STANDARD_PROGRAM_MAP_ENV" #define LDAP_URI "LDAP_URI" #define ENV_LDAP_TIMEOUT "LDAP_TIMEOUT" @@ -519,6 +520,7 @@ unsigned int defaults_read_config(unsign check_set_config_value(key, ENV_NAME_NEGATIVE_TIMEOUT, value, to_syslog) || check_set_config_value(key, ENV_NAME_BROWSE_MODE, value, to_syslog) || check_set_config_value(key, ENV_NAME_LOGGING, value, to_syslog) || + check_set_config_value(key, ENV_NAME_FORCE_STD_PROG_MAP_ENV, value, to_syslog) || check_set_config_value(key, ENV_LDAP_TIMEOUT, value, to_syslog) || check_set_config_value(key, ENV_LDAP_NETWORK_TIMEOUT, value, to_syslog) || check_set_config_value(key, ENV_NAME_MAP_OBJ_CLASS, value, to_syslog) || @@ -629,6 +631,17 @@ unsigned int defaults_get_logging(void) return logging; } +unsigned int defaults_force_std_prog_map_env(void) +{ + int res; + + res = get_env_yesno(ENV_NAME_FORCE_STD_PROG_MAP_ENV); + if (res < 0) + res = DEFAULT_FORCE_STD_PROG_MAP_ENV; + + return res; +} + unsigned int defaults_get_ldap_timeout(void) { int res; --- a/man/autofs.5 +++ b/man/autofs.5 @@ -174,6 +174,11 @@ SHOST Short hostname (domain part remove .fi .RE .sp +If a program map is used these standard environment variables will have +a prefix of "AUTOFS_" to prevent interpreted languages like python from +being able to load and execute arbitray code from a user home directory. +.RE +.sp Additional entries can be defined with the -Dvariable=Value map-option to .BR automount (8). .SS Executable Maps --- a/modules/lookup_program.c +++ b/modules/lookup_program.c @@ -132,6 +132,7 @@ int lookup_mount(struct autofs_point *ap int ret = 1; int distance; int alloci = 1; + char *prefix; source = ap->entry->current; ap->entry->current = NULL; @@ -265,6 +266,17 @@ int lookup_mount(struct autofs_point *ap warn(ap->logopt, MODPREFIX "failed to set PWD to %s for map %s", ap->path, ctxt->mapname); + + /* + * By default use a prefix with standard environment + * variables to prevent system subversion by interpreted + * languages. + */ + if (defaults_force_std_prog_map_env()) + prefix = NULL; + else + prefix = "AUTOFS_"; + /* * MAPFMT_DEFAULT must be "sun" for ->parse_init() to have setup * the macro table. @@ -272,7 +284,7 @@ int lookup_mount(struct autofs_point *ap if (ctxt->mapfmt && strcmp(ctxt->mapfmt, "MAPFMT_DEFAULT")) { struct parse_context *pctxt = (struct parse_context *) ctxt->parse->context; /* Add standard environment as seen by sun map parser */ - pctxt->subst = addstdenv(pctxt->subst, "AUTOFS_"); + pctxt->subst = addstdenv(pctxt->subst, prefix); macro_setenv(pctxt->subst); } execl(ctxt->mapname, ctxt->mapname, name, NULL); --- a/samples/autofs.conf.default.in +++ b/samples/autofs.conf.default.in @@ -80,6 +80,17 @@ BROWSE_MODE="no" # #LDAP_NETWORK_TIMEOUT=8 # +# FORCE_STANDARD_PROGRAM_MAP_ENV - disable the use of the "AUTOFS_" +# prefix for standard environment variables when +# executing a program map. Since program maps +# are run as the privileded user this opens +# automount(8) to potential user privilege +# escalation when the program map is written +# in a language that can load components from, +# for example, a user home directory. +# +#FORCE_STANDARD_PROGRAM_MAP_ENV="no" +# # Define base dn for map dn lookup. # # SEARCH_BASE - base dn to use for searching for map search dn.
_______________________________________________ Secure-testing-team mailing list [email protected] http://lists.alioth.debian.org/cgi-bin/mailman/listinfo/secure-testing-team

