Browse Source

Import upstream version 5.03

Christos Zoulas 15 years ago
parent
commit
a0ff519f1d
6 changed files with 84 additions and 50 deletions
  1. 6 0
      ChangeLog
  2. 10 10
      configure
  3. 1 1
      configure.ac
  4. 58 26
      src/cdf.c
  5. 5 2
      src/patchlevel.h
  6. 4 11
      src/readcdf.c

+ 6 - 0
ChangeLog

@@ -1,3 +1,9 @@
+2009-05-06  10:25  Christos Zoulas <christos@zoulas.com>
+
+	* Avoid null dereference in cdf code (Drew Yao)
+
+	* More cdf bounds checks and overflow checks
+
 2009-05-01  18:37  Christos Zoulas <christos@zoulas.com>
 
 	* Buffer overflow fixes from Drew Yao

+ 10 - 10
configure

@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.61 for file 5.02.
+# Generated by GNU Autoconf 2.61 for file 5.03.
 #
 # Report bugs to <christos@astron.com>.
 #
@@ -728,8 +728,8 @@ SHELL=${CONFIG_SHELL-/bin/sh}
 # Identity of this package.
 PACKAGE_NAME='file'
 PACKAGE_TARNAME='file'
-PACKAGE_VERSION='5.02'
-PACKAGE_STRING='file 5.02'
+PACKAGE_VERSION='5.03'
+PACKAGE_STRING='file 5.03'
 PACKAGE_BUGREPORT='christos@astron.com'
 
 # Factoring default headers for most tests.
@@ -1399,7 +1399,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures file 5.02 to adapt to many kinds of systems.
+\`configure' configures file 5.03 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1469,7 +1469,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of file 5.02:";;
+     short | recursive ) echo "Configuration of file 5.03:";;
    esac
   cat <<\_ACEOF
 
@@ -1576,7 +1576,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-file configure 5.02
+file configure 5.03
 generated by GNU Autoconf 2.61
 
 Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -1590,7 +1590,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by file $as_me 5.02, which was
+It was created by file $as_me 5.03, which was
 generated by GNU Autoconf 2.61.  Invocation command line was
 
   $ $0 $@
@@ -2280,7 +2280,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='file'
- VERSION='5.02'
+ VERSION='5.03'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -24303,7 +24303,7 @@ exec 6>&1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by file $as_me 5.02, which was
+This file was extended by file $as_me 5.03, which was
 generated by GNU Autoconf 2.61.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -24356,7 +24356,7 @@ Report bugs to <bug-autoconf@gnu.org>."
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF
 ac_cs_version="\\
-file config.status 5.02
+file config.status 5.03
 configured by $0, generated by GNU Autoconf 2.61,
   with options \\"`echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
 

+ 1 - 1
configure.ac

@@ -1,5 +1,5 @@
 dnl Process this file with autoconf to produce a configure script.
-AC_INIT(file, 5.02, christos@astron.com)
+AC_INIT(file, 5.03, christos@astron.com)
 AM_INIT_AUTOMAKE
 AM_CONFIG_HEADER(config.h)
 #AC_CONFIG_MACRO_DIR([m4])

+ 58 - 26
src/cdf.c

@@ -32,7 +32,7 @@
 #include "file.h"
 
 #ifndef lint
-FILE_RCSID("@(#)$File: cdf.c,v 1.26 2009/05/02 20:06:55 christos Exp $")
+FILE_RCSID("@(#)$File: cdf.c,v 1.30 2009/05/06 14:29:47 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 (e >= b && (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:
@@ -467,7 +482,7 @@ cdf_read_short_sector_chain(const cdf_header_t *h,
 	scn->sst_len = cdf_count_chain(ssat, sid, CDF_SEC_SIZE(h));
 	scn->sst_dirlen = len;
 
-	if (scn->sst_len == (size_t)-1)
+	if (sst->sst_tab == NULL || scn->sst_len == (size_t)-1)
 		return -1;
 
 	scn->sst_tab = calloc(scn->sst_len, ss);
@@ -618,22 +633,21 @@ 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) {
-		scn->sst_tab = NULL;
-		scn->sst_len = 0;
-		return 0;
-	}
+	if (i == dir->dir_len)
+		goto out;
 	d = &dir->dir_tab[i];
 
 	/* If the it is not there, just fake it; some docs don't have it */
-	if (d->d_stream_first_sector < 0) {
-		scn->sst_tab = NULL;
-		scn->sst_len = 0;
-		return 0;
-	}
+	if (d->d_stream_first_sector < 0)
+		goto out;
 
 	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;
+	return 0;
 }
 
 static int
@@ -686,16 +700,27 @@ 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_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_LIM (UINT32_MAX / (4 * sizeof(*inp)))
-	if (sh.sh_properties > CDF_PROP_LIM)
+#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_LIM)
+		if (*maxcount > CDF_PROP_LIMIT)
 			goto out;
 		*maxcount += sh.sh_properties;
 		inp = realloc(*info, *maxcount * sizeof(*inp));
@@ -710,6 +735,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;
@@ -767,8 +794,8 @@ 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)
+				if (*maxcount > CDF_PROP_LIMIT
+				    || nelements > CDF_PROP_LIMIT)
 					goto out;
 				*maxcount += nelements;
 				inp = realloc(*info, *maxcount * sizeof(*inp));
@@ -822,6 +849,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 +966,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);

+ 5 - 2
src/patchlevel.h

@@ -1,11 +1,14 @@
 #define	FILE_VERSION_MAJOR	5
-#define	patchlevel		2
+#define	patchlevel		3
 
 /*
  * Patchlevel file for Ian Darwin's MAGIC command.
- * $File: patchlevel.h,v 1.73 2009/05/04 15:15:13 christos Exp $
+ * $File: patchlevel.h,v 1.74 2009/05/06 20:32:48 christos Exp $
  *
  * $Log: patchlevel.h,v $
+ * Revision 1.74  2009/05/06 20:32:48  christos
+ * welcome to 5.03
+ *
  * Revision 1.73  2009/05/04 15:15:13  christos
  * 5.02...
  *

+ 4 - 11
src/readcdf.c

@@ -26,7 +26,7 @@
 #include "file.h"
 
 #ifndef lint
-FILE_RCSID("@(#)$File: readcdf.c,v 1.16 2009/05/01 22:36:58 christos Exp $")
+FILE_RCSID("@(#)$File: readcdf.c,v 1.18 2009/05/06 20:48:22 christos Exp $")
 #endif
 
 #include <stdlib.h>
@@ -147,15 +147,8 @@ cdf_file_summary_info(struct magic_set *ms, const cdf_stream_t *sst)
 	size_t count;
 	int m;
 
-	if (cdf_unpack_summary_info(sst, &si, &info, &count) == -1) {
-		if (si.si_byte_order != 0xfffe)
-			return 0;
-		else
-			return -1;
-	}
-
-	if (si.si_byte_order != 0xfffe)
-		return 0;
+	if (cdf_unpack_summary_info(sst, &si, &info, &count) == -1)
+		return -1;
 
 	if (NOTMIME(ms)) {
 		if (file_printf(ms, "CDF V2 Document") == -1)
@@ -246,7 +239,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