diff options
author | Oliver Smith <osmith@sysmocom.de> | 2019-06-06 16:11:32 +0200 |
---|---|---|
committer | Oliver Smith <osmith@sysmocom.de> | 2019-06-07 11:01:51 +0200 |
commit | 186f87826608fe43060f446ae6d171cd7c56d27b (patch) | |
tree | bda352effc081a97888a3a899f90f1e75cce4628 | |
parent | 8c9befeaee7df8758a0584a7fdc988ab9afb14af (diff) |
gsm48_decode_bcd_number2: fix ENOSPC edge case
Return ENOSPC if the decoding buffer is one byte too small, instead of
returning 0 and silently truncating the string. Add a new "truncated"
variable to detect if the loop breaks in the final iteration.
The string is not truncated if there is exactly one 0xf ('\0') higher
nibble remaining. This is covered by the existing test case "long
15-digit (maximum) MSISDN, limited buffer".
Related: OS#4049
Change-Id: Ie05900aca50cc7fe8a45d17844dbfcd905fd82fe
-rw-r--r-- | src/gsm/gsm48_ie.c | 16 | ||||
-rw-r--r-- | tests/gsm0408/gsm0408_test.c | 11 | ||||
-rw-r--r-- | tests/gsm0408/gsm0408_test.ok | 4 |
3 files changed, 28 insertions, 3 deletions
diff --git a/src/gsm/gsm48_ie.c b/src/gsm/gsm48_ie.c index 59f931b2..31028ba4 100644 --- a/src/gsm/gsm48_ie.c +++ b/src/gsm/gsm48_ie.c @@ -82,6 +82,7 @@ int gsm48_decode_bcd_number2(char *output, size_t output_len, { uint8_t in_len; int i; + bool truncated = false; if (output_len < 1) return -ENOSPC; *output = '\0'; @@ -94,14 +95,23 @@ int gsm48_decode_bcd_number2(char *output, size_t output_len, for (i = 1 + h_len; i <= in_len; i++) { /* lower nibble */ - if (output_len <= 1) + if (output_len <= 1) { + truncated = true; break; + } *output++ = bcd_num_digits[bcd_lv[i] & 0xf]; output_len--; /* higher nibble */ - if (output_len <= 1) + if (output_len <= 1) { + /* not truncated if there is exactly one 0xf ('\0') higher nibble remaining */ + if (i == in_len && (bcd_lv[i] & 0xf0) == 0xf0) { + break; + } + + truncated = true; break; + } *output++ = bcd_num_digits[bcd_lv[i] >> 4]; output_len--; } @@ -109,7 +119,7 @@ int gsm48_decode_bcd_number2(char *output, size_t output_len, *output++ = '\0'; /* Indicate whether the output was truncated */ - if (i < in_len) + if (truncated) return -ENOSPC; return 0; diff --git a/tests/gsm0408/gsm0408_test.c b/tests/gsm0408/gsm0408_test.c index b5f80614..db1d45ad 100644 --- a/tests/gsm0408/gsm0408_test.c +++ b/tests/gsm0408/gsm0408_test.c @@ -727,6 +727,17 @@ static const struct bcd_number_test { .dec_ascii = "(none)", .dec_rc = -EIO, }, + { + .test_name = "decoding buffer is one byte too small (OS#4049)", + + /* Decoding test */ + .dec_hex = "022143", /* "1234" */ + .dec_ascii = "123", /* '4' was truncated */ + .dec_rc = -ENOSPC, + + /* Buffer length limitations */ + .dec_buf_lim = 4, + }, }; static void test_bcd_number_encode_decode() diff --git a/tests/gsm0408/gsm0408_test.ok b/tests/gsm0408/gsm0408_test.ok index 844c2018..d343869f 100644 --- a/tests/gsm0408/gsm0408_test.ok +++ b/tests/gsm0408/gsm0408_test.ok @@ -186,6 +186,10 @@ BSD number encoding / decoding test - Decoding HEX (buffer limit=0) ''... - Expected: (rc=-5) '(none)' - Actual: (rc=-5) '(none)' +- Running test: decoding buffer is one byte too small (OS#4049) + - Decoding HEX (buffer limit=4) '022143'... + - Expected: (rc=-28) '123' + - Actual: (rc=-28) '123' Constructed RA: 077-121-666-5 |