2005-05-31  Dmitry V. Levin  <ldv@altlinux.org>

	Deal with memory management issues.
	* defs.h (tprint_iov): Update prototype.
	* desc.c (sys_epoll_wait) [HAVE_SYS_EPOLL_H]: Do not allocate
	epoll_event array of arbitrary size on the stack, to avoid
	stack overflow.
	* file.c (print_xattr_val): Check for integer overflow during
	malloc size calculation, to avoid heap corruption.
	* io.c (tprint_iov) [HAVE_SYS_UIO_H]: Check for integer overflow
	during malloc size calculation, to avoid heap corruption.
	Change iovec array handling to avoid heap memory allocation.
	* mem.c (get_nodes) [LINUX]: Check for integer overflow during
	size calculation and do not allocate array of arbitrary size on
	the stack, to avoid stack overflow.
	* net.c (printcmsghdr) [HAVE_SENDMSG]: Do not allocate array of
	arbitrary size on the stack, to avoid stack overflow.  Do not
	trust cmsg.cmsg_len to avoid read beyond the end of allocated
	object.
	(printmsghdr) [HAVE_SENDMSG]: Update tprint_iov() usage.
	* process.c (sys_setgroups): Check for integer overflow during
	malloc size calculation, to avoid heap corruption.  Change gid_t
	array handling to avoid heap memory allocation.
	(sys_getgroups): Likewise.
	(sys_setgroups32) [LINUX]: Likewise.
	(sys_getgroups32) [LINUX]: Likewise.
	* stream.c (sys_poll) [HAVE_SYS_POLL_H]: Check for integer
	overflow during malloc size calculation, to avoid heap corruption.
	Change pollfd array handling to avoid heap memory allocation.
	* system.c (sys_sysctl) [LINUX]: Check for integer overflow
	during malloc size calculation, to avoid heap corruption.
	* util.c (dumpiov) [HAVE_SYS_UIO_H]: Check for integer overflow
	during malloc size calculation, to avoid heap corruption.
	Fixes RH#159196.
diff --git a/process.c b/process.c
index badcba6..bc116a4 100644
--- a/process.c
+++ b/process.c
@@ -1225,34 +1225,53 @@
 sys_setgroups(tcp)
 struct tcb *tcp;
 {
-	int i, len;
-	GETGROUPS_T *gidset;
-
 	if (entering(tcp)) {
+		unsigned long len, size, start, cur, end, abbrev_end;
+		GETGROUPS_T gid;
+		int failed = 0;
+
 		len = tcp->u_arg[0];
-		tprintf("%u, ", len);
-		if (len <= 0) {
+		tprintf("%lu, ", len);
+		if (len == 0) {
 			tprintf("[]");
 			return 0;
 		}
-		gidset = (GETGROUPS_T *) malloc(len * sizeof(GETGROUPS_T));
-		if (gidset == NULL) {
-			fprintf(stderr, "sys_setgroups: out of memory\n");
-			return -1;
+		start = tcp->u_arg[1];
+		if (start == 0) {
+			tprintf("NULL");
+			return 0;
 		}
-		if (!verbose(tcp))
-			tprintf("%#lx", tcp->u_arg[1]);
-		else if (umoven(tcp, tcp->u_arg[1],
-		    len * sizeof(GETGROUPS_T), (char *) gidset) < 0)
-			tprintf("[?]");
-		else {
-			tprintf("[");
-			for (i = 0; i < len; i++)
-				tprintf("%s%lu", i ? ", " : "",
-					(unsigned long) gidset[i]);
-			tprintf("]");
+		size = len * sizeof(gid);
+		end = start + size;
+		if (!verbose(tcp) || size / sizeof(gid) != len || end < start) {
+			tprintf("%#lx", start);
+			return 0;
 		}
-		free((char *) gidset);
+		if (abbrev(tcp)) {
+			abbrev_end = start + max_strlen * sizeof(gid);
+			if (abbrev_end < start)
+				abbrev_end = end;
+		} else {
+			abbrev_end = end;
+		}
+		tprintf("[");
+		for (cur = start; cur < end; cur += sizeof(gid)) {
+			if (cur > start)
+				tprintf(", ");
+			if (cur >= abbrev_end) {
+				tprintf("...");
+				break;
+			}
+			if (umoven(tcp, cur, sizeof(gid), (char *) &gid) < 0) {
+				tprintf("?");
+				failed = 1;
+				break;
+			}
+			tprintf("%lu", (unsigned long) gid);
+		}
+		tprintf("]");
+		if (failed)
+			tprintf(" %#lx", tcp->u_arg[1]);
 	}
 	return 0;
 }
@@ -1261,38 +1280,62 @@
 sys_getgroups(tcp)
 struct tcb *tcp;
 {
-	int i, len;
-	GETGROUPS_T *gidset;
+	unsigned long len;
 
 	if (entering(tcp)) {
 		len = tcp->u_arg[0];
-		tprintf("%u, ", len);
+		tprintf("%lu, ", len);
 	} else {
+		unsigned long size, start, cur, end, abbrev_end;
+		GETGROUPS_T gid;
+		int failed = 0;
+
 		len = tcp->u_rval;
-		if (len <= 0) {
+		if (len == 0) {
 			tprintf("[]");
 			return 0;
 		}
-		gidset = (GETGROUPS_T *) malloc(len * sizeof(GETGROUPS_T));
-		if (gidset == NULL) {
-			fprintf(stderr, "sys_getgroups: out of memory\n");
-			return -1;
-		}
-		if (!tcp->u_arg[1])
+		start = tcp->u_arg[1];
+		if (start == 0) {
 			tprintf("NULL");
-		else if (!verbose(tcp) || tcp->u_arg[0] == 0)
-			tprintf("%#lx", tcp->u_arg[1]);
-		else if (umoven(tcp, tcp->u_arg[1],
-		    len * sizeof(GETGROUPS_T), (char *) gidset) < 0)
-			tprintf("[?]");
-		else {
-			tprintf("[");
-			for (i = 0; i < len; i++)
-				tprintf("%s%lu", i ? ", " : "",
-					(unsigned long) gidset[i]);
-			tprintf("]");
+			return 0;
 		}
-		free((char *)gidset);
+		if (tcp->u_arg[0] == 0) {
+			tprintf("%#lx", start);
+			return 0;
+		}
+		size = len * sizeof(gid);
+		end = start + size;
+		if (!verbose(tcp) || tcp->u_arg[0] == 0 ||
+		    size / sizeof(gid) != len || end < start) {
+			tprintf("%#lx", start);
+			return 0;
+		}
+		if (abbrev(tcp)) {
+			abbrev_end = start + max_strlen * sizeof(gid);
+			if (abbrev_end < start)
+				abbrev_end = end;
+		} else {
+			abbrev_end = end;
+		}
+		tprintf("[");
+		for (cur = start; cur < end; cur += sizeof(gid)) {
+			if (cur > start)
+				tprintf(", ");
+			if (cur >= abbrev_end) {
+				tprintf("...");
+				break;
+			}
+			if (umoven(tcp, cur, sizeof(gid), (char *) &gid) < 0) {
+				tprintf("?");
+				failed = 1;
+				break;
+			}
+			tprintf("%lu", (unsigned long) gid);
+		}
+		tprintf("]");
+		if (failed)
+			tprintf(" %#lx", tcp->u_arg[1]);
 	}
 	return 0;
 }
@@ -1302,34 +1345,53 @@
 sys_setgroups32(tcp)
 struct tcb *tcp;
 {
-	int i, len;
-	GETGROUPS32_T *gidset;
-
 	if (entering(tcp)) {
+		unsigned long len, size, start, cur, end, abbrev_end;
+		GETGROUPS32_T gid;
+		int failed = 0;
+
 		len = tcp->u_arg[0];
-		tprintf("%u, ", len);
-		if (len <= 0) {
+		tprintf("%lu, ", len);
+		if (len == 0) {
 			tprintf("[]");
 			return 0;
 		}
-		gidset = (GETGROUPS32_T *) malloc(len * sizeof(GETGROUPS32_T));
-		if (gidset == NULL) {
-			fprintf(stderr, "sys_setgroups32: out of memory\n");
-			return -1;
+		start = tcp->u_arg[1];
+		if (start == 0) {
+			tprintf("NULL");
+			return 0;
 		}
-		if (!verbose(tcp))
-			tprintf("%#lx", tcp->u_arg[1]);
-		else if (umoven(tcp, tcp->u_arg[1],
-		    len * sizeof(GETGROUPS32_T), (char *) gidset) < 0)
-			tprintf("[?]");
-		else {
-			tprintf("[");
-			for (i = 0; i < len; i++)
-				tprintf("%s%lu", i ? ", " : "",
-					(unsigned long) gidset[i]);
-			tprintf("]");
+		size = len * sizeof(gid);
+		end = start + size;
+		if (!verbose(tcp) || size / sizeof(gid) != len || end < start) {
+			tprintf("%#lx", start);
+			return 0;
 		}
-		free((char *) gidset);
+		if (abbrev(tcp)) {
+			abbrev_end = start + max_strlen * sizeof(gid);
+			if (abbrev_end < start)
+				abbrev_end = end;
+		} else {
+			abbrev_end = end;
+		}
+		tprintf("[");
+		for (cur = start; cur < end; cur += sizeof(gid)) {
+			if (cur > start)
+				tprintf(", ");
+			if (cur >= abbrev_end) {
+				tprintf("...");
+				break;
+			}
+			if (umoven(tcp, cur, sizeof(gid), (char *) &gid) < 0) {
+				tprintf("?");
+				failed = 1;
+				break;
+			}
+			tprintf("%lu", (unsigned long) gid);
+		}
+		tprintf("]");
+		if (failed)
+			tprintf(" %#lx", tcp->u_arg[1]);
 	}
 	return 0;
 }
@@ -1338,38 +1400,58 @@
 sys_getgroups32(tcp)
 struct tcb *tcp;
 {
-	int i, len;
-	GETGROUPS32_T *gidset;
+	unsigned long len;
 
 	if (entering(tcp)) {
 		len = tcp->u_arg[0];
-		tprintf("%u, ", len);
+		tprintf("%lu, ", len);
 	} else {
+		unsigned long size, start, cur, end, abbrev_end;
+		GETGROUPS32_T gid;
+		int failed = 0;
+
 		len = tcp->u_rval;
-		if (len <= 0) {
+		if (len == 0) {
 			tprintf("[]");
 			return 0;
 		}
-		gidset = (GETGROUPS32_T *) malloc(len * sizeof(GETGROUPS32_T));
-		if (gidset == NULL) {
-			fprintf(stderr, "sys_getgroups32: out of memory\n");
-			return -1;
-		}
-		if (!tcp->u_arg[1])
+		start = tcp->u_arg[1];
+		if (start == 0) {
 			tprintf("NULL");
-		else if (!verbose(tcp) || tcp->u_arg[0] == 0)
-			tprintf("%#lx", tcp->u_arg[1]);
-		else if (umoven(tcp, tcp->u_arg[1],
-		    len * sizeof(GETGROUPS32_T), (char *) gidset) < 0)
-			tprintf("[?]");
-		else {
-			tprintf("[");
-			for (i = 0; i < len; i++)
-				tprintf("%s%lu", i ? ", " : "",
-					(unsigned long) gidset[i]);
-			tprintf("]");
+			return 0;
 		}
-		free((char *)gidset);
+		size = len * sizeof(gid);
+		end = start + size;
+		if (!verbose(tcp) || tcp->u_arg[0] == 0 ||
+		    size / sizeof(gid) != len || end < start) {
+			tprintf("%#lx", start);
+			return 0;
+		}
+		if (abbrev(tcp)) {
+			abbrev_end = start + max_strlen * sizeof(gid);
+			if (abbrev_end < start)
+				abbrev_end = end;
+		} else {
+			abbrev_end = end;
+		}
+		tprintf("[");
+		for (cur = start; cur < end; cur += sizeof(gid)) {
+			if (cur > start)
+				tprintf(", ");
+			if (cur >= abbrev_end) {
+				tprintf("...");
+				break;
+			}
+			if (umoven(tcp, cur, sizeof(gid), (char *) &gid) < 0) {
+				tprintf("?");
+				failed = 1;
+				break;
+			}
+			tprintf("%lu", (unsigned long) gid);
+		}
+		tprintf("]");
+		if (failed)
+			tprintf(" %#lx", tcp->u_arg[1]);
 	}
 	return 0;
 }