All of lore.kernel.org
 help / color / mirror / Atom feed
From: Simon Glass <sjg@chromium.org>
To: u-boot@lists.denx.de
Subject: [PATCH 4/8] test: Add tests for the 'evil' vboot attacks
Date: Mon, 15 Feb 2021 17:08:08 -0700	[thread overview]
Message-ID: <20210216000812.2091481-5-sjg@chromium.org> (raw)
In-Reply-To: <20210216000812.2091481-1-sjg@chromium.org>

Add tests to check that these two attacks are mitigated by recent patches.

Signed-off-by: Simon Glass <sjg@chromium.org>
Reported-by: Bruce Monroe <bruce.monroe@intel.com>
Reported-by: Arie Haenel <arie.haenel@intel.com>
Reported-by: Julien Lenoir <julien.lenoir@intel.com>
---

 test/py/tests/test_vboot.py | 93 ++++++++++++++++++++++++++-----------
 1 file changed, 65 insertions(+), 28 deletions(-)

diff --git a/test/py/tests/test_vboot.py b/test/py/tests/test_vboot.py
index e45800d94c0..9cdc290b9fc 100644
--- a/test/py/tests/test_vboot.py
+++ b/test/py/tests/test_vboot.py
@@ -24,22 +24,26 @@ For configuration verification:
 Tests run with both SHA1 and SHA256 hashing.
 """
 
+import shutil
 import struct
 import pytest
 import u_boot_utils as util
 import vboot_forge
+import vboot_evil
 
+# Only run the full suite on a few combinations, since it doesn't add any more
+# test coverage.
 TESTDATA = [
-    ['sha1', '', None, False],
-    ['sha1', '', '-E -p 0x10000', False],
-    ['sha1', '-pss', None, False],
-    ['sha1', '-pss', '-E -p 0x10000', False],
-    ['sha256', '', None, False],
-    ['sha256', '', '-E -p 0x10000', False],
-    ['sha256', '-pss', None, False],
-    ['sha256', '-pss', '-E -p 0x10000', False],
-    ['sha256', '-pss', None, True],
-    ['sha256', '-pss', '-E -p 0x10000', True],
+    ['sha1', '', None, False, True],
+    ['sha1', '', '-E -p 0x10000', False, False],
+    ['sha1', '-pss', None, False, False],
+    ['sha1', '-pss', '-E -p 0x10000', False, False],
+    ['sha256', '', None, False, False],
+    ['sha256', '', '-E -p 0x10000', False, False],
+    ['sha256', '-pss', None, False, False],
+    ['sha256', '-pss', '-E -p 0x10000', False, False],
+    ['sha256', '-pss', None, True, False],
+    ['sha256', '-pss', '-E -p 0x10000', True, True],
 ]
 
 @pytest.mark.boardspec('sandbox')
@@ -48,8 +52,10 @@ TESTDATA = [
 @pytest.mark.requiredtool('fdtget')
 @pytest.mark.requiredtool('fdtput')
 @pytest.mark.requiredtool('openssl')
- at pytest.mark.parametrize("sha_algo,padding,sign_options,required", TESTDATA)
-def test_vboot(u_boot_console, sha_algo, padding, sign_options, required):
+ at pytest.mark.parametrize("sha_algo,padding,sign_options,required,full_test",
+                         TESTDATA)
+def test_vboot(u_boot_console, sha_algo, padding, sign_options, required,
+               full_test):
     """Test verified boot signing with mkimage and verification with 'bootm'.
 
     This works using sandbox only as it needs to update the device tree used
@@ -71,7 +77,7 @@ def test_vboot(u_boot_console, sha_algo, padding, sign_options, required):
         util.run_and_log(cons, 'dtc %s %s%s -O dtb '
                          '-o %s%s' % (dtc_args, datadir, dts, tmpdir, dtb))
 
-    def run_bootm(sha_algo, test_type, expect_string, boots):
+    def run_bootm(sha_algo, test_type, expect_string, boots, fit=None):
         """Run a 'bootm' command U-Boot.
 
         This always starts a fresh U-Boot instance since the device tree may
@@ -84,11 +90,14 @@ def test_vboot(u_boot_console, sha_algo, padding, sign_options, required):
                     use.
             boots: A boolean that is True if Linux should boot and False if
                     we are expected to not boot
+            fit: FIT filename to load and verify
         """
+        if not fit:
+            fit = '%stest.fit' % tmpdir
         cons.restart_uboot()
         with cons.log.section('Verified boot %s %s' % (sha_algo, test_type)):
             output = cons.run_command_list(
-                ['host load hostfs - 100 %stest.fit' % tmpdir,
+                ['host load hostfs - 100 %s' % fit,
                  'fdt addr 100',
                  'bootm 100'])
         assert expect_string in ''.join(output)
@@ -222,18 +231,41 @@ def test_vboot(u_boot_console, sha_algo, padding, sign_options, required):
 
         util.run_and_log(cons, [fit_check_sign, '-f', fit, '-k', dtb])
 
-        # Make sure that U-Boot checks that the config is in the list of hashed
-        # nodes. If it isn't, a security bypass is possible.
-        with open(fit, 'rb') as fd:
-            root, strblock = vboot_forge.read_fdt(fd)
-        root, strblock = vboot_forge.manipulate(root, strblock)
-        with open(fit, 'w+b') as fd:
-            vboot_forge.write_fdt(root, strblock, fd)
-        util.run_and_log_expect_exception(
-            cons, [fit_check_sign, '-f', fit, '-k', dtb],
-            1, 'Failed to verify required signature')
-
-        run_bootm(sha_algo, 'forged config', 'Bad Data Hash', False)
+        if full_test:
+            # Make sure that U-Boot checks that the config is in the list of hashed
+            # nodes. If it isn't, a security bypass is possible.
+            ffit = '%stest.forged.fit' % tmpdir
+            shutil.copyfile(fit, ffit)
+            with open(ffit, 'rb') as fd:
+                root, strblock = vboot_forge.read_fdt(fd)
+            root, strblock = vboot_forge.manipulate(root, strblock)
+            with open(ffit, 'w+b') as fd:
+                vboot_forge.write_fdt(root, strblock, fd)
+            util.run_and_log_expect_exception(
+                cons, [fit_check_sign, '-f', ffit, '-k', dtb],
+                1, 'Failed to verify required signature')
+
+            run_bootm(sha_algo, 'forged config', 'Bad Data Hash', False, ffit)
+
+            # Try adding an evil root node. This should be detected.
+            efit = '%stest.evilf.fit' % tmpdir
+            shutil.copyfile(fit, efit)
+            vboot_evil.add_evil_node(fit, efit, evil_kernel, 'fakeroot')
+
+            util.run_and_log_expect_exception(
+                cons, [fit_check_sign, '-f', efit, '-k', dtb],
+                1, 'Failed to verify required signature')
+            run_bootm(sha_algo, 'evil fakeroot', 'Bad Data Hash', False, efit)
+
+            # Try adding an @ to the kernel node name. This should be detected.
+            efit = '%stest.evilk.fit' % tmpdir
+            shutil.copyfile(fit, efit)
+            vboot_evil.add_evil_node(fit, efit, evil_kernel, 'kernel@')
+
+            util.run_and_log_expect_exception(
+                cons, [fit_check_sign, '-f', efit, '-k', dtb],
+                1, 'Node name contains @')
+            run_bootm(sha_algo, 'evil kernel@', 'Bad Data Hash', False, efit)
 
         # Create a new properly signed fit and replace header bytes
         make_fit('sign-configs-%s%s.its' % (sha_algo, padding))
@@ -344,8 +376,13 @@ def test_vboot(u_boot_console, sha_algo, padding, sign_options, required):
     create_rsa_pair('prod')
 
     # Create a number kernel image with zeroes
-    with open('%stest-kernel.bin' % tmpdir, 'w') as fd:
-        fd.write(500 * chr(0))
+    with open('%stest-kernel.bin' % tmpdir, 'wb') as fd:
+        fd.write(500 * b'\0')
+
+    # Create a second kernel image with ones
+    evil_kernel = '%stest-kernel1.bin' % tmpdir
+    with open(evil_kernel, 'wb') as fd:
+        fd.write(500 * b'\x01')
 
     try:
         # We need to use our own device tree file. Remember to restore it
-- 
2.30.0.478.g8a0d178c01-goog

  parent reply	other threads:[~2021-02-16  0:08 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-02-16  0:08 [PATCH 0/8] vboot: Correct vulnerabilities identified by Intel Simon Glass
2021-02-16  0:08 ` [PATCH 1/8] fdt_region: Check for a single root node of the correct name Simon Glass
2021-02-16  3:35   ` Tom Rini
2021-02-16  0:08 ` [PATCH 2/8] fit: Don't allow verification of images with @ nodes Simon Glass
2021-02-16  3:35   ` Tom Rini
2021-02-16  0:08 ` [PATCH 3/8] test: Add vboot_evil implementation Simon Glass
2021-02-16  3:36   ` Tom Rini
2021-02-16  0:08 ` Simon Glass [this message]
2021-02-16  3:36   ` [PATCH 4/8] test: Add tests for the 'evil' vboot attacks Tom Rini
2021-02-16  0:08 ` [PATCH 5/8] image: Adjust the workings of fit_check_format() Simon Glass
2021-02-16  3:36   ` Tom Rini
2021-02-17 13:30   ` Jesper Schmitz Mouridsen
2021-02-17 13:43     ` Tom Rini
2021-02-17 14:12       ` Jesper Schmitz Mouridsen
2021-02-16  0:08 ` [PATCH 6/8] image: Add an option to do a full check of the FIT Simon Glass
2021-02-16  3:36   ` Tom Rini
2021-02-16  0:08 ` [PATCH 7/8] libfdt: Check for multiple/invalid root nodes Simon Glass
2021-02-16  3:36   ` Tom Rini
2021-02-16  0:08 ` [PATCH 8/8] image: Check for unit addresses in FITs Simon Glass
2021-02-16  3:36   ` Tom Rini

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210216000812.2091481-5-sjg@chromium.org \
    --to=sjg@chromium.org \
    --cc=u-boot@lists.denx.de \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.