Subject: Try to clean this up; the vector code is still fishy Origin: FILE5_30-28-g393555f2 Upstream-Author: Christos Zoulas Date: Mon Mar 27 20:58:11 2017 +0000 [ Also contains the spello fix FILE5_30-10-ga25f230f -CB ] --- a/src/cdf.c +++ b/src/cdf.c @@ -818,6 +818,66 @@ return 0; } +#define CDF_SHLEN_LIMIT (UINT32_MAX / 8) +#define CDF_PROP_LIMIT (UINT32_MAX / (4 * sizeof(cdf_property_info_t))) + +static const void * +cdf_offset(const void *p, size_t l) +{ + return CAST(const void *, CAST(const uint8_t *, p) + l); +} + +static const uint8_t * +cdf_get_property_info_pos(const cdf_stream_t *sst, const cdf_header_t *h, + const uint8_t *p, const uint8_t *e, size_t i) +{ + size_t tail = (i << 1) + 1; + size_t ofs; + const uint8_t *q; + + if (cdf_check_stream_offset(sst, h, p, tail * sizeof(uint32_t), + __LINE__) == -1) + return NULL; + ofs = CDF_GETUINT32(p, tail); + q = CAST(const uint8_t *, cdf_offset(CAST(const void *, p), + ofs - 2 * sizeof(uint32_t))); + + if (q < p) { + DPRINTF(("Wrapped around %p < %p\n", q, p)); + return NULL; + } + + if (q >= e) { + DPRINTF(("Ran off the end %p >= %p\n", q, e)); + return NULL; + } + return q; +} + +static cdf_property_info_t * +cdf_grow_info(cdf_property_info_t **info, size_t *maxcount, size_t incr) +{ + cdf_property_info_t *inp; + size_t newcount = *maxcount + incr; + + if (newcount > CDF_PROP_LIMIT) + goto out; + + inp = CAST(cdf_property_info_t *, + realloc(*info, newcount * sizeof(*inp))); + if (inp == NULL) + goto out; + + *info = inp; + *maxcount = newcount; + return inp; +out: + free(*info); + *maxcount = 0; + *info = NULL; + return NULL; +} + int cdf_read_property_info(const cdf_stream_t *sst, const cdf_header_t *h, uint32_t offs, cdf_property_info_t **info, size_t *count, size_t *maxcount) @@ -831,70 +891,40 @@ int64_t s64; uint64_t u64; cdf_timestamp_t tp; - size_t i, o, o4, nelements, j; + size_t i, o4, nelements, j, slen; cdf_property_info_t *inp; if (offs > UINT32_MAX / 4) { errno = EFTYPE; goto out; } - shp = CAST(const cdf_section_header_t *, (const void *) - ((const char *)sst->sst_tab + offs)); + shp = CAST(const cdf_section_header_t *, + cdf_offset(sst->sst_tab, offs)); if (cdf_check_stream_offset(sst, h, shp, sizeof(*shp), __LINE__) == -1) goto out; sh.sh_len = CDF_TOLE4(shp->sh_len); -#define CDF_SHLEN_LIMIT (UINT32_MAX / 8) if (sh.sh_len > CDF_SHLEN_LIMIT) { errno = EFTYPE; goto out; } sh.sh_properties = CDF_TOLE4(shp->sh_properties); -#define CDF_PROP_LIMIT (UINT32_MAX / (4 * sizeof(*inp))) if (sh.sh_properties > CDF_PROP_LIMIT) goto out; DPRINTF(("section len: %u properties %u\n", sh.sh_len, sh.sh_properties)); - if (*maxcount) { - if (*maxcount > CDF_PROP_LIMIT) - goto out; - *maxcount += sh.sh_properties; - inp = CAST(cdf_property_info_t *, - realloc(*info, *maxcount * sizeof(*inp))); - } else { - *maxcount = sh.sh_properties; - inp = CAST(cdf_property_info_t *, - malloc(*maxcount * sizeof(*inp))); - } + inp = cdf_grow_info(info, maxcount, sh.sh_properties); if (inp == NULL) - goto out1; - *info = inp; + goto out; inp += *count; *count += sh.sh_properties; - p = CAST(const uint8_t *, (const void *) - ((const char *)(const void *)sst->sst_tab + - offs + sizeof(sh))); - e = CAST(const uint8_t *, (const void *) - (((const char *)(const void *)shp) + sh.sh_len)); + p = CAST(const uint8_t *, cdf_offset(sst->sst_tab, offs + sizeof(sh))); + e = CAST(const uint8_t *, cdf_offset(shp, sh.sh_len)); if (cdf_check_stream_offset(sst, h, e, 0, __LINE__) == -1) goto out; + for (i = 0; i < sh.sh_properties; i++) { - size_t tail = (i << 1) + 1; - size_t ofs; - if (cdf_check_stream_offset(sst, h, p, tail * sizeof(uint32_t), - __LINE__) == -1) - goto out; - ofs = CDF_GETUINT32(p, tail); - q = (const uint8_t *)(const void *) - ((const char *)(const void *)p + ofs - - 2 * sizeof(uint32_t)); - if (q < p) { - DPRINTF(("Wrapped around %p < %p\n", q, p)); - goto out; - } - if (q >= e) { - DPRINTF(("Ran of the end %p >= %p\n", q, e)); + if ((q = cdf_get_property_info_pos(sst, h, p, e, i)) == NULL) goto out; - } inp[i].pi_id = CDF_GETUINT32(p, i << 1); inp[i].pi_type = CDF_GETUINT32(q, 0); DPRINTF(("%" SIZE_T_FORMAT "u) id=%x type=%x offs=0x%tx,0x%x\n", @@ -905,12 +935,12 @@ DPRINTF(("CDF_VECTOR with nelements == 0\n")); goto out; } - o = 2; + slen = 2; } else { nelements = 1; - o = 1; + slen = 1; } - o4 = o * sizeof(uint32_t); + o4 = slen * sizeof(uint32_t); if (inp[i].pi_type & (CDF_ARRAY|CDF_BYREF|CDF_RESERVED)) goto unknown; switch (inp[i].pi_type & CDF_TYPEMASK) { @@ -966,16 +996,10 @@ case CDF_LENGTH32_WSTRING: if (nelements > 1) { size_t nelem = inp - *info; - if (*maxcount > CDF_PROP_LIMIT - || nelements > CDF_PROP_LIMIT) - goto out; - *maxcount += nelements; - inp = CAST(cdf_property_info_t *, - realloc(*info, *maxcount * sizeof(*inp))); + inp = cdf_grow_info(info, maxcount, nelements); if (inp == NULL) - goto out1; - *info = inp; - inp = *info + nelem; + goto out; + inp += nelem; } DPRINTF(("nelements = %" SIZE_T_FORMAT "u\n", nelements)); @@ -984,28 +1008,28 @@ { uint32_t l; - if (q + o + sizeof(uint32_t) >= e) + if (q + slen + sizeof(uint32_t) >= e) goto out; - l = CDF_GETUINT32(q, o); + l = CDF_GETUINT32(q, slen); o4 += sizeof(uint32_t); - if (q + o4 + l >= e) + if (o4 + l > CAST(size_t, e - q)) goto out; inp[i].pi_str.s_len = l; inp[i].pi_str.s_buf = CAST(const char *, CAST(const void *, &q[o4])); - DPRINTF(("l = %d, r = %" SIZE_T_FORMAT - "u, s = %s\n", l, - CDF_ROUND(l, sizeof(l)), + DPRINTF(("o=%zu l=%d(%" SIZE_T_FORMAT + "u), t=%td s=%s\n", o4, l, + CDF_ROUND(l, sizeof(l)), e - q, inp[i].pi_str.s_buf)); if (l & 1) l++; - o += l >> 1; - o4 = o * sizeof(uint32_t); + slen += l >> 1; + o4 = slen * sizeof(uint32_t); } i--; break; @@ -1029,8 +1053,6 @@ return 0; out: errno = EFTYPE; -out1: - free(*info); return -1; }