Trent Mick <trentm@activestate.com>:

This patch fixes possible overflow in the use of
PyOS_GetLastModificationTime in getmtime.c and Python/import.c.

Currently PyOS_GetLastModificationTime returns a C long. This can
overflow on Win64 where sizeof(time_t) > sizeof(long). Besides it
should logically return a time_t anyway (this patch changes this).

As well, import.c uses PyOS_GetLastModificationTime for .pyc
timestamping.  There has been recent discussion about the .pyc header
format on python-dev.  This patch adds oveflow checking to import.c so
that an exception will be raised if the modification time
overflows. There are a few other minor 64-bit readiness changes made
to the module as well:

- size_t instead of int or long for function-local buffer and string
length variables

- one buffer overflow check was added (raises an exception on possible
overflow, this overflow chance exists on 32-bit platforms as well), no
other possible buffer overflows existed (from my analysis anyway)

Closes SourceForge patch #100509.
diff --git a/Python/import.c b/Python/import.c
index a23b71b..ede6cb6 100644
--- a/Python/import.c
+++ b/Python/import.c
@@ -74,7 +74,7 @@
 #endif
 
 
-extern long PyOS_GetLastModificationTime(); /* In getmtime.c */
+extern time_t PyOS_GetLastModificationTime(); /* In getmtime.c */
 
 /* Magic word to reject .pyc files generated by other Python versions */
 /* Change for each incompatible change */
@@ -549,9 +549,9 @@
 make_compiled_pathname(pathname, buf, buflen)
 	char *pathname;
 	char *buf;
-	int buflen;
+	size_t buflen;
 {
-	int len;
+	size_t len;
 
 	len = strlen(pathname);
 	if (len+2 > buflen)
@@ -732,7 +732,7 @@
 	char *pathname;
 	FILE *fp;
 {
-	long mtime;
+	time_t mtime;
 	FILE *fpc;
 	char buf[MAXPATHLEN+1];
 	char *cpathname;
@@ -740,7 +740,20 @@
 	PyObject *m;
 
 	mtime = PyOS_GetLastModificationTime(pathname, fp);
-	cpathname = make_compiled_pathname(pathname, buf, MAXPATHLEN+1);
+	if (mtime == -1)
+		return NULL;
+#if SIZEOF_TIME_T > 4
+	/* Python's .pyc timestamp handling presumes that the timestamp fits
+	   in 4 bytes. This will be fine until sometime in the year 2038,
+	   when a 4-byte signed time_t will overflow.
+	 */
+	if (mtime >> 32) {
+		PyErr_SetString(PyExc_OverflowError,
+			"modification time overflows a 4 bytes");
+		return NULL;
+	}
+#endif
+	cpathname = make_compiled_pathname(pathname, buf, (size_t)MAXPATHLEN+1);
 	if (cpathname != NULL &&
 	    (fpc = check_compiled_module(pathname, mtime, cpathname))) {
 		co = read_compiled_module(cpathname, fpc);
@@ -771,7 +784,7 @@
 /* Forward */
 static PyObject *load_module Py_PROTO((char *, FILE *, char *, int));
 static struct filedescr *find_module Py_PROTO((char *, PyObject *,
-					       char *, int, FILE **));
+					       char *, size_t, FILE **));
 static struct _frozen *find_frozen Py_PROTO((char *name));
 
 /* Load a package and return its module object WITH INCREMENTED
@@ -869,10 +882,11 @@
 	PyObject *path;
 	/* Output parameters: */
 	char *buf;
-	int buflen;
+	size_t buflen;
 	FILE **p_fp;
 {
-	int i, npath, len, namelen;
+	int i, npath;
+	size_t len, namelen;
 	struct _frozen *f;
 	struct filedescr *fdp = NULL;
 	FILE *fp = NULL;
@@ -882,6 +896,10 @@
 	static struct filedescr fd_package = {"", "", PKG_DIRECTORY};
 	char name[MAXPATHLEN+1];
 
+	if (strlen(realname) > MAXPATHLEN) {
+		PyErr_SetString(PyExc_OverflowError, "module name is too long");
+		return NULL;
+	}
 	strcpy(name, realname);
 
 	if (path != NULL && PyString_Check(path)) {
@@ -933,7 +951,7 @@
 		if (len + 2 + namelen + MAXSUFFIXSIZE >= buflen)
 			continue; /* Too long */
 		strcpy(buf, PyString_AsString(v));
-		if ((int)strlen(buf) != len)
+		if (strlen(buf) != len)
 			continue; /* v contains '\0' */
 #ifdef macintosh
 #ifdef INTERN_STRINGS
@@ -1181,8 +1199,8 @@
 find_init_module(buf)
 	char *buf;
 {
-	int save_len = strlen(buf);
-	int i = save_len;
+	size_t save_len = strlen(buf);
+	size_t i = save_len;
 	struct stat statbuf;
 
 	if (save_len + 13 >= MAXPATHLEN)
@@ -1577,7 +1595,7 @@
 	else {
 		char *start = PyString_AS_STRING(modname);
 		char *lastdot = strrchr(start, '.');
-		int len;
+		size_t len;
 		if (lastdot == NULL)
 			return Py_None;
 		len = lastdot - start;
@@ -1612,7 +1630,7 @@
 {
 	char *name = *p_name;
 	char *dot = strchr(name, '.');
-	int len;
+	size_t len;
 	char *p;
 	PyObject *result;