]> git.ipfire.org Git - thirdparty/Python/cpython.git/commitdiff
[3.13] gh-142282 Fix winreg.QueryValueEx() under race condition (GH-142283) (GH-142456)
authorSerhiy Storchaka <storchaka@gmail.com>
Tue, 9 Dec 2025 14:46:24 +0000 (16:46 +0200)
committerGitHub <noreply@github.com>
Tue, 9 Dec 2025 14:46:24 +0000 (16:46 +0200)
(cherry picked from commit 3ec941b364778bce4fac6c6100730e120b426849)

Co-authored-by: Jeong, YunWon <69878+youknowone@users.noreply.github.com>
Lib/test/test_winreg.py
Misc/NEWS.d/next/Library/2025-12-05-18-26-50.gh-issue-142282.g6RQUN.rst [new file with mode: 0644]
PC/winreg.c

index 924a962781a75bfaf5a446660414e27cf582064e..1bc830c02c39ce51e8a7a40d4efb6317fbdd314b 100644 (file)
@@ -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 (file)
index 0000000..d038cd4
--- /dev/null
@@ -0,0 +1 @@
+Fix :func:`winreg.QueryValueEx` to not accidentally read garbage buffer under race condition.
index ed2cce51cb709aaa21e453c47b466aa4894b4c10..b81b0590eb9cb17538cf02427bc6923ef0f90610 100644 (file)
@@ -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;