def test_cbfs_no_space(self): """Check handling of running out of space in the CBFS""" size = 0x60 cbw = CbfsWriter(size) cbw.add_file_raw('u-boot', U_BOOT_DATA) with self.assertRaises(ValueError) as e: cbw.get_data() self.assertIn('No space for header', str(e.exception))
def test_cbfs_no_space_skip(self): """Check handling of running out of space in CBFS with file header""" size = 0x5c cbw = CbfsWriter(size, arch=cbfs_util.ARCHITECTURE_PPC64) cbw._add_fileheader = True cbw.add_file_raw('u-boot', U_BOOT_DATA) with self.assertRaises(ValueError) as e: cbw.get_data() self.assertIn('No space for data before offset', str(e.exception))
def test_cbfs_no_space_pad(self): """Check handling of running out of space in CBFS with file header""" size = 0x70 cbw = CbfsWriter(size) cbw._add_fileheader = True cbw.add_file_raw('u-boot', U_BOOT_DATA) with self.assertRaises(ValueError) as e: cbw.get_data() self.assertIn('No space for data before pad offset', str(e.exception))
def test_cbfs_offset_conflict(self): """Test a CBFS with files that want to overlap""" size = 0x200 cbw = CbfsWriter(size) cbw.add_file_raw('u-boot', U_BOOT_DATA, 0x40) cbw.add_file_raw('u-boot-dtb', U_BOOT_DTB_DATA, 0x80) with self.assertRaises(ValueError) as e: cbw.get_data() self.assertIn('No space for data before pad offset', str(e.exception))
def test_cbfs_invalid_file_type_header(self): """Check handling of an invalid file type when outputting a header""" size = 0xb0 cbw = CbfsWriter(size) cfile = cbw.add_file_raw('u-boot', U_BOOT_DATA, 0) # Change the type manually before generating the CBFS, and make sure # that the generator complains cfile.ftype = 0xff with self.assertRaises(ValueError) as e: cbw.get_data() self.assertIn('Unknown file type 0xff', str(e.exception))
def test_cbfs_missing_attribute(self): """Check handling of an incomplete attribute tag""" if not self.have_lz4: self.skipTest('lz4 --no-frame-crc not available') size = 0x140 cbw = CbfsWriter(size) cbw.add_file_raw('u-boot', COMPRESS_DATA, None, compress=cbfs_util.COMPRESS_LZ4) data = cbw.get_data() # Read in the CBFS master header (only), then stop cbr = cbfs_util.CbfsReader(data, read=False) with io.BytesIO(data) as fd: self.assertTrue(cbr._find_and_read_header(fd, len(data))) pos = fd.tell() # Create a new CBFS with only the first 4 bytes of the compression tag, # then try to read the file tag_pos = pos + cbfs_util.FILE_HEADER_LEN + cbfs_util.FILENAME_ALIGN newdata = data[:tag_pos + 4] with test_util.capture_sys_output() as (stdout, _stderr): with io.BytesIO(newdata) as fd: fd.seek(pos) self.assertEqual(False, cbr._read_next_file(fd)) self.assertIn('Attribute tag at %x ran out of data' % tag_pos, stdout.getvalue())
def test_cbfs_bad_attribute(self): """Check handling of bad attribute tag""" if not self.have_lz4: self.skipTest('lz4 --no-frame-crc not available') size = 0x140 cbw = CbfsWriter(size) cbw.add_file_raw('u-boot', COMPRESS_DATA, None, compress=cbfs_util.COMPRESS_LZ4) data = cbw.get_data() # Search the CBFS for the expected compression tag with io.BytesIO(data) as fd: while True: pos = fd.tell() tag, = struct.unpack('>I', fd.read(4)) if tag == cbfs_util.FILE_ATTR_TAG_COMPRESSION: break # Create a new CBFS with the tag changed to something invalid newdata = data[:pos] + struct.pack('>I', 0x123) + data[pos + 4:] with test_util.capture_sys_output() as (stdout, _stderr): cbfs_util.CbfsReader(newdata) self.assertEqual('Unknown attribute tag 123\n', stdout.getvalue())
def test_cbfs_invalid_file_type_on_read(self): """Check handling of an invalid file type when reading the CBFS""" size = 0xb0 cbw = CbfsWriter(size) cbw.add_file_raw('u-boot', U_BOOT_DATA) data = cbw.get_data() # Read in the first file header cbr = cbfs_util.CbfsReader(data, read=False) with io.BytesIO(data) as fd: self.assertTrue(cbr._find_and_read_header(fd, len(data))) pos = fd.tell() hdr_data = fd.read(cbfs_util.FILE_HEADER_LEN) magic, size, ftype, attr, offset = struct.unpack( cbfs_util.FILE_HEADER_FORMAT, hdr_data) # Create a new CBFS with a change to the file type ftype = 0xff newdata = data[:pos] newdata += struct.pack(cbfs_util.FILE_HEADER_FORMAT, magic, size, ftype, attr, offset) newdata += data[pos + cbfs_util.FILE_HEADER_LEN:] # Read in this CBFS and make sure that the reader complains with self.assertRaises(ValueError) as e: cbfs_util.CbfsReader(newdata) self.assertIn('Unknown type 0xff when reading', str(e.exception))
def ObtainContents(self, skip=None): arch = cbfs_util.find_arch(self._cbfs_arg) if arch is None: self.Raise("Invalid architecture '%s'" % self._cbfs_arg) if self.size is None: self.Raise("'cbfs' entry must have a size property") cbfs = CbfsWriter(self.size, arch) for entry in self._cbfs_entries.values(): # First get the input data and put it in a file. If not available, # try later. if entry != skip and not entry.ObtainContents(): return False data = entry.GetData() cfile = None if entry._type == 'raw': cfile = cbfs.add_file_raw(entry._cbfs_name, data, entry._cbfs_offset, entry._cbfs_compress) elif entry._type == 'stage': cfile = cbfs.add_file_stage(entry._cbfs_name, data, entry._cbfs_offset) else: entry.Raise("Unknown cbfs-type '%s' (use 'raw', 'stage')" % entry._type) if cfile: entry._cbfs_file = cfile data = cbfs.get_data() self.SetContents(data) return True
def test_cbfs_stage(self): """Tests handling of a Coreboot Filesystem (CBFS)""" if not elf.ELF_TOOLS: self.skipTest('Python elftools not available') elf_fname = os.path.join(self._indir, 'cbfs-stage.elf') elf.MakeElf(elf_fname, U_BOOT_DATA, U_BOOT_DTB_DATA) size = 0xb0 cbw = CbfsWriter(size) cbw.add_file_stage('u-boot', tools.ReadFile(elf_fname)) data = cbw.get_data() cbfs = self._check_hdr(data, size) load = 0xfef20000 entry = load + 2 cfile = self._check_uboot(cbfs, cbfs_util.TYPE_STAGE, offset=0x28, data=U_BOOT_DATA + U_BOOT_DTB_DATA) self.assertEqual(entry, cfile.entry) self.assertEqual(load, cfile.load) self.assertEqual( len(U_BOOT_DATA) + len(U_BOOT_DTB_DATA), cfile.data_len) # Compare against what cbfstool creates if self.have_cbfstool: cbfs_fname = os.path.join(self._indir, 'test.cbfs') self.cbfstool.create_new(cbfs_fname, size) self.cbfstool.add_stage(cbfs_fname, 'u-boot', elf_fname) self._compare_expected_cbfs(data, cbfs_fname)
def test_cbfs_raw_space(self): """Test files with unused space in the CBFS""" size = 0xf0 cbw = CbfsWriter(size) cbw.add_file_raw('u-boot', U_BOOT_DATA) cbw.add_file_raw('u-boot-dtb', U_BOOT_DTB_DATA) data = cbw.get_data() self._check_raw(data, size) cbfs_fname = self._get_expected_cbfs(size=size) self._compare_expected_cbfs(data, cbfs_fname)
def test_cbfs_raw(self): """Test base handling of a Coreboot Filesystem (CBFS)""" size = 0xb0 cbw = CbfsWriter(size) cbw.add_file_raw('u-boot', U_BOOT_DATA) cbw.add_file_raw('u-boot-dtb', U_BOOT_DTB_DATA) data = cbw.get_data() self._check_raw(data, size) cbfs_fname = self._get_expected_cbfs(size=size) self._compare_expected_cbfs(data, cbfs_fname)
def test_cbfs_file_master_header(self): """Check handling of a file containing a master header""" size = 0x100 cbw = CbfsWriter(size) cbw._add_fileheader = True cbw.add_file_raw('u-boot', U_BOOT_DATA) data = cbw.get_data() cbr = cbfs_util.CbfsReader(data) self.assertIn('u-boot', cbr.files) self.assertEqual(size, cbr.rom_size)
def test_cbfs_check_offset(self): """Test that we can discover the offset of a file after writing it""" size = 0xb0 cbw = CbfsWriter(size) cbw.add_file_raw('u-boot', U_BOOT_DATA) cbw.add_file_raw('u-boot-dtb', U_BOOT_DTB_DATA) data = cbw.get_data() cbfs = cbfs_util.CbfsReader(data) self.assertEqual(0x38, cbfs.files['u-boot'].cbfs_offset) self.assertEqual(0x78, cbfs.files['u-boot-dtb'].cbfs_offset)
def test_cbfs_arch(self): """Test on non-x86 architecture""" size = 0x100 cbw = CbfsWriter(size, arch=cbfs_util.ARCHITECTURE_PPC64) cbw.add_file_raw('u-boot', U_BOOT_DATA) cbw.add_file_raw('u-boot-dtb', U_BOOT_DTB_DATA) data = cbw.get_data() self._check_raw(data, size, offset=0x40, arch=cbfs_util.ARCHITECTURE_PPC64) # Compare against what cbfstool creates cbfs_fname = self._get_expected_cbfs(size=size, arch='ppc64') self._compare_expected_cbfs(data, cbfs_fname)
def test_cbfs_bad_header(self): """Check handling of a bad master header""" size = 0x70 cbw = CbfsWriter(size) cbw.add_file_raw('u-boot', U_BOOT_DATA) data = cbw.get_data() # Drop most of the header and try reading the modified CBFS newdata = data[:cbw._header_offset + 4] with test_util.capture_sys_output() as (stdout, _stderr): with self.assertRaises(ValueError) as e: cbfs_util.CbfsReader(newdata) self.assertIn('Relative offset seems wrong', stdout.getvalue()) self.assertIn('Cannot find master header', str(e.exception))
def test_cbfs_debug(self): """Check debug output""" size = 0x70 cbw = CbfsWriter(size) cbw.add_file_raw('u-boot', U_BOOT_DATA) data = cbw.get_data() try: cbfs_util.DEBUG = True with test_util.capture_sys_output() as (stdout, _stderr): cbfs_util.CbfsReader(data) self.assertEqual('name u-boot\ndata %s\n' % U_BOOT_DATA, stdout.getvalue()) finally: cbfs_util.DEBUG = False
def ObtainContents(self, skip_entry=None): arch = cbfs_util.find_arch(self._cbfs_arg) if arch is None: self.Raise("Invalid architecture '%s'" % self._cbfs_arg) if self.size is None: self.Raise("'cbfs' entry must have a size property") cbfs = CbfsWriter(self.size, arch) for entry in self._entries.values(): if entry != skip_entry and not entry.ObtainContents(): return False cfile = self.ObtainCfile(cbfs, entry) if cfile: entry._cbfs_file = cfile data = cbfs.get_data() self.SetContents(data) return True
def test_cbfs_bad_header_ptr(self): """Check handling of a bad master-header pointer""" size = 0x70 cbw = CbfsWriter(size) cbw.add_file_raw('u-boot', U_BOOT_DATA) data = cbw.get_data() # Add one to the pointer to make it invalid newdata = data[:-4] + struct.pack('<I', cbw._header_offset + 1) # We should still be able to find the master header by searching with test_util.capture_sys_output() as (stdout, _stderr): cbfs = cbfs_util.CbfsReader(newdata) self.assertIn('Relative offset seems wrong', stdout.getvalue()) self.assertIn('u-boot', cbfs.files) self.assertEqual(size, cbfs.rom_size)
def test_cbfs_offset(self): """Test a CBFS with files at particular offsets""" size = 0x200 cbw = CbfsWriter(size) cbw.add_file_raw('u-boot', U_BOOT_DATA, 0x40) cbw.add_file_raw('u-boot-dtb', U_BOOT_DTB_DATA, 0x140) data = cbw.get_data() cbfs = self._check_hdr(data, size) self._check_uboot(cbfs, ftype=cbfs_util.TYPE_RAW, offset=0x40, cbfs_offset=0x40) self._check_dtb(cbfs, offset=0x40, cbfs_offset=0x140) cbfs_fname = self._get_expected_cbfs(size=size, base=(0x40, 0x140)) self._compare_expected_cbfs(data, cbfs_fname)
def test_cbfs_bad_file_header(self): """Check handling of a bad file header""" size = 0x70 cbw = CbfsWriter(size) cbw.add_file_raw('u-boot', U_BOOT_DATA) data = cbw.get_data() # Read in the CBFS master header (only), then stop cbr = cbfs_util.CbfsReader(data, read=False) with io.BytesIO(data) as fd: self.assertTrue(cbr._find_and_read_header(fd, len(data))) pos = fd.tell() # Remove all but 4 bytes of the file headerm and try to read the file newdata = data[:pos + 4] with test_util.capture_sys_output() as (stdout, _stderr): with io.BytesIO(newdata) as fd: fd.seek(pos) self.assertEqual(False, cbr._read_next_file(fd)) self.assertIn('File header at 0x0 ran out of data', stdout.getvalue())
def test_cbfs_raw_compress(self): """Test base handling of compressing raw files""" if not self.have_lz4: self.skipTest('lz4 --no-frame-crc not available') size = 0x140 cbw = CbfsWriter(size) cbw.add_file_raw('u-boot', COMPRESS_DATA, None, compress=cbfs_util.COMPRESS_LZ4) cbw.add_file_raw('u-boot-dtb', COMPRESS_DATA, None, compress=cbfs_util.COMPRESS_LZMA) data = cbw.get_data() cbfs = self._check_hdr(data, size) self.assertIn('u-boot', cbfs.files) cfile = cbfs.files['u-boot'] self.assertEqual(cfile.name, 'u-boot') self.assertEqual(cfile.offset, 56) self.assertEqual(cfile.data, COMPRESS_DATA) self.assertEqual(cfile.ftype, cbfs_util.TYPE_RAW) self.assertEqual(cfile.compress, cbfs_util.COMPRESS_LZ4) self.assertEqual(cfile.memlen, len(COMPRESS_DATA)) self.assertIn('u-boot-dtb', cbfs.files) cfile = cbfs.files['u-boot-dtb'] self.assertEqual(cfile.name, 'u-boot-dtb') self.assertEqual(cfile.offset, 56) self.assertEqual(cfile.data, COMPRESS_DATA) self.assertEqual(cfile.ftype, cbfs_util.TYPE_RAW) self.assertEqual(cfile.compress, cbfs_util.COMPRESS_LZMA) self.assertEqual(cfile.memlen, len(COMPRESS_DATA)) cbfs_fname = self._get_expected_cbfs(size=size, compress=['lz4', 'lzma']) self._compare_expected_cbfs(data, cbfs_fname)
def test_cbfs_bad_file_string(self): """Check handling of an incomplete filename string""" size = 0x70 cbw = CbfsWriter(size) cbw.add_file_raw('16-characters xx', U_BOOT_DATA) data = cbw.get_data() # Read in the CBFS master header (only), then stop cbr = cbfs_util.CbfsReader(data, read=False) with io.BytesIO(data) as fd: self.assertTrue(cbr._find_and_read_header(fd, len(data))) pos = fd.tell() # Create a new CBFS with only the first 16 bytes of the file name, then # try to read the file newdata = data[:pos + cbfs_util.FILE_HEADER_LEN + 16] with test_util.capture_sys_output() as (stdout, _stderr): with io.BytesIO(newdata) as fd: fd.seek(pos) self.assertEqual(False, cbr._read_next_file(fd)) self.assertIn( 'String at %#x ran out of data' % cbfs_util.FILE_HEADER_LEN, stdout.getvalue())