mirror of
https://github.com/u-boot/u-boot.git
synced 2025-05-08 10:39:08 +00:00
test: Add tests for the 'evil' vboot attacks
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>
This commit is contained in:
parent
fafafacb47
commit
d5f3aadacb
1 changed files with 64 additions and 27 deletions
|
@ -24,22 +24,26 @@ For configuration verification:
|
||||||
Tests run with both SHA1 and SHA256 hashing.
|
Tests run with both SHA1 and SHA256 hashing.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
import shutil
|
||||||
import struct
|
import struct
|
||||||
import pytest
|
import pytest
|
||||||
import u_boot_utils as util
|
import u_boot_utils as util
|
||||||
import vboot_forge
|
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 = [
|
TESTDATA = [
|
||||||
['sha1', '', None, False],
|
['sha1', '', None, False, True],
|
||||||
['sha1', '', '-E -p 0x10000', False],
|
['sha1', '', '-E -p 0x10000', False, False],
|
||||||
['sha1', '-pss', None, False],
|
['sha1', '-pss', None, False, False],
|
||||||
['sha1', '-pss', '-E -p 0x10000', False],
|
['sha1', '-pss', '-E -p 0x10000', False, False],
|
||||||
['sha256', '', None, False],
|
['sha256', '', None, False, False],
|
||||||
['sha256', '', '-E -p 0x10000', False],
|
['sha256', '', '-E -p 0x10000', False, False],
|
||||||
['sha256', '-pss', None, False],
|
['sha256', '-pss', None, False, False],
|
||||||
['sha256', '-pss', '-E -p 0x10000', False],
|
['sha256', '-pss', '-E -p 0x10000', False, False],
|
||||||
['sha256', '-pss', None, True],
|
['sha256', '-pss', None, True, False],
|
||||||
['sha256', '-pss', '-E -p 0x10000', True],
|
['sha256', '-pss', '-E -p 0x10000', True, True],
|
||||||
]
|
]
|
||||||
|
|
||||||
@pytest.mark.boardspec('sandbox')
|
@pytest.mark.boardspec('sandbox')
|
||||||
|
@ -48,8 +52,10 @@ TESTDATA = [
|
||||||
@pytest.mark.requiredtool('fdtget')
|
@pytest.mark.requiredtool('fdtget')
|
||||||
@pytest.mark.requiredtool('fdtput')
|
@pytest.mark.requiredtool('fdtput')
|
||||||
@pytest.mark.requiredtool('openssl')
|
@pytest.mark.requiredtool('openssl')
|
||||||
@pytest.mark.parametrize("sha_algo,padding,sign_options,required", TESTDATA)
|
@pytest.mark.parametrize("sha_algo,padding,sign_options,required,full_test",
|
||||||
def test_vboot(u_boot_console, sha_algo, padding, sign_options, required):
|
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'.
|
"""Test verified boot signing with mkimage and verification with 'bootm'.
|
||||||
|
|
||||||
This works using sandbox only as it needs to update the device tree used
|
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 '
|
util.run_and_log(cons, 'dtc %s %s%s -O dtb '
|
||||||
'-o %s%s' % (dtc_args, datadir, dts, tmpdir, 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.
|
"""Run a 'bootm' command U-Boot.
|
||||||
|
|
||||||
This always starts a fresh U-Boot instance since the device tree may
|
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.
|
use.
|
||||||
boots: A boolean that is True if Linux should boot and False if
|
boots: A boolean that is True if Linux should boot and False if
|
||||||
we are expected to not boot
|
we are expected to not boot
|
||||||
|
fit: FIT filename to load and verify
|
||||||
"""
|
"""
|
||||||
|
if not fit:
|
||||||
|
fit = '%stest.fit' % tmpdir
|
||||||
cons.restart_uboot()
|
cons.restart_uboot()
|
||||||
with cons.log.section('Verified boot %s %s' % (sha_algo, test_type)):
|
with cons.log.section('Verified boot %s %s' % (sha_algo, test_type)):
|
||||||
output = cons.run_command_list(
|
output = cons.run_command_list(
|
||||||
['host load hostfs - 100 %stest.fit' % tmpdir,
|
['host load hostfs - 100 %s' % fit,
|
||||||
'fdt addr 100',
|
'fdt addr 100',
|
||||||
'bootm 100'])
|
'bootm 100'])
|
||||||
assert expect_string in ''.join(output)
|
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])
|
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
|
if full_test:
|
||||||
# nodes. If it isn't, a security bypass is possible.
|
# Make sure that U-Boot checks that the config is in the list of hashed
|
||||||
with open(fit, 'rb') as fd:
|
# nodes. If it isn't, a security bypass is possible.
|
||||||
root, strblock = vboot_forge.read_fdt(fd)
|
ffit = '%stest.forged.fit' % tmpdir
|
||||||
root, strblock = vboot_forge.manipulate(root, strblock)
|
shutil.copyfile(fit, ffit)
|
||||||
with open(fit, 'w+b') as fd:
|
with open(ffit, 'rb') as fd:
|
||||||
vboot_forge.write_fdt(root, strblock, fd)
|
root, strblock = vboot_forge.read_fdt(fd)
|
||||||
util.run_and_log_expect_exception(
|
root, strblock = vboot_forge.manipulate(root, strblock)
|
||||||
cons, [fit_check_sign, '-f', fit, '-k', dtb],
|
with open(ffit, 'w+b') as fd:
|
||||||
1, 'Failed to verify required signature')
|
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)
|
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
|
# Create a new properly signed fit and replace header bytes
|
||||||
make_fit('sign-configs-%s%s.its' % (sha_algo, padding))
|
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_rsa_pair('prod')
|
||||||
|
|
||||||
# Create a number kernel image with zeroes
|
# Create a number kernel image with zeroes
|
||||||
with open('%stest-kernel.bin' % tmpdir, 'w') as fd:
|
with open('%stest-kernel.bin' % tmpdir, 'wb') as fd:
|
||||||
fd.write(500 * chr(0))
|
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:
|
try:
|
||||||
# We need to use our own device tree file. Remember to restore it
|
# We need to use our own device tree file. Remember to restore it
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue