diff Modules/socketmodule.c @ 36452:7789cc557e1e legacy-trunk

Bug #876637, prevent stack corruption when socket descriptor is larger than FD_SETSIZE. This can only be acheived with ulimit -n SOME_NUMBER_BIGGER_THAN_FD_SETSIZE which is typically only available to root. Since this wouldn't normally be run in a test (ie, run as root), it doesn't seem too worthwhile to add a normal test. The bug report has one version of a test. I've written another. Not sure what the best thing to do is. Do the check before calling internal_select() because we can't set an error in between Py_BEGIN_ALLOW_THREADS and Py_END_ALLOW_THREADS. This seemed the clearest solution, ie handle before calling internal_select() rather than inside. Plus there is at least one place outside of internal_select() that needed to be handled. Will backport.
author Neal Norwitz <nnorwitz@gmail.com>
date Tue, 07 Feb 2006 07:04:46 +0000
parents 1af7f719ed28
children c073dffbe70e
line wrap: on
line diff
--- a/Modules/socketmodule.c	Tue Feb 07 06:59:20 2006 +0000
+++ b/Modules/socketmodule.c	Tue Feb 07 07:04:46 2006 +0000
@@ -395,6 +395,16 @@
    there has to be a circular reference. */
 static PyTypeObject sock_type;
 
+/* Can we call select() with this socket without a buffer overrun? */
+#define IS_SELECTABLE(s) ((s)->sock_fd < FD_SETSIZE)
+
+static PyObject*
+select_error(void)
+{
+	PyErr_SetString(socket_error, "unable to select on socket");
+	return NULL;
+}
+
 /* Convenience function to raise an error according to errno
    and return a NULL pointer from a function. */
 
@@ -1408,6 +1418,9 @@
 	newfd = -1;
 #endif
 
+	if (!IS_SELECTABLE(s))
+		return select_error();
+
 	Py_BEGIN_ALLOW_THREADS
 	timeout = internal_select(s, 0);
 	if (!timeout)
@@ -1736,7 +1749,8 @@
 #ifdef MS_WINDOWS
 
 	if (s->sock_timeout > 0.0) {
-		if (res < 0 && WSAGetLastError() == WSAEWOULDBLOCK) {
+		if (res < 0 && WSAGetLastError() == WSAEWOULDBLOCK &&
+		    IS_SELECTABLE(s)) {
 			/* This is a mess.  Best solution: trust select */
 			fd_set fds;
 			fd_set fds_exc;
@@ -1781,7 +1795,7 @@
 #else
 
 	if (s->sock_timeout > 0.0) {
-		if (res < 0 && errno == EINPROGRESS) {
+		if (res < 0 && errno == EINPROGRESS && IS_SELECTABLE(s)) {
 			timeout = internal_select(s, 1);
 			res = connect(s->sock_fd, addr, addrlen);
 			if (res < 0 && errno == EISCONN)
@@ -2084,6 +2098,9 @@
 	if (buf == NULL)
 		return NULL;
 
+	if (!IS_SELECTABLE(s))
+		return select_error();
+
 #ifndef __VMS
 	Py_BEGIN_ALLOW_THREADS
 	timeout = internal_select(s, 0);
@@ -2177,6 +2194,9 @@
 	if (buf == NULL)
 		return NULL;
 
+	if (!IS_SELECTABLE(s))
+		return select_error();
+
 	Py_BEGIN_ALLOW_THREADS
 	memset(&addrbuf, 0, addrlen);
 	timeout = internal_select(s, 0);
@@ -2238,6 +2258,9 @@
 	if (!PyArg_ParseTuple(args, "s#|i:send", &buf, &len, &flags))
 		return NULL;
 
+	if (!IS_SELECTABLE(s))
+		return select_error();
+
 #ifndef __VMS
 	Py_BEGIN_ALLOW_THREADS
 	timeout = internal_select(s, 1);
@@ -2303,6 +2326,9 @@
 	if (!PyArg_ParseTuple(args, "s#|i:sendall", &buf, &len, &flags))
 		return NULL;
 
+	if (!IS_SELECTABLE(s))
+		return select_error();
+
 	Py_BEGIN_ALLOW_THREADS
 	do {
 		timeout = internal_select(s, 1);
@@ -2357,6 +2383,9 @@
 	if (!getsockaddrarg(s, addro, &addr, &addrlen))
 		return NULL;
 
+	if (!IS_SELECTABLE(s))
+		return select_error();
+
 	Py_BEGIN_ALLOW_THREADS
 	timeout = internal_select(s, 1);
 	if (!timeout)