Skip to content

Commit c6dd415

Browse files
committed
Issue python#28522: Fixes mishandled buffer reallocation in getpathp.c
1 parent e45ef4e commit c6dd415

3 files changed

Lines changed: 72 additions & 4 deletions

File tree

Lib/test/test_site.py

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -488,6 +488,58 @@ def test_startup_interactivehook_isolated_explicit(self):
488488
'import site, sys; site.enablerlcompleter(); sys.exit(hasattr(sys, "__interactivehook__"))']).wait()
489489
self.assertTrue(r, "'__interactivehook__' not added by enablerlcompleter()")
490490

491+
@unittest.skipUnless(sys.platform == 'win32', "only supported on Windows")
492+
def test_underpth_nosite_file(self):
493+
_pth_file = os.path.splitext(sys.executable)[0] + '._pth'
494+
try:
495+
libpath = os.path.dirname(os.path.dirname(encodings.__file__))
496+
with open(_pth_file, 'w') as f:
497+
print('fake-path-name', file=f)
498+
# Ensure the generated path is very long so that buffer
499+
# resizing in getpathp.c is exercised
500+
for _ in range(200):
501+
print(libpath, file=f)
502+
print('# comment', file=f)
503+
504+
env = os.environ.copy()
505+
env['PYTHONPATH'] = 'from-env'
506+
rc = subprocess.call([sys.executable, '-c',
507+
'import sys; sys.exit(sys.flags.no_site and '
508+
'len(sys.path) > 200 and '
509+
'%r in sys.path and %r in sys.path and %r not in sys.path)' % (
510+
os.path.join(sys.prefix, 'fake-path-name'),
511+
libpath,
512+
os.path.join(sys.prefix, 'from-env'),
513+
)], env=env)
514+
self.assertEqual(rc, 0)
515+
finally:
516+
os.unlink(_pth_file)
517+
518+
@unittest.skipUnless(sys.platform == 'win32', "only supported on Windows")
519+
def test_underpth_file(self):
520+
_pth_file = os.path.splitext(sys.executable)[0] + '._pth'
521+
try:
522+
libpath = os.path.dirname(os.path.dirname(encodings.__file__))
523+
with open(_pth_file, 'w') as f:
524+
print('fake-path-name', file=f)
525+
for _ in range(200):
526+
print(libpath, file=f)
527+
print('# comment', file=f)
528+
print('import site', file=f)
529+
530+
env = os.environ.copy()
531+
env['PYTHONPATH'] = 'from-env'
532+
rc = subprocess.call([sys.executable, '-c',
533+
'import sys; sys.exit(not sys.flags.no_site and '
534+
'%r in sys.path and %r in sys.path and %r not in sys.path)' % (
535+
os.path.join(sys.prefix, 'fake-path-name'),
536+
libpath,
537+
os.path.join(sys.prefix, 'from-env'),
538+
)], env=env)
539+
self.assertEqual(rc, 0)
540+
finally:
541+
os.unlink(_pth_file)
542+
491543

492544
if __name__ == "__main__":
493545
unittest.main()

Misc/NEWS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,11 @@ Library
8585
threadpool executor.
8686
Initial patch by Hans Lawrenz.
8787

88+
Windows
89+
-------
90+
91+
- Issue #28522: Fixes mishandled buffer reallocation in getpathp.c
92+
8893
Build
8994
-----
9095

PC/getpathp.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -581,7 +581,8 @@ read_pth_file(const wchar_t *path, wchar_t *prefix, int *isolated, int *nosite)
581581
wn = MultiByteToWideChar(CP_UTF8, 0, line, -1, wline, wn + 1);
582582
wline[wn] = '\0';
583583

584-
while (wn + prefixlen + 4 > bufsiz) {
584+
size_t usedsiz = wcslen(buf);
585+
while (usedsiz + wn + prefixlen + 4 > bufsiz) {
585586
bufsiz += MAXPATHLEN;
586587
buf = (wchar_t*)PyMem_RawRealloc(buf, (bufsiz + 1) * sizeof(wchar_t));
587588
if (!buf) {
@@ -590,11 +591,21 @@ read_pth_file(const wchar_t *path, wchar_t *prefix, int *isolated, int *nosite)
590591
}
591592
}
592593

593-
if (buf[0])
594+
if (usedsiz) {
594595
wcscat_s(buf, bufsiz, L";");
596+
usedsiz += 1;
597+
}
595598

596-
wchar_t *b = &buf[wcslen(buf)];
597-
wcscat_s(buf, bufsiz, prefix);
599+
errno_t result;
600+
_Py_BEGIN_SUPPRESS_IPH
601+
result = wcscat_s(buf, bufsiz, prefix);
602+
_Py_END_SUPPRESS_IPH
603+
if (result == EINVAL) {
604+
Py_FatalError("invalid argument during ._pth processing");
605+
} else if (result == ERANGE) {
606+
Py_FatalError("buffer overflow during ._pth processing");
607+
}
608+
wchar_t *b = &buf[usedsiz];
598609
join(b, wline);
599610

600611
PyMem_RawFree(wline);

0 commit comments

Comments
 (0)