Blame SOURCES/autofs-5.1.2-limit-getgrgid_r-buffer-size.patch

23b4c9
autofs-5.1.2 - limit getgrgid_r() buffer size
23b4c9
23b4c9
From: Ian Kent <raven@themaw.net>
23b4c9
23b4c9
Some older versions of glibc use stack allocation to store group
23b4c9
information during calls to getgrgid_r(). But before doing this
23b4c9
it checks if the size of the response info. can fit in the user
23b4c9
supplied buffer and returns ERANGE if it can't.
23b4c9
23b4c9
Now automount(8) doesn't check if the size of the buffer it is
23b4c9
passing is larger than it's stack size. That's not vey accurrate
23b4c9
since current stack usage isn't known but better than not checking
23b4c9
at all.
23b4c9
23b4c9
Signed-off-by: Ian Kent <raven@themaw.net>
23b4c9
---
23b4c9
 CHANGELOG    |    1 +
23b4c9
 lib/mounts.c |   47 +++++++++++++++++++++++++++++++++--------------
23b4c9
 2 files changed, 34 insertions(+), 14 deletions(-)
23b4c9
23b4c9
--- autofs-5.0.7.orig/CHANGELOG
23b4c9
+++ autofs-5.0.7/CHANGELOG
23b4c9
@@ -248,6 +248,7 @@
23b4c9
 - improve scalability of direct mount path component.
23b4c9
 - fix invalid reference in remount_active_mount().
23b4c9
 - increase worker thread per-thread stack size.
23b4c9
+- limit getgrgid_r() buffer size.
23b4c9
 
23b4c9
 25/07/2012 autofs-5.0.7
23b4c9
 =======================
23b4c9
--- autofs-5.0.7.orig/lib/mounts.c
23b4c9
+++ autofs-5.0.7/lib/mounts.c
23b4c9
@@ -48,6 +48,9 @@ static const char mnt_name_template[]
23b4c9
 static struct kernel_mod_version kver = {0, 0};
23b4c9
 static const char kver_options_template[]  = "fd=%d,pgrp=%u,minproto=3,maxproto=5";
23b4c9
 
23b4c9
+extern size_t detached_thread_stack_size;
23b4c9
+static size_t maxgrpbuf = 0;
23b4c9
+
23b4c9
 #define EXT_MOUNTS_HASH_SIZE    50
23b4c9
 
23b4c9
 struct ext_mount {
23b4c9
@@ -1503,14 +1506,22 @@ void set_tsd_user_vars(unsigned int logo
23b4c9
 	}
23b4c9
 
23b4c9
 	gr_tmp = NULL;
23b4c9
+	status = ERANGE;
23b4c9
+	if (!maxgrpbuf)
23b4c9
+		maxgrpbuf = detached_thread_stack_size * 0.9;
23b4c9
+
23b4c9
+	/* If getting the group name fails go on without it. It's
23b4c9
+	 * used to set an environment variable for program maps
23b4c9
+	 * which may or may not use it so it isn't critical to
23b4c9
+	 * operation.
23b4c9
+	 */
23b4c9
+
23b4c9
 	tmplen = grplen;
23b4c9
 	while (1) {
23b4c9
 		char *tmp = realloc(gr_tmp, tmplen + 1);
23b4c9
 		if (!tmp) {
23b4c9
 			error(logopt, "failed to malloc buffer for getgrgid_r");
23b4c9
-			if (gr_tmp)
23b4c9
-				free(gr_tmp);
23b4c9
-			goto free_tsv_home;
23b4c9
+			goto no_group;
23b4c9
 		}
23b4c9
 		gr_tmp = tmp;
23b4c9
 		pgr = &gr;
23b4c9
@@ -1519,22 +1530,29 @@ void set_tsd_user_vars(unsigned int logo
23b4c9
 		if (status != ERANGE)
23b4c9
 			break;
23b4c9
 		tmplen += grplen;
23b4c9
+
23b4c9
+		/* Don't tempt glibc to alloca() larger than is (likely)
23b4c9
+		 * available on the stack.
23b4c9
+		 */
23b4c9
+		if (tmplen < maxgrpbuf)
23b4c9
+			continue;
23b4c9
+
23b4c9
+		/* Add a message so we know this happened */
23b4c9
+		debug(logopt, "group buffer allocation would be too large");
23b4c9
+		break;
23b4c9
 	}
23b4c9
 
23b4c9
-	if (status || !pgr) {
23b4c9
+no_group:
23b4c9
+	if (status || !pgr)
23b4c9
 		error(logopt, "failed to get group info from getgrgid_r");
23b4c9
-		free(gr_tmp);
23b4c9
-		goto free_tsv_home;
23b4c9
+	else {
23b4c9
+		tsv->group = strdup(gr.gr_name);
23b4c9
+		if (!tsv->group)
23b4c9
+			error(logopt, "failed to malloc buffer for group");
23b4c9
 	}
23b4c9
 
23b4c9
-	tsv->group = strdup(gr.gr_name);
23b4c9
-	if (!tsv->group) {
23b4c9
-		error(logopt, "failed to malloc buffer for group");
23b4c9
+	if (gr_tmp)
23b4c9
 		free(gr_tmp);
23b4c9
-		goto free_tsv_home;
23b4c9
-	}
23b4c9
-
23b4c9
-	free(gr_tmp);
23b4c9
 
23b4c9
 	status = pthread_setspecific(key_thread_stdenv_vars, tsv);
23b4c9
 	if (status) {
23b4c9
@@ -1545,7 +1563,8 @@ void set_tsd_user_vars(unsigned int logo
23b4c9
 	return;
23b4c9
 
23b4c9
 free_tsv_group:
23b4c9
-	free(tsv->group);
23b4c9
+	if (tsv->group)
23b4c9
+		free(tsv->group);
23b4c9
 free_tsv_home:
23b4c9
 	free(tsv->home);
23b4c9
 free_tsv_user: