diff --git a/src/ncp/spinel.c b/src/ncp/spinel.c index d50e03c0d..f746befd0 100644 --- a/src/ncp/spinel.c +++ b/src/ncp/spinel.c @@ -128,6 +128,8 @@ typedef struct { va_list obj; } va_list_obj; +#define SPINEL_MAX_PACK_LENGTH 32767 + // ---------------------------------------------------------------------------- // MARK: - @@ -247,6 +249,9 @@ spinel_datatype_vunpack_(bool in_place, const uint8_t *data_ptr, spinel_size_t d { spinel_ssize_t ret = 0; + // Buffer length sanity check + require_action(data_len <= SPINEL_MAX_PACK_LENGTH, bail, (ret = -1, errno = EINVAL)); + for (; *pack_format != 0; pack_format = spinel_next_packed_datatype(pack_format)) { if (*pack_format == ')') @@ -425,9 +430,18 @@ spinel_datatype_vunpack_(bool in_place, const uint8_t *data_ptr, spinel_size_t d case SPINEL_DATATYPE_UTF8_C: { - size_t len = strnlen((const char *)data_ptr, data_len) + 1; + size_t len; - require_action((len <= data_len) || (data_ptr[data_len - 1] != 0), bail, (ret = -1, errno = EOVERFLOW)); + // Make sure we have at least one byte. + require_action(data_len > 0, bail, (ret = -1, errno = EOVERFLOW)); + + // Add 1 for zero termination. If not zero terminated, + // len will then be data_len+1, which we will detect + // in the next check. + len = strnlen((const char *)data_ptr, data_len) + 1; + + // Verify that the string is zero terminated. + require_action(len <= data_len, bail, (ret = -1, errno = EOVERFLOW)); if (in_place) { @@ -630,6 +644,9 @@ spinel_datatype_vpack_(uint8_t *data_ptr, spinel_size_t data_len_max, const char { spinel_ssize_t ret = 0; + // Buffer length sanity check + require_action(data_len_max <= SPINEL_MAX_PACK_LENGTH, bail, (ret = -1, errno = EINVAL)); + for (; *pack_format != 0; pack_format = spinel_next_packed_datatype(pack_format)) { if (*pack_format == ')') @@ -2029,6 +2046,27 @@ main(void) goto bail; } + { + const char *str = NULL; + + // Length ends right before the string. + len = spinel_datatype_unpack(buffer, 8, "CiiLU", NULL, NULL, NULL, NULL, &str); + + if (len != -1) + { + printf("error:%d: len != -1; (%d)\n", __LINE__, (int)len); + goto bail; + } + + if (str != NULL) + { + printf("error:%d: str != NULL\n", __LINE__); + goto bail; + } + } + + len = 30; + { uint8_t c = 0; unsigned int i1 = 0;