]> git.dujemihanovic.xyz Git - u-boot.git/commitdiff
binman: Allow vblock to include devicetree blobs
authorSimon Glass <sjg@chromium.org>
Thu, 7 Jan 2021 04:35:17 +0000 (21:35 -0700)
committerSimon Glass <sjg@chromium.org>
Sat, 30 Jan 2021 21:25:41 +0000 (14:25 -0700)
At present if a devicetree blob is included in a vblock it does not deal
with updates. This is because the vblock is created once at the start and
does not have a method to update itself later, after all the entry
contents are finalised.

Fix this by adjusting how the vblock is created.

Also simplify Image.ProcessEntryContents() since it effectively duplicates
the code in Section.ProcessContents().

Signed-off-by: Simon Glass <sjg@chromium.org>
tools/binman/etype/blob.py
tools/binman/etype/vblock.py
tools/binman/ftest.py
tools/binman/image.py
tools/binman/test/189_vblock_content.dts [new file with mode: 0644]

index 301ac55e3b21dab3b9cd286e5bbc643526912193..81756c326d9420acfe1c8392ba29e27f00d9f128 100644 (file)
@@ -66,3 +66,7 @@ class Entry_blob(Entry):
 
     def GetDefaultFilename(self):
         return self._filename
+
+    def ProcessContents(self):
+        # The blob may have changed due to WriteSymbols()
+        return self.ProcessContentsUpdate(self.data)
index f734fbaec495c690cc5c710ec787a89c6c6ac0c4..eba5351dd526f708cdb966243fabcc2b646e6b65 100644 (file)
@@ -49,7 +49,7 @@ class Entry_vblock(Entry):
             EntryArg('kernelkey', str),
             EntryArg('preamble-flags', int)])
 
-    def ObtainContents(self):
+    def GetVblock(self):
         # Join up the data files to be signed
         input_data = b''
         for entry_phandle in self.content:
@@ -76,5 +76,16 @@ class Entry_vblock(Entry):
         ]
         #out.Notice("Sign '%s' into %s" % (', '.join(self.value), self.label))
         stdout = tools.Run('futility', *args)
-        self.SetContents(tools.ReadFile(output_fname))
+        return tools.ReadFile(output_fname)
+
+    def ObtainContents(self):
+        data = self.GetVblock()
+        if data is False:
+            return False
+        self.SetContents(data)
         return True
+
+    def ProcessContents(self):
+        # The blob may have changed due to WriteSymbols()
+        data = self.GetVblock()
+        return self.ProcessContentsUpdate(data)
index 8b928eb406de079fb244ed074e5ea76777608589..7f7827b6a7d977b54d5705a30d196703b16a75b9 100644 (file)
@@ -1638,15 +1638,37 @@ class TestFunctional(unittest.TestCase):
                       str(e.exception))
 
     def _HandleVblockCommand(self, pipe_list):
-        """Fake calls to the futility utility"""
+        """Fake calls to the futility utility
+
+        The expected pipe is:
+
+           [('futility', 'vbutil_firmware', '--vblock',
+             'vblock.vblock', '--keyblock', 'devkeys/firmware.keyblock',
+             '--signprivate', 'devkeys/firmware_data_key.vbprivk',
+             '--version', '1', '--fv', 'input.vblock', '--kernelkey',
+             'devkeys/kernel_subkey.vbpubk', '--flags', '1')]
+
+        This writes to the output file (here, 'vblock.vblock'). If
+        self._hash_data is False, it writes VBLOCK_DATA, else it writes a hash
+        of the input data (here, 'input.vblock').
+        """
         if pipe_list[0][0] == 'futility':
             fname = pipe_list[0][3]
             with open(fname, 'wb') as fd:
-                fd.write(VBLOCK_DATA)
+                if self._hash_data:
+                    infile = pipe_list[0][11]
+                    m = hashlib.sha256()
+                    data = tools.ReadFile(infile)
+                    m.update(data)
+                    fd.write(m.digest())
+                else:
+                    fd.write(VBLOCK_DATA)
+
             return command.CommandResult()
 
     def testVblock(self):
         """Test for the Chromium OS Verified Boot Block"""
+        self._hash_data = False
         command.test_result = self._HandleVblockCommand
         entry_args = {
             'keydir': 'devkeys',
@@ -1677,6 +1699,29 @@ class TestFunctional(unittest.TestCase):
         self.assertIn("Node '/binman/vblock': Cannot find entry for node "
                       "'other'", str(e.exception))
 
+    def testVblockContent(self):
+        """Test that the vblock signs the right data"""
+        self._hash_data = True
+        command.test_result = self._HandleVblockCommand
+        entry_args = {
+            'keydir': 'devkeys',
+        }
+        data = self._DoReadFileDtb(
+            '189_vblock_content.dts', use_real_dtb=True, update_dtb=True,
+            entry_args=entry_args)[0]
+        hashlen = 32  # SHA256 hash is 32 bytes
+        self.assertEqual(U_BOOT_DATA, data[:len(U_BOOT_DATA)])
+        hashval = data[-hashlen:]
+        dtb = data[len(U_BOOT_DATA):-hashlen]
+
+        expected_data = U_BOOT_DATA + dtb
+
+        # The hashval should be a hash of the dtb
+        m = hashlib.sha256()
+        m.update(expected_data)
+        expected_hashval = m.digest()
+        self.assertEqual(expected_hashval, hashval)
+
     def testTpl(self):
         """Test that an image with TPL and its device tree can be created"""
         # ELF file with a '__bss_size' symbol
index 3c2fe5ea62025b524691f0a51090c2b6b4937922..e94943524131d674d9b90328ef5f4ad645bee247 100644 (file)
@@ -136,12 +136,7 @@ class Image(section.Entry_section):
         Returns:
             True if the new data size is OK, False if expansion is needed
         """
-        sizes_ok = True
-        for entry in self._entries.values():
-            if not entry.ProcessContents():
-                sizes_ok = False
-                tout.Debug("Entry '%s' size change" % self._node.path)
-        return sizes_ok
+        return super().ProcessContents()
 
     def WriteSymbols(self):
         """Write symbol values into binary files for access at run time"""
diff --git a/tools/binman/test/189_vblock_content.dts b/tools/binman/test/189_vblock_content.dts
new file mode 100644 (file)
index 0000000..dcc7444
--- /dev/null
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0+
+/dts-v1/;
+
+/ {
+       #address-cells = <1>;
+       #size-cells = <1>;
+
+       binman {
+               u_boot: u-boot {
+               };
+
+               dtb: u-boot-dtb {
+               };
+
+               /*
+                * Put the vblock after the dtb so that the dtb is updated
+                * before the vblock reads its data. At present binman does not
+                * understand dependencies between entries, but simply
+                * iterates again when it thinks something needs to be
+                * recalculated.
+                */
+               vblock {
+                       content = <&u_boot &dtb>;
+                       keyblock = "firmware.keyblock";
+                       signprivate = "firmware_data_key.vbprivk";
+                       version = <1>;
+                       kernelkey = "kernel_subkey.vbpubk";
+                       preamble-flags = <1>;
+               };
+       };
+};