CVE-2026-49759
Description
Erlang OTP's inet_drv contains a stack buffer overflow in SCTP error chunk parsing, allowing remote attackers to crash the VM.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Erlang OTP's inet_drv contains a stack buffer overflow in SCTP error chunk parsing, allowing remote attackers to crash the VM.
Vulnerability
Erlang OTP's inet_drv contains a stack-based buffer overflow vulnerability in the sctp_parse_error_chunk function located in erts/emulator/drivers/common/inet_drv.c. This function parses SCTP ERROR chunks and writes cause codes into a fixed-size stack-allocated array without proper bounds checking. This vulnerability affects OTP versions from OTP 17.0 before 27.3.4.13, 28.5.0.2, and 29.0.2 [3].
Exploitation
An unauthenticated remote attacker can exploit this vulnerability by establishing an SCTP association to a listening port and then sending a single crafted SCTP ERROR chunk containing sufficient cause codes to overflow the stack buffer. This action is required to trigger the crash [3, 4].
Impact
Successful exploitation of this vulnerability leads to a Denial of Service by crashing the Erlang BEAM VM. While the overflow does not provide a controlled return address for Remote Code Execution, a crafted chunk may also leak small amounts of Erlang VM memory into the received error packet, though this data is typically already readable by the system user running the VM [3, 4].
Mitigation
This vulnerability is fixed in OTP versions 27.3.4.13, 28.5.0.2, and 29.0.2. There are no workarounds other than avoiding the opening of an SCTP listening socket on a network reachable by attackers. Running a VM built with standard stack protection is also recommended [4].
AI Insight generated on Jun 10, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
3Patches
13983d4952843Protect the output term buffer from overflow
1 file changed · +34 −18
erts/emulator/drivers/common/inet_drv.c+34 −18 modified@@ -3392,7 +3392,7 @@ static int sctp_parse_ancillary_data ** concerns the protocol implementation), so we omit it: */ static int sctp_parse_error_chunk - (ErlDrvTermData * spec, int i, char * chunk, int chlen) + (ErlDrvTermData * spec, int i, int spec_size, char * chunk, int chlen) { /* The "chunk" itself contains its length, which must not be greater than the "chlen" derived from the over-all msg size: @@ -3415,16 +3415,26 @@ static int sctp_parse_error_chunk { ccode = sock_ntohs (*((uint16_t*)(cause))); clen = sock_ntohs (*((uint16_t*)(cause + 2))); - if (clen <= 0) - /* Strange, but must guard against that! */ - break; - - /* Install the corresp atom for this "ccode": */ + /* Install the corresp atom for this "ccode": */ i = LOAD_INT (spec, i, ccode); + s ++; + if (clen <= 0 || /* Overflow - truncate here */ + i + 2*LOAD_INT_CNT+LOAD_NIL_CNT+LOAD_LIST_CNT > spec_size) + /* We do not have room for two INT:s which is + * the worst case for the next iteration, so truncate now. + * + * We should have room for the truncation marker since + * we have added at most one INT after the previous check. + */ { + i = LOAD_INT (spec, i, 0); + /* Truncation marker - there is no error 0 */ + s ++; + break; + } cause += clen; coff += clen; - s ++; } + /* Finalize the list */ i = LOAD_NIL (spec, i); i = LOAD_LIST(spec, i, s+1); return i; @@ -3435,7 +3445,7 @@ static int sctp_parse_error_chunk ** are sent IN PLACE OF, not in conjunction with, the normal data: */ static int sctp_parse_async_event - (ErlDrvTermData * spec, int i, int ok_pos, + (ErlDrvTermData * spec, int i, int spec_size, int ok_pos, ErlDrvTermData error_atom, inet_descriptor* desc, ErlDrvBinary * bin, int offs, int sz) { @@ -3569,7 +3579,7 @@ static int sctp_parse_async_event + sizeof(sptr->sre_assoc_id); # endif chlen = sptr->sre_length - (chunk - (char *)sptr); - i = sctp_parse_error_chunk(spec, i, chunk, chlen); + i = sctp_parse_error_chunk(spec, i, spec_size, chunk, chlen); i = LOAD_TUPLE (spec, i, 4); /* The {error, {...}} will be closed by the caller */ @@ -3809,6 +3819,7 @@ inet_async_binary_data ErlDrvBinary * bin, int offs, int len, void *mp) { unsigned int hsz = desc->hsz + phsz; + const int spec_size = PACKET_ERL_DRV_TERM_DATA_LEN; ErlDrvTermData spec [PACKET_ERL_DRV_TERM_DATA_LEN]; ErlDrvTermData caller; int aid; @@ -3859,7 +3870,8 @@ inet_async_binary_data condition; in the latter case, the 'ok' above is overridden by an 'error', and the Event we receive contains the error term: */ i = sctp_parse_async_event - (spec, i, ok_pos, am_error, desc, bin, offs+hsz, sz); + (spec, i, spec_size - 3*LOAD_TUPLE_CNT, + ok_pos, am_error, desc, bin, offs+hsz, sz); else /* This is SCTP data, not a notification event. The data can be returned as a List or as a Binary, similar to the generic case: @@ -4045,6 +4057,7 @@ static int packet_binary_message(inet_descriptor* desc, void *mp) { unsigned int hsz = desc->hsz; + const int spec_size = PACKET_ERL_DRV_TERM_DATA_LEN; ErlDrvTermData spec [PACKET_ERL_DRV_TERM_DATA_LEN]; int i = 0; int alen; @@ -4107,14 +4120,16 @@ static int packet_binary_message(inet_descriptor* desc, i = sctp_parse_ancillary_data (spec, i, mptr); /* Then: Data or Event (Notification)? */ - if (mptr->msg_flags & MSG_NOTIFICATION) + if (mptr->msg_flags & MSG_NOTIFICATION) { /* This is an Event, parse it. It may indicate a normal or an error condition; in the latter case, the initial 'sctp' atom is over- ridden by 'sctp_error', and the Event we receive contains the error term: */ i = sctp_parse_async_event - (spec, i, 0, am_sctp_error, desc, bin, offs, len); - else + (spec, i, spec_size - 2*LOAD_TUPLE_CNT, + 0, am_sctp_error, desc, bin, offs, len); + } + else { /* This is SCTP data, not a notification event. The data can be returned as a List or as a Binary, similar to the generic case: */ @@ -4126,6 +4141,7 @@ static int packet_binary_message(inet_descriptor* desc, else /* INET_MODE_BINARY => Binary */ i = LOAD_BINARY(spec, i, bin, offs, len); + } /* Close up the {[AncilData], Event_OR_Data} tuple: */ i = LOAD_TUPLE (spec, i, 2); @@ -9497,8 +9513,8 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc, int i = 0; int length = 0; /* Number of result list entries */ - int spec_allocated = PACKET_ERL_DRV_TERM_DATA_LEN; - spec = ALLOC(sizeof(* spec) * spec_allocated); + int spec_size = PACKET_ERL_DRV_TERM_DATA_LEN; + spec = ALLOC(sizeof(* spec) * spec_size); # define RETURN_ERROR(Spec, Errno) \ do { \ @@ -9510,18 +9526,18 @@ static ErlDrvSSizeT sctp_fill_opts(inet_descriptor* desc, # define PLACE_FOR(Spec, Index, N) \ do { \ int need; \ - if ((Index) > spec_allocated) { \ + if ((Index) > spec_size) { \ erts_exit(ERTS_ERROR_EXIT,"Internal error in inet_drv, " \ "miscalculated buffer size"); \ } \ need = (Index) + (N); \ if (need > INET_MAX_OPT_BUFFER/sizeof(ErlDrvTermData)) {\ RETURN_ERROR((Spec), -ENOMEM); \ } \ - if (need > spec_allocated) { \ + if (need > spec_size) { \ (Spec) = REALLOC((Spec), \ sizeof(* (Spec)) \ - * (spec_allocated = need + 20)); \ + * (spec_size = need + 20)); \ } \ } while (0)
Vulnerability mechanics
Root cause
"The sctp_parse_error_chunk function does not validate the size of SCTP ERROR chunk cause codes before writing them to a fixed-size stack buffer."
Attack vector
An unauthenticated remote attacker must establish an SCTP association to a listening port on the target system. The attacker then sends a single, crafted SCTP ERROR chunk containing sufficient cause codes to overflow the stack buffer in the `sctp_parse_error_chunk` function. This overflow causes the Erlang VM to crash, leading to a denial-of-service condition [ref_id=2].
Affected code
The vulnerability resides in the `sctp_parse_error_chunk` function located in `erts/emulator/drivers/common/inet_drv.c`. This function is responsible for parsing SCTP ERROR chunks and writing cause codes into a stack-allocated buffer without proper bounds checking.
What the fix does
The patch introduces an overflow check within the loop that parses SCTP ERROR chunks in the `sctp_parse_error_chunk` function [patch_id=5502027]. This check ensures that the total size of the parsed cause codes does not exceed the allocated buffer size (`spec_size`). By truncating the data when an overflow is detected, the vulnerability is mitigated, preventing the stack buffer overflow and subsequent VM crash [ref_id=1].
Preconditions
- configSCTP support must be compiled into Erlang OTP.
- networkA listening SCTP socket must be open and reachable from the attacker's network.
Generated on Jun 10, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
5News mentions
1- Erlang OTP: Seven Vulnerabilities Disclosed, Including High-Severity FlawsVypr Intelligence · Jun 10, 2026