Add a library which performs two different attacks on a FIT.
Signed-off-by: Julien Lenoir
Signed-off-by: Bruce Monroe
Signed-off-by: Arie Haenel
Signed-off-by: Simon Glass
---
test/py/tests/vboot_evil.py | 485
1 file changed, 485 insertions(+)
create mode 100644 test/py/tests/vboot_evil.py
diff --git a/test/py/tests/vboot_evil.py b/test/py/tests/vboot_evil.py
new file mode 100644
index 000..9825c21716b
--- /dev/null
+++ b/test/py/tests/vboot_evil.py
@@ -0,0 +1,485 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2020, Intel Corporation
+
+"""Modifies a devicetree to add a fake root node, for testing purposes"""
+
+import hashlib
+import struct
+import sys
+
+FDT_PROP = 0x3
+FDT_BEGIN_NODE = 0x1
+FDT_END_NODE = 0x2
+FDT_END = 0x9
+
+FAKE_ROOT_ATTACK = 0
+KERNEL_AT = 1
+
+MAGIC = 0xd00dfeed
+
+EVIL_KERNEL_NAME = b'evil_kernel'
+FAKE_ROOT_NAME = b'f@keroot'
+
+
+def getstr(dt_strings, off):
+"""Get a string from the devicetree string table
+
+Args:
+dt_strings (bytes): Devicetree strings section
+off (int): Offset of string to read
+
+Returns:
+str: String read from the table
+"""
+output = ''
+while dt_strings[off]:
+output += chr(dt_strings[off])
+off += 1
+
+return output
+
+
+def align(offset):
+"""Align an offset to a multiple of 4
+
+Args:
+offset (int): Offset to align
+
+Returns:
+int: Resulting aligned offset (rounds up to nearest multiple)
+"""
+return (offset + 3) & ~3
+
+
+def determine_offset(dt_struct, dt_strings, searched_node_name):
+"""Determines the offset of an element, either a node or a property
+
+Args:
+dt_struct (bytes): Devicetree struct section
+dt_strings (bytes): Devicetree strings section
+searched_node_name (str): element path, ex: /images/kernel@1/data
+
+Returns:
+tuple: (node start offset, node end offset)
+if element is not found, returns (None, None)
+"""
+offset = 0
+depth = -1
+
+path = '/'
+
+object_start_offset = None
+object_end_offset = None
+object_depth = None
+
+while offset < len(dt_struct):
+(tag,) = struct.unpack('>I', dt_struct[offset:offset + 4])
+
+if tag == FDT_BEGIN_NODE:
+depth += 1
+
+begin_node_offset = offset
+offset += 4
+
+node_name = getstr(dt_struct, offset)
+offset += len(node_name) + 1
+offset = align(offset)
+
+if path[-1] != '/':
+path += '/'
+
+path += str(node_name)
+
+if path == searched_node_name:
+object_start_offset = begin_node_offset
+object_depth = depth
+
+elif tag == FDT_PROP:
+begin_prop_offset = offset
+
+offset += 4
+len_tag, nameoff = struct.unpack('>II',
+ dt_struct[offset:offset + 8])
+offset += 8
+prop_name = getstr(dt_strings, nameoff)
+
+len_tag = align(len_tag)
+
+offset += len_tag
+
+node_path = path + '/' + str(prop_name)
+
+if node_path == searched_node_name:
+object_start_offset = begin_prop_offset
+
+elif tag == FDT_END_NODE:
+offset += 4
+
+path = path[:path.rfind('/')]
+if not path:
+path = '/'
+
+if depth == object_depth:
+object_end_offset = offset
+break
+depth -= 1
+elif tag == FDT_END:
+break
+
+else:
+print('unknown tag=0x%x, offset=0x%x found!' % (tag, offset))
+break
+
+return object_start_offset, object_end_offset
+
+
+def modify_node_name(dt_struct, node_offset, replcd_name):
+"""Change the name of a node
+
+Args:
+dt_struct (bytes): Devicetree struct section
+node_offset (int): Offset of node
+replcd_name (str): New name for node
+
+Returns:
+bytes: New dt_struct contents
+"""
+
+# skip 4 bytes for the FDT_BEGIN_NODE
+node_offset += 4
+
+node_name = getstr(dt_struct, node_offset)
+node_name_len = len(node_name) + 1
+
+node_name_len = align(node_name_len)
+
+replcd_name += b'\0'
+
+# align on 4 bytes
+while len(replcd_name) % 4:
+replcd_name += b'\0'
+
+dt_struct = (dt_struct[:node_offset] + replcd_name +
+ dt_struct[node_offset + node_name_len:])
+
+return dt_struct
+
+
+def modify_prop_content(dt_struct, prop_offset, content):
+"""Overwrite the value of a property
+
+Args:
+dt_struct (bytes): Devicetree struct section
+prop_offset (int): Offset of property (FDT_PROP tag)
+content (bytes): New content for the property
+
+Returns:
+bytes: New dt_struct contents
+"""
+# skip FDT_PROP
+prop_