Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 4c82b23

Browse files
committed
Trent Mick <[email protected]>:
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.
1 parent 4358b2c commit 4c82b23

2 files changed

Lines changed: 33 additions & 14 deletions

File tree

Python/getmtime.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,14 @@ PERFORMANCE OF THIS SOFTWARE.
3333

3434
/* (A separate file because this may be OS dependent) */
3535

36+
#include "Python.h"
3637
#include "config.h"
3738

3839
#include <stdio.h>
3940
#include <sys/types.h>
4041
#include <sys/stat.h>
4142

42-
long
43+
time_t
4344
PyOS_GetLastModificationTime(path, fp)
4445
char *path;
4546
FILE *fp;

Python/import.c

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ PERFORMANCE OF THIS SOFTWARE.
7474
#endif
7575

7676

77-
extern long PyOS_GetLastModificationTime(); /* In getmtime.c */
77+
extern time_t PyOS_GetLastModificationTime(); /* In getmtime.c */
7878

7979
/* Magic word to reject .pyc files generated by other Python versions */
8080
/* Change for each incompatible change */
@@ -549,9 +549,9 @@ static char *
549549
make_compiled_pathname(pathname, buf, buflen)
550550
char *pathname;
551551
char *buf;
552-
int buflen;
552+
size_t buflen;
553553
{
554-
int len;
554+
size_t len;
555555

556556
len = strlen(pathname);
557557
if (len+2 > buflen)
@@ -732,15 +732,28 @@ load_source_module(name, pathname, fp)
732732
char *pathname;
733733
FILE *fp;
734734
{
735-
long mtime;
735+
time_t mtime;
736736
FILE *fpc;
737737
char buf[MAXPATHLEN+1];
738738
char *cpathname;
739739
PyCodeObject *co;
740740
PyObject *m;
741741

742742
mtime = PyOS_GetLastModificationTime(pathname, fp);
743-
cpathname = make_compiled_pathname(pathname, buf, MAXPATHLEN+1);
743+
if (mtime == -1)
744+
return NULL;
745+
#if SIZEOF_TIME_T > 4
746+
/* Python's .pyc timestamp handling presumes that the timestamp fits
747+
in 4 bytes. This will be fine until sometime in the year 2038,
748+
when a 4-byte signed time_t will overflow.
749+
*/
750+
if (mtime >> 32) {
751+
PyErr_SetString(PyExc_OverflowError,
752+
"modification time overflows a 4 bytes");
753+
return NULL;
754+
}
755+
#endif
756+
cpathname = make_compiled_pathname(pathname, buf, (size_t)MAXPATHLEN+1);
744757
if (cpathname != NULL &&
745758
(fpc = check_compiled_module(pathname, mtime, cpathname))) {
746759
co = read_compiled_module(cpathname, fpc);
@@ -771,7 +784,7 @@ load_source_module(name, pathname, fp)
771784
/* Forward */
772785
static PyObject *load_module Py_PROTO((char *, FILE *, char *, int));
773786
static struct filedescr *find_module Py_PROTO((char *, PyObject *,
774-
char *, int, FILE **));
787+
char *, size_t, FILE **));
775788
static struct _frozen *find_frozen Py_PROTO((char *name));
776789

777790
/* Load a package and return its module object WITH INCREMENTED
@@ -869,10 +882,11 @@ find_module(realname, path, buf, buflen, p_fp)
869882
PyObject *path;
870883
/* Output parameters: */
871884
char *buf;
872-
int buflen;
885+
size_t buflen;
873886
FILE **p_fp;
874887
{
875-
int i, npath, len, namelen;
888+
int i, npath;
889+
size_t len, namelen;
876890
struct _frozen *f;
877891
struct filedescr *fdp = NULL;
878892
FILE *fp = NULL;
@@ -882,6 +896,10 @@ find_module(realname, path, buf, buflen, p_fp)
882896
static struct filedescr fd_package = {"", "", PKG_DIRECTORY};
883897
char name[MAXPATHLEN+1];
884898

899+
if (strlen(realname) > MAXPATHLEN) {
900+
PyErr_SetString(PyExc_OverflowError, "module name is too long");
901+
return NULL;
902+
}
885903
strcpy(name, realname);
886904

887905
if (path != NULL && PyString_Check(path)) {
@@ -933,7 +951,7 @@ find_module(realname, path, buf, buflen, p_fp)
933951
if (len + 2 + namelen + MAXSUFFIXSIZE >= buflen)
934952
continue; /* Too long */
935953
strcpy(buf, PyString_AsString(v));
936-
if ((int)strlen(buf) != len)
954+
if (strlen(buf) != len)
937955
continue; /* v contains '\0' */
938956
#ifdef macintosh
939957
#ifdef INTERN_STRINGS
@@ -1181,8 +1199,8 @@ static int
11811199
find_init_module(buf)
11821200
char *buf;
11831201
{
1184-
int save_len = strlen(buf);
1185-
int i = save_len;
1202+
size_t save_len = strlen(buf);
1203+
size_t i = save_len;
11861204
struct stat statbuf;
11871205

11881206
if (save_len + 13 >= MAXPATHLEN)
@@ -1577,7 +1595,7 @@ get_parent(globals, buf, p_buflen)
15771595
else {
15781596
char *start = PyString_AS_STRING(modname);
15791597
char *lastdot = strrchr(start, '.');
1580-
int len;
1598+
size_t len;
15811599
if (lastdot == NULL)
15821600
return Py_None;
15831601
len = lastdot - start;
@@ -1612,7 +1630,7 @@ load_next(mod, altmod, p_name, buf, p_buflen)
16121630
{
16131631
char *name = *p_name;
16141632
char *dot = strchr(name, '.');
1615-
int len;
1633+
size_t len;
16161634
char *p;
16171635
PyObject *result;
16181636

0 commit comments

Comments
 (0)