Add four malformed kernel partitions to the ChromiumOS test disk:

- partition 6 (KERN_C): a keyblock with a valid magic but an
  out-of-range keyblock_size, placing the preamble far outside the
  probed area
- partition 13 (KERN_D): an accepted keyblock_size with a preamble_size
  that puts the kernel body offset inside the probed area
- partition 14 (KERN_E): a preamble_size that wraps the 32-bit sum
  forming the kernel body offset
- partition 15 (KERN_F): a keyblock_size smaller than the keyblock
  header itself, placing the claimed preamble inside the header

All four must be rejected while scanning, so the existing bootflow_cros
and bootstd_images assertions (bootflow rows and counts) are unchanged.
Without the previous fix, partition 6 crashes sandbox with SIGSEGV, and
the other three scan successfully and surface as spurious ready
bootflows, so each check is covered by an observable failure.

Signed-off-by: Aristo Chen <[email protected]>
---
 test/boot/bootflow.c     |  6 ++++++
 test/py/tests/test_ut.py | 44 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 50 insertions(+)

diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c
index ef4638ec700..b7a8df293ad 100644
--- a/test/boot/bootflow.c
+++ b/test/boot/bootflow.c
@@ -1255,6 +1255,12 @@ BOOTSTD_TEST(bootflow_cmdline_special, 0);
 /* Test ChromiumOS bootmeth */
 static int bootflow_cros(struct unit_test_state *uts)
 {
+       /*
+        * mmc5 has valid kernels in partitions 2 and 4 and corrupt kernel
+        * metadata in partitions 6, 13, 14 and 15 (oversized keyblock,
+        * undersized body offset, wrapped body offset, undersized keyblock),
+        * none of which may produce a bootflow
+        */
        ut_assertok(scan_mmc_bootdev(uts, "mmc5", true));
        ut_assertok(run_command("bootflow list", 0));
 
diff --git a/test/py/tests/test_ut.py b/test/py/tests/test_ut.py
index fa50c8008a5..605274075e0 100644
--- a/test/py/tests/test_ut.py
+++ b/test/py/tests/test_ut.py
@@ -10,6 +10,7 @@ test one at a time, as well setting up some files needed by 
the tests.
 import collections
 import gzip
 import os
+import struct
 import os.path
 import re
 import pytest
@@ -319,6 +320,10 @@ def setup_cros_image(ubman):
         {'num': 5, 'label':'ROOT_B', 'type': uuid_root, 'size': '1'},
         {'num': 3, 'label':'ROOT_A', 'type': uuid_root, 'size': '1'},
         {'num': 1, 'label':'STATE', 'type': uuid_state, 'size': '1M'},
+
+        {'num': 0xd, 'label':'KERN_D', 'type': uuid_kern, 'size': '1'},
+        {'num': 0xe, 'label':'KERN_E', 'type': uuid_kern, 'size': '1'},
+        {'num': 0xf, 'label':'KERN_F', 'type': uuid_kern, 'size': '1'},
         ]
 
     for part in required_parts:
@@ -373,6 +378,45 @@ def setup_cros_image(ubman):
     set_part_data(2, pack_kernel(ubman, 'x86', kern, dummy))
     set_part_data(4, pack_kernel(ubman, 'arm', kern, dummy))
 
+    def bad_kernel_part(keyblock_size, preamble_size):
+        """Build corrupt-kernel-partition data that U-Boot must reject
+
+        The keyblock carries a valid magic and the given keyblock_size; a
+        preamble with the given preamble_size follows it. The bootloader
+        address/size fields are chosen so that, were the partition not
+        rejected, scanning it would succeed and produce a spurious ready
+        bootflow, which the bootflow-list assertions would then catch.
+
+        Args:
+            keyblock_size (int): Value for the keyblock_size field
+            preamble_size (int): Value for the preamble_size field
+
+        Return:
+            bytes: Data to place at the start of the partition
+        """
+        kblock = b'CHROMEOS' + struct.pack('<IIII', 2, 1, keyblock_size, 0)
+        kblock = kblock.ljust(min(keyblock_size, 0x100), b'\0')
+        # preamble_size, then body_load_address / bootloader_address /
+        # bootloader_size at offsets 48 / 56 / 64, body-signature data_size
+        # at offset 88
+        pre = struct.pack('<I', preamble_size).ljust(48, b'\0')
+        pre += struct.pack('<QQI', 0x100000, 0x103000, 0x1000)
+        pre = pre.ljust(88, b'\0') + struct.pack('<I', 0x4000)
+        return kblock + pre
+
+    # add corrupt kernel partitions, all of which must be rejected:
+    # - partition 6 (KERN_C): keyblock_size placing the preamble far outside
+    #   the probed data
+    # - partition 13 (KERN_D): preamble_size placing the kernel body offset
+    #   inside the probed data
+    # - partition 14 (KERN_E): preamble_size wrapping the 32-bit body offset
+    # - partition 15 (KERN_F): keyblock_size smaller than the keyblock header,
+    #   placing the claimed preamble inside the header
+    set_part_data(6, bad_kernel_part(0xffffffff, 0x800))
+    set_part_data(0xd, bad_kernel_part(0x100, 0x800))
+    set_part_data(0xe, bad_kernel_part(0x100, 0xffffff10))
+    set_part_data(0xf, bad_kernel_part(0x18, 0x1000))
+
     with open(fname, 'wb') as outf:
         outf.write(disk_data)
 
-- 
2.43.0

Reply via email to