]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
gh-142282 Fix winreg.QueryValueEx() under race condition (GH-142283)
authorJeong, YunWon <69878+youknowone@users.noreply.github.com>
Tue, 9 Dec 2025 12:09:07 +0000 (21:09 +0900)
committerGitHub <noreply@github.com>
Tue, 9 Dec 2025 12:09:07 +0000 (12:09 +0000)
Lib/test/test_winreg.py
Misc/NEWS.d/next/Core_and_Builtins/2025-12-05-18-26-50.gh-issue-142282.g6RQUN.rst [new file with mode: 0644]
PC/winreg.c

index 733d30b3922d35d73d9de40ab59c0a4f42bb2e73..fc0533c6e1531f6a8344b7046c61bd4e37dbe480 100644 (file)
@@ -3,6 +3,7 @@
 
 import gc
 import os, sys, errno
+import itertools
 import threading
 import unittest
 from platform import machine, win32_edition
@@ -318,6 +319,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/Core_and_Builtins/2025-12-05-18-26-50.gh-issue-142282.g6RQUN.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-12-05-18-26-50.gh-issue-142282.g6RQUN.rst
new file mode 100644 (file)
index 0000000..d038cd4
--- /dev/null
@@ -0,0 +1 @@
+Fix :func:`winreg.QueryValueEx` to not accidentally read garbage buffer under race condition.
index c1be920fc1d92f38668e400974df9ded58cf03fb..bcb02b1229905571e5f4342aff9dc38f15b1297e 100644 (file)
@@ -1651,7 +1651,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;