Segmentation fault in array sorting with GC interaction
Port, board and/or hardware
unix port
MicroPython version
v1.26.0-46-g1588c455c on 2025-08-17
Reproduction
- Create a comparison class that modifies the array being sorted
- Call gc.collect() within the comparison function
- Attempt to sort the array
import gc
class check:
def __init__(self, arr1, arr2):
self.arr1 = arr1
self.arr2 = arr2
def __lt__(self, other):
# Clear one array, modify another
self.arr1.clear()
self.arr2.extend([777] * 5)
gc.collect()
self.arr2.clear()
return True
d1 = []
d2 = []
contaminators = [check(d1, d2) for _ in range(3)]
d1.extend(contaminators)
d2.extend(contaminators)
d1.sort()
Expected behaviour
The code should either:
- Raise a Python exception (e.g., RuntimeError, ValueError)
- Handle the edge case gracefully without crashing
Observed behaviour
MicroPython crashes with a segmentation fault when array.clear() and gc.collect() are called within comparison functions during array sorting operations. This appears to be caused by a NULL pointer dereference in py/obj.c at line 61.
AddressSanitizer:DEADLYSIGNAL
=================================================================
==1758094==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x64c7a2bd4b4b bp 0x000000000000 sp 0x7fffd2494c90 T0)
==1758094==The signal is caused by a READ memory access.
==1758094==Hint: address points to the zero page.
#0 0x64c7a2bd4b4b in mp_obj_get_type ../../py/obj.c:61
#1 0x64c7a2bccdac in mp_binary_op ../../py/runtime.c:640
#2 0x64c7a2bf012d in mp_quicksort ../../py/objlist.c:288
#3 0x64c7a2bf0405 in mp_obj_list_sort ../../py/objlist.c:330
#4 0x64c7a2be8192 in fun_builtin_var_call ../../py/objfun.c:118
#5 0x64c7a2bc6984 in mp_call_function_n_kw ../../py/runtime.c:727
#6 0x64c7a2bc7547 in mp_call_method_n_kw ../../py/runtime.c:743
#7 0x64c7a2c2b5cd in mp_execute_bytecode ../../py/vm.c:1069
#8 0x64c7a2be85a9 in fun_bc_call ../../py/objfun.c:295
#9 0x64c7a2bc6984 in mp_call_function_n_kw ../../py/runtime.c:727
#10 0x64c7a2bcadb3 in mp_call_function_0 ../../py/runtime.c:701
#11 0x64c7a2d4adc6 in execute_from_lexer /home/kai/project/hypothesmith/micropython/ports/unix/main.c:162
#12 0x64c7a2d4aedc in do_file /home/kai/project/hypothesmith/micropython/ports/unix/main.c:311
#13 0x64c7a2d4c825 in main_ /home/kai/project/hypothesmith/micropython/ports/unix/main.c:728
#14 0x64c7a2d4ce63 in main /home/kai/project/hypothesmith/micropython/ports/unix/main.c:494
#15 0x7b69f7c2a3b7 in __libc_start_call_main ../sysdeps/nptl/libc_start_call_main.h:58
#16 0x7b69f7c2a47a in __libc_start_main_impl ../csu/libc-start.c:360
#17 0x64c7a2b69734 in _start (micropython/ports/unix/build-coverage/micropython+0x1a8734) (BuildId: bb66085681e6f5a07b78002d60ef2779d5eae802)
The AddressSanitizer output shows a NULL pointer dereference at address 0x000000000000. The call stack reveals:
mp_quicksort (objlist.c:288) - Sorting algorithm in progress
mp_binary_op (runtime.c:640) - Calls comparison operation
mp_obj_get_type (obj.c:61) - CRASH HERE - Dereferencing NULL pointer
Additional Information
No, I've provided everything above.
Code of Conduct
Yes, I agree
Segmentation Fault (NULL Pointer Dereference) in mp_obj_get_type via mp_binary_op
Port, board and/or hardware
unix
MicroPython version
v1.27.0 and master-branch
Issue Report
Description
We discovered a Segmentation Fault vulnerability in MicroPython. The crash occurs within mp_obj_get_type when it is called by mp_binary_op.
The ASAN report indicates a READ memory access violation at address 0x000000000000, confirming a NULL Pointer Dereference. The runtime attempts to retrieve the type of a NULL object pointer during a binary operation.
Environment
- OS: Linux x86_64
- Complier: gcc 11.5.0
- Tools: AddressSanitizer
- Affected Version:
master branch - Build Configure:
make CFLAGS_EXTRA="-fsanitize=address --param asan-use-after-return=0" \
LDFLAGS_EXTRA="-fsanitize=address --param asan-use-after-return=0" \
CC=gcc STRIP= -j$(nproc)
Vulnerability Details
- Target: MicroPython (Unix Port)
- Vulnerability Type: Segmentation Fault (NULL Pointer Dereference)
- Function: mp_obj_get_type (called from mp_binary_op)
- Location: py/obj.c:61
- Root Cause Analysis: The crash occurs when the VM executes a binary operation (e.g., addition, subtraction, or comparison). The stack trace shows:
#0 0x56082b58782e in mp_obj_get_type ../../py/obj.c:61
#1 0x56082b584a14 in mp_binary_op ../../py/runtime.c:625
mp_binary_op typically calls mp_obj_get_type on its operands (LHS or RHS) to dispatch the operation to the correct type handler. The crash at 0x0 implies that one of the operands passed to mp_binary_op is NULL. This suggests that a previous bytecode instruction or internal routine pushed a NULL pointer onto the stack (or failed to initialize an object), which was then consumed by the binary operator.
Reproduce
- Compile the micropython with gcc compiler and AddressSanitizer enabled
- Run the micropython with the POC input.
Proof of Concept:
@micropython.native
def f(n):
while n:v+=0
f(2)
ASAN report
AddressSanitizer:DEADLYSIGNAL
=================================================================
==36398==ERROR: AddressSanitizer: SEGV on unknown address 0x000000000000 (pc 0x56082b58782e bp 0x000000000003 sp 0x7fff63474370 T0)
==36398==The signal is caused by a READ memory access.
==36398==Hint: address points to the zero page.
#0 0x56082b58782e in mp_obj_get_type ../../py/obj.c:61
#1 0x56082b584a14 in mp_binary_op ../../py/runtime.c:625
#2 0x7f08871c70fd (<unknown module>)
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV ../../py/obj.c:61 in mp_obj_get_type
==36398==ABORTING
What does this issue allow an attacker to do?
Denial of Service (DoS). An attacker can crash the MicroPython interpreter by executing a specific script that triggers a binary operation on an invalid (NULL) object state.
How does the attacker exploit this issue?
The attacker provides a Python script that likely contains a sequence of operations leading to an invalid object state on the stack. When a binary operator (like +, -, or a comparison) is subsequently executed, the VM attempts to inspect the type of this NULL object, triggering the segmentation fault.
Code of Conduct
Yes, I agree