Преглед изворни кода

Avoid info database corruption and bogus accesses on unknown format values

Make sure to always read the format file whenever we are about to access
the info database, so that we can verify that we understand the format,
and bail out otherwise.

This fixes a currently possible info database corruption and bogus
access, whenever the format is lower than 0 or higher than the last
understood one, and makes the info database code future-proof in case
new actual formats get introduced.
Guillem Jover пре 14 година
родитељ
комит
98be9e91b2
5 измењених фајлова са 24 додато и 4 уклоњено
  1. 2 0
      debian/changelog
  2. 5 1
      src/infodb-access.c
  3. 10 2
      src/infodb-format.c
  4. 6 1
      src/infodb-upgrade.c
  5. 1 0
      src/infodb.h

+ 2 - 0
debian/changelog

@@ -42,6 +42,8 @@ dpkg (1.16.9) UNRELEASED; urgency=low
     hash from the previously processed entries.
   * Fix logic for previously configured conffiles, so that the shared
     conffile checks actually work on reinstallation. Closes: #684776
+  * Avoid info database corruption and bogus accesses on unknown format
+    values, by always reading the format file and validating it.
 
   [ Updated programs translations ]
   * Czech (Miroslav Kure).

+ 5 - 1
src/infodb-access.c

@@ -62,9 +62,13 @@ pkg_infodb_foreach(struct pkginfo *pkg, struct pkgbin *pkgbin,
 	struct varbuf db_path = VARBUF_INIT;
 	const char *pkgname;
 	size_t db_path_len;
+	enum pkg_infodb_format db_format;
+
+	/* Make sure to always read and verify the format version. */
+	db_format = pkg_infodb_get_format();
 
 	if (pkgbin->multiarch == multiarch_same &&
-	    pkg_infodb_get_format() == pkg_infodb_format_multiarch)
+	    db_format == pkg_infodb_format_multiarch)
 		pkgname = pkgbin_name(pkg, pkgbin, pnaw_always);
 	else
 		pkgname = pkgbin_name(pkg, pkgbin, pnaw_never);

+ 10 - 2
src/infodb-format.c

@@ -84,6 +84,10 @@ pkg_infodb_read_format(void)
 	atomic_file_free(file);
 	free(filename);
 
+	if (db_format < 0 || db_format >= pkg_infodb_format_last)
+		ohshit(_("info database format (%d) is bogus or too new; "
+		         "try getting a newer dpkg"), db_format);
+
 	return db_format;
 }
 
@@ -127,14 +131,18 @@ pkg_infodb_get_file(struct pkginfo *pkg, struct pkgbin *pkgbin,
                     const char *filetype)
 {
 	static struct varbuf vb;
+	enum pkg_infodb_format format;
+
+	/* Make sure to always read and verify the format version. */
+	format = pkg_infodb_get_format();
 
 	varbuf_reset(&vb);
 	varbuf_add_str(&vb, pkg_infodb_get_dir());
 	varbuf_add_char(&vb, '/');
 	varbuf_add_str(&vb, pkg->set->name);
 	if (pkgbin->multiarch == multiarch_same &&
-		pkg_infodb_get_format() == pkg_infodb_format_multiarch)
-	varbuf_add_archqual(&vb, pkgbin->arch);
+	    format == pkg_infodb_format_multiarch)
+		varbuf_add_archqual(&vb, pkgbin->arch);
 	varbuf_add_char(&vb, '.');
 	varbuf_add_str(&vb, filetype);
 	varbuf_end_str(&vb);

+ 6 - 1
src/infodb-upgrade.c

@@ -238,10 +238,15 @@ pkg_infodb_upgrade_to_multiarch(void)
 void
 pkg_infodb_upgrade(void)
 {
+	enum pkg_infodb_format db_format;
+
+	/* Make sure to always read and verify the format version. */
+	db_format = pkg_infodb_get_format();
+
 	if (modstatdb_get_status() < msdbrw_write)
 		return;
 
-	if (pkg_infodb_get_format() < pkg_infodb_format_multiarch ||
+	if (db_format < pkg_infodb_format_multiarch ||
 	    pkg_infodb_is_upgrading())
 		pkg_infodb_upgrade_to_multiarch();
 }

+ 1 - 0
src/infodb.h

@@ -29,6 +29,7 @@ enum pkg_infodb_format {
 	pkg_infodb_format_unknown = -1,
 	pkg_infodb_format_legacy = 0,
 	pkg_infodb_format_multiarch = 1,
+	pkg_infodb_format_last,
 };
 
 enum pkg_infodb_format pkg_infodb_get_format(void);