Skip to content

mbc_master_delete() causes use-after-free: mb_port_ser_delete() frees memory before mb_port_timer_delete() uses it (IDFGH-15380) #120

@brabema

Description

@brabema

Checklist

  • Checked the issue tracker for similar issues to ensure this is not a duplicate
  • Read the documentation to confirm the issue is not addressed there and your configuration is set correctly
  • Tested with the latest version to ensure the issue hasn't been fixed

How often does this bug occurs?

always

Expected behavior

  • The port_obj pointer should be deleted only once during cleanup.
  • Any further references to port_obj after mb_port_ser_delete() must be avoided.
  • The Modbus controller shutdown process should not result in use-after-free errors, even with HEAP_POISONING_COMPREHENSIVE enabled.

Actual behavior (suspected bug)

When mbm_rtu_transp_delete() is called, the mb_port_ser_delete() function frees port_obj.
Despite that, the same port_obj is still used later in mb_port_timer_delete() and mb_port_event_delete().

With HEAP_POISONING_COMPREHENSIVE enabled, this results in accessing memory filled with 0xFEFEFEFE, leading to:

  • use-after-free issues
  • potential crashes or undefined behavior

Error logs or terminal output

I (1899) MASTER_TEST: Destroy master...
Guru Meditation Error: Core  0 panic'ed (LoadProhibited). Exception was unhandled.

Core  0 register dump:
PC      : 0x400dcc51  PS      : 0x00060130  A0      : 0x800dcdd1  A1      : 0x3ffb5300  
--- 0x400dcc51: mb_port_timer_delete at <project_root>/managed_components/espressif__esp-modbus/modbus/mb_ports/common/port_timer.c:100

A2      : 0x3ffb8dd0  A3      : 0x00060d23  A4      : 0x00060d20  A5      : 0x00060d23  
A6      : 0x3ffb5200  A7      : 0x0000cdcd  A8      : 0xfefefefe  A9      : 0x3ffb52e0  
A10     : 0x3ffb8dd0  A11     : 0x3ffb655c  A12     : 0xb33fffff  A13     : 0x00000000  
A14     : 0x3ffb2a10  A15     : 0x3ffb8e6c  SAR     : 0x00000018  EXCCAUSE: 0x0000001c  
EXCVADDR: 0xfefefefe  LBEG    : 0x4000c46c  LEND    : 0x4000c477  LCOUNT  : 0x00000000  
--- 0x4000c46c: memset in ROM
--- 0x4000c477: memset in ROM



Backtrace: 0x400dcc4e:0x3ffb5300 0x400dcdce:0x3ffb5320 0x400db065:0x3ffb5340 0x400daf8d:0x3ffb5360 0x400d94c9:0x3ffb5390 0x400d943c:0x3ffb53c0 0x400d9472:0x3ffb5420 0x400ee988:0x3ffb5440 0x40087635:0x3ffb5470
--- 0x400dcc4e: mb_port_timer_delete at <project_root>/managed_components/espressif__esp-modbus/modbus/mb_ports/common/port_timer.c:98
--- 0x400dcdce: mbm_rtu_transp_delete at <project_root>/managed_components/espressif__esp-modbus/modbus/mb_transports/rtu/rtu_master.c:108
--- 0x400db065: mbm_delete at <project_root>/managed_components/espressif__esp-modbus/modbus/mb_objects/mb_master.c:279
--- 0x400daf8d: mbc_serial_master_delete at <project_root>/managed_components/espressif__esp-modbus/modbus/mb_controller/serial/mbc_serial_master.c:125
--- 0x400d94c9: mbc_master_delete at <project_root>/managed_components/espressif__esp-modbus/modbus/mb_controller/common/esp_modbus_master.c:25
--- 0x400d943c: master_operation_func at <project_root>/managed_components/espressif__esp-modbus/examples/serial/mb_serial_master/main/serial_master.c:456
--- 0x400d9472: app_main at <project_root>/managed_components/espressif__esp-modbus/examples/serial/mb_serial_master/main/serial_master.c:518
--- 0x400ee988: main_task at <IDF_PATH>/components/freertos/app_startup.c:208
--- 0x40087635: vPortTaskWrapper at <IDF_PATH>/components/freertos/FreeRTOS-Kernel/portable/xtensa/port.c:139

Steps to reproduce the behavior

  1. Enable CONFIG_HEAP_POISONING_COMPREHENSIVE=y in sdkconfig.
  2. Build and flash the Modbus master example located at examples/protocols/modbus/serial/mb_serial_master.
  3. When mbc_master_delete(master_handle) is called, the program crashes.
  4. Observe the heap poisoning violation or crash in the logs.

Project release version

modbus version 2.0.2, idf version v5.5-dev-2119

System architecture

Intel/AMD 64-bit (modern PC, older Mac)

Operating system

Linux

Operating system version

openSUSE Leap 15.6

Shell

ZSH

Additional context

When mbm_rtu_transp_delete(mb_trans_base_t *inst) is called, the mb_port_ser_delete(transp->base.port_obj) function frees port_obj. However, after this memory is freed, the same port_obj is still accessed later in mb_port_timer_delete() and mb_port_event_delete(), causing a use-after-free error. This issue becomes critical especially when HEAP_POISONING_COMPREHENSIVE is enabled, as freed objects are overwritten with patterns like 0xfefefefe instead of zeros, making the problem more apparent.

Calling mb_port_ser_delete(transp->base.port_obj) after mb_port_timer_delete(transp->base.port_obj) and mb_port_event_delete(transp->base.port_obj) solves my problem. However, I have noticed that this function is called in the reverse order (i.e., ser_delete is called first) multiple times throughout the codebase, indicating that the deletion sequence requires a major revision to prevent use-after-free errors reliably.

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions