GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — UAF when writing to a bytearray with an element implementing `__index__` with side-effects · Issue #91153 · python/cpython

UAF when writing to a bytearray with an element implementing __index__ with side-effects #91153

New issue
Copy link
New issue
Copy link
Closed
Closed
UAF when writing to a bytearray with an element implementing __index__ with side-effects#91153
Copy link
Assignees
brandtbucher
Labels
interpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)type-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump

Description

@JelleZijlstra
JelleZijlstra
opened on Mar 13, 2022
Issue body actions
BPO 46997
Nosy @gvanrossum, @JelleZijlstra

Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

Show more details

GitHub fields:

assignee = None
closed_at = None
created_at = <Date 2022-03-13.02:05:03.024>
labels = ['interpreter-core', '3.9', '3.10', '3.11']
title = 'Invalid memory write in bytearray'
updated_at = <Date 2022-03-13.02:14:01.825>
user = 'https://github.com/JelleZijlstra'

bugs.python.org fields:

activity = <Date 2022-03-13.02:14:01.825>
actor = 'JelleZijlstra'
assignee = 'none'
closed = False
closed_date = None
closer = None
components = ['Interpreter Core']
creation = <Date 2022-03-13.02:05:03.024>
creator = 'JelleZijlstra'
dependencies = []
files = []
hgrepos = []
issue_num = 46997
keywords = []
message_count = 2.0
messages = ['415021', '415022']
nosy_count = 2.0
nosy_names = ['gvanrossum', 'JelleZijlstra']
pr_nums = []
priority = 'normal'
resolution = None
stage = None
status = 'open'
superseder = None
type = None
url = 'https://bugs.python.org/issue46997'
versions = ['Python 3.9', 'Python 3.10', 'Python 3.11']

Linked PRs

  • gh-91153: Fix bytearray holding a reference to its internal buffer when calling into potentially mutating __index__ methods #132379
  • [3.14] gh-91153: prevent a crash in bytearray.__setitem__(ind, ...) when ind.__index__ has side-effects (GH-132379) #136581
  • [3.13] gh-91153: prevent a crash in bytearray.__setitem__(ind, ...) when ind.__index__ has side-effects (GH-132379) #136582

Activity

Next
  1. JelleZijlstra commented on Mar 13, 2022

    @JelleZijlstra
    JelleZijlstra
    on Mar 13, 2022
    MemberAuthor
    More actions

    Inspired by Guido's comment in https://github.com/python/cpython/pull/31834/files#r825352900, I found that there are some places in bytearrayobject.c where we can write to free'd memory if we encounter an object with a sneaky __index__ method:

    $ cat basneak.py 
    ba = bytearray([0 for _ in range(10000)])
    
    class sneaky:
        def __index__(self):
            ba.clear()
            return 1
    
    ba[-1] = sneaky()
    $ valgrind ./python basneak.py 
    ==87894== Memcheck, a memory error detector
    ==87894== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
    ==87894== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
    ==87894== Command: ./python basneak.py
    ==87894== 
    ==87894== Invalid write of size 1
    ==87894==    at 0x49B70F: bytearray_ass_subscript (bytearrayobject.c:632)
    ==87894==    by 0x488E03: PyObject_SetItem (abstract.c:211)
    <snip>
    

    In bytearray_setitem(), we first do bounds checking, and then call _getbytevalue() to get the numeric value of the argument.

    I think there's a similar bug in bytearray_ass_subscript().

  2. JelleZijlstra
    added
    interpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)
    3.10 (EOL)end of lifeend of life
    3.11only security fixesonly security fixes
    on Mar 13, 2022
  3. JelleZijlstra commented on Mar 13, 2022

    @JelleZijlstra
    JelleZijlstra
    on Mar 13, 2022
    MemberAuthor
    More actions

    3.9 segfaults.

    (gdb) bt
    #0 bytearray_ass_subscript (self=<optimized out>, index=0x7ffff7e118f0, values=0x7ffff6f918b0) at Objects/bytearrayobject.c:640
    #1 0x0000000000536302 in _PyEval_EvalFrameDefault (tstate=<optimized out>, f=0x999a80, throwflag=<optimized out>) at Python/ceval.c:1990
    #2 0x0000000000534775 in _PyEval_EvalFrame (throwflag=0, f=0x999a80, tstate=0x93de90) at ./Include/internal/pycore_ceval.h:40

  4. JelleZijlstra
    added
    3.9 (EOL)end of lifeend of life
    on Mar 13, 2022
  5. ezio-melotti
    transferred this issue fromon Apr 10, 2022
  6. gvanrossum
    added
    type-crashA hard crash of the interpreter, possibly with a core dumpA hard crash of the interpreter, possibly with a core dump
    on Apr 22, 2022
  7. chilaxan commented on May 19, 2022

    @chilaxan
    chilaxan
    on May 19, 2022
    Contributor
    More actions
    to_write_after_free = bytearray(bytearray.__basicsize__)
    class sneaky:
        def __index__(self):
            global to_corrupt_ob_exports, to_uaf
            del to_write_after_free[:]
            to_corrupt_ob_exports = bytearray(bytearray.__basicsize__)
            to_write_after_free.__init__(bytearray.__basicsize__)
            to_uaf = memoryview(to_corrupt_ob_exports)
            return -tuple.__itemsize__
    
    to_write_after_free[sneaky()] = 0
    occupy_uaf = to_corrupt_ob_exports.clear() \
              or bytearray()
    
    view_backing = to_uaf.cast('P')
    view = occupy_uaf
    
    view_backing[2] = (2 ** (tuple.__itemsize__ * 8) - 1) // 2
    memory = memoryview(view)
    memory[id(250) + int.__basicsize__] = 100
    print(250)

    proof of concept that this bug can be used to corrupt memory in a malicious/useful way
    tested on Python 3.12.0a0 built with ./configure --enable-optimizations

    image

    Reacted by Jelle Zijlstra and Eritque Arcus
  8. kumaraditya303 commented on Jul 13, 2022

    @kumaraditya303
    kumaraditya303
    on Jul 13, 2022
    Contributor
    More actions

    ASAN report:

    =================================================================
    ==17089==ERROR: AddressSanitizer: heap-use-after-free on address 0x62600000580f at pc 0x55f0875e0b57 bp 0x7fff4c7822e0 sp 0x7fff4c7822d0
    WRITE of size 1 at 0x62600000580f thread T0
        #0 0x55f0875e0b56 in bytearray_ass_subscript Objects/bytearrayobject.c:618
        #1 0x55f08758e10f in PyObject_SetItem Objects/abstract.c:212
        #2 0x55f087bc13ec in _PyEval_EvalFrameDefault Python/ceval.c:2333
        #3 0x55f087c304a3 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:74
        #4 0x55f087c304a3 in _PyEval_Vector Python/ceval.c:6472
        #5 0x55f087c309c9 in PyEval_EvalCode Python/ceval.c:1161
        #6 0x55f087daf6b2 in run_eval_code_obj Python/pythonrun.c:1713
        #7 0x55f087db12ac in run_mod Python/pythonrun.c:1734
        #8 0x55f087db1667 in pyrun_file Python/pythonrun.c:1629
        #9 0x55f087dbf998 in _PyRun_SimpleFileObject Python/pythonrun.c:439
        #10 0x55f087dc0151 in _PyRun_AnyFileObject Python/pythonrun.c:78
        #11 0x55f087e616b7 in pymain_run_file_obj Modules/main.c:360
        #12 0x55f087e6234c in pymain_run_file Modules/main.c:379
        #13 0x55f087e66d2a in pymain_run_python Modules/main.c:610
        #14 0x55f087e66fa5 in Py_RunMain Modules/main.c:689
        #15 0x55f087e67195 in pymain_main Modules/main.c:719
        #16 0x55f087e674fc in Py_BytesMain Modules/main.c:743
        #17 0x55f0873362c5 in main Programs/python.c:15
        #18 0x7f73bfe63082 in __libc_start_main ../csu/libc-start.c:308
        #19 0x55f0873361fd in _start (/workspaces/cpython/python+0x18491fd)
    
    0x62600000580f is located 9999 bytes inside of 10001-byte region [0x626000003100,0x626000005811)
    freed by thread T0 here:
        #0 0x7f73c0c2ac3e in __interceptor_realloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:163
        #1 0x55f0878484bb in _PyMem_RawRealloc Objects/obmalloc.c:123
        #2 0x55f08784cb06 in PyObject_Realloc Objects/obmalloc.c:735
        #3 0x55f0875d5540 in PyByteArray_Resize Objects/bytearrayobject.c:233
        #4 0x55f0875dfdcc in bytearray_clear_impl Objects/bytearrayobject.c:1134
        #5 0x55f0875dfec4 in bytearray_clear Objects/clinic/bytearrayobject.c.h:89
        #6 0x55f087689006 in method_vectorcall_NOARGS Objects/descrobject.c:454
        #7 0x55f08763a245 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:92
        #8 0x55f08763a245 in PyObject_Vectorcall Objects/call.c:300
        #9 0x55f087c101b1 in _PyEval_EvalFrameDefault Python/ceval.c:4841
        #10 0x55f087c304a3 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:74
        #11 0x55f087c304a3 in _PyEval_Vector Python/ceval.c:6472
        #12 0x55f087636edd in _PyFunction_Vectorcall Objects/call.c:396
        #13 0x55f0878ee41e in _PyObject_VectorcallTstate Include/internal/pycore_call.h:92
        #14 0x55f0878ee41e in vectorcall_unbound Objects/typeobject.c:1651
        #15 0x55f0878ee41e in vectorcall_method Objects/typeobject.c:1682
        #16 0x55f0878efe5a in slot_nb_index Objects/typeobject.c:7643
        #17 0x55f087585d45 in _PyNumber_Index Objects/abstract.c:1418
        #18 0x55f08776dd33 in PyLong_AsLongAndOverflow Objects/longobject.c:503
        #19 0x55f0875a70bc in _getbytevalue Objects/bytearrayobject.c:27
        #20 0x55f0875e0765 in bytearray_ass_subscript Objects/bytearrayobject.c:616
        #21 0x55f08758e10f in PyObject_SetItem Objects/abstract.c:212
        #22 0x55f087bc13ec in _PyEval_EvalFrameDefault Python/ceval.c:2333
        #23 0x55f087c304a3 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:74
        #24 0x55f087c304a3 in _PyEval_Vector Python/ceval.c:6472
        #25 0x55f087c309c9 in PyEval_EvalCode Python/ceval.c:1161
        #26 0x55f087daf6b2 in run_eval_code_obj Python/pythonrun.c:1713
        #27 0x55f087db12ac in run_mod Python/pythonrun.c:1734
        #28 0x55f087db1667 in pyrun_file Python/pythonrun.c:1629
        #29 0x55f087dbf998 in _PyRun_SimpleFileObject Python/pythonrun.c:439
        #30 0x55f087dc0151 in _PyRun_AnyFileObject Python/pythonrun.c:78
        #31 0x55f087e616b7 in pymain_run_file_obj Modules/main.c:360
        #32 0x55f087e6234c in pymain_run_file Modules/main.c:379
        #33 0x55f087e66d2a in pymain_run_python Modules/main.c:610
        #34 0x55f087e66fa5 in Py_RunMain Modules/main.c:689
    
    previously allocated by thread T0 here:
        #0 0x7f73c0c2ac3e in __interceptor_realloc ../../../../src/libsanitizer/asan/asan_malloc_linux.cc:163
        #1 0x55f0878484bb in _PyMem_RawRealloc Objects/obmalloc.c:123
        #2 0x55f08784cb06 in PyObject_Realloc Objects/obmalloc.c:735
        #3 0x55f0875d5540 in PyByteArray_Resize Objects/bytearrayobject.c:233
        #4 0x55f0875d6f5c in bytearray___init___impl Objects/bytearrayobject.c:835
        #5 0x55f0875d8f83 in bytearray___init__ Objects/clinic/bytearrayobject.c.h:68
        #6 0x55f0878d9f4e in type_call Objects/typeobject.c:1112
        #7 0x55f087637615 in _PyObject_MakeTpCall Objects/call.c:215
        #8 0x55f08763a2a6 in _PyObject_VectorcallTstate Include/internal/pycore_call.h:90
        #9 0x55f08763a2a6 in PyObject_Vectorcall Objects/call.c:300
        #10 0x55f087c101b1 in _PyEval_EvalFrameDefault Python/ceval.c:4841
        #11 0x55f087c304a3 in _PyEval_EvalFrame Include/internal/pycore_ceval.h:74
        #12 0x55f087c304a3 in _PyEval_Vector Python/ceval.c:6472
        #13 0x55f087c309c9 in PyEval_EvalCode Python/ceval.c:1161
        #14 0x55f087daf6b2 in run_eval_code_obj Python/pythonrun.c:1713
        #15 0x55f087db12ac in run_mod Python/pythonrun.c:1734
        #16 0x55f087db1667 in pyrun_file Python/pythonrun.c:1629
        #17 0x55f087dbf998 in _PyRun_SimpleFileObject Python/pythonrun.c:439
        #18 0x55f087dc0151 in _PyRun_AnyFileObject Python/pythonrun.c:78
        #19 0x55f087e616b7 in pymain_run_file_obj Modules/main.c:360
        #20 0x55f087e6234c in pymain_run_file Modules/main.c:379
        #21 0x55f087e66d2a in pymain_run_python Modules/main.c:610
        #22 0x55f087e66fa5 in Py_RunMain Modules/main.c:689
        #23 0x55f087e67195 in pymain_main Modules/main.c:719
        #24 0x55f087e674fc in Py_BytesMain Modules/main.c:743
        #25 0x55f0873362c5 in main Programs/python.c:15
        #26 0x7f73bfe63082 in __libc_start_main ../csu/libc-start.c:308
    
    SUMMARY: AddressSanitizer: heap-use-after-free Objects/bytearrayobject.c:618 in bytearray_ass_subscript
    Shadow bytes around the buggy address:
      0x0c4c7fff8ab0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
      0x0c4c7fff8ac0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
      0x0c4c7fff8ad0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
      0x0c4c7fff8ae0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
      0x0c4c7fff8af0: fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd fd
    =>0x0c4c7fff8b00: fd[fd]fd fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c4c7fff8b10: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c4c7fff8b20: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c4c7fff8b30: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c4c7fff8b40: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
      0x0c4c7fff8b50: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
    Shadow 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
      Shadow gap:              cc
    ==17089==ABORTING
    
  9. brandtbucher
    self-assigned this
    on Jul 16, 2022
  10. brandtbucher
    added a commit that references this issue on Jul 19, 2022

    GH-91153: Handle mutating __index__ methods in bytearray item assignm…

    f365895
  11. miss-islington
    added 2 commits that reference this issue on Jul 19, 2022

    pythonGH-91153: Handle mutating __index__ methods in bytearray item a…

    da3610c

    pythonGH-91153: Handle mutating __index__ methods in bytearray item a…

    d61a2fa
  12. 32 remaining items

  13. picnixz
    added 2 commits that reference this issue on Jul 12, 2025

    Merge branch 'main' into bast0006/pythongh-91153

    9b28503

    gh-91153: prevent a crash in `bytearray.__setitem__(ind, ...)` when `…

    5e1e21d
  14. miss-islington
    added a commit that references this issue on Jul 12, 2025

    pythongh-91153: prevent a crash in `bytearray.__setitem__(ind, ...)` …

    02aa323
  15. picnixz
    added 3 commits that reference this issue on Jul 12, 2025

    [3.13] pythongh-91153: prevent a crash in `bytearray.__setitem__(ind,…

    0e827aa

    [3.13] gh-91153: prevent a crash in `bytearray.__setitem__(ind, ...)`…

    360540f

    [3.14] gh-91153: prevent a crash in `bytearray.__setitem__(ind, ...)`…

    d5866a8
  16. picnixz
    closed this as completedon Jul 12, 2025
  17. Pranjal095
    added a commit that references this issue on Jul 12, 2025

    pythongh-91153: prevent a crash in `bytearray.__setitem__(ind, ...)` …

    fc46948
  18. picnixz
    added a commit that references this issue on Jul 13, 2025

    pythongh-91153: prevent a crash in `bytearray.__setitem__(ind, ...)` …

    2aa177d
  19. taegyunkim
    added a commit that references this issue on Aug 4, 2025

    pythongh-91153: prevent a crash in `bytearray.__setitem__(ind, ...)` …

    a70a3ef
  20. Agent-Hellboy
    added a commit that references this issue on Aug 19, 2025

    pythongh-91153: prevent a crash in `bytearray.__setitem__(ind, ...)` …

    cfc56bb
  21. kumaraditya303
    added a commit that references this issue on Sep 9, 2025

    [3.14] pythongh-91153: prevent a crash in `bytearray.__setitem__(ind,…

    4278eb4
  22. vstinner
    added 2 commits that reference this issue on Jul 24, 2026

    gh-153570: Fix use-after-free in bytearray.take_bytes() with a reentr…

    ee21d99

    [3.15] gh-153570: Fix use-after-free in bytearray.take_bytes() with a…

    848f0ba
  23. mbeijen
    added a commit that references this issue on Aug 14, 2026

    pythongh-153570: Fix use-after-free in bytearray.take_bytes() with a …

    946e49f
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

  • @brandtbucher
    brandtbucher

Labels

interpreter-core(Objects, Python, Grammar, and Parser dirs)(Objects, Python, Grammar, and Parser dirs)type-crashA hard crash of the interpreter, possibly with a core dumpA 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

    You are visitor 01402503 — GeezerVison does not store the pages you look up.
    Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.