From c6dd415252f255b583fcdae5d51a28e027284b06 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Thu, 27 Oct 2016 14:28:07 -0700 Subject: Issue #28522: Fixes mishandled buffer reallocation in getpathp.c --- Lib/test/test_site.py | 52 +++++++++++++++++++++++++++++++++++++++++++++++++++ Misc/NEWS | 5 +++++ PC/getpathp.c | 19 +++++++++++++++---- 3 files changed, 72 insertions(+), 4 deletions(-) diff --git a/Lib/test/test_site.py b/Lib/test/test_site.py index d2fbb7b..5aedbdb 100644 --- a/Lib/test/test_site.py +++ b/Lib/test/test_site.py @@ -488,6 +488,58 @@ class StartupImportTests(unittest.TestCase): 'import site, sys; site.enablerlcompleter(); sys.exit(hasattr(sys, "__interactivehook__"))']).wait() self.assertTrue(r, "'__interactivehook__' not added by enablerlcompleter()") + @unittest.skipUnless(sys.platform == 'win32', "only supported on Windows") + def test_underpth_nosite_file(self): + _pth_file = os.path.splitext(sys.executable)[0] + '._pth' + try: + libpath = os.path.dirname(os.path.dirname(encodings.__file__)) + with open(_pth_file, 'w') as f: + print('fake-path-name', file=f) + # Ensure the generated path is very long so that buffer + # resizing in getpathp.c is exercised + for _ in range(200): + print(libpath, file=f) + print('# comment', file=f) + + env = os.environ.copy() + env['PYTHONPATH'] = 'from-env' + rc = subprocess.call([sys.executable, '-c', + 'import sys; sys.exit(sys.flags.no_site and ' + 'len(sys.path) > 200 and ' + '%r in sys.path and %r in sys.path and %r not in sys.path)' % ( + os.path.join(sys.prefix, 'fake-path-name'), + libpath, + os.path.join(sys.prefix, 'from-env'), + )], env=env) + self.assertEqual(rc, 0) + finally: + os.unlink(_pth_file) + + @unittest.skipUnless(sys.platform == 'win32', "only supported on Windows") + def test_underpth_file(self): + _pth_file = os.path.splitext(sys.executable)[0] + '._pth' + try: + libpath = os.path.dirname(os.path.dirname(encodings.__file__)) + with open(_pth_file, 'w') as f: + print('fake-path-name', file=f) + for _ in range(200): + print(libpath, file=f) + print('# comment', file=f) + print('import site', file=f) + + env = os.environ.copy() + env['PYTHONPATH'] = 'from-env' + rc = subprocess.call([sys.executable, '-c', + 'import sys; sys.exit(not sys.flags.no_site and ' + '%r in sys.path and %r in sys.path and %r not in sys.path)' % ( + os.path.join(sys.prefix, 'fake-path-name'), + libpath, + os.path.join(sys.prefix, 'from-env'), + )], env=env) + self.assertEqual(rc, 0) + finally: + os.unlink(_pth_file) + if __name__ == "__main__": unittest.main() diff --git a/Misc/NEWS b/Misc/NEWS index 8665081..9c2dc4e 100644 --- a/Misc/NEWS +++ b/Misc/NEWS @@ -85,6 +85,11 @@ Library threadpool executor. Initial patch by Hans Lawrenz. +Windows +------- + +- Issue #28522: Fixes mishandled buffer reallocation in getpathp.c + Build ----- diff --git a/PC/getpathp.c b/PC/getpathp.c index 31f973e..0b0ae49 100644 --- a/PC/getpathp.c +++ b/PC/getpathp.c @@ -581,7 +581,8 @@ read_pth_file(const wchar_t *path, wchar_t *prefix, int *isolated, int *nosite) wn = MultiByteToWideChar(CP_UTF8, 0, line, -1, wline, wn + 1); wline[wn] = '\0'; - while (wn + prefixlen + 4 > bufsiz) { + size_t usedsiz = wcslen(buf); + while (usedsiz + wn + prefixlen + 4 > bufsiz) { bufsiz += MAXPATHLEN; buf = (wchar_t*)PyMem_RawRealloc(buf, (bufsiz + 1) * sizeof(wchar_t)); if (!buf) { @@ -590,11 +591,21 @@ read_pth_file(const wchar_t *path, wchar_t *prefix, int *isolated, int *nosite) } } - if (buf[0]) + if (usedsiz) { wcscat_s(buf, bufsiz, L";"); + usedsiz += 1; + } - wchar_t *b = &buf[wcslen(buf)]; - wcscat_s(buf, bufsiz, prefix); + errno_t result; + _Py_BEGIN_SUPPRESS_IPH + result = wcscat_s(buf, bufsiz, prefix); + _Py_END_SUPPRESS_IPH + if (result == EINVAL) { + Py_FatalError("invalid argument during ._pth processing"); + } else if (result == ERANGE) { + Py_FatalError("buffer overflow during ._pth processing"); + } + wchar_t *b = &buf[usedsiz]; join(b, wline); PyMem_RawFree(wline); -- cgit v0.12