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

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