/
proc
/
1387183
/
root
/
snap
/
lxd
/
35616
/
lib
/
python3
/
dist-packages
/
pyuefivars
/
File Upload :
llllll
Current File: //proc/1387183/root/snap/lxd/35616/lib/python3/dist-packages/pyuefivars/edk2.py
#!/usr/bin/env python3 # # Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. # SPDX-License-Identifier: MIT import struct import tempfile import os from .aws_file import AWSVarStoreFile from .varstore import UEFIVar, UEFIVarStore class EDK2Cert(object): def __init__(self, name: str, guid: bytes, digest: bytes): self.name = name self.guid = guid self.digest = digest class EDK2CertDB(object): GUID_CERTDB = b'\x6e\xe5\xbe\xd9\xdc\x75\xd9\x49\xb4\xd7\xb5\x34\x21\x0f\x63\x7a' def __init__(self, uefivar: UEFIVar = None): self.certs = [] if uefivar is not None: self.init_from_var(uefivar) def init_from_var(self, uefivar: UEFIVar): file = tempfile.SpooledTemporaryFile() file.write(uefivar.data) file.seek(0, os.SEEK_SET) file = AWSVarStoreFile(file) size = file.read32() if size != len(uefivar.data): raise Exception("Invalid certdb length") size = size - 4 while size != 0: guid = file.readguid() cert_node_size = file.read32() cert_node_size # Unused, silence F841 name_size = file.read32() * 2 digest_size = file.read32() name = file.read(name_size).decode('utf-16le').rstrip('\0') digest = file.read(digest_size) self.certs.append(EDK2Cert(name, guid, digest)) size = size - (16 + 4 + 4 + 4 + name_size + digest_size) def to_var(self, vars: UEFIVar): file = tempfile.SpooledTemporaryFile() file = AWSVarStoreFile(file) file.write32(0) # file size, gets patched in later pubkeyidx = 0 for var in vars: if not var.digest: continue name_size = len(var.name) + 1 digest_size = len(var.digest) file.writeguid(var.guid) file.write32(16 + 4 + 4 + 4 + name_size + digest_size) file.write32(name_size) file.write32(digest_size) file.write(var.name.encode('utf-16le') + b'\0\0') file.write(var.digest) var.pubkeyidx = pubkeyidx pubkeyidx = pubkeyidx + 1 filesize = file.file.tell() file.file.seek(0, os.SEEK_SET) file.write32(filesize) file.file.seek(0, os.SEEK_SET) data = file.file.read() return UEFIVar("certdb", data, self.GUID_CERTDB, 0x7) class EDK2UEFIVarStore(UEFIVarStore): GUID_CERTDB = b'\x6e\xe5\xbe\xd9\xdc\x75\xd9\x49\xb4\xd7\xb5\x34\x21\x0f\x63\x7a' GUID_NVFS = b'\x8d\x2b\xf1\xff\x96\x76\x8b\x4c\xa9\x85\x27\x47\x07\x5b\x4f\x50' GUID_VARSTORE = b'\x78\x2c\xf3\xaa\x7b\x94\x9a\x43\xa1\x80\x2e\x14\x4e\xc3\x77\x92' STATE_SETTLED = 0x3f VARSTORE_STATUS = b'\x5a\xfe\x00\x00\x00\x00\x00\x00' DEFAULT_LENGTH = 540672 EFI_FVB2_READ_DISABLED_CAP = 0x00000001 EFI_FVB2_READ_ENABLED_CAP = 0x00000002 EFI_FVB2_READ_STATUS = 0x00000004 EFI_FVB2_WRITE_DISABLED_CAP = 0x00000008 EFI_FVB2_WRITE_ENABLED_CAP = 0x00000010 EFI_FVB2_WRITE_STATUS = 0x00000020 EFI_FVB2_LOCK_CAP = 0x00000040 EFI_FVB2_LOCK_STATUS = 0x00000080 EFI_FVB2_STICKY_WRITE = 0x00000200 EFI_FVB2_MEMORY_MAPPED = 0x00000400 EFI_FVB2_ERASE_POLARITY = 0x00000800 EFI_FVB2_READ_LOCK_CAP = 0x00001000 EFI_FVB2_READ_LOCK_STATUS = 0x00002000 EFI_FVB2_WRITE_LOCK_CAP = 0x00004000 EFI_FVB2_WRITE_LOCK_STATUS = 0x00008000 EFI_FVB2_ALIGNMENT = 0x001F0000 EFI_FVB2_WEAK_ALIGNMENT = 0x80000000 EFI_FVB2_ALIGNMENT_1 = 0x00000000 EFI_FVB2_ALIGNMENT_2 = 0x00010000 EFI_FVB2_ALIGNMENT_4 = 0x00020000 EFI_FVB2_ALIGNMENT_8 = 0x00030000 EFI_FVB2_ALIGNMENT_16 = 0x00040000 EFI_FVB2_ALIGNMENT_32 = 0x00050000 EFI_FVB2_ALIGNMENT_64 = 0x00060000 EFI_FVB2_ALIGNMENT_128 = 0x00070000 EFI_FVB2_ALIGNMENT_256 = 0x00080000 EFI_FVB2_ALIGNMENT_512 = 0x00090000 EFI_FVB2_ALIGNMENT_1K = 0x000A0000 EFI_FVB2_ALIGNMENT_2K = 0x000B0000 EFI_FVB2_ALIGNMENT_4K = 0x000C0000 EFI_FVB2_ALIGNMENT_8K = 0x000D0000 EFI_FVB2_ALIGNMENT_16K = 0x000E0000 EFI_FVB2_ALIGNMENT_32K = 0x000F0000 EFI_FVB2_ALIGNMENT_64K = 0x00100000 EFI_FVB2_ALIGNMENT_128K = 0x00110000 EFI_FVB2_ALIGNMENT_256K = 0x00120000 EFI_FVB2_ALIGNMENT_512K = 0x00130000 EFI_FVB2_ALIGNMENT_1M = 0x00140000 EFI_FVB2_ALIGNMENT_2M = 0x00150000 EFI_FVB2_ALIGNMENT_4M = 0x00160000 EFI_FVB2_ALIGNMENT_8M = 0x00170000 EFI_FVB2_ALIGNMENT_16M = 0x00180000 EFI_FVB2_ALIGNMENT_32M = 0x00190000 EFI_FVB2_ALIGNMENT_64M = 0x001A0000 EFI_FVB2_ALIGNMENT_128M = 0x001B0000 EFI_FVB2_ALIGNMENT_256M = 0x001C0000 EFI_FVB2_ALIGNMENT_512M = 0x001D0000 EFI_FVB2_ALIGNMENT_1G = 0x001E0000 EFI_FVB2_ALIGNMENT_2G = 0x001F0000 AAVMF_BLOCK_SIZE = 0x00040000 OVMF_BLOCK_SIZE = 0x00001000 def __init__(self, data): super().__init__() self.certdb = EDK2CertDB() # Get a streaming file object file = tempfile.SpooledTemporaryFile() file.write(data) file.seek(0, os.SEEK_SET) file = AWSVarStoreFile(file) # Parse FV header zerovector = file.read(0x10) if zerovector != b'\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0': raise Exception("Invalid Zero Vector: %s" % zerovector) fsguid = file.readguid() if fsguid != self.GUID_NVFS: raise Exception("Invalid GUID: %s" % fsguid) self.length = file.read64() if self.length > len(data): raise Exception("Invalid length: %s" % self.length) sig = file.read(4) if sig != b'_FVH': raise Exception('Invalid FVH signature: %s' % sig) self.attrs = file.read32() hlength = file.read16() csum_hdr = file.read16() if (self.csum16(data[:hlength]) != 0): raise Exception("Invalid header checksum: 0x%x" % csum_hdr) # Ensure there isn't an extension header we don't understand ext_hdr_offset = file.read16() if ext_hdr_offset != 0: raise Exception('FVH with extension header not supported') # Reserved field (should always be 0) reserved = file.read8() if reserved != 0: raise Exception('Wrong value for FVH.Reserved: %s' % reserved) # Read revision rev = file.read8() if rev != 0x2: raise Exception('Invalid FVH Revision: 0x%x' % rev) # Read blockmap self.blockmap = [] total_bytes = 0 while True: block_cnt, block_bytes = file.read32(), file.read32() if block_cnt == 0 and block_bytes == 0: break self.blockmap.append((block_cnt, block_bytes)) total_bytes += block_cnt * block_bytes if self.length != total_bytes: raise Exception('Invalid blockmap: %s' % self.blockmap) # Verify header length (ext headers not supported so must match current pos) if hlength != file.file.tell(): raise Exception('Invalid header length: %s' % hlength) # Parse varstore header vsguid = file.readguid() if vsguid != self.GUID_VARSTORE: raise Exception('Invalid Varstore GUID: %s' % vsguid) self.varsize = file.read32() status = file.read(8) if status != self.VARSTORE_STATUS: raise Exception('Invalid Varstore Status: %s' % status) # Extract all variables while file.read16() == 0x55aa: state = file.read8() file.read8() attr = file.read32() monotoniccount = file.read64() monotoniccount # Unused, silence F841 timestamp = file.readtimestamp() pubkeyidx = file.read32() pubkeyidx # Unused, silence F841 namelen = file.read32() datalen = file.read32() guid = file.readguid() name = file.read(namelen).decode('utf-16le').rstrip('\0') data = file.read(datalen) if state == self.STATE_SETTLED: if timestamp == self.EMPTY_TIMESTAMP: timestamp = None var = UEFIVar(name, data, guid, attr, timestamp, None) if name == "certdb" and guid == self.GUID_CERTDB: self.certdb = EDK2CertDB(var) else: self.vars.append(var) file.file.seek((file.file.tell() + 0x3) & ~0x3, os.SEEK_SET) # Extract all certdb entries into digest fields for cert in self.certdb.certs: for var in self.vars: if var.name == cert.name and var.guid == cert.guid: var.digest = cert.digest def csum16(self, var: bytes): u16 = struct.unpack("<" + str(int(len(var) / 2)) + "H", var) csum = 0 for b in u16: # print("0x%x + 0x%x = 0x%x" % (csum, b, csum + b)) csum = csum + b return (csum & 0xffff) def write_var(self, raw: AWSVarStoreFile, var: UEFIVar): raw.write16(0x55aa) raw.write8(self.STATE_SETTLED) raw.write8(0) raw.write32(var.attr) raw.write64(0) # monotonic count if var.timestamp: raw.write(var.timestamp) else: raw.write(b'\0' * 16) if hasattr(var, 'pubkeyidx'): raw.write32(var.pubkeyidx) else: raw.write32(0) raw.write32(len(var.name + '\0') * 2) raw.write32(len(var.data)) raw.write(var.guid) raw.write((var.name + '\0').encode('utf-16le')) raw.write(var.data) raw.file.seek((raw.file.tell() + 0x3) & ~0x3, os.SEEK_SET) def __bytes__(self) -> bytes: if not hasattr(self, 'certdb'): self.certdb = EDK2CertDB() if not hasattr(self, 'length'): self.length = self.DEFAULT_LENGTH if not hasattr(self, 'attrs'): self.attrs = self.EFI_FVB2_READ_DISABLED_CAP | \ self.EFI_FVB2_READ_ENABLED_CAP | \ self.EFI_FVB2_READ_STATUS | \ self.EFI_FVB2_WRITE_DISABLED_CAP | \ self.EFI_FVB2_WRITE_ENABLED_CAP | \ self.EFI_FVB2_WRITE_STATUS | \ self.EFI_FVB2_LOCK_CAP | \ self.EFI_FVB2_LOCK_STATUS | \ self.EFI_FVB2_STICKY_WRITE | \ self.EFI_FVB2_MEMORY_MAPPED | \ self.EFI_FVB2_ERASE_POLARITY | \ self.EFI_FVB2_READ_LOCK_CAP | \ self.EFI_FVB2_READ_LOCK_STATUS | \ self.EFI_FVB2_WRITE_LOCK_CAP | \ self.EFI_FVB2_WRITE_LOCK_STATUS | \ self.EFI_FVB2_ALIGNMENT_16 if not hasattr(self, 'varsize'): self.varsize = int(self.length / 2) - 8264 if not hasattr(self, 'blockmap'): # What is a sensible default here? Examples: # - AAVMF uses 256K blocks (virtual NOR) # - OVMF uses 4K blocks (page size) self.blockmap = [(self.length // self.OVMF_BLOCK_SIZE, self.OVMF_BLOCK_SIZE)] # Assemble the flash file raw = AWSVarStoreFile(tempfile.SpooledTemporaryFile()) # Write FV header raw.write(b'\0' * 16) raw.write(self.GUID_NVFS) raw.write64(self.length) raw.write(b'_FVH') raw.write32(self.attrs) # Leave room for header length hlength_pos = raw.file.tell() raw.write16(0) # Skip checksum - need to fill in later csum_pos = raw.file.tell() raw.write16(0) # No ext header offset + set reversed byte to 0 raw.write(b'\0' * 3) # Revision raw.write8(0x2) # Blockmap for block_cnt, block_bytes in self.blockmap: raw.write32(block_cnt) raw.write32(block_bytes) raw.write32(0) raw.write32(0) # Write header length hlength = raw.file.tell() raw.file.seek(hlength_pos, os.SEEK_SET) raw.write16(hlength) # Checksum raw.file.seek(0, os.SEEK_SET) fvh = raw.file.read(hlength) raw.file.seek(csum_pos, os.SEEK_SET) raw.write16((0x10000 - self.csum16(fvh) & 0xffff)) # Go to end of FV header raw.file.seek(hlength, os.SEEK_SET) # Write varstore header raw.write(self.GUID_VARSTORE) raw.write32(self.varsize) raw.write(self.VARSTORE_STATUS) # Write variables self.write_var(raw, self.certdb.to_var(self.vars)) for var in self.vars: self.write_var(raw, var) # Make sure it all fits if raw.file.tell() > self.length: raise Exception("Can not fit variables into store") # Expand to maximum file size raw.file.seek(self.length - 1, os.SEEK_SET) raw.write8(0) raw.file.seek(0, os.SEEK_SET) return raw.file.read() def set_output_options(self, options): for option in [option.strip().split("=") for option in options]: if option[0] == 'filesize': if (len(option) != 2 or not option[1]): raise SystemExit( 'option "filesize" requires a second argument' ) self.length = int(option[1]) * 1024 else: raise SystemExit( 'Unknown Option type "{}"'.format(option) )
Copyright ©2k19 -
Hexid
|
Tex7ure