|
@@ -32,7 +32,7 @@
|
|
|
#include "file.h"
|
|
|
|
|
|
#ifndef lint
|
|
|
-FILE_RCSID("@(#)$File: cdf.c,v 1.22 2009/04/30 21:03:26 christos Exp $")
|
|
|
+FILE_RCSID("@(#)$File: cdf.c,v 1.26 2009/05/02 20:06:55 christos Exp $")
|
|
|
#endif
|
|
|
|
|
|
#include <assert.h>
|
|
@@ -268,10 +268,21 @@ cdf_read_header(const cdf_info_t *info, cdf_header_t *h)
|
|
|
DPRINTF(("Bad magic 0x%llx != 0x%llx\n",
|
|
|
(unsigned long long)h->h_magic,
|
|
|
(unsigned long long)CDF_MAGIC));
|
|
|
- errno = EFTYPE;
|
|
|
- return -1;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ if (h->h_sec_size_p2 > 20) {
|
|
|
+ DPRINTF(("Bad sector size 0x%u\n", h->h_sec_size_p2));
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ if (h->h_short_sec_size_p2 > 20) {
|
|
|
+ DPRINTF(("Bad short sector size 0x%u\n",
|
|
|
+ h->h_short_sec_size_p2));
|
|
|
+ goto out;
|
|
|
}
|
|
|
return 0;
|
|
|
+out:
|
|
|
+ errno = EFTYPE;
|
|
|
+ return -1;
|
|
|
}
|
|
|
|
|
|
|
|
@@ -302,14 +313,23 @@ cdf_read_sat(const cdf_info_t *info, cdf_header_t *h, cdf_sat_t *sat)
|
|
|
{
|
|
|
size_t i, j, k;
|
|
|
size_t ss = CDF_SEC_SIZE(h);
|
|
|
- cdf_secid_t *msa, mid;
|
|
|
+ cdf_secid_t *msa, mid, sec;
|
|
|
size_t nsatpersec = (ss / sizeof(mid)) - 1;
|
|
|
|
|
|
for (i = 0; i < __arraycount(h->h_master_sat); i++)
|
|
|
if (h->h_master_sat[i] == CDF_SECID_FREE)
|
|
|
break;
|
|
|
|
|
|
- sat->sat_len = h->h_num_sectors_in_master_sat + i;
|
|
|
+#define CDF_SEC_LIMIT (UINT32_MAX / (4 * ss))
|
|
|
+ if (h->h_num_sectors_in_master_sat > CDF_SEC_LIMIT ||
|
|
|
+ i > CDF_SEC_LIMIT / nsatpersec) {
|
|
|
+ DPRINTF(("Number of sectors in master SAT too big %u %zu\n",
|
|
|
+ h->h_num_sectors_in_master_sat, i));
|
|
|
+ errno = EFTYPE;
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ sat->sat_len = h->h_num_sectors_in_master_sat + i * nsatpersec;
|
|
|
DPRINTF(("sat_len = %zu ss = %zu\n", sat->sat_len, ss));
|
|
|
if ((sat->sat_tab = calloc(sat->sat_len, ss)) == NULL)
|
|
|
return -1;
|
|
@@ -339,8 +359,19 @@ cdf_read_sat(const cdf_info_t *info, cdf_header_t *h, cdf_sat_t *sat)
|
|
|
goto out2;
|
|
|
}
|
|
|
for (k = 0; k < nsatpersec; k++, i++) {
|
|
|
+ sec = CDF_TOLE4(msa[k]);
|
|
|
+ if (sec < 0) {
|
|
|
+ sat->sat_len = i;
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ if (i >= sat->sat_len) {
|
|
|
+ DPRINTF(("Out of bounds reading MSA %u >= %u",
|
|
|
+ i, sat->sat_len));
|
|
|
+ errno = EFTYPE;
|
|
|
+ goto out2;
|
|
|
+ }
|
|
|
if (cdf_read_sector(info, sat->sat_tab, ss * i, ss, h,
|
|
|
- CDF_TOLE4(msa[k])) != (ssize_t)ss) {
|
|
|
+ sec) != (ssize_t)ss) {
|
|
|
DPRINTF(("Reading sector %d",
|
|
|
CDF_TOLE4(msa[k])));
|
|
|
goto out2;
|
|
@@ -399,6 +430,17 @@ cdf_read_long_sector_chain(const cdf_info_t *info, const cdf_header_t *h,
|
|
|
return -1;
|
|
|
|
|
|
for (j = i = 0; sid >= 0; i++, j++) {
|
|
|
+ if (j >= CDF_LOOP_LIMIT) {
|
|
|
+ DPRINTF(("Read long sector chain loop limit"));
|
|
|
+ errno = EFTYPE;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+ if (i >= scn->sst_len) {
|
|
|
+ DPRINTF(("Out of bounds reading long sector chain "
|
|
|
+ "%u > %u\n", i, scn->sst_len));
|
|
|
+ errno = EFTYPE;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
if ((nr = cdf_read_sector(info, scn->sst_tab, i * ss, ss, h,
|
|
|
sid)) != (ssize_t)ss) {
|
|
|
if (i == scn->sst_len - 1 && nr > 0) {
|
|
@@ -409,11 +451,6 @@ cdf_read_long_sector_chain(const cdf_info_t *info, const cdf_header_t *h,
|
|
|
goto out;
|
|
|
}
|
|
|
sid = CDF_TOLE4(sat->sat_tab[sid]);
|
|
|
- if (j >= CDF_LOOP_LIMIT) {
|
|
|
- DPRINTF(("Read long sector chain loop limit"));
|
|
|
- errno = EFTYPE;
|
|
|
- goto out;
|
|
|
- }
|
|
|
}
|
|
|
return 0;
|
|
|
out:
|
|
@@ -443,6 +480,12 @@ cdf_read_short_sector_chain(const cdf_header_t *h,
|
|
|
errno = EFTYPE;
|
|
|
goto out;
|
|
|
}
|
|
|
+ if (i >= scn->sst_len) {
|
|
|
+ DPRINTF(("Out of bounds reading short sector chain "
|
|
|
+ "%u > %u\n", i, scn->sst_len));
|
|
|
+ errno = EFTYPE;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
if (cdf_read_short_sector(sst, scn->sst_tab, i * ss, ss, h,
|
|
|
sid) != (ssize_t)ss) {
|
|
|
DPRINTF(("Reading short sector chain %d", sid));
|
|
@@ -544,6 +587,12 @@ cdf_read_ssat(const cdf_info_t *info, const cdf_header_t *h,
|
|
|
errno = EFTYPE;
|
|
|
goto out;
|
|
|
}
|
|
|
+ if (i >= ssat->sat_len) {
|
|
|
+ DPRINTF(("Out of bounds reading short sector chain "
|
|
|
+ "%u > %u\n", i, ssat->sat_len));
|
|
|
+ errno = EFTYPE;
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
if (cdf_read_sector(info, ssat->sat_tab, i * ss, ss, h, sid) !=
|
|
|
(ssize_t)ss) {
|
|
|
DPRINTF(("Reading short sat sector %d", sid));
|
|
@@ -640,9 +689,14 @@ cdf_read_property_info(const cdf_stream_t *sst, uint32_t offs,
|
|
|
shp = (const void *)((const char *)sst->sst_tab + offs);
|
|
|
sh.sh_len = CDF_TOLE4(shp->sh_len);
|
|
|
sh.sh_properties = CDF_TOLE4(shp->sh_properties);
|
|
|
- DPRINTF(("section len: %d properties %d\n", sh.sh_len,
|
|
|
+#define CDF_PROP_LIM (UINT32_MAX / (4 * sizeof(*inp)))
|
|
|
+ if (sh.sh_properties > CDF_PROP_LIM)
|
|
|
+ goto out;
|
|
|
+ DPRINTF(("section len: %u properties %u\n", sh.sh_len,
|
|
|
sh.sh_properties));
|
|
|
if (*maxcount) {
|
|
|
+ if (*maxcount > CDF_PROP_LIM)
|
|
|
+ goto out;
|
|
|
*maxcount += sh.sh_properties;
|
|
|
inp = realloc(*info, *maxcount * sizeof(*inp));
|
|
|
} else {
|
|
@@ -713,6 +767,9 @@ cdf_read_property_info(const cdf_stream_t *sst, uint32_t offs,
|
|
|
case CDF_LENGTH32_STRING:
|
|
|
if (nelements > 1) {
|
|
|
size_t nelem = inp - *info;
|
|
|
+ if (*maxcount > CDF_PROP_LIM
|
|
|
+ || nelements > CDF_PROP_LIM)
|
|
|
+ goto out;
|
|
|
*maxcount += nelements;
|
|
|
inp = realloc(*info, *maxcount * sizeof(*inp));
|
|
|
if (inp == NULL)
|