Skip to content

ESP RTC crash due to valid fragmented OPTIONS request #1611

@stevenoonan

Description

@stevenoonan

Checklist

  • I have read the documentation Espressif Audio Development Framework Guide and the issue is not addressed there.
  • I have updated my ADF and IDF branch (master or release) to the latest version and checked that the issue is present there.
  • I have searched the issue tracker for a similar issue and not found a matching issue for this exact failure mode.

Related issue: #1501

Issue #1501 appears to fix a leading-CRLF OPTIONS parser/double-free path. The crash below looks different: a valid OPTIONS request delivered over TLS in two stream fragments causes sip_receive() to call strcasecmp(NULL, ...) on the second fragment.

Environment

  • Audio development kit: none
  • Audio kit version (for ESP32-LyraT/ESP32-LyraT-Mini/ESP32-S3-Korvo-2): n/a
  • [Required] Module or chip used: ESP32-WROVER-E
  • [Required] IDF version (run git describe --tags in $IDF_PATH folder to find it):
    • v5.3.3
  • [Required] ADF version (run git describe --tags in $ADF_PATH folder to find it):
    • v2.7-based tree pinned to commit 9cf556de500019bb79f3bb84c821fda37668c052
  • Build system: idf.py
  • [Required] Running log: attached below excerpted from monitor output; full log available
  • Compiler version (run xtensa-esp32-elf-gcc --version in your project folder to find it):
    • xtensa-esp-elf-gcc (crosstool-NG esp-13.2.0_20240530) 13.2.0
  • Operating system: Linux
  • (Windows only) Environment type: n/a
  • Using an IDE?: Yes (VS Code dev container)
  • Power supply: USB

Problem Description

We are using esp_rtc over SIP/TLS against Kamailio. The ESP32 crashes reproducibly when Kamailio sends an inbound OPTIONS keepalive and the SIP request arrives split across two TLS reads.

We added TLS adapter logging around the ADF media library boundary and captured the exact inbound signaling. The OPTIONS request is valid, but it is delivered as two stream fragments:

  1. first read contains the request line, Via, and From
  2. second read contains To, Call-ID, CSeq: 80 OPTIONS, and Content-Length: 0

Immediately after the second read, the ESP32 panics in ROM strcasecmp, called from sip_receive() inside esp_rtc_sip.c.

The crash strongly suggests that the parser is treating the second TLS fragment as if it were a fresh SIP message instead of a continuation of the previous one. Because the second fragment begins with To: rather than a request line, the parsed method pointer appears to be null, and sip_receive() ends up executing strcasecmp(NULL, ...).

This is different from issue #1501. That issue discusses leading \r\nOPTIONS and cleanup/double-free behavior. In this case, the inbound request is valid and the trigger is normal TCP/TLS stream fragmentation.

The OPTIONS requests are Kamailio usrloc keepalives, identified by:

  • From: <sip:server@kamailio.org>
  • Call-ID: ksrulka-...
  • CSeq: 80 OPTIONS

Expected Behavior

esp_rtc should correctly reassemble and parse SIP requests received over TLS/TCP even when they arrive across multiple reads. A valid fragmented inbound OPTIONS request should not crash the device.

Actual Behavior

The ESP32 panics with LoadProhibited in ROM strcasecmp immediately after receiving the second fragment of a valid inbound OPTIONS request over TLS.

Backtrace:

  • strcasecmp in ROM
  • sip_receive at /builds/adf/esp-adf-libs-source/esp_media_protocols/esp_rtc/esp_rtc_core/esp_rtc_sip/esp_rtc_sip.c:1977
  • _sip_task at /builds/adf/esp-adf-libs-source/esp_media_protocols/esp_rtc/esp_rtc_core/esp_rtc_sip/esp_rtc_sip.c:2003

Steps to Reproduce

  1. Run an ESP32 firmware using esp_rtc over SIP/TLS.
  2. Register and place a call through Kamailio.
  3. Enable Kamailio usrloc keepalives so it sends inbound OPTIONS requests to the registered TLS contact.
  4. Ensure the inbound OPTIONS request is delivered across multiple TLS reads. This happens naturally in our setup and does not require malformed traffic.
  5. Observe that when the second fragment arrives, the device crashes in sip_receive().

Notes:

Code to Reproduce This Issue

Project-specific SIP service wrapper around esp_rtc:

  • custom firmware based on ESP-IDF + ESP-ADF 2.7
  • SIP/TLS transport
  • esp_rtc_service_init() and normal call flow

The failure appears to be inside the prebuilt ADF SIP/media protocols library rather than in application code. If useful, I can provide a reduced repro project similar to the one attached in issue #1501.

Debug Logs

I (95568) sip_signal: TLS_READ fd=58 peer_port=5061 bytes=221
I (95568) sip_signal: TLS_READ payload=OPTIONS sip:user-id@192.168.x.x:port;transport=TLS SIP/2.0\r\nVia: SIP/2.0/TLS X.X.X.X:5061;branch=z9hG4bKx.REDACTED\r\nFrom: <sip:server@kamailio.org>;tag=uloc-REDACTED\r\n
I (95748) sip_signal: TLS_READ fd=58 peer_port=5061 bytes=116
I (95758) sip_signal: TLS_READ payload=To: <sip:user-id@kamailio.org>\r\nCall-ID: ksrulka-REDACTED\r\nCSeq: 80 OPTIONS\r\nContent-Length: 0\r\n\r\n
Guru Meditation Error: Core  0 panic'ed (LoadProhibited). Exception was unhandled.

PC      : 0x400011da  PS      : 0x00060330  A0      : 0x8013ed03  A1      : 0x3f849fb0
--- 0x400011da: strcasecmp in ROM
A2      : 0x00000000
EXCCAUSE: 0x0000001c
EXCVADDR: 0x00000000

Backtrace: 0x400011d7:0x3f849fb0 0x4013ed00:0x3f849fd0 0x40093a0e:0x3f84a030
--- 0x400011d7: strcasecmp in ROM
--- 0x4013ed00: sip_receive at /builds/adf/esp-adf-libs-source/esp_media_protocols/esp_rtc/esp_rtc_core/esp_rtc_sip/esp_rtc_sip.c:1977
--- (inlined by) _sip_task at /builds/adf/esp-adf-libs-source/esp_media_protocols/esp_rtc/esp_rtc_core/esp_rtc_sip/esp_rtc_sip.c:2003
--- 0x40093a0e: vPortTaskWrapper at /COMPONENT_FREERTOS_DIR/FreeRTOS-Kernel/portable/xtensa/port.c:139

Additional observations:

  • A2 == 0x00000000 at the strcasecmp call site, which is consistent with a null method pointer.
  • The panic happens immediately after the second fragment of the OPTIONS request arrives.
  • This is over TLS, so multi-read delivery is expected and legal.

Notes

If useful, I can also provide the patched libesp_media_protocols.a currently in use

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions