Title: Use-after-free in unregister() of atexit module · Issue #112127 · python/cpython · GitHub
Open Graph Title: Use-after-free in unregister() of atexit module · Issue #112127 · python/cpython
X Title: Use-after-free in unregister() of atexit module · Issue #112127 · python/cpython
Description: Bug report Bug description: Version 3.10.13 (tags/v3.10.13:49965601d6, Nov 12 2023, 04:15:18) bisect from commit 670e692, Root cause atexit_unregister dont’ consider counting reference and reentering other functions including atexit_unre...
Open Graph Description: Bug report Bug description: Version 3.10.13 (tags/v3.10.13:49965601d6, Nov 12 2023, 04:15:18) bisect from commit 670e692, Root cause atexit_unregister dont’ consider counting reference and reenteri...
X Description: Bug report Bug description: Version 3.10.13 (tags/v3.10.13:49965601d6, Nov 12 2023, 04:15:18) bisect from commit 670e692, Root cause atexit_unregister dont’ consider counting reference and reenteri...
Opengraph URL: https://github.com/python/cpython/issues/112127
X: @github
Domain: github.com
{"@context":"https://schema.org","@type":"DiscussionForumPosting","headline":"Use-after-free in unregister() of atexit module","articleBody":"# Bug report\r\n\r\n### Bug description:\r\n\r\n## Version\r\n3.10.13 (tags/v3.10.13:49965601d6, Nov 12 2023, 04:15:18)\r\n\r\nbisect from commit 670e6921349dd408b6958a0c5d3b1486725f9beb,\r\n\r\n\r\n\r\n## Root cause\r\n`atexit_unregister` dont’ consider counting reference and reentering other functions including `atexit_unregister` , `atexit_clear` .\r\n\r\nIt causes a free `cb-func` in the second loop while the first loop holds that reference.\r\n\r\nThis vulnerability caused by calling `PyObject_RichCompareBool` in c code, which call arbitrary user defined code like __eq__\r\n\r\n\r\n```c\r\nstatic PyObject *\r\natexit_unregister(PyObject *module, PyObject *func)\r\n{\r\n struct atexit_state *state = get_atexit_state();\r\n for (int i = 0; i \u003c state-\u003encallbacks; i++)\r\n {\r\n atexit_py_callback *cb = state-\u003ecallbacks[i];\r\n if (cb == NULL) {\r\n continue;\r\n }\r\n\r\n int eq = PyObject_RichCompareBool(cb-\u003efunc, func, Py_EQ); //\u003c--here\r\n if (eq \u003c 0) {\r\n return NULL;\r\n }\r\n if (eq) {\r\n atexit_delete_cb(state, i);\r\n }\r\n }\r\n Py_RETURN_NONE;\r\n}\r\n```\r\n\r\n## Poc\r\n\r\n```python\r\nimport atexit\r\n\r\n\r\nclass test(object):\r\n def __eq__(self,o):\r\n atexit._clear()\r\n return NotImplemented\r\n def __call__(self): \r\n return\r\n\r\natexit.register(test())\r\natexit.unregister(test())\r\n```\r\n\r\n## Asan\r\n\u003cdetails\u003e\r\n\u003csummary\u003easan\u003c/summary\u003e\r\n\r\n=75703==ERROR: AddressSanitizer: heap-use-after-free on address 0x607000644cb0 at pc 0x563a1a579158 bp 0x7f\r\nfeb4ffa460 sp 0x7ffeb4ffa450 \r\nREAD of size 8 at 0x607000644cb0 thread T0 \r\n #0 0x563a1a579157 in _Py_INCREF Include/object.h:472 \r\n #1 0x563a1a579157 in _PyEval_MakeFrameVector Python/ceval.c:4826 \r\n #2 0x563a1a57a8b7 in _PyEval_Vector Python/ceval.c:5059 \r\n #3 0x563a1a3b8c9a in _PyFunction_Vectorcall Objects/call.c:342 \r\n #4 0x563a1a494550 in _PyObject_VectorcallTstate Include/cpython/abstract.h:114 \r\n #5 0x563a1a494550 in vectorcall_unbound Objects/typeobject.c:1629 \r\n #6 0x563a1a494550 in slot_tp_richcompare Objects/typeobject.c:7628 \r\n #7 0x563a1a440c51 in do_richcompare Objects/object.c:699 \r\n #8 0x563a1a440f93 in PyObject_RichCompare Objects/object.c:743 \r\n #9 0x563a1a4410a9 in PyObject_RichCompareBool Objects/object.c:765 \r\n #10 0x563a1a71618c in atexit_unregister Modules/atexitmodule.c:241 \r\n #11 0x563a1a7ef56d in cfunction_vectorcall_O Objects/methodobject.c:516 \r\n #12 0x563a1a548745 in _PyObject_VectorcallTstate Include/cpython/abstract.h:114\r\n #13 0x563a1a551b8f in PyObject_Vectorcall Include/cpython/abstract.h:123\r\n #14 0x563a1a551b8f in call_function Python/ceval.c:5893\r\n #15 0x563a1a574978 in _PyEval_EvalFrameDefault Python/ceval.c:4181 \r\n #16 0x563a1a57a95d in _PyEval_EvalFrame Include/internal/pycore_ceval.h:46\r\n #17 0x563a1a57a95d in _PyEval_Vector Python/ceval.c:5067 \r\n #18 0x563a1a57af25 in PyEval_EvalCode Python/ceval.c:1134 \r\n #19 0x563a1a60c907 in run_eval_code_obj Python/pythonrun.c:1291 \r\n #20 0x563a1a60d329 in run_mod Python/pythonrun.c:1312 \r\n #21 0x563a1a60d4c3 in pyrun_file Python/pythonrun.c:1208 \r\n #22 0x563a1a612b87 in _PyRun_SimpleFileObject Python/pythonrun.c:456\r\n #23 0x563a1a612e80 in _PyRun_AnyFileObject Python/pythonrun.c:90 \r\n #24 0x563a1a3939b4 in pymain_run_file_obj Modules/main.c:353 \r\n #25 0x563a1a394184 in pymain_run_file Modules/main.c:372 \r\n #26 0x563a1a39668b in pymain_run_python Modules/main.c:587 \r\n #27 0x563a1a396809 in Py_RunMain Modules/main.c:666 \r\n #28 0x563a1a3969f9 in pymain_main Modules/main.c:696 \r\n #29 0x563a1a396d71 in Py_BytesMain Modules/main.c:720 \r\n #30 0x563a1a393245 in main Programs/python.c:15\r\n #31 0x7f6c90d20d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58\r\n #32 0x7f6c90d20e3f in __libc_start_main_impl ../csu/libc-start.c:392\r\n #33 0x563a1a393174 in _start (/home/ubuntu/cpython/python+0x1fa174)\r\n\r\n0x607000644cb0 is located 32 bytes inside of 72-byte region [0x607000644c90,0x607000644cd8)\r\nfreed by thread T0 here:\r\n #0 0x7f6c910ba537 in __interceptor_free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:127\r\n #1 0x563a1a4460e8 in _PyMem_RawFree Objects/obmalloc.c:127\r\n #2 0x563a1a446e01 in _PyMem_DebugRawFree Objects/obmalloc.c:2538\r\n #3 0x563a1a4476e2 in _PyMem_DebugFree Objects/obmalloc.c:2671\r\n #4 0x563a1a449273 in PyObject_Free Objects/obmalloc.c:709\r\n #5 0x563a1a663cf0 in PyObject_GC_Del Modules/gcmodule.c:2375\r\n #6 0x563a1a46a386 in object_dealloc Objects/typeobject.c:4510\r\n #7 0x563a1a47da06 in subtype_dealloc Objects/typeobject.c:1460\r\n #8 0x563a1a43ed59 in _Py_Dealloc Objects/object.c:2301\r\n #9 0x563a1a7e0a89 in _Py_DECREF Include/object.h:500\r\n #10 0x563a1a7e0a89 in frame_dealloc Objects/frameobject.c:591\r\n #11 0x563a1a43ed59 in _Py_Dealloc Objects/object.c:2301\r\n #12 0x563a1a57acc7 in _Py_DECREF Include/object.h:500\r\n #13 0x563a1a57acc7 in _PyEval_Vector Python/ceval.c:5080\r\n #14 0x563a1a3b8c9a in _PyFunction_Vectorcall Objects/call.c:342\r\n #15 0x563a1a494550 in _PyObject_VectorcallTstate Include/cpython/abstract.h:114\r\n #16 0x563a1a494550 in vectorcall_unbound Objects/typeobject.c:1629\r\n #17 0x563a1a494550 in slot_tp_richcompare Objects/typeobject.c:7628\r\n #18 0x563a1a440b52 in do_richcompare Objects/object.c:693\r\n #19 0x563a1a440f93 in PyObject_RichCompare Objects/object.c:743\r\n #20 0x563a1a4410a9 in PyObject_RichCompareBool Objects/object.c:765\r\n #21 0x563a1a71618c in atexit_unregister Modules/atexitmodule.c:241\r\n #22 0x563a1a7ef56d in cfunction_vectorcall_O Objects/methodobject.c:516\r\n #23 0x563a1a548745 in _PyObject_VectorcallTstate Include/cpython/abstract.h:114\r\n #24 0x563a1a551b8f in PyObject_Vectorcall Include/cpython/abstract.h:123\r\n #25 0x563a1a551b8f in call_function Python/ceval.c:5893\r\n #26 0x563a1a574978 in _PyEval_EvalFrameDefault Python/ceval.c:4181\r\n #27 0x563a1a57a95d in _PyEval_EvalFrame Include/internal/pycore_ceval.h:46\r\n #28 0x563a1a57a95d in _PyEval_Vector Python/ceval.c:5067\r\n #29 0x563a1a57af25 in PyEval_EvalCode Python/ceval.c:1134\r\n #30 0x563a1a60c907 in run_eval_code_obj Python/pythonrun.c:1291\r\n #31 0x563a1a60d329 in run_mod Python/pythonrun.c:1312\r\n #32 0x563a1a60d4c3 in pyrun_file Python/pythonrun.c:1208\r\n #33 0x563a1a612b87 in _PyRun_SimpleFileObject Python/pythonrun.c:456\r\n #34 0x563a1a612e80 in _PyRun_AnyFileObject Python/pythonrun.c:90\r\n #35 0x563a1a3939b4 in pymain_run_file_obj Modules/main.c:353\r\n\r\npreviously allocated by thread T0 here:\r\n #0 0x7f6c910ba887 in __interceptor_malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:145\r\n #1 0x563a1a446164 in _PyMem_RawMalloc Objects/obmalloc.c:99\r\n #2 0x563a1a446c5c in _PyMem_DebugRawAlloc Objects/obmalloc.c:2471\r\n #3 0x563a1a446cbb in _PyMem_DebugRawMalloc Objects/obmalloc.c:2504\r\n #4 0x563a1a447724 in _PyMem_DebugMalloc Objects/obmalloc.c:2656\r\n #5 0x563a1a4491ec in PyObject_Malloc Objects/obmalloc.c:685\r\n #6 0x563a1a661abe in _PyObject_GC_Alloc Modules/gcmodule.c:2280\r\n #7 0x563a1a663816 in _PyObject_GC_Malloc Modules/gcmodule.c:2307\r\n #8 0x563a1a477585 in PyType_GenericAlloc Objects/typeobject.c:1156\r\n #9 0x563a1a47b189 in object_new Objects/typeobject.c:4504\r\n #10 0x563a1a48200c in type_call Objects/typeobject.c:1123\r\n #11 0x563a1a3b9378 in _PyObject_MakeTpCall Objects/call.c:215\r\n #12 0x563a1a548874 in _PyObject_VectorcallTstate Include/cpython/abstract.h:112\r\n #13 0x563a1a551b8f in PyObject_Vectorcall Include/cpython/abstract.h:123\r\n #14 0x563a1a551b8f in call_function Python/ceval.c:5893\r\n #15 0x563a1a574b5d in _PyEval_EvalFrameDefault Python/ceval.c:4213\r\n #16 0x563a1a57a95d in _PyEval_EvalFrame Include/internal/pycore_ceval.h:46\r\n #17 0x563a1a57a95d in _PyEval_Vector Python/ceval.c:5067\r\n #18 0x563a1a57af25 in PyEval_EvalCode Python/ceval.c:1134\r\n #19 0x563a1a60c907 in run_eval_code_obj Python/pythonrun.c:1291\r\n #20 0x563a1a60d329 in run_mod Python/pythonrun.c:1312\r\n #21 0x563a1a60d4c3 in pyrun_file Python/pythonrun.c:1208\r\n #22 0x563a1a612b87 in _PyRun_SimpleFileObject Python/pythonrun.c:456\r\n #23 0x563a1a612e80 in _PyRun_AnyFileObject Python/pythonrun.c:90\r\n #24 0x563a1a3939b4 in pymain_run_file_obj Modules/main.c:353\r\n #25 0x563a1a394184 in pymain_run_file Modules/main.c:372\r\n #26 0x563a1a39668b in pymain_run_python Modules/main.c:587\r\n #27 0x563a1a396809 in Py_RunMain Modules/main.c:666\r\n #28 0x563a1a3969f9 in pymain_main Modules/main.c:696\r\n #29 0x563a1a396d71 in Py_BytesMain Modules/main.c:720\r\n #30 0x563a1a393245 in main Programs/python.c:15\r\n #31 0x7f6c90d20d8f in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:5\r\n\r\nSUMMARY: AddressSanitizer: heap-use-after-free Include/object.h:472 in _Py_INCREF \r\nShadow bytes around the buggy address: \r\n 0x0c0e800c0940: fd fd fd fd fd fd fd fd fa fa fa fa fd fd fd fd \r\n 0x0c0e800c0950: fd fd fd fd fd fd fa fa fa fa fd fd fd fd fd fd \r\n 0x0c0e800c0960: fd fd fd fd fa fa fa fa fd fd fd fd fd fd fd fd \r\n 0x0c0e800c0970: fd fd fa fa fa fa fd fd fd fd fd fd fd fd fd fd \r\n 0x0c0e800c0980: fa fa fa fa 00 00 00 00 00 00 00 00 00 fa fa fa \r\n=\u003e0x0c0e800c0990: fa fa fd fd fd fd[fd]fd fd fd fd fa fa fa fa fa \r\n 0x0c0e800c09a0: 00 00 00 00 00 00 00 00 00 02 fa fa fa fa fd fd \r\n 0x0c0e800c09b0: fd fd fd fd fd fd fd fd fa fa fa fa fd fd fd fd\r\n 0x0c0e800c09c0: fd fd fd fd fd fd fa fa fa fa fd fd fd fd fd fd\r\n 0x0c0e800c09d0: fd fd fd fd fa fa fa fa fd fd fd fd fd fd fd fd\r\n 0x0c0e800c09e0: fd fd fa fa fa fa fd fd fd fd fd fd fd fd fd fd\r\nShadow byte legend (one shadow byte represents 8 application bytes):\r\n Addressable: 00 \r\n Partially addressable: 01 02 03 04 05 06 07 \r\n Heap left redzone: fa\r\n Freed heap region: fd \r\n Stack left redzone: f1 \r\n Stack mid redzone: f2\r\n Stack right redzone: f3\r\n Stack after return: f5\r\n Stack use after scope: f8\r\n Global redzone: f9\r\n Global init order: f6\r\n Poisoned by user: f7\r\n Container overflow: fc\r\n Array cookie: ac\r\n Intra object redzone: bb\r\n ASan internal: fe\r\n Left alloca redzone: ca\r\n Right alloca redzone: cb\r\n Shadow gap: cc\r\n==75703==ABORTING\r\n\u003c/details\u003e\r\n\r\n\r\n### CPython versions tested on:\r\n\r\n3.10\r\n\r\n### Operating systems tested on:\r\n\r\nLinux\r\n\r\n\u003c!-- gh-linked-prs --\u003e\r\n### Linked PRs\r\n* gh-114092\r\n* gh-142878\n* gh-142880\n\u003c!-- /gh-linked-prs --\u003e\r\n","author":{"url":"https://github.com/kcatss","@type":"Person","name":"kcatss"},"datePublished":"2023-11-15T20:56:18.000Z","interactionStatistic":{"@type":"InteractionCounter","interactionType":"https://schema.org/CommentAction","userInteractionCount":5},"url":"https://github.com/112127/cpython/issues/112127"}
| route-pattern | /_view_fragments/issues/show/:user_id/:repository/:id/issue_layout(.:format) |
| route-controller | voltron_issues_fragments |
| route-action | issue_layout |
| fetch-nonce | v2:05715d6f-0e15-2c4a-51e1-041a6365bf23 |
| current-catalog-service-hash | 81bb79d38c15960b92d99bca9288a9108c7a47b18f2423d0f6438c5b7bcd2114 |
| request-id | C7EA:3244AB:27B019:3577E7:69697963 |
| html-safe-nonce | e6c2902e10661c334767ab0ab38c9f06b1426e0ee79dab06ce39795d32db660c |
| visitor-payload | eyJyZWZlcnJlciI6IiIsInJlcXVlc3RfaWQiOiJDN0VBOjMyNDRBQjoyN0IwMTk6MzU3N0U3OjY5Njk3OTYzIiwidmlzaXRvcl9pZCI6Ijg5OTk2NzAyOTkwOTg3MDgzMjMiLCJyZWdpb25fZWRnZSI6ImlhZCIsInJlZ2lvbl9yZW5kZXIiOiJpYWQifQ== |
| visitor-hmac | 6a77be8221c80336115a9a4399e2c548c47ac35a91faf9a0ded205b9800e7be8 |
| hovercard-subject-tag | issue:1995556440 |
| github-keyboard-shortcuts | repository,issues,copilot |
| google-site-verification | Apib7-x98H0j5cPqHWwSMm6dNU4GmODRoqxLiDzdx9I |
| octolytics-url | https://collector.github.com/github/collect |
| analytics-location | / |
| fb:app_id | 1401488693436528 |
| apple-itunes-app | app-id=1477376905, app-argument=https://github.com/_view_fragments/issues/show/python/cpython/112127/issue_layout |
| twitter:image | https://opengraph.githubassets.com/ed4c87ad8699491062c9fff0799620952106a44a893671e7204136afc083631e/python/cpython/issues/112127 |
| twitter:card | summary_large_image |
| og:image | https://opengraph.githubassets.com/ed4c87ad8699491062c9fff0799620952106a44a893671e7204136afc083631e/python/cpython/issues/112127 |
| og:image:alt | Bug report Bug description: Version 3.10.13 (tags/v3.10.13:49965601d6, Nov 12 2023, 04:15:18) bisect from commit 670e692, Root cause atexit_unregister dont’ consider counting reference and reenteri... |
| og:image:width | 1200 |
| og:image:height | 600 |
| og:site_name | GitHub |
| og:type | object |
| og:author:username | kcatss |
| hostname | github.com |
| expected-hostname | github.com |
| None | c6f193beb8ff08443adc07685d75302ab8aaf0a135f6e251c3ff3112c8deb881 |
| turbo-cache-control | no-preview |
| go-import | github.com/python/cpython git https://github.com/python/cpython.git |
| octolytics-dimension-user_id | 1525981 |
| octolytics-dimension-user_login | python |
| octolytics-dimension-repository_id | 81598961 |
| octolytics-dimension-repository_nwo | python/cpython |
| octolytics-dimension-repository_public | true |
| octolytics-dimension-repository_is_fork | false |
| octolytics-dimension-repository_network_root_id | 81598961 |
| octolytics-dimension-repository_network_root_nwo | python/cpython |
| turbo-body-classes | logged-out env-production page-responsive |
| disable-turbo | false |
| browser-stats-url | https://api.github.com/_private/browser/stats |
| browser-errors-url | https://api.github.com/_private/browser/errors |
| release | 212e3e3d3298bf5b313830edfd2399e869f7ea76 |
| ui-target | full |
| theme-color | #1e2327 |
| color-scheme | light dark |
Links:
Viewport: width=device-width