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

Reply via email to