gsm0808_enc_aoip_trasp_addr: add length check
Instead of running into OSMO_ASSERT in msgb_put(), return early if the
msgb is too small. As suggested by Pau in [1].
I would have returned -EMSGSIZE, but the function returns uint8_t.
[1]: https://gerrit.osmocom.org/c/osmo-bsc-nat/+/28582/2#message-a183c463ea20a8d958465ce45a83e62c46214cf6
Change-Id: I632986b99d841abff0f14c6da65f030175f5c4a1
diff --git a/src/gsm/gsm0808_utils.c b/src/gsm/gsm0808_utils.c
index 040872b..f1569c9 100644
--- a/src/gsm/gsm0808_utils.c
+++ b/src/gsm/gsm0808_utils.c
@@ -78,7 +78,7 @@
/*! Encode TS 08.08 AoIP transport address IE
* \param[out] msg Message Buffer to which to append IE
* \param[in] ss Socket Address to be used in IE
- * \returns number of bytes added to \a msg */
+ * \returns number of bytes added to \a msg; 0 if msg is too small */
uint8_t gsm0808_enc_aoip_trasp_addr(struct msgb *msg,
const struct sockaddr_storage *ss)
{
@@ -87,16 +87,27 @@
struct sockaddr_in6 *sin6;
uint16_t port = 0;
uint8_t *ptr;
- uint8_t *old_tail;
- uint8_t *tlv_len;
+ const uint8_t len_tl = 2;
+ uint8_t len_v = sizeof(port);
OSMO_ASSERT(msg);
OSMO_ASSERT(ss);
OSMO_ASSERT(ss->ss_family == AF_INET || ss->ss_family == AF_INET6);
+ switch (ss->ss_family) {
+ case AF_INET:
+ len_v += IP_V4_ADDR_LEN;
+ break;
+ case AF_INET6:
+ len_v += IP_V6_ADDR_LEN;
+ break;
+ }
+
+ if (msgb_tailroom(msg) < len_tl + len_v)
+ return 0;
+
msgb_put_u8(msg, GSM0808_IE_AOIP_TRASP_ADDR);
- tlv_len = msgb_put(msg,1);
- old_tail = msg->tail;
+ msgb_put_u8(msg, len_v);
switch (ss->ss_family) {
case AF_INET:
@@ -114,9 +125,7 @@
}
msgb_put_u16(msg, port);
-
- *tlv_len = (uint8_t) (msg->tail - old_tail);
- return *tlv_len + 2;
+ return len_tl + len_v;
}
/*! Decode TS 08.08 AoIP transport address IE
diff --git a/tests/gsm0808/gsm0808_test.c b/tests/gsm0808/gsm0808_test.c
index 158aeba..b3aa3ab 100644
--- a/tests/gsm0808/gsm0808_test.c
+++ b/tests/gsm0808/gsm0808_test.c
@@ -924,6 +924,28 @@
msgb_free(msg);
}
+static void test_enc_aoip_trasp_addr_msg_too_small()
+{
+ struct msgb *msg;
+ struct sockaddr_storage enc_addr;
+ struct sockaddr_in enc_addr_in;
+ uint8_t rc_enc;
+
+ memset(&enc_addr_in, 0, sizeof(enc_addr_in));
+ enc_addr_in.sin_family = AF_INET;
+ enc_addr_in.sin_port = htons(1234);
+ inet_aton("255.0.255.255", &enc_addr_in.sin_addr);
+
+ memset(&enc_addr, 0, sizeof(enc_addr));
+ memcpy(&enc_addr, &enc_addr_in, sizeof(enc_addr_in));
+
+ msg = msgb_alloc(7, "output buffer");
+ rc_enc = gsm0808_enc_aoip_trasp_addr(msg, &enc_addr);
+ OSMO_ASSERT(rc_enc == 0);
+
+ msgb_free(msg);
+}
+
static void test_gsm0808_enc_dec_speech_codec()
{
struct gsm0808_speech_codec enc_sc = {
@@ -2540,6 +2562,7 @@
test_enc_dec_aoip_trasp_addr_v4();
test_enc_dec_aoip_trasp_addr_v6();
+ test_enc_aoip_trasp_addr_msg_too_small();
test_gsm0808_enc_dec_speech_codec();
test_gsm0808_enc_dec_speech_codec_ext_with_cfg();
test_gsm0808_enc_dec_speech_codec_with_cfg();