From b125c7860a5b70bbe9b2bb0dcacda75025f3fa51 Mon Sep 17 00:00:00 2001 From: Manjusaka Date: Mon, 16 Jun 2025 02:31:08 +0800 Subject: [PATCH 01/21] gh-135543: emit sys.remote_exec audit event when sys.remote_exec has been called Signed-off-by: Manjusaka --- Doc/library/sys.rst | 5 +++++ Lib/test/test_sys.py | 1 + Python/sysmodule.c | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 55e442b20ff877..cc2be1f3aa07c7 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1933,6 +1933,11 @@ always available. Unless explicitly noted otherwise, all variables are read-only interpreter is pre-release (alpha, beta, or release candidate) then the local and remote interpreters must be the same exact version. + .. audit-event:: remove_exec pid script_path + + When the code is executed in the remote process, an :ref:`auditing event ` + ``remove_exec`` is raised with the *pid* and the path to the script file. + .. availability:: Unix, Windows. .. versionadded:: 3.14 diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 39e62027f03e5a..3406ead2fb1430 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -2118,6 +2118,7 @@ def audit_hook(event, arg): self.assertEqual(returncode, 0) self.assertIn(b"Remote script executed successfully!", stdout) self.assertIn(b"Audit event: remote_debugger_script, arg: ", stdout) + self.assertIn(b"Audit event: remote_exec, arg: ", stdout) self.assertEqual(stderr, b"") def test_remote_exec_with_exception(self): diff --git a/Python/sysmodule.c b/Python/sysmodule.c index e5ae841d195d4f..7640753662cd94 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2485,6 +2485,10 @@ sys_remote_exec_impl(PyObject *module, int pid, PyObject *script) PyObject *path; const char *debugger_script_path; + if (PySys_Audit("remote_exec", "iO", pid, script) < 0) { + return NULL; + } + if (PyUnicode_FSConverter(script, &path) == 0) { return NULL; } From afab662d3b4bc3f1fc37f133a85b40fefbd14560 Mon Sep 17 00:00:00 2001 From: Manjusaka Date: Mon, 16 Jun 2025 02:31:51 +0800 Subject: [PATCH 02/21] add news Signed-off-by: Manjusaka --- .../2025-06-16-02-31-42.gh-issue-135543.6b0HOF.rst | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 Misc/NEWS.d/next/Core_and_Builtins/2025-06-16-02-31-42.gh-issue-135543.6b0HOF.rst diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-16-02-31-42.gh-issue-135543.6b0HOF.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-16-02-31-42.gh-issue-135543.6b0HOF.rst new file mode 100644 index 00000000000000..0a4fa10e8368b7 --- /dev/null +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-16-02-31-42.gh-issue-135543.6b0HOF.rst @@ -0,0 +1,2 @@ +emit ``sys.remote_exec`` audit event when ``sys.remote_exec`` has been +called From 31c6575b6cd96ddba93356e484c9bf992ce71d05 Mon Sep 17 00:00:00 2001 From: Manjusaka Date: Mon, 16 Jun 2025 03:09:32 +0800 Subject: [PATCH 03/21] fix code Signed-off-by: Manjusaka --- Lib/test/test_sys.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 3406ead2fb1430..22882c73df8a33 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -2114,12 +2114,18 @@ def audit_hook(event, arg): script = ''' print("Remote script executed successfully!") ''' + remote_exec_event_triggered = False + def audit_hook(event, arg): + if event == "remote_exec": + nonlocal remote_exec_event_triggered + remote_exec_event_triggered = True + sys.addaudithook(audit_hook) returncode, stdout, stderr = self._run_remote_exec_test(script, prologue=prologue) self.assertEqual(returncode, 0) self.assertIn(b"Remote script executed successfully!", stdout) self.assertIn(b"Audit event: remote_debugger_script, arg: ", stdout) - self.assertIn(b"Audit event: remote_exec, arg: ", stdout) self.assertEqual(stderr, b"") + self.assertTrue(remote_exec_event_triggered) def test_remote_exec_with_exception(self): """Test remote exec with an exception raised in the target process From 55e3470ce39c78c7d813245b0243bbf090c6ce52 Mon Sep 17 00:00:00 2001 From: Nadeshiko Manju Date: Tue, 17 Jun 2025 03:06:55 +0800 Subject: [PATCH 04/21] Update Doc/library/sys.rst Co-authored-by: Victor Stinner --- Doc/library/sys.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index bf5ac2ba85c0ae..ef9118faecd48f 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1936,7 +1936,7 @@ always available. Unless explicitly noted otherwise, all variables are read-only .. audit-event:: remove_exec pid script_path When the code is executed in the remote process, an :ref:`auditing event ` - ``remove_exec`` is raised with the *pid* and the path to the script file. + ``remote_exec`` is raised with the *pid* and the path to the script file. .. audit-event:: remote_debugger_script script_path From e3fd3cabdd437f1006899036067efb4cb46f2884 Mon Sep 17 00:00:00 2001 From: Nadeshiko Manju Date: Tue, 17 Jun 2025 03:07:05 +0800 Subject: [PATCH 05/21] Update Doc/library/sys.rst Co-authored-by: Victor Stinner --- Doc/library/sys.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index ef9118faecd48f..a759a6e0f78a30 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1933,7 +1933,7 @@ always available. Unless explicitly noted otherwise, all variables are read-only interpreter is pre-release (alpha, beta, or release candidate) then the local and remote interpreters must be the same exact version. - .. audit-event:: remove_exec pid script_path + .. audit-event:: remote_exec pid script_path When the code is executed in the remote process, an :ref:`auditing event ` ``remote_exec`` is raised with the *pid* and the path to the script file. From 732e3fd5bb899f7e419a239481b13e22286d317a Mon Sep 17 00:00:00 2001 From: Nadeshiko Manju Date: Tue, 17 Jun 2025 03:07:13 +0800 Subject: [PATCH 06/21] Update Misc/NEWS.d/next/Core_and_Builtins/2025-06-16-02-31-42.gh-issue-135543.6b0HOF.rst Co-authored-by: Victor Stinner --- .../2025-06-16-02-31-42.gh-issue-135543.6b0HOF.rst | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-16-02-31-42.gh-issue-135543.6b0HOF.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-16-02-31-42.gh-issue-135543.6b0HOF.rst index 0a4fa10e8368b7..d16977db6bdca1 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-16-02-31-42.gh-issue-135543.6b0HOF.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-16-02-31-42.gh-issue-135543.6b0HOF.rst @@ -1,2 +1 @@ -emit ``sys.remote_exec`` audit event when ``sys.remote_exec`` has been -called +Emit ``remote_exec`` audit event when :func:`sys.remote_exec` is called. From daed532e3f2bd6bb8c03011e16826f66c0052805 Mon Sep 17 00:00:00 2001 From: Manjusaka Date: Tue, 17 Jun 2025 03:31:22 +0800 Subject: [PATCH 07/21] fix review idea Signed-off-by: Manjusaka --- Lib/test/audit-tests.py | 19 +++++++++++++++++++ Lib/test/test_audit.py | 19 +++++++++++++++++++ Lib/test/test_sys.py | 7 ------- 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/Lib/test/audit-tests.py b/Lib/test/audit-tests.py index 08b638e4b8d524..13d2932b54da46 100644 --- a/Lib/test/audit-tests.py +++ b/Lib/test/audit-tests.py @@ -8,6 +8,7 @@ import contextlib import os import sys +import tempfile class TestHook: @@ -643,6 +644,24 @@ def test_assert_unicode(): else: raise RuntimeError("Expected sys.audit(9) to fail.") +def test_sys_remote_exec(): + import sys + pid = os.getpid() + event_pid = -1 + remote_exec_trigger = False + def hook(event, args): + if event == "remote_exec": + nonlocal remote_exec_trigger + remote_exec_trigger = True + nonlocal event_pid + event_pid = args[0] + sys.addaudithook(hook) + with tempfile.NamedTemporaryFile(mode='w+', delete=True) as tmp_file: + tmp_file.write("print('Hello from remote_exec!')\n") + tmp_file.flush() + sys.remote_exec(pid, tmp_file.name) + assert remote_exec_trigger + assert event_pid == pid if __name__ == "__main__": from test.support import suppress_msvcrt_asserts diff --git a/Lib/test/test_audit.py b/Lib/test/test_audit.py index 5f9eb381f605d9..98959cdbb6a24f 100644 --- a/Lib/test/test_audit.py +++ b/Lib/test/test_audit.py @@ -14,6 +14,15 @@ AUDIT_TESTS_PY = support.findfile("audit-tests.py") +def _supports_remote_attaching(): + PROCESS_VM_READV_SUPPORTED = False + + try: + from _remote_debugging import PROCESS_VM_READV_SUPPORTED + except ImportError: + pass + + return PROCESS_VM_READV_SUPPORTED class AuditTest(unittest.TestCase): maxDiff = None @@ -322,6 +331,16 @@ def test_assert_unicode(self): if returncode: self.fail(stderr) + @unittest.skipIf(not sys.is_remote_debug_enabled(), "Remote debugging is not enabled") + @unittest.skipIf(sys.platform != "darwin" and sys.platform != "linux" and sys.platform != "win32", + "Test only runs on Linux, Windows and MacOS") + @unittest.skipIf(sys.platform == "linux" and not _supports_remote_attaching(), + "Test only runs on Linux with process_vm_readv support") + @support.cpython_only + def test_sys_remote_exec(self): + returncode, stdout, stderr = self.run_python("test_sys_remote_exec") + if returncode: + self.fail(stderr) if __name__ == "__main__": unittest.main() diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 22882c73df8a33..39e62027f03e5a 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -2114,18 +2114,11 @@ def audit_hook(event, arg): script = ''' print("Remote script executed successfully!") ''' - remote_exec_event_triggered = False - def audit_hook(event, arg): - if event == "remote_exec": - nonlocal remote_exec_event_triggered - remote_exec_event_triggered = True - sys.addaudithook(audit_hook) returncode, stdout, stderr = self._run_remote_exec_test(script, prologue=prologue) self.assertEqual(returncode, 0) self.assertIn(b"Remote script executed successfully!", stdout) self.assertIn(b"Audit event: remote_debugger_script, arg: ", stdout) self.assertEqual(stderr, b"") - self.assertTrue(remote_exec_event_triggered) def test_remote_exec_with_exception(self): """Test remote exec with an exception raised in the target process From f1c6f0347bad60cc7f3cb83460b9094833bb7775 Mon Sep 17 00:00:00 2001 From: Manjusaka Date: Tue, 17 Jun 2025 03:50:05 +0800 Subject: [PATCH 08/21] update test Signed-off-by: Manjusaka --- Lib/test/audit-tests.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/Lib/test/audit-tests.py b/Lib/test/audit-tests.py index 13d2932b54da46..f0988e90a4d0da 100644 --- a/Lib/test/audit-tests.py +++ b/Lib/test/audit-tests.py @@ -648,6 +648,7 @@ def test_sys_remote_exec(): import sys pid = os.getpid() event_pid = -1 + event_script_path = "" remote_exec_trigger = False def hook(event, args): if event == "remote_exec": @@ -655,13 +656,17 @@ def hook(event, args): remote_exec_trigger = True nonlocal event_pid event_pid = args[0] + nonlocal event_script_path + event_script_path = args[1] + sys.addaudithook(hook) with tempfile.NamedTemporaryFile(mode='w+', delete=True) as tmp_file: tmp_file.write("print('Hello from remote_exec!')\n") tmp_file.flush() sys.remote_exec(pid, tmp_file.name) - assert remote_exec_trigger - assert event_pid == pid + assert remote_exec_trigger + assert event_pid == pid + assert event_script_path == tmp_file.name if __name__ == "__main__": from test.support import suppress_msvcrt_asserts From b9bc94e8faea8627b358733b54bffd483a1e2478 Mon Sep 17 00:00:00 2001 From: Manjusaka Date: Tue, 17 Jun 2025 22:44:01 +0800 Subject: [PATCH 09/21] Fix review idea Signed-off-by: Manjusaka --- Lib/test/audit-tests.py | 22 +++++++++------------- Lib/test/support/__init__.py | 19 +++++++++++++++++++ Lib/test/test_audit.py | 6 +----- Lib/test/test_sys.py | 17 +---------------- 4 files changed, 30 insertions(+), 34 deletions(-) diff --git a/Lib/test/audit-tests.py b/Lib/test/audit-tests.py index f0988e90a4d0da..e005abf11d933e 100644 --- a/Lib/test/audit-tests.py +++ b/Lib/test/audit-tests.py @@ -8,7 +8,6 @@ import contextlib import os import sys -import tempfile class TestHook: @@ -645,28 +644,25 @@ def test_assert_unicode(): raise RuntimeError("Expected sys.audit(9) to fail.") def test_sys_remote_exec(): - import sys + import tempfile + pid = os.getpid() event_pid = -1 event_script_path = "" - remote_exec_trigger = False def hook(event, args): - if event == "remote_exec": - nonlocal remote_exec_trigger - remote_exec_trigger = True - nonlocal event_pid - event_pid = args[0] - nonlocal event_script_path - event_script_path = args[1] + if event != "remote_exec": return + nonlocal event_pid + event_pid = args[0] + nonlocal event_script_path + event_script_path = args[1] sys.addaudithook(hook) with tempfile.NamedTemporaryFile(mode='w+', delete=True) as tmp_file: tmp_file.write("print('Hello from remote_exec!')\n") tmp_file.flush() sys.remote_exec(pid, tmp_file.name) - assert remote_exec_trigger - assert event_pid == pid - assert event_script_path == tmp_file.name + assertEqual(pid, event_pid) + assertEqual(tmp_file.name, event_script_path) if __name__ == "__main__": from test.support import suppress_msvcrt_asserts diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 48e74adcce3bb7..51b29ef457c1da 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -46,6 +46,7 @@ # sys "MS_WINDOWS", "is_jython", "is_android", "is_emscripten", "is_wasi", "is_apple_mobile", "check_impl_detail", "unix_shell", "setswitchinterval", + "support_remote_exec_only", # os "get_pagesize", # network @@ -3069,6 +3070,24 @@ def is_libssl_fips_mode(): return False # more of a maybe, unless we add this to the _ssl module. return get_fips_mode() != 0 +def _supports_remote_attaching(): + PROCESS_VM_READV_SUPPORTED = False + + try: + from _remote_debugging import PROCESS_VM_READV_SUPPORTED + except ImportError: + pass + + return PROCESS_VM_READV_SUPPORTED + +def support_remote_exec_only(test): + if not sys.is_remote_debug_enabled(): + return unittest.skip("Remote debugging is not enabled") + if sys.platform != "darwin" and sys.platform != "linux" and sys.platform != "win32": + return unittest.skip("Test only runs on Linux, Windows and MacOS") + if sys.platform == "linux" and not _supports_remote_attaching(): + return unittest.skip("Test only runs on Linux with process_vm_readv support") + return _id(test) class EqualToForwardRef: """Helper to ease use of annotationlib.ForwardRef in tests. diff --git a/Lib/test/test_audit.py b/Lib/test/test_audit.py index 98959cdbb6a24f..f510ebbca11e00 100644 --- a/Lib/test/test_audit.py +++ b/Lib/test/test_audit.py @@ -331,11 +331,7 @@ def test_assert_unicode(self): if returncode: self.fail(stderr) - @unittest.skipIf(not sys.is_remote_debug_enabled(), "Remote debugging is not enabled") - @unittest.skipIf(sys.platform != "darwin" and sys.platform != "linux" and sys.platform != "win32", - "Test only runs on Linux, Windows and MacOS") - @unittest.skipIf(sys.platform == "linux" and not _supports_remote_attaching(), - "Test only runs on Linux with process_vm_readv support") + @support.support_remote_exec_only @support.cpython_only def test_sys_remote_exec(self): returncode, stdout, stderr = self.run_python("test_sys_remote_exec") diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index 39e62027f03e5a..d030c6d8c3b503 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -1943,22 +1943,7 @@ def write(self, s): self.assertEqual(out, b"") self.assertEqual(err, b"") - -def _supports_remote_attaching(): - PROCESS_VM_READV_SUPPORTED = False - - try: - from _remote_debugging import PROCESS_VM_READV_SUPPORTED - except ImportError: - pass - - return PROCESS_VM_READV_SUPPORTED - -@unittest.skipIf(not sys.is_remote_debug_enabled(), "Remote debugging is not enabled") -@unittest.skipIf(sys.platform != "darwin" and sys.platform != "linux" and sys.platform != "win32", - "Test only runs on Linux, Windows and MacOS") -@unittest.skipIf(sys.platform == "linux" and not _supports_remote_attaching(), - "Test only runs on Linux with process_vm_readv support") +@test.support.support_remote_exec_only @test.support.cpython_only class TestRemoteExec(unittest.TestCase): def tearDown(self): From b158a2b1721c8ae504d8493db247cf1854947215 Mon Sep 17 00:00:00 2001 From: Manjusaka Date: Tue, 17 Jun 2025 22:44:42 +0800 Subject: [PATCH 10/21] Fix review idea Signed-off-by: Manjusaka --- Lib/test/test_audit.py | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/Lib/test/test_audit.py b/Lib/test/test_audit.py index f510ebbca11e00..0a7f32d7098b25 100644 --- a/Lib/test/test_audit.py +++ b/Lib/test/test_audit.py @@ -14,16 +14,6 @@ AUDIT_TESTS_PY = support.findfile("audit-tests.py") -def _supports_remote_attaching(): - PROCESS_VM_READV_SUPPORTED = False - - try: - from _remote_debugging import PROCESS_VM_READV_SUPPORTED - except ImportError: - pass - - return PROCESS_VM_READV_SUPPORTED - class AuditTest(unittest.TestCase): maxDiff = None From 2394b275be6d42fe04ea39e95150ab8d9509bdf0 Mon Sep 17 00:00:00 2001 From: Manjusaka Date: Tue, 17 Jun 2025 22:57:40 +0800 Subject: [PATCH 11/21] Fix review idea Signed-off-by: Manjusaka --- Lib/test/support/__init__.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 51b29ef457c1da..43ab01ee4bf4f1 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -3082,11 +3082,11 @@ def _supports_remote_attaching(): def support_remote_exec_only(test): if not sys.is_remote_debug_enabled(): - return unittest.skip("Remote debugging is not enabled") + return unittest.skip("Remote debugging is not enabled")(test) if sys.platform != "darwin" and sys.platform != "linux" and sys.platform != "win32": - return unittest.skip("Test only runs on Linux, Windows and MacOS") + return unittest.skip("Test only runs on Linux, Windows and MacOS")(test) if sys.platform == "linux" and not _supports_remote_attaching(): - return unittest.skip("Test only runs on Linux with process_vm_readv support") + return unittest.skip("Test only runs on Linux with process_vm_readv support")(test) return _id(test) class EqualToForwardRef: From 9302ef32b48c867d70991eadc76bce5929174f0c Mon Sep 17 00:00:00 2001 From: Nadeshiko Manju Date: Tue, 17 Jun 2025 23:40:06 +0800 Subject: [PATCH 12/21] Update Lib/test/support/__init__.py Co-authored-by: Victor Stinner --- Lib/test/support/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 43ab01ee4bf4f1..f088d95da75ae0 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -3084,7 +3084,7 @@ def support_remote_exec_only(test): if not sys.is_remote_debug_enabled(): return unittest.skip("Remote debugging is not enabled")(test) if sys.platform != "darwin" and sys.platform != "linux" and sys.platform != "win32": - return unittest.skip("Test only runs on Linux, Windows and MacOS")(test) + return unittest.skip("Test only runs on Linux, Windows and macOS")(test) if sys.platform == "linux" and not _supports_remote_attaching(): return unittest.skip("Test only runs on Linux with process_vm_readv support")(test) return _id(test) From 70dd3534075aeed2ce8db4cc3b92bc9697b0fca0 Mon Sep 17 00:00:00 2001 From: Nadeshiko Manju Date: Tue, 17 Jun 2025 23:40:13 +0800 Subject: [PATCH 13/21] Update Lib/test/support/__init__.py Co-authored-by: Victor Stinner --- Lib/test/support/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index f088d95da75ae0..9092a0cda4a8b3 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -3083,7 +3083,7 @@ def _supports_remote_attaching(): def support_remote_exec_only(test): if not sys.is_remote_debug_enabled(): return unittest.skip("Remote debugging is not enabled")(test) - if sys.platform != "darwin" and sys.platform != "linux" and sys.platform != "win32": + if sys.platform not in ("darwin", "linux", "win32"): return unittest.skip("Test only runs on Linux, Windows and macOS")(test) if sys.platform == "linux" and not _supports_remote_attaching(): return unittest.skip("Test only runs on Linux with process_vm_readv support")(test) From 1424d0e1e14cbca37201f8fc595f7cefbab0a769 Mon Sep 17 00:00:00 2001 From: Nadeshiko Manju Date: Tue, 17 Jun 2025 23:40:22 +0800 Subject: [PATCH 14/21] Update Lib/test/audit-tests.py Co-authored-by: Victor Stinner --- Lib/test/audit-tests.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Lib/test/audit-tests.py b/Lib/test/audit-tests.py index e005abf11d933e..43f353186556cd 100644 --- a/Lib/test/audit-tests.py +++ b/Lib/test/audit-tests.py @@ -661,8 +661,8 @@ def hook(event, args): tmp_file.write("print('Hello from remote_exec!')\n") tmp_file.flush() sys.remote_exec(pid, tmp_file.name) - assertEqual(pid, event_pid) - assertEqual(tmp_file.name, event_script_path) + assertEqual(event_pid, pid) + assertEqual(event_script_path, tmp_file.name) if __name__ == "__main__": from test.support import suppress_msvcrt_asserts From 914f8a19489cc089133f9d157f765f827a69386b Mon Sep 17 00:00:00 2001 From: Manjusaka Date: Tue, 17 Jun 2025 23:41:20 +0800 Subject: [PATCH 15/21] Fix review idea Signed-off-by: Manjusaka --- Lib/test/test_audit.py | 1 + 1 file changed, 1 insertion(+) diff --git a/Lib/test/test_audit.py b/Lib/test/test_audit.py index 0a7f32d7098b25..f50819cc14090d 100644 --- a/Lib/test/test_audit.py +++ b/Lib/test/test_audit.py @@ -14,6 +14,7 @@ AUDIT_TESTS_PY = support.findfile("audit-tests.py") + class AuditTest(unittest.TestCase): maxDiff = None From 2fcb502703371a74d03d4d21c4a6c7472b8c77fc Mon Sep 17 00:00:00 2001 From: Manjusaka Date: Wed, 18 Jun 2025 18:39:49 +0800 Subject: [PATCH 16/21] Update code Signed-off-by: Manjusaka --- Lib/test/support/__init__.py | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 9092a0cda4a8b3..cd1797ae9fa60c 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -3080,14 +3080,17 @@ def _supports_remote_attaching(): return PROCESS_VM_READV_SUPPORTED -def support_remote_exec_only(test): +def _support_remote_exec_only_impl(test): if not sys.is_remote_debug_enabled(): - return unittest.skip("Remote debugging is not enabled")(test) + return unittest.skip("Remote debugging is not enabled") if sys.platform not in ("darwin", "linux", "win32"): - return unittest.skip("Test only runs on Linux, Windows and macOS")(test) + return unittest.skip("Test only runs on Linux, Windows and macOS") if sys.platform == "linux" and not _supports_remote_attaching(): - return unittest.skip("Test only runs on Linux with process_vm_readv support")(test) - return _id(test) + return unittest.skip("Test only runs on Linux with process_vm_readv support") + return _id + +def support_remote_exec_only(test): + return _support_remote_exec_only_impl(test) class EqualToForwardRef: """Helper to ease use of annotationlib.ForwardRef in tests. From 6561e818dbb7a3f0a835798fce497b98937d2d40 Mon Sep 17 00:00:00 2001 From: Manjusaka Date: Wed, 18 Jun 2025 22:38:34 +0800 Subject: [PATCH 17/21] Update code Signed-off-by: Manjusaka --- Lib/test/support/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index cd1797ae9fa60c..39798d15c24561 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -3090,7 +3090,7 @@ def _support_remote_exec_only_impl(test): return _id def support_remote_exec_only(test): - return _support_remote_exec_only_impl(test) + return _support_remote_exec_only_impl()(test) class EqualToForwardRef: """Helper to ease use of annotationlib.ForwardRef in tests. From 4e7c3844f99a1f4c0ed8ca02043dd10454971fba Mon Sep 17 00:00:00 2001 From: Manjusaka Date: Wed, 18 Jun 2025 22:58:38 +0800 Subject: [PATCH 18/21] Update code Signed-off-by: Manjusaka --- Lib/test/support/__init__.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Lib/test/support/__init__.py b/Lib/test/support/__init__.py index 39798d15c24561..51c0ce11e8269d 100644 --- a/Lib/test/support/__init__.py +++ b/Lib/test/support/__init__.py @@ -3080,7 +3080,7 @@ def _supports_remote_attaching(): return PROCESS_VM_READV_SUPPORTED -def _support_remote_exec_only_impl(test): +def _support_remote_exec_only_impl(): if not sys.is_remote_debug_enabled(): return unittest.skip("Remote debugging is not enabled") if sys.platform not in ("darwin", "linux", "win32"): From 20ac399e233889c7a521244ca009257e071cf74f Mon Sep 17 00:00:00 2001 From: Manjusaka Date: Thu, 19 Jun 2025 02:42:10 +0800 Subject: [PATCH 19/21] fix review idea Signed-off-by: Manjusaka --- Doc/library/sys.rst | 8 ++++---- Lib/test/audit-tests.py | 2 +- Lib/test/test_sys.py | 2 +- Python/ceval_gil.c | 2 +- Python/sysmodule.c | 5 +++-- 5 files changed, 10 insertions(+), 9 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index a759a6e0f78a30..90057cb1caf721 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1933,16 +1933,16 @@ always available. Unless explicitly noted otherwise, all variables are read-only interpreter is pre-release (alpha, beta, or release candidate) then the local and remote interpreters must be the same exact version. - .. audit-event:: remote_exec pid script_path + .. audit-event:: sys.remote_exec pid script_path When the code is executed in the remote process, an :ref:`auditing event ` - ``remote_exec`` is raised with the *pid* and the path to the script file. + ``sys.remote_exec`` is raised with the *pid* and the path to the script file. - .. audit-event:: remote_debugger_script script_path + .. audit-event:: cpython.remote_debugger_script script_path When the script is executed in the remote process, an :ref:`auditing event ` - ``sys.remote_debugger_script`` is raised + ``cpython.remote_debugger_script`` is raised with the path in the remote process. .. availability:: Unix, Windows. diff --git a/Lib/test/audit-tests.py b/Lib/test/audit-tests.py index 43f353186556cd..eaaa672d3313a7 100644 --- a/Lib/test/audit-tests.py +++ b/Lib/test/audit-tests.py @@ -650,7 +650,7 @@ def test_sys_remote_exec(): event_pid = -1 event_script_path = "" def hook(event, args): - if event != "remote_exec": return + if event != "sys.remote_exec": return nonlocal event_pid event_pid = args[0] nonlocal event_script_path diff --git a/Lib/test/test_sys.py b/Lib/test/test_sys.py index d030c6d8c3b503..73a72024bba84d 100644 --- a/Lib/test/test_sys.py +++ b/Lib/test/test_sys.py @@ -2102,7 +2102,7 @@ def audit_hook(event, arg): returncode, stdout, stderr = self._run_remote_exec_test(script, prologue=prologue) self.assertEqual(returncode, 0) self.assertIn(b"Remote script executed successfully!", stdout) - self.assertIn(b"Audit event: remote_debugger_script, arg: ", stdout) + self.assertIn(b"Audit event: cpython.remote_debugger_script, arg: ", stdout) self.assertEqual(stderr, b"") def test_remote_exec_with_exception(self): diff --git a/Python/ceval_gil.c b/Python/ceval_gil.c index 6d2383ac7c1c65..57d8f68b000b60 100644 --- a/Python/ceval_gil.c +++ b/Python/ceval_gil.c @@ -1220,7 +1220,7 @@ static inline int run_remote_debugger_source(PyObject *source) // that would be an easy target for a ROP gadget. static inline void run_remote_debugger_script(PyObject *path) { - if (0 != PySys_Audit("remote_debugger_script", "O", path)) { + if (0 != PySys_Audit("cpython.remote_debugger_script", "O", path)) { PyErr_FormatUnraisable( "Audit hook failed for remote debugger script %U", path); return; diff --git a/Python/sysmodule.c b/Python/sysmodule.c index 7640753662cd94..b3a2512a99d2fc 100644 --- a/Python/sysmodule.c +++ b/Python/sysmodule.c @@ -2485,13 +2485,14 @@ sys_remote_exec_impl(PyObject *module, int pid, PyObject *script) PyObject *path; const char *debugger_script_path; - if (PySys_Audit("remote_exec", "iO", pid, script) < 0) { + if (PyUnicode_FSConverter(script, &path) == 0) { return NULL; } - if (PyUnicode_FSConverter(script, &path) == 0) { + if (PySys_Audit("sys.remote_exec", "iO", pid, script) < 0) { return NULL; } + debugger_script_path = PyBytes_AS_STRING(path); #ifdef MS_WINDOWS PyObject *unicode_path; From 8682689bfcd847b2cc57c2bb20b289645585f911 Mon Sep 17 00:00:00 2001 From: Manjusaka Date: Thu, 19 Jun 2025 02:43:18 +0800 Subject: [PATCH 20/21] update news Signed-off-by: Manjusaka --- .../2025-06-16-02-31-42.gh-issue-135543.6b0HOF.rst | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-16-02-31-42.gh-issue-135543.6b0HOF.rst b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-16-02-31-42.gh-issue-135543.6b0HOF.rst index d16977db6bdca1..6efe2a47bac5d4 100644 --- a/Misc/NEWS.d/next/Core_and_Builtins/2025-06-16-02-31-42.gh-issue-135543.6b0HOF.rst +++ b/Misc/NEWS.d/next/Core_and_Builtins/2025-06-16-02-31-42.gh-issue-135543.6b0HOF.rst @@ -1 +1,2 @@ -Emit ``remote_exec`` audit event when :func:`sys.remote_exec` is called. +Emit ``sys.remote_exec`` audit event when :func:`sys.remote_exec` is called +and migrate ``remote_debugger_script`` to ``cpython.remote_debugger_script``. From 60725afe317e932df83e647b0dec8248277ea868 Mon Sep 17 00:00:00 2001 From: Manjusaka Date: Thu, 19 Jun 2025 22:56:28 +0800 Subject: [PATCH 21/21] fix review idea Signed-off-by: Manjusaka --- Doc/library/sys.rst | 8 ++++++-- Lib/test/audit-tests.py | 20 ++++++++++++++------ Lib/test/test_audit.py | 4 +++- 3 files changed, 23 insertions(+), 9 deletions(-) diff --git a/Doc/library/sys.rst b/Doc/library/sys.rst index 90057cb1caf721..f8f727f4a23410 100644 --- a/Doc/library/sys.rst +++ b/Doc/library/sys.rst @@ -1935,8 +1935,10 @@ always available. Unless explicitly noted otherwise, all variables are read-only .. audit-event:: sys.remote_exec pid script_path - When the code is executed in the remote process, an :ref:`auditing event ` - ``sys.remote_exec`` is raised with the *pid* and the path to the script file. + When the code is executed in the remote process, an + :ref:`auditing event ` ``sys.remote_exec`` is raised with + the *pid* and the path to the script file. + This event is raised in the process that called :func:`sys.remote_exec`. .. audit-event:: cpython.remote_debugger_script script_path @@ -1944,6 +1946,8 @@ always available. Unless explicitly noted otherwise, all variables are read-only :ref:`auditing event ` ``cpython.remote_debugger_script`` is raised with the path in the remote process. + This event is raised in the remote process, not the one + that called :func:`sys.remote_exec`. .. availability:: Unix, Windows. .. versionadded:: 3.14 diff --git a/Lib/test/audit-tests.py b/Lib/test/audit-tests.py index eaaa672d3313a7..6884ac0dbe6ff0 100644 --- a/Lib/test/audit-tests.py +++ b/Lib/test/audit-tests.py @@ -649,20 +649,28 @@ def test_sys_remote_exec(): pid = os.getpid() event_pid = -1 event_script_path = "" + remote_event_script_path = "" def hook(event, args): - if event != "sys.remote_exec": return - nonlocal event_pid - event_pid = args[0] - nonlocal event_script_path - event_script_path = args[1] + if event not in ["sys.remote_exec", "cpython.remote_debugger_script"]: + return + print(event, args) + match event: + case "sys.remote_exec": + nonlocal event_pid, event_script_path + event_pid = args[0] + event_script_path = args[1] + case "cpython.remote_debugger_script": + nonlocal remote_event_script_path + remote_event_script_path = args[0] sys.addaudithook(hook) with tempfile.NamedTemporaryFile(mode='w+', delete=True) as tmp_file: - tmp_file.write("print('Hello from remote_exec!')\n") + tmp_file.write("a = 1+1\n") tmp_file.flush() sys.remote_exec(pid, tmp_file.name) assertEqual(event_pid, pid) assertEqual(event_script_path, tmp_file.name) + assertEqual(remote_event_script_path, tmp_file.name) if __name__ == "__main__": from test.support import suppress_msvcrt_asserts diff --git a/Lib/test/test_audit.py b/Lib/test/test_audit.py index f50819cc14090d..077765fcda210a 100644 --- a/Lib/test/test_audit.py +++ b/Lib/test/test_audit.py @@ -325,7 +325,9 @@ def test_assert_unicode(self): @support.support_remote_exec_only @support.cpython_only def test_sys_remote_exec(self): - returncode, stdout, stderr = self.run_python("test_sys_remote_exec") + returncode, events, stderr = self.run_python("test_sys_remote_exec") + self.assertTrue(any(["sys.remote_exec" in event for event in events])) + self.assertTrue(any(["cpython.remote_debugger_script" in event for event in events])) if returncode: self.fail(stderr)