[PATCH] gpt: verify CRC32 of partition table entry array, too

Jim Meyering meyering at redhat.com
Wed Oct 14 18:50:39 UTC 2009


The partition table entry array's CRC was not being verified at all.
This adds an interim check.  The full-blown change required to make
this implementation conform to the EFI spec will be more invasive.
* libparted/labels/gpt.c (gpt_read): Check CRC of PTE array, too.
* tests/t0280-gpt-corrupt.sh: New test for this.
Reported by Karel Zak.
---
 libparted/labels/gpt.c     |   16 ++++++--
 tests/t0280-gpt-corrupt.sh |   95 ++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 107 insertions(+), 4 deletions(-)
 create mode 100755 tests/t0280-gpt-corrupt.sh

diff --git a/libparted/labels/gpt.c b/libparted/labels/gpt.c
index 3f4edf7..7fa70d5 100644
--- a/libparted/labels/gpt.c
+++ b/libparted/labels/gpt.c
@@ -819,7 +819,6 @@ gpt_read (PedDisk * disk)
 	GPTDiskData *gpt_disk_data = disk->disk_specific;
 	GuidPartitionTableHeader_t* gpt;
 	void* ptes;
-	size_t ptes_sectors;
 	int i;
 #ifndef DISCOVER_ONLY
 	int write_back = 0;
@@ -914,9 +913,9 @@ gpt_read (PedDisk * disk)
 		goto error_free_gpt;

 	uint32_t p_ent_size = PED_LE32_TO_CPU (gpt->SizeOfPartitionEntry);
-	ptes_sectors = ped_div_round_up (p_ent_size
-					 * gpt_disk_data->entry_count,
-					 disk->dev->sector_size);
+	size_t ptes_bytes = p_ent_size * gpt_disk_data->entry_count;
+	size_t ptes_sectors = ped_div_round_up (ptes_bytes,
+						disk->dev->sector_size);

 	if (xalloc_oversized (ptes_sectors, disk->dev->sector_size))
 		goto error_free_gpt;
@@ -927,6 +926,15 @@ gpt_read (PedDisk * disk)
 			      ptes_sectors))
 		goto error_free_ptes;

+	uint32_t ptes_crc = efi_crc32 (ptes, ptes_bytes);
+	if (ptes_crc != gpt->PartitionEntryArrayCRC32) {
+		ped_exception_throw (
+			PED_EXCEPTION_ERROR,
+			PED_EXCEPTION_CANCEL,
+			_("partition table array (FIXME:which?) CRC mismatch"));
+		goto error_free_ptes;
+        }
+
 	for (i = 0; i < gpt_disk_data->entry_count; i++) {
 		GuidPartitionEntry_t* pte
 		  = (GuidPartitionEntry_t*) ((char *)ptes + i * p_ent_size);
diff --git a/tests/t0280-gpt-corrupt.sh b/tests/t0280-gpt-corrupt.sh
new file mode 100755
index 0000000..89ab818
--- /dev/null
+++ b/tests/t0280-gpt-corrupt.sh
@@ -0,0 +1,95 @@
+#!/bin/sh
+
+# Copyright (C) 2009 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+test_description="corrupt a GPT table; ensure parted takes notice"
+
+peek()
+{
+  case $# in 2) ;; *) echo "usage: peek FILE 0_BASED_OFFSET" >&2; exit 1;; esac
+  case $2 in *[^0-9]*) echo "peek: invalid offset: $2"; exit 1 ;; esac
+  dd if="$1" bs=1 skip="$2" count=1
+}
+
+poke()
+{
+  case $# in 3) ;; *) echo "usage: poke FILE 0_BASED_OFFSET BYTE" >&2; exit 1;;
+    esac
+  case $2 in *[^0-9]*) echo "poke: invalid offset: $2"; exit 1 ;; esac
+  case $3 in ?) ;; *) echo "poke: invalid byte: '$3'"; exit 1 ;; esac
+  printf %s "$3" | dd of="$1" bs=1 seek="$2" count=1 conv=notrunc
+}
+
+: ${srcdir=.}
+. $srcdir/test-lib.sh
+
+dev=loop-file
+
+ss=$sector_size_
+n_sectors=200
+
+test_expect_success \
+    "setup: create zeroed device" \
+    'dd if=/dev/null of=$dev bs=$ss seek=$n_sectors'
+
+test_expect_success \
+    'create gpt label' \
+    'parted -s $dev mklabel gpt > empty 2>&1'
+test_expect_success 'expect no output' 'compare /dev/null empty'
+
+test_expect_success \
+    'print the empty table' \
+    'parted -m -s $dev unit s print > t 2>&1 &&
+     sed 's,.*/$dev:,$dev:,' t > out'
+
+test_expect_success \
+    'check for expected output' \
+    'printf "BYT;\n$dev:${n_sectors}s:file:$sector_size_:$sector_size_:gpt:;\n"\
+       > exp &&
+     compare exp out'
+
+test_expect_success \
+    'create a partition' \
+    'parted -s $dev mkpart sw linux-swap 60s 100s > empty 2>&1'
+test_expect_success 'expect no output' 'compare /dev/null empty'
+
+# We're going to change the name of the first partition,
+# thus invalidating the PartitionEntryArrayCRC32 checksum.
+
+# byte 56 of the partition entry is the first byte of its 72-byte name field
+pte_offset=$(expr $ss \* 2 + 56)
+
+test_expect_success \
+    'get the first byte of the name' \
+    'pte_byte=$(peek $dev $pte_offset)'
+
+test x"$pte_byte" = xA && new_byte=B || new_byte=A
+
+test_expect_success \
+    'Replace with a different byte' \
+    'poke $dev $pte_offset "$new_byte"'
+
+test_expect_success \
+    'try to print the table' \
+    'parted -s $dev print > err 2>&1;
+     test $? = 1'
+
+test_expect_success \
+    'check for expected diagnostic' \
+    'echo "Error: partition table array CRC mismatch" > exp &&
+     compare exp err'
+
+test_done
--
1.6.5.1.258.g5b20



More information about the parted-devel mailing list