From 4d228c411bf23ff71e36db7d285d7e23e875b926 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Wed, 17 Jun 2026 00:16:06 +0100 Subject: [PATCH 1/4] gh-151544: Fixes CVE-2026-12003 by removing the fallback to %VPATH%/Modules/Setup.local for discovering sources in getpath.py (GH-151545) (cherry picked from commit 9e863fab283eddca9c2a8f9d1ee30f4dc243e314) Co-authored-by: Steve Dower --- Makefile.pre.in | 2 ++ ...2026-06-16-14-58-02.gh-issue-151544._bexVy.rst | 4 ++++ Modules/getpath.py | 15 ++++----------- 3 files changed, 10 insertions(+), 11 deletions(-) create mode 100644 Misc/NEWS.d/next/Security/2026-06-16-14-58-02.gh-issue-151544._bexVy.rst diff --git a/Makefile.pre.in b/Makefile.pre.in index f86d7363e0900fa..75a892e94b0965e 100644 --- a/Makefile.pre.in +++ b/Makefile.pre.in @@ -1679,6 +1679,8 @@ Programs/_bootstrap_python.o: Programs/_bootstrap_python.c $(BOOTSTRAP_HEADERS) _bootstrap_python: $(LIBRARY_OBJS_OMIT_FROZEN) Programs/_bootstrap_python.o Modules/getpath.o Modules/Setup.local $(LINKCC) $(PY_LDFLAGS_NOLTO) -o $@ $(LIBRARY_OBJS_OMIT_FROZEN) \ Programs/_bootstrap_python.o Modules/getpath.o $(LIBS) $(MODLIBS) $(SYSLIBS) + # Dummy pybuilddir.txt is needed for _bootstrap_python to be runnable + @echo "none" > ./pybuilddir.txt ############################################################################ diff --git a/Misc/NEWS.d/next/Security/2026-06-16-14-58-02.gh-issue-151544._bexVy.rst b/Misc/NEWS.d/next/Security/2026-06-16-14-58-02.gh-issue-151544._bexVy.rst new file mode 100644 index 000000000000000..418e3b4b9677943 --- /dev/null +++ b/Misc/NEWS.d/next/Security/2026-06-16-14-58-02.gh-issue-151544._bexVy.rst @@ -0,0 +1,4 @@ +:file:`Modules/Setup.local` is no longer used as a landmark to discover +whether Python is running in a source tree, as it could potentially affect +actual installs. The :file:`pybuilddir.txt` file is now the sole indicator +of running in a source tree. diff --git a/Modules/getpath.py b/Modules/getpath.py index b89d7427e3febdd..0e4f1e87e7342a3 100644 --- a/Modules/getpath.py +++ b/Modules/getpath.py @@ -129,8 +129,7 @@ # checked by looking for the BUILDDIR_TXT file, which contains the # relative path to the platlib dir. The executable_dir value is # derived from joining the VPATH preprocessor variable to the -# directory containing pybuilddir.txt. If it is not found, the -# BUILD_LANDMARK file is found, which is part of the source tree. +# directory containing pybuilddir.txt. # prefix is then found by searching up for a file that should only # exist in the source tree, and the stdlib dir is set to prefix/Lib. @@ -177,7 +176,6 @@ if os_name == 'posix' or os_name == 'darwin': BUILDDIR_TXT = 'pybuilddir.txt' - BUILD_LANDMARK = 'Modules/Setup.local' DEFAULT_PROGRAM_NAME = f'python{VERSION_MAJOR}' STDLIB_SUBDIR = f'{platlibdir}/python{VERSION_MAJOR}.{VERSION_MINOR}{ABI_THREAD}' STDLIB_LANDMARKS = [f'{STDLIB_SUBDIR}/os.py', f'{STDLIB_SUBDIR}/os.pyc'] @@ -190,7 +188,6 @@ elif os_name == 'nt': BUILDDIR_TXT = 'pybuilddir.txt' - BUILD_LANDMARK = f'{VPATH}\\Modules\\Setup.local' DEFAULT_PROGRAM_NAME = f'python' STDLIB_SUBDIR = 'Lib' STDLIB_LANDMARKS = [f'{STDLIB_SUBDIR}\\os.py', f'{STDLIB_SUBDIR}\\os.pyc'] @@ -512,13 +509,9 @@ def search_up(prefix, *landmarks, test=isfile): platstdlib_dir = real_executable_dir build_prefix = joinpath(real_executable_dir, VPATH) except (FileNotFoundError, PermissionError): - if isfile(joinpath(real_executable_dir, BUILD_LANDMARK)): - build_prefix = joinpath(real_executable_dir, VPATH) - if os_name == 'nt': - # QUIRK: Windows builds need platstdlib_dir to be the executable - # dir. Normally the builddir marker handles this, but in this - # case we need to correct manually. - platstdlib_dir = real_executable_dir + # We used to check for an alternate landmark here, but now we require + # BUILDDIR_TXT to exist. (gh-151544; CVE-2026-12003) + pass if build_prefix: if os_name == 'nt': From b76f1f9ba175c511063c086c083614b8bd5cd4bc Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Wed, 17 Jun 2026 19:36:56 +0100 Subject: [PATCH 2/4] Add argv0 setting for Python process in WASM --- Tools/wasm/wasi/__main__.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Tools/wasm/wasi/__main__.py b/Tools/wasm/wasi/__main__.py index b57bcaca924380a..25c1829e1295e94 100644 --- a/Tools/wasm/wasi/__main__.py +++ b/Tools/wasm/wasi/__main__.py @@ -421,6 +421,8 @@ def main(): "--wasm max-wasm-stack=16777216 " # Enable thread support; causes use of preview1. # "--wasm threads=y --wasi threads=y " + # Set argv0 to the Python process + "--argv0 {PYTHON_WASM} " # Map the checkout to / to load the stdlib from /Lib. "--dir {HOST_DIR}::{GUEST_DIR} " # Set PYTHONPATH to the sysconfig data. From b002dba22ac4bdec24e7b89cad3e4cc50dbec081 Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Wed, 17 Jun 2026 20:46:53 +0100 Subject: [PATCH 3/4] Add symlink creation for pybuilddir.txt --- Tools/wasm/wasi/__main__.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/Tools/wasm/wasi/__main__.py b/Tools/wasm/wasi/__main__.py index 25c1829e1295e94..3d15b9f62df000c 100644 --- a/Tools/wasm/wasi/__main__.py +++ b/Tools/wasm/wasi/__main__.py @@ -368,6 +368,10 @@ def configure_wasi_python(context, working_dir): file.write(f'#!/bin/sh\nexec {host_runner} {python_wasm} "$@"\n') exec_script.chmod(0o755) log("๐Ÿƒ", f"Created {exec_script} (--host-runner)... ") + pybuilddir_txt = working_dir / "pybuilddir.txt" + if not pybuilddir_txt.exists(): + os.symlink(CHECKOUT / "pybuilddir.txt", pybuilddir_txt) + log("๐Ÿ“", f"Symlinked {pybuilddir_txt} to normal location") sys.stdout.flush() @@ -399,6 +403,11 @@ def clean_contents(context): if LOCAL_SETUP.read_bytes() == LOCAL_SETUP_MARKER: log("๐Ÿงน", f"Deleting generated {LOCAL_SETUP} ...") + pybuilddir_txt = working_dir / "pybuilddir.txt" + if pybuilddir_txt.exists(): + log("๐Ÿงน", f"Deleting {pybuilddir_txt} ...") + pybuilddir_txt.unlink() + def build_steps(*steps): """Construct a command from other steps.""" @@ -421,8 +430,6 @@ def main(): "--wasm max-wasm-stack=16777216 " # Enable thread support; causes use of preview1. # "--wasm threads=y --wasi threads=y " - # Set argv0 to the Python process - "--argv0 {PYTHON_WASM} " # Map the checkout to / to load the stdlib from /Lib. "--dir {HOST_DIR}::{GUEST_DIR} " # Set PYTHONPATH to the sysconfig data. From c5125ff1e63a50694f17b712a600b4f971e8d1ff Mon Sep 17 00:00:00 2001 From: Steve Dower Date: Wed, 17 Jun 2026 21:02:34 +0100 Subject: [PATCH 4/4] Remove unnecessary deletion of pybuilddir.txt --- Tools/wasm/wasi/__main__.py | 5 ----- 1 file changed, 5 deletions(-) diff --git a/Tools/wasm/wasi/__main__.py b/Tools/wasm/wasi/__main__.py index 3d15b9f62df000c..abe30fe0b4c77f9 100644 --- a/Tools/wasm/wasi/__main__.py +++ b/Tools/wasm/wasi/__main__.py @@ -403,11 +403,6 @@ def clean_contents(context): if LOCAL_SETUP.read_bytes() == LOCAL_SETUP_MARKER: log("๐Ÿงน", f"Deleting generated {LOCAL_SETUP} ...") - pybuilddir_txt = working_dir / "pybuilddir.txt" - if pybuilddir_txt.exists(): - log("๐Ÿงน", f"Deleting {pybuilddir_txt} ...") - pybuilddir_txt.unlink() - def build_steps(*steps): """Construct a command from other steps."""