From 55e16b74fd9f4fbafac43d7b51d5e3c87d2860dd Mon Sep 17 00:00:00 2001 From: Serhiy Storchaka Date: Tue, 9 Dec 2025 16:46:24 +0200 Subject: [PATCH] [3.13] gh-142282 Fix winreg.QueryValueEx() under race condition (GH-142283) (GH-142456) (cherry picked from commit 3ec941b364778bce4fac6c6100730e120b426849) Co-authored-by: Jeong, YunWon <69878+youknowone@users.noreply.github.com> --- Lib/test/test_winreg.py | 32 +++++++++++++++++++ ...-12-05-18-26-50.gh-issue-142282.g6RQUN.rst | 1 + PC/winreg.c | 2 +- 3 files changed, 34 insertions(+), 1 deletion(-) create mode 100644 Misc/NEWS.d/next/Library/2025-12-05-18-26-50.gh-issue-142282.g6RQUN.rst diff --git a/Lib/test/test_winreg.py b/Lib/test/test_winreg.py index 924a962781a7..1bc830c02c39 100644 --- a/Lib/test/test_winreg.py +++ b/Lib/test/test_winreg.py @@ -3,6 +3,7 @@ import gc import os, sys, errno +import itertools import threading import unittest from platform import machine, win32_edition @@ -291,6 +292,37 @@ class LocalWinregTests(BaseWinregTests): DeleteKey(HKEY_CURRENT_USER, test_key_name+'\\changing_value') DeleteKey(HKEY_CURRENT_USER, test_key_name) + def test_queryvalueex_race_condition(self): + # gh-142282: QueryValueEx could read garbage buffer under race + # condition when another thread changes the value size + done = False + ready = threading.Event() + values = [b'ham', b'spam'] + + class WriterThread(threading.Thread): + def run(self): + with CreateKey(HKEY_CURRENT_USER, test_key_name) as key: + values_iter = itertools.cycle(values) + while not done: + val = next(values_iter) + SetValueEx(key, 'test_value', 0, REG_BINARY, val) + ready.set() + + thread = WriterThread() + thread.start() + try: + ready.wait() + with CreateKey(HKEY_CURRENT_USER, test_key_name) as key: + for _ in range(1000): + result, typ = QueryValueEx(key, 'test_value') + # The result must be one of the written values, + # not garbage data from uninitialized buffer + self.assertIn(result, values) + finally: + done = True + thread.join() + DeleteKey(HKEY_CURRENT_USER, test_key_name) + def test_long_key(self): # Issue2810, in 2.6 and 3.1 when the key name was exactly 256 # characters, EnumKey raised "WindowsError: More data is diff --git a/Misc/NEWS.d/next/Library/2025-12-05-18-26-50.gh-issue-142282.g6RQUN.rst b/Misc/NEWS.d/next/Library/2025-12-05-18-26-50.gh-issue-142282.g6RQUN.rst new file mode 100644 index 000000000000..d038cd40f4f5 --- /dev/null +++ b/Misc/NEWS.d/next/Library/2025-12-05-18-26-50.gh-issue-142282.g6RQUN.rst @@ -0,0 +1 @@ +Fix :func:`winreg.QueryValueEx` to not accidentally read garbage buffer under race condition. diff --git a/PC/winreg.c b/PC/winreg.c index ed2cce51cb70..b81b0590eb9c 100644 --- a/PC/winreg.c +++ b/PC/winreg.c @@ -1660,7 +1660,7 @@ winreg_QueryValueEx_impl(PyObject *module, HKEY key, const wchar_t *name) return PyErr_SetFromWindowsErrWithFunction(rc, "RegQueryValueEx"); } - obData = Reg2Py(retBuf, bufSize, typ); + obData = Reg2Py(retBuf, retSize, typ); PyMem_Free(retBuf); if (obData == NULL) return NULL; -- 2.47.3