2005-02-05  Roland McGrath  <roland@redhat.com>

	* desc.c (decode_select): Calculate size of passed fd_set vectors and
	copy in the user's size rather than the standard sizeof(fd_set).
	Fixes Debian bug #65654.
diff --git a/desc.c b/desc.c
index eaff3e0..bc86a5d 100644
--- a/desc.c
+++ b/desc.c
@@ -405,7 +405,9 @@
 int bitness;
 {
 	int i, j, nfds;
-	fd_set fds;
+	unsigned int fdsize = ((((args[0] + 7) / 8) + sizeof(long) - 1)
+			       & -sizeof(long));
+	fd_set *fds;
 	struct timeval tv;
 #ifdef ALPHA
 	struct timeval32 {
@@ -418,6 +420,11 @@
 	long arg;
 
 	if (entering(tcp)) {
+		fds = (fd_set *) malloc(fdsize);
+		if (fds == NULL) {
+			tprintf("out of memory\n");
+			return 0;
+		}
 		nfds = args[0];
 		tprintf("%d", nfds);
 		for (i = 0; i < 3; i++) {
@@ -430,19 +437,20 @@
 				tprintf(", %#lx", arg);
 				continue;
 			}
-			if (umove(tcp, arg, &fds) < 0) {
+			if (umoven(tcp, arg, fdsize, (char *) fds) < 0) {
 				tprintf(", [?]");
 				continue;
 			}
 			tprintf(", [");
 			for (j = 0, sep = ""; j < nfds; j++) {
-				if (FD_ISSET(j, &fds)) {
+				if (FD_ISSET(j, fds)) {
 					tprintf("%s%u", sep, j);
 					sep = " ";
 				}
 			}
 			tprintf("]");
 		}
+		free(fds);
 		if (!args[4])
 			tprintf(", NULL");
 		else if (!verbose(tcp))
@@ -472,6 +480,13 @@
 			tcp->auxstr = "Timeout";
 			return RVAL_STR;
 		}
+
+		fds = (fd_set *) malloc(fdsize);
+		if (fds == NULL) {
+			tprintf("out of memory\n");
+			return 0;
+		}
+
 		outstr[0] = '\0';
 		for (i = 0; i < 3; i++) {
 			int first = 1;
@@ -479,10 +494,10 @@
 
 			tcp->auxstr = outstr;
 			arg = args[i+1];
-			if (!arg || umove(tcp, arg, &fds) < 0)
+			if (!arg || umoven(tcp, arg, fdsize, (char *) fds) < 0)
 				continue;
 			for (j = 0; j < args[0]; j++) {
-				if (FD_ISSET(j, &fds)) {
+				if (FD_ISSET(j, fds)) {
 					if (first) {
 						sprintf(str, "%s%s [%u", sep,
 							i == 0 ? "in" :
@@ -504,6 +519,7 @@
 			if (nfds == 0)
 				break;
 		}
+		free(fds);
 #ifdef LINUX
 		/* This contains no useful information on SunOS.  */
 		if (args[4]) {