]> granicus.if.org Git - file/commitdiff
more protection for the cdf code. FILE5_03
authorChristos Zoulas <christos@zoulas.com>
Tue, 5 May 2009 22:48:51 +0000 (22:48 +0000)
committerChristos Zoulas <christos@zoulas.com>
Tue, 5 May 2009 22:48:51 +0000 (22:48 +0000)
src/cdf.c
src/readcdf.c

index 9ca9c44cd7efe52417ff0ddac4438bb4560554c3..06e91bedd9131e4678ec78bfcdd36b7d1d9794d8 100644 (file)
--- a/src/cdf.c
+++ b/src/cdf.c
@@ -32,7 +32,7 @@
 #include "file.h"
 
 #ifndef lint
-FILE_RCSID("@(#)$File: cdf.c,v 1.25 2009/05/02 16:36:17 christos Exp $")
+FILE_RCSID("@(#)$File: cdf.c,v 1.26 2009/05/02 20:06:55 christos Exp $")
 #endif
 
 #include <assert.h>
@@ -227,6 +227,19 @@ cdf_unpack_dir(cdf_directory_t *d, char *buf)
        CDF_UNPACK(d->d_unused0);
 }
 
+static int
+cdf_check_stream_offset(const cdf_stream_t *sst, const void *p, size_t tail)
+{
+       const char *b = (const char *)sst->sst_tab;
+       const char *e = ((const char *)p) + tail;
+       if ((size_t)(e - b) < sst->sst_dirlen * sst->sst_len)
+               return 0;
+       DPRINTF((stderr, "offset begin %p end %p %zu >= %zu\n", b, e,
+           (size_t)(e - b), sst->sst_dirlen * sst->sst_len));
+       errno = EFTYPE;
+       return -1;
+}
+
 static ssize_t
 cdf_read(const cdf_info_t *info, off_t off, void *buf, size_t len)
 {
@@ -321,15 +334,15 @@ cdf_read_sat(const cdf_info_t *info, cdf_header_t *h, cdf_sat_t *sat)
                        break;
 
 #define CDF_SEC_LIMIT (UINT32_MAX / (4 * ss))
-       if (h->h_num_sectors_in_master_sat > CDF_SEC_LIMIT ||
-           i > CDF_SEC_LIMIT / nsatpersec) {
+       if (h->h_num_sectors_in_master_sat > CDF_SEC_LIMIT / nsatpersec ||
+           i > CDF_SEC_LIMIT) {
                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;
+       sat->sat_len = h->h_num_sectors_in_master_sat * nsatpersec + i;
        DPRINTF(("sat_len = %zu ss = %zu\n", sat->sat_len, ss));
        if ((sat->sat_tab = calloc(sat->sat_len, ss)) == NULL)
                return -1;
@@ -349,6 +362,8 @@ cdf_read_sat(const cdf_info_t *info, cdf_header_t *h, cdf_sat_t *sat)
 
        mid = h->h_secid_first_sector_in_master_sat;
        for (j = 0; j < h->h_num_sectors_in_master_sat; j++) {
+               if (mid < 0)
+                       goto out;
                if (j >= CDF_LOOP_LIMIT) {
                        DPRINTF(("Reading master sector loop limit"));
                        errno = EFTYPE;
@@ -360,10 +375,8 @@ cdf_read_sat(const cdf_info_t *info, cdf_header_t *h, cdf_sat_t *sat)
                }
                for (k = 0; k < nsatpersec; k++, i++) {
                        sec = CDF_TOLE4(msa[k]);
-                       if (sec < 0) {
-                               sat->sat_len = i;
-                               break;
-                       }
+                       if (sec < 0)
+                               goto out;
                        if (i >= sat->sat_len) {
                            DPRINTF(("Out of bounds reading MSA %u >= %u",
                                i, sat->sat_len));
@@ -379,6 +392,8 @@ cdf_read_sat(const cdf_info_t *info, cdf_header_t *h, cdf_sat_t *sat)
                }
                mid = CDF_TOLE4(msa[nsatpersec]);
        }
+out:
+       sat->sat_len = i;
        free(msa);
        return 0;
 out2:
@@ -686,8 +701,19 @@ cdf_read_property_info(const cdf_stream_t *sst, uint32_t offs,
        size_t i, o, nelements, j;
        cdf_property_info_t *inp;
 
+       if (offs > UINT32_MAX / 4) {
+               errno = EFTYPE;
+               goto out;
+       }
        shp = (const void *)((const char *)sst->sst_tab + offs);
+       if (cdf_check_stream_offset(sst, shp, sizeof(*shp)) == -1)
+               goto out;
        sh.sh_len = CDF_TOLE4(shp->sh_len);
+#define CDF_SHLEN_LIM (UINT32_MAX / 8)
+       if (sh.sh_len > CDF_SHLEN_LIM) {
+               errno = EFTYPE;
+               goto out;
+       }
        sh.sh_properties = CDF_TOLE4(shp->sh_properties);
 #define CDF_PROP_LIM (UINT32_MAX / (4 * sizeof(*inp)))
        if (sh.sh_properties > CDF_PROP_LIM)
@@ -710,6 +736,8 @@ cdf_read_property_info(const cdf_stream_t *sst, uint32_t offs,
        *count += sh.sh_properties;
        p = (const void *)((const char *)sst->sst_tab + offs + sizeof(sh));
        e = (const void *)(((const char *)shp) + sh.sh_len);
+       if (cdf_check_stream_offset(sst, e, 0) == -1)
+               goto out;
        for (i = 0; i < sh.sh_properties; i++) {
                q = (const uint32_t *)((const char *)p +
                    CDF_TOLE4(p[(i << 1) + 1])) - 2;
@@ -822,6 +850,9 @@ cdf_unpack_summary_info(const cdf_stream_t *sst, cdf_summary_info_header_t *ssi,
        const cdf_section_declaration_t *sd = (const void *)
            ((const char *)sst->sst_tab + CDF_SECTION_DECLARATION_OFFSET);
 
+       if (cdf_check_stream_offset(sst, si, sizeof(*si)) == -1 ||
+           cdf_check_stream_offset(sst, sd, sizeof(*sd)) == -1)
+               return -1;
        ssi->si_byte_order = CDF_TOLE2(si->si_byte_order);
        ssi->si_os_version = CDF_TOLE2(si->si_os_version);
        ssi->si_os = CDF_TOLE2(si->si_os);
@@ -936,11 +967,13 @@ cdf_dump_header(const cdf_header_t *h)
        size_t i;
 
 #define DUMP(a, b) (void)fprintf(stderr, "%40.40s = " a "\n", # b, h->h_ ## b)
+#define DUMP2(a, b) (void)fprintf(stderr, "%40.40s = " a " (" a ")\n", # b, \
+    h->h_ ## b, 1 << h->h_ ## b)
        DUMP("%d", revision);
        DUMP("%d", version);
        DUMP("0x%x", byte_order);
-       DUMP("%d", sec_size_p2);
-       DUMP("%d", short_sec_size_p2);
+       DUMP2("%d", sec_size_p2);
+       DUMP2("%d", short_sec_size_p2);
        DUMP("%d", num_sectors_in_sat);
        DUMP("%d", secid_first_directory);
        DUMP("%d", min_size_standard_stream);
index a543b07cf1d7b9d4eeb7b6534f3c78b7ff7279b1..0ed53729b04d8d0e5e6747d3432f31f176671eb5 100644 (file)
@@ -26,7 +26,7 @@
 #include "file.h"
 
 #ifndef lint
-FILE_RCSID("@(#)$File: readcdf.c,v 1.15 2009/04/30 21:03:26 christos Exp $")
+FILE_RCSID("@(#)$File: readcdf.c,v 1.16 2009/05/01 22:36:58 christos Exp $")
 #endif
 
 #include <stdlib.h>
@@ -246,7 +246,7 @@ file_trycdf(struct magic_set *ms, int fd, const unsigned char *buf,
 
        if ((i = cdf_read_summary_info(&info, &h, &sat, &ssat, &sst, &dir,
            &scn)) == -1) {
-               expn = "";
+               expn = "Cannot read summary info";
                goto out4;
        }
 #ifdef CDF_DEBUG