소스 검색

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);