diff options
Diffstat (limited to 'src/cdf.c')
-rw-r--r-- | src/cdf.c | 593 |
1 files changed, 376 insertions, 217 deletions
@@ -35,7 +35,7 @@ #include "file.h" #ifndef lint -FILE_RCSID("@(#)$File: cdf.c,v 1.69 2014/12/04 15:56:46 christos Exp $") +FILE_RCSID("@(#)$File: cdf.c,v 1.106 2017/04/30 17:05:02 christos Exp $") #endif #include <assert.h> @@ -73,10 +73,41 @@ static union { #define CDF_TOLE8(x) ((uint64_t)(NEED_SWAP ? _cdf_tole8(x) : (uint64_t)(x))) #define CDF_TOLE4(x) ((uint32_t)(NEED_SWAP ? _cdf_tole4(x) : (uint32_t)(x))) #define CDF_TOLE2(x) ((uint16_t)(NEED_SWAP ? _cdf_tole2(x) : (uint16_t)(x))) -#define CDF_TOLE(x) (sizeof(x) == 2 ? CDF_TOLE2(x) : (sizeof(x) == 4 ? \ - CDF_TOLE4(x) : CDF_TOLE8(x))) +#define CDF_TOLE(x) (/*CONSTCOND*/sizeof(x) == 2 ? \ + CDF_TOLE2(CAST(uint16_t, x)) : \ + (/*CONSTCOND*/sizeof(x) == 4 ? \ + CDF_TOLE4(CAST(uint32_t, x)) : \ + CDF_TOLE8(CAST(uint64_t, x)))) #define CDF_GETUINT32(x, y) cdf_getuint32(x, y) +#define CDF_MALLOC(n) cdf_malloc(__FILE__, __LINE__, (n)) +#define CDF_REALLOC(p, n) cdf_realloc(__FILE__, __LINE__, (p), (n)) +#define CDF_CALLOC(n, u) cdf_calloc(__FILE__, __LINE__, (n), (u)) + + +static void * +cdf_malloc(const char *file __attribute__((__unused__)), + size_t line __attribute__((__unused__)), size_t n) +{ + DPRINTF(("%s,%zu: %s %zu\n", file, line, __func__, n)); + return malloc(n); +} + +static void * +cdf_realloc(const char *file __attribute__((__unused__)), + size_t line __attribute__((__unused__)), void *p, size_t n) +{ + DPRINTF(("%s,%zu: %s %zu\n", file, line, __func__, n)); + return realloc(p, n); +} + +static void * +cdf_calloc(const char *file __attribute__((__unused__)), + size_t line __attribute__((__unused__)), size_t n, size_t u) +{ + DPRINTF(("%s,%zu: %s %zu %zu\n", file, line, __func__, n, u)); + return calloc(n, u); +} /* * swap a short @@ -263,15 +294,34 @@ cdf_unpack_dir(cdf_directory_t *d, char *buf) CDF_UNPACK(d->d_unused0); } +int +cdf_zero_stream(cdf_stream_t *scn) +{ + scn->sst_len = 0; + scn->sst_dirlen = 0; + scn->sst_ss = 0; + free(scn->sst_tab); + scn->sst_tab = NULL; + return -1; +} + +static size_t +cdf_check_stream(const cdf_stream_t *sst, const cdf_header_t *h) +{ + size_t ss = sst->sst_dirlen < h->h_min_size_standard_stream ? + CDF_SHORT_SEC_SIZE(h) : CDF_SEC_SIZE(h); + assert(ss == sst->sst_ss); + return sst->sst_ss; +} + static int cdf_check_stream_offset(const cdf_stream_t *sst, const cdf_header_t *h, const void *p, size_t tail, int line) { const char *b = (const char *)sst->sst_tab; const char *e = ((const char *)p) + tail; - size_t ss = sst->sst_dirlen < h->h_min_size_standard_stream ? - CDF_SHORT_SEC_SIZE(h) : CDF_SEC_SIZE(h); - (void)&line; + size_t ss = cdf_check_stream(sst, h); + /*LINTED*/(void)&line; if (e >= b && (size_t)(e - b) <= ss * sst->sst_len) return 0; DPRINTF(("%d: offset begin %p < end %p || %" SIZE_T_FORMAT "u" @@ -287,10 +337,8 @@ cdf_read(const cdf_info_t *info, off_t off, void *buf, size_t len) { size_t siz = (size_t)off + len; - if ((off_t)(off + len) != (off_t)siz) { - errno = EINVAL; - return -1; - } + if ((off_t)(off + len) != (off_t)siz) + goto out; if (info->i_buf != NULL && info->i_len >= siz) { (void)memcpy(buf, &info->i_buf[off], len); @@ -298,12 +346,15 @@ cdf_read(const cdf_info_t *info, off_t off, void *buf, size_t len) } if (info->i_fd == -1) - return -1; + goto out; if (pread(info->i_fd, buf, len, off) != (ssize_t)len) return -1; return (ssize_t)len; +out: + errno = EINVAL; + return -1; } int @@ -317,18 +368,18 @@ cdf_read_header(const cdf_info_t *info, cdf_header_t *h) cdf_unpack_header(h, buf); cdf_swap_header(h); if (h->h_magic != CDF_MAGIC) { - DPRINTF(("Bad magic 0x%" INT64_T_FORMAT "x != 0x%" + DPRINTF(("Bad magic %#" INT64_T_FORMAT "x != %#" INT64_T_FORMAT "x\n", (unsigned long long)h->h_magic, (unsigned long long)CDF_MAGIC)); goto out; } if (h->h_sec_size_p2 > 20) { - DPRINTF(("Bad sector size 0x%u\n", h->h_sec_size_p2)); + DPRINTF(("Bad sector size %hu\n", h->h_sec_size_p2)); goto out; } if (h->h_short_sec_size_p2 > 20) { - DPRINTF(("Bad short sector size 0x%u\n", + DPRINTF(("Bad short sector size %hu\n", h->h_short_sec_size_p2)); goto out; } @@ -360,11 +411,14 @@ cdf_read_short_sector(const cdf_stream_t *sst, void *buf, size_t offs, DPRINTF(("Out of bounds read %" SIZE_T_FORMAT "u > %" SIZE_T_FORMAT "u\n", pos + len, CDF_SEC_SIZE(h) * sst->sst_len)); - return -1; + goto out; } (void)memcpy(((char *)buf) + offs, ((const char *)sst->sst_tab) + pos, len); return len; +out: + errno = EFTYPE; + return -1; } /* @@ -382,7 +436,7 @@ cdf_read_sat(const cdf_info_t *info, cdf_header_t *h, cdf_sat_t *sat) if (h->h_master_sat[i] == CDF_SECID_FREE) break; -#define CDF_SEC_LIMIT (UINT32_MAX / (4 * ss)) +#define CDF_SEC_LIMIT (UINT32_MAX / (8 * ss)) if ((nsatpersec > 0 && h->h_num_sectors_in_master_sat > CDF_SEC_LIMIT / nsatpersec) || i > CDF_SEC_LIMIT) { @@ -395,7 +449,7 @@ cdf_read_sat(const cdf_info_t *info, cdf_header_t *h, cdf_sat_t *sat) sat->sat_len = h->h_num_sectors_in_master_sat * nsatpersec + i; DPRINTF(("sat_len = %" SIZE_T_FORMAT "u ss = %" SIZE_T_FORMAT "u\n", sat->sat_len, ss)); - if ((sat->sat_tab = CAST(cdf_secid_t *, calloc(sat->sat_len, ss))) + if ((sat->sat_tab = CAST(cdf_secid_t *, CDF_CALLOC(sat->sat_len, ss))) == NULL) return -1; @@ -409,7 +463,7 @@ cdf_read_sat(const cdf_info_t *info, cdf_header_t *h, cdf_sat_t *sat) } } - if ((msa = CAST(cdf_secid_t *, calloc(1, ss))) == NULL) + if ((msa = CAST(cdf_secid_t *, CDF_CALLOC(1, ss))) == NULL) goto out1; mid = h->h_secid_first_sector_in_master_sat; @@ -418,8 +472,7 @@ cdf_read_sat(const cdf_info_t *info, cdf_header_t *h, cdf_sat_t *sat) goto out; if (j >= CDF_LOOP_LIMIT) { DPRINTF(("Reading master sector loop limit")); - errno = EFTYPE; - goto out2; + goto out3; } if (cdf_read_sector(info, msa, 0, ss, h, mid) != (ssize_t)ss) { DPRINTF(("Reading master sector %d", mid)); @@ -432,8 +485,7 @@ cdf_read_sat(const cdf_info_t *info, cdf_header_t *h, cdf_sat_t *sat) if (i >= sat->sat_len) { DPRINTF(("Out of bounds reading MSA %" SIZE_T_FORMAT "u >= %" SIZE_T_FORMAT "u", i, sat->sat_len)); - errno = EFTYPE; - goto out2; + goto out3; } if (cdf_read_sector(info, sat->sat_tab, ss * i, ss, h, sec) != (ssize_t)ss) { @@ -448,6 +500,8 @@ out: sat->sat_len = i; free(msa); return 0; +out3: + errno = EFTYPE; out2: free(msa); out1: @@ -473,23 +527,24 @@ cdf_count_chain(const cdf_sat_t *sat, cdf_secid_t sid, size_t size) DPRINTF((" %d", sid)); if (j >= CDF_LOOP_LIMIT) { DPRINTF(("Counting chain loop limit")); - errno = EFTYPE; - return (size_t)-1; + goto out; } if (sid >= maxsector) { DPRINTF(("Sector %d >= %d\n", sid, maxsector)); - errno = EFTYPE; - return (size_t)-1; + goto out; } sid = CDF_TOLE4((uint32_t)sat->sat_tab[sid]); } if (i == 0) { DPRINTF((" none, sid: %d\n", sid)); - return (size_t)-1; + goto out; } DPRINTF(("\n")); return i; +out: + errno = EFTYPE; + return (size_t)-1; } int @@ -498,27 +553,30 @@ cdf_read_long_sector_chain(const cdf_info_t *info, const cdf_header_t *h, { size_t ss = CDF_SEC_SIZE(h), i, j; ssize_t nr; + scn->sst_tab = NULL; scn->sst_len = cdf_count_chain(sat, sid, ss); - scn->sst_dirlen = len; + scn->sst_dirlen = MAX(h->h_min_size_standard_stream, len); + scn->sst_ss = ss; + + if (sid == CDF_SECID_END_OF_CHAIN || len == 0) + return cdf_zero_stream(scn); if (scn->sst_len == (size_t)-1) - return -1; + goto out; - scn->sst_tab = calloc(scn->sst_len, ss); + scn->sst_tab = CDF_CALLOC(scn->sst_len, ss); if (scn->sst_tab == NULL) - return -1; + return cdf_zero_stream(scn); 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 " "%" SIZE_T_FORMAT "u > %" SIZE_T_FORMAT "u\n", i, scn->sst_len)); - errno = EFTYPE; goto out; } if ((nr = cdf_read_sector(info, scn->sst_tab, i * ss, ss, h, @@ -534,8 +592,8 @@ cdf_read_long_sector_chain(const cdf_info_t *info, const cdf_header_t *h, } return 0; out: - free(scn->sst_tab); - return -1; + errno = EFTYPE; + return cdf_zero_stream(scn); } int @@ -544,27 +602,27 @@ cdf_read_short_sector_chain(const cdf_header_t *h, cdf_secid_t sid, size_t len, cdf_stream_t *scn) { size_t ss = CDF_SHORT_SEC_SIZE(h), i, j; + scn->sst_tab = NULL; scn->sst_len = cdf_count_chain(ssat, sid, CDF_SEC_SIZE(h)); scn->sst_dirlen = len; + scn->sst_ss = ss; - if (sst->sst_tab == NULL || scn->sst_len == (size_t)-1) - return -1; + if (scn->sst_len == (size_t)-1) + goto out; - scn->sst_tab = calloc(scn->sst_len, ss); + scn->sst_tab = CDF_CALLOC(scn->sst_len, ss); if (scn->sst_tab == NULL) - return -1; + return cdf_zero_stream(scn); for (j = i = 0; sid >= 0; i++, j++) { if (j >= CDF_LOOP_LIMIT) { DPRINTF(("Read short sector chain loop limit")); - errno = EFTYPE; goto out; } if (i >= scn->sst_len) { DPRINTF(("Out of bounds reading short sector chain " "%" SIZE_T_FORMAT "u > %" SIZE_T_FORMAT "u\n", i, scn->sst_len)); - errno = EFTYPE; goto out; } if (cdf_read_short_sector(sst, scn->sst_tab, i * ss, ss, h, @@ -576,8 +634,8 @@ cdf_read_short_sector_chain(const cdf_header_t *h, } return 0; out: - free(scn->sst_tab); - return -1; + errno = EFTYPE; + return cdf_zero_stream(scn); } int @@ -610,11 +668,11 @@ cdf_read_dir(const cdf_info_t *info, const cdf_header_t *h, dir->dir_len = ns * nd; dir->dir_tab = CAST(cdf_directory_t *, - calloc(dir->dir_len, sizeof(dir->dir_tab[0]))); + CDF_CALLOC(dir->dir_len, sizeof(dir->dir_tab[0]))); if (dir->dir_tab == NULL) return -1; - if ((buf = CAST(char *, malloc(ss))) == NULL) { + if ((buf = CAST(char *, CDF_MALLOC(ss))) == NULL) { free(dir->dir_tab); return -1; } @@ -622,7 +680,6 @@ cdf_read_dir(const cdf_info_t *info, const cdf_header_t *h, for (j = i = 0; i < ns; i++, j++) { if (j >= CDF_LOOP_LIMIT) { DPRINTF(("Read dir loop limit")); - errno = EFTYPE; goto out; } if (cdf_read_sector(info, buf, 0, ss, h, sid) != (ssize_t)ss) { @@ -643,6 +700,7 @@ cdf_read_dir(const cdf_info_t *info, const cdf_header_t *h, out: free(dir->dir_tab); free(buf); + errno = EFTYPE; return -1; } @@ -655,36 +713,37 @@ cdf_read_ssat(const cdf_info_t *info, const cdf_header_t *h, size_t ss = CDF_SEC_SIZE(h); cdf_secid_t sid = h->h_secid_first_sector_in_short_sat; - ssat->sat_len = cdf_count_chain(sat, sid, CDF_SEC_SIZE(h)); + ssat->sat_tab = NULL; + ssat->sat_len = cdf_count_chain(sat, sid, ss); if (ssat->sat_len == (size_t)-1) - return -1; + goto out; - ssat->sat_tab = CAST(cdf_secid_t *, calloc(ssat->sat_len, ss)); + ssat->sat_tab = CAST(cdf_secid_t *, CDF_CALLOC(ssat->sat_len, ss)); if (ssat->sat_tab == NULL) - return -1; + goto out1; for (j = i = 0; sid >= 0; i++, j++) { if (j >= CDF_LOOP_LIMIT) { DPRINTF(("Read short sat sector loop limit")); - errno = EFTYPE; goto out; } if (i >= ssat->sat_len) { DPRINTF(("Out of bounds reading short sector chain " "%" SIZE_T_FORMAT "u > %" SIZE_T_FORMAT "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)); - goto out; + goto out1; } sid = CDF_TOLE4((uint32_t)sat->sat_tab[sid]); } return 0; out: + errno = EFTYPE; +out1: free(ssat->sat_tab); return -1; } @@ -703,21 +762,24 @@ cdf_read_short_stream(const cdf_info_t *info, const cdf_header_t *h, break; /* If the it is not there, just fake it; some docs don't have it */ - if (i == dir->dir_len) + if (i == dir->dir_len) { + DPRINTF(("Cannot find root storage dir\n")); goto out; + } d = &dir->dir_tab[i]; *root = d; /* If the it is not there, just fake it; some docs don't have it */ - if (d->d_stream_first_sector < 0) + if (d->d_stream_first_sector < 0) { + DPRINTF(("No first secror in dir\n")); goto out; + } - return cdf_read_long_sector_chain(info, h, sat, + return cdf_read_long_sector_chain(info, h, sat, d->d_stream_first_sector, d->d_size, scn); out: scn->sst_tab = NULL; - scn->sst_len = 0; - scn->sst_dirlen = 0; + (void)cdf_zero_stream(scn); return 0; } @@ -731,6 +793,15 @@ cdf_namecmp(const char *d, const uint16_t *s, size_t l) } int +cdf_read_doc_summary_info(const cdf_info_t *info, const cdf_header_t *h, + const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst, + const cdf_dir_t *dir, cdf_stream_t *scn) +{ + return cdf_read_user_stream(info, h, sat, ssat, sst, dir, + "\05DocumentSummaryInformation", scn); +} + +int cdf_read_summary_info(const cdf_info_t *info, const cdf_header_t *h, const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst, const cdf_dir_t *dir, cdf_stream_t *scn) @@ -744,24 +815,129 @@ cdf_read_user_stream(const cdf_info_t *info, const cdf_header_t *h, const cdf_sat_t *sat, const cdf_sat_t *ssat, const cdf_stream_t *sst, const cdf_dir_t *dir, const char *name, cdf_stream_t *scn) { - size_t i; const cdf_directory_t *d; - size_t name_len = strlen(name) + 1; + int i = cdf_find_stream(dir, name, CDF_DIR_TYPE_USER_STREAM); + + if (i <= 0) { + memset(scn, 0, sizeof(*scn)); + return -1; + } + + d = &dir->dir_tab[i - 1]; + return cdf_read_sector_chain(info, h, sat, ssat, sst, + d->d_stream_first_sector, d->d_size, scn); +} + +int +cdf_find_stream(const cdf_dir_t *dir, const char *name, int type) +{ + size_t i, name_len = strlen(name) + 1; for (i = dir->dir_len; i > 0; i--) - if (dir->dir_tab[i - 1].d_type == CDF_DIR_TYPE_USER_STREAM && + if (dir->dir_tab[i - 1].d_type == type && cdf_namecmp(name, dir->dir_tab[i - 1].d_name, name_len) == 0) break; + if (i > 0) + return CAST(int, i); - if (i == 0) { - DPRINTF(("Cannot find user stream `%s'\n", name)); - errno = ESRCH; - return -1; + DPRINTF(("Cannot find type %d `%s'\n", type, name)); + errno = ESRCH; + return 0; +} + +#define CDF_SHLEN_LIMIT (UINT32_MAX / 8) +#define CDF_PROP_LIMIT (UINT32_MAX / (8 * 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 (p >= e) { + DPRINTF(("Past end %p < %p\n", e, p)); + return NULL; } - d = &dir->dir_tab[i - 1]; - return cdf_read_sector_chain(info, h, sat, ssat, sst, - d->d_stream_first_sector, d->d_size, scn); + if (cdf_check_stream_offset(sst, h, p, (tail + 1) * 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) { + DPRINTF(("exceeded property limit %zu > %zu\n", + newcount, CDF_PROP_LIMIT)); + goto out; + } + inp = CAST(cdf_property_info_t *, + CDF_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; +} + +static int +cdf_copy_info(cdf_property_info_t *inp, const void *p, const void *e, + size_t len) +{ + if (inp->pi_type & CDF_VECTOR) + return 0; + + if ((size_t)(CAST(const char *, e) - CAST(const char *, p)) < len) + return 0; + + (void)memcpy(&inp->pi_val, p, len); + + switch (len) { + case 2: + inp->pi_u16 = CDF_TOLE2(inp->pi_u16); + break; + case 4: + inp->pi_u32 = CDF_TOLE4(inp->pi_u32); + break; + case 8: + inp->pi_u64 = CDF_TOLE8(inp->pi_u64); + break; + default: + abort(); + } + return 1; } int @@ -771,92 +947,69 @@ cdf_read_property_info(const cdf_stream_t *sst, const cdf_header_t *h, const cdf_section_header_t *shp; cdf_section_header_t sh; const uint8_t *p, *q, *e; - int16_t s16; - int32_t s32; - uint32_t u32; - int64_t s64; - uint64_t u64; - cdf_timestamp_t tp; - size_t i, o, o4, nelements, j; + size_t i, o4, nelements, j, slen, left; 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) + + if (cdf_check_stream_offset(sst, h, shp, sh.sh_len, __LINE__) == -1) goto out; + + sh.sh_properties = CDF_TOLE4(shp->sh_properties); 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))); - } + if (sh.sh_properties > CDF_PROP_LIMIT) + goto out; + inp = cdf_grow_info(info, maxcount, sh.sh_properties); if (inp == NULL) goto out; - *info = inp; 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)); - if (cdf_check_stream_offset(sst, h, e, 0, __LINE__) == -1) + 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 (p >= e || 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) + if ((q = cdf_get_property_info_pos(sst, h, p, e, i)) == NULL) 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)); + inp[i].pi_id = CDF_GETUINT32(p, i << 1); + left = CAST(size_t, e - q); + if (left < sizeof(uint32_t)) { + DPRINTF(("short info (no type)_\n")); 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", + DPRINTF(("%" SIZE_T_FORMAT "u) id=%#x type=%#x offs=%#tx,%#x\n", i, inp[i].pi_id, inp[i].pi_type, q - p, offs)); if (inp[i].pi_type & CDF_VECTOR) { + if (left < sizeof(uint32_t) * 2) { + DPRINTF(("missing CDF_VECTOR length\n")); + goto out; + } nelements = CDF_GETUINT32(q, 1); if (nelements == 0) { 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) { @@ -864,100 +1017,72 @@ cdf_read_property_info(const cdf_stream_t *sst, const cdf_header_t *h, case CDF_EMPTY: break; case CDF_SIGNED16: - if (inp[i].pi_type & CDF_VECTOR) + if (!cdf_copy_info(&inp[i], &q[o4], e, sizeof(int16_t))) goto unknown; - (void)memcpy(&s16, &q[o4], sizeof(s16)); - inp[i].pi_s16 = CDF_TOLE2(s16); break; case CDF_SIGNED32: - if (inp[i].pi_type & CDF_VECTOR) - goto unknown; - (void)memcpy(&s32, &q[o4], sizeof(s32)); - inp[i].pi_s32 = CDF_TOLE4((uint32_t)s32); - break; case CDF_BOOL: case CDF_UNSIGNED32: - if (inp[i].pi_type & CDF_VECTOR) + case CDF_FLOAT: + if (!cdf_copy_info(&inp[i], &q[o4], e, sizeof(int32_t))) goto unknown; - (void)memcpy(&u32, &q[o4], sizeof(u32)); - inp[i].pi_u32 = CDF_TOLE4(u32); break; case CDF_SIGNED64: - if (inp[i].pi_type & CDF_VECTOR) - goto unknown; - (void)memcpy(&s64, &q[o4], sizeof(s64)); - inp[i].pi_s64 = CDF_TOLE8((uint64_t)s64); - break; case CDF_UNSIGNED64: - if (inp[i].pi_type & CDF_VECTOR) - goto unknown; - (void)memcpy(&u64, &q[o4], sizeof(u64)); - inp[i].pi_u64 = CDF_TOLE8((uint64_t)u64); - break; - case CDF_FLOAT: - if (inp[i].pi_type & CDF_VECTOR) - goto unknown; - (void)memcpy(&u32, &q[o4], sizeof(u32)); - u32 = CDF_TOLE4(u32); - memcpy(&inp[i].pi_f, &u32, sizeof(inp[i].pi_f)); - break; case CDF_DOUBLE: - if (inp[i].pi_type & CDF_VECTOR) + case CDF_FILETIME: + if (!cdf_copy_info(&inp[i], &q[o4], e, sizeof(int64_t))) goto unknown; - (void)memcpy(&u64, &q[o4], sizeof(u64)); - u64 = CDF_TOLE8((uint64_t)u64); - memcpy(&inp[i].pi_d, &u64, sizeof(inp[i].pi_d)); break; case CDF_LENGTH32_STRING: 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 out; - *info = inp; - inp = *info + nelem; + inp += nelem; } DPRINTF(("nelements = %" SIZE_T_FORMAT "u\n", nelements)); for (j = 0; j < nelements && i < sh.sh_properties; j++, i++) { - uint32_t l = CDF_GETUINT32(q, o); + uint32_t l; + + if (o4 + sizeof(uint32_t) > left) + goto out; + + l = CDF_GETUINT32(q, slen); + o4 += sizeof(uint32_t); + if (o4 + l > left) + goto out; + inp[i].pi_str.s_len = l; - inp[i].pi_str.s_buf = (const char *) - (const void *)(&q[o4 + sizeof(l)]); - DPRINTF(("l = %d, r = %" SIZE_T_FORMAT - "u, s = %s\n", l, - CDF_ROUND(l, sizeof(l)), + inp[i].pi_str.s_buf = CAST(const char *, + CAST(const void *, &q[o4])); + + DPRINTF(("o=%zu l=%d(%" SIZE_T_FORMAT + "u), t=%zu s=%s\n", o4, l, + CDF_ROUND(l, sizeof(l)), left, inp[i].pi_str.s_buf)); + if (l & 1) l++; - o += l >> 1; - if (q + o >= e) - goto out; - o4 = o * sizeof(uint32_t); + + slen += l >> 1; + o4 = slen * sizeof(uint32_t); } i--; break; - case CDF_FILETIME: - if (inp[i].pi_type & CDF_VECTOR) - goto unknown; - (void)memcpy(&tp, &q[o4], sizeof(tp)); - inp[i].pi_tp = CDF_TOLE8((uint64_t)tp); - break; case CDF_CLIPBOARD: if (inp[i].pi_type & CDF_VECTOR) goto unknown; break; default: unknown: - DPRINTF(("Don't know how to deal with %x\n", + memset(&inp[i].pi_val, 0, sizeof(inp[i].pi_val)); + DPRINTF(("Don't know how to deal with %#x\n", inp[i].pi_type)); break; } @@ -965,6 +1090,10 @@ cdf_read_property_info(const cdf_stream_t *sst, const cdf_header_t *h, return 0; out: free(*info); + *info = NULL; + *count = 0; + *maxcount = 0; + errno = EFTYPE; return -1; } @@ -998,52 +1127,79 @@ cdf_unpack_summary_info(const cdf_stream_t *sst, const cdf_header_t *h, } -#define extract_catalog_field(f, l) \ - memcpy(&ce[i].f, b + (l), sizeof(ce[i].f)); \ - ce[i].f = CDF_TOLE(ce[i].f) +#define extract_catalog_field(t, f, l) \ + if (b + l + sizeof(cep->f) > eb) { \ + cep->ce_namlen = 0; \ + break; \ + } \ + memcpy(&cep->f, b + (l), sizeof(cep->f)); \ + ce[i].f = CAST(t, CDF_TOLE(cep->f)) int cdf_unpack_catalog(const cdf_header_t *h, const cdf_stream_t *sst, cdf_catalog_t **cat) { - size_t ss = sst->sst_dirlen < h->h_min_size_standard_stream ? - CDF_SHORT_SEC_SIZE(h) : CDF_SEC_SIZE(h); + size_t ss = cdf_check_stream(sst, h); const char *b = CAST(const char *, sst->sst_tab); - const char *eb = b + ss * sst->sst_len; - size_t nr, i, k; + const char *nb, *eb = b + ss * sst->sst_len; + size_t nr, i, j, k; cdf_catalog_entry_t *ce; uint16_t reclen; const uint16_t *np; - for (nr = 0; b < eb; nr++) { + for (nr = 0;; nr++) { memcpy(&reclen, b, sizeof(reclen)); reclen = CDF_TOLE2(reclen); if (reclen == 0) break; b += reclen; + if (b > eb) + break; } + if (nr == 0) + return -1; + nr--; *cat = CAST(cdf_catalog_t *, - malloc(sizeof(cdf_catalog_t) + nr * sizeof(*ce))); - (*cat)->cat_num = nr; + CDF_MALLOC(sizeof(cdf_catalog_t) + nr * sizeof(*ce))); + if (*cat == NULL) + return -1; ce = (*cat)->cat_e; + memset(ce, 0, nr * sizeof(*ce)); b = CAST(const char *, sst->sst_tab); - for (i = 0; i < nr; i++) { - extract_catalog_field(ce_namlen, 0); - extract_catalog_field(ce_num, 2); - extract_catalog_field(ce_timestamp, 6); - reclen = ce[i].ce_namlen; - ce[i].ce_namlen = - sizeof(ce[i].ce_name) / sizeof(ce[i].ce_name[0]) - 1; - if (ce[i].ce_namlen > reclen - 14) - ce[i].ce_namlen = reclen - 14; - np = CAST(const uint16_t *, (b + 16)); - for (k = 0; k < ce[i].ce_namlen; k++) { - ce[i].ce_name[k] = np[k]; - CDF_TOLE2(ce[i].ce_name[k]); + for (j = i = 0; i < nr; b += reclen) { + cdf_catalog_entry_t *cep = &ce[j]; + uint16_t rlen; + + extract_catalog_field(uint16_t, ce_namlen, 0); + extract_catalog_field(uint16_t, ce_num, 4); + extract_catalog_field(uint64_t, ce_timestamp, 8); + reclen = cep->ce_namlen; + + if (reclen < 14) { + cep->ce_namlen = 0; + continue; } - ce[i].ce_name[ce[i].ce_namlen] = 0; - b += reclen; + + cep->ce_namlen = __arraycount(cep->ce_name) - 1; + rlen = reclen - 14; + if (cep->ce_namlen > rlen) + cep->ce_namlen = rlen; + + np = CAST(const uint16_t *, CAST(const void *, (b + 16))); + nb = CAST(const char *, CAST(const void *, + (np + cep->ce_namlen))); + if (nb > eb) { + cep->ce_namlen = 0; + break; + } + + for (k = 0; k < cep->ce_namlen; k++) + cep->ce_name[k] = np[k]; /* XXX: CDF_TOLE2? */ + cep->ce_name[cep->ce_namlen] = 0; + j = i; + i++; } + (*cat)->cat_num = j; return 0; } @@ -1091,7 +1247,7 @@ cdf_print_property_name(char *buf, size_t bufsiz, uint32_t p) for (i = 0; i < __arraycount(vn); i++) if (vn[i].v == p) return snprintf(buf, bufsiz, "%s", vn[i].n); - return snprintf(buf, bufsiz, "0x%x", p); + return snprintf(buf, bufsiz, "%#x", p); } int @@ -1150,7 +1306,7 @@ cdf_dump_header(const cdf_header_t *h) h->h_ ## b, 1 << h->h_ ## b) DUMP("%d", revision); DUMP("%d", version); - DUMP("0x%x", byte_order); + DUMP("%#x", byte_order); DUMP2("%d", sec_size_p2); DUMP2("%d", short_sec_size_p2); DUMP("%d", num_sectors_in_sat); @@ -1188,11 +1344,12 @@ cdf_dump_sat(const char *prefix, const cdf_sat_t *sat, size_t size) } void -cdf_dump(void *v, size_t len) +cdf_dump(const void *v, size_t len) { size_t i, j; - unsigned char *p = v; + const unsigned char *p = v; char abuf[16]; + (void)fprintf(stderr, "%.4x: ", 0); for (i = 0, j = 0; i < len; i++, p++) { (void)fprintf(stderr, "%.2x ", *p); @@ -1208,10 +1365,9 @@ cdf_dump(void *v, size_t len) } void -cdf_dump_stream(const cdf_header_t *h, const cdf_stream_t *sst) +cdf_dump_stream(const cdf_stream_t *sst) { - size_t ss = sst->sst_dirlen < h->h_min_size_standard_stream ? - CDF_SHORT_SEC_SIZE(h) : CDF_SEC_SIZE(h); + size_t ss = sst->sst_ss; cdf_dump(sst->sst_tab, ss * sst->sst_len); } @@ -1244,7 +1400,7 @@ cdf_dump_dir(const cdf_info_t *info, const cdf_header_t *h, d->d_color ? "black" : "red"); (void)fprintf(stderr, "Left child: %d\n", d->d_left_child); (void)fprintf(stderr, "Right child: %d\n", d->d_right_child); - (void)fprintf(stderr, "Flags: 0x%x\n", d->d_flags); + (void)fprintf(stderr, "Flags: %#x\n", d->d_flags); cdf_timestamp_to_timespec(&ts, d->d_created); (void)fprintf(stderr, "Created %s", cdf_ctime(&ts.tv_sec, buf)); cdf_timestamp_to_timespec(&ts, d->d_modified); @@ -1265,7 +1421,7 @@ cdf_dump_dir(const cdf_info_t *info, const cdf_header_t *h, name, d->d_stream_first_sector, d->d_size); break; } - cdf_dump_stream(h, &scn); + cdf_dump_stream(&scn); free(scn.sst_tab); break; default: @@ -1327,17 +1483,17 @@ cdf_dump_property_info(const cdf_property_info_t *info, size_t count) cdf_print_elapsed_time(buf, sizeof(buf), tp); (void)fprintf(stderr, "timestamp %s\n", buf); } else { - char buf[26]; + char tbuf[26]; cdf_timestamp_to_timespec(&ts, tp); (void)fprintf(stderr, "timestamp %s", - cdf_ctime(&ts.tv_sec, buf)); + cdf_ctime(&ts.tv_sec, tbuf)); } break; case CDF_CLIPBOARD: (void)fprintf(stderr, "CLIPBOARD %u\n", info[i].pi_u32); break; default: - DPRINTF(("Don't know how to deal with %x\n", + DPRINTF(("Don't know how to deal with %#x\n", info[i].pi_type)); break; } @@ -1356,7 +1512,7 @@ cdf_dump_summary_info(const cdf_header_t *h, const cdf_stream_t *sst) (void)&h; if (cdf_unpack_summary_info(sst, h, &ssi, &info, &count) == -1) return; - (void)fprintf(stderr, "Endian: %x\n", ssi.si_byte_order); + (void)fprintf(stderr, "Endian: %#x\n", ssi.si_byte_order); (void)fprintf(stderr, "Os Version %d.%d\n", ssi.si_os_version & 0xff, ssi.si_os_version >> 8); (void)fprintf(stderr, "Os %d\n", ssi.si_os); @@ -1401,7 +1557,10 @@ main(int argc, char *argv[]) cdf_dir_t dir; cdf_info_t info; const cdf_directory_t *root; - +#ifdef __linux__ +#define getprogname() __progname + extern char *__progname; +#endif if (argc < 2) { (void)fprintf(stderr, "Usage: %s <filename>\n", getprogname()); return -1; @@ -1438,7 +1597,7 @@ main(int argc, char *argv[]) == -1) err(1, "Cannot read short stream"); #ifdef CDF_DEBUG - cdf_dump_stream(&h, &sst); + cdf_dump_stream(&sst); #endif #ifdef CDF_DEBUG @@ -1453,8 +1612,8 @@ main(int argc, char *argv[]) else cdf_dump_summary_info(&h, &scn); #endif - if (cdf_read_catalog(&info, &h, &sat, &ssat, &sst, &dir, - &scn) == -1) + if (cdf_read_user_stream(&info, &h, &sat, &ssat, &sst, + &dir, "Catalog", &scn) == -1) warn("Cannot read catalog"); #ifdef CDF_DEBUG else |