Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/unblob/handlers/filesystem/extfs.py: 95%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

39 statements  

1from structlog import get_logger 

2 

3from unblob.file_utils import InvalidInputFormat 

4 

5from ...extractors import Command 

6from ...models import ( 

7 File, 

8 HandlerDoc, 

9 HandlerType, 

10 HexString, 

11 Reference, 

12 StructHandler, 

13 ValidChunk, 

14) 

15 

16logger = get_logger() 

17 

18 

19EXT_BLOCK_SIZE = 0x400 

20MAGIC_OFFSET = 0x438 

21 

22OS_LIST = [ 

23 (0x0, "Linux"), 

24 (0x1, "GNU HURD"), 

25 (0x2, "MASIX"), 

26 (0x3, "FreeBSD"), 

27 ( 

28 0x4, 

29 "Other", 

30 ), # Other "Lites" (BSD4.4-Lite derivatives such as NetBSD, OpenBSD, XNU/Darwin, etc.) 

31] 

32 

33 

34class EXTHandler(StructHandler): 

35 NAME = "extfs" 

36 

37 PATTERNS = [HexString("53 ef ( 00 | 01 | 02 ) 00 ( 00 | 01 | 02 | 03 | 04 ) 00")] 

38 

39 C_DEFINITIONS = r""" 

40 typedef struct ext4_superblock { 

41 char blank[0x400]; // Not a part of the spec. But we expect the magic to be at 0x438. 

42 uint32 s_inodes_count; // Total number of inodes in file system 

43 uint32 s_blocks_count_lo; // Total number of blocks in file system 

44 uint32 s_r_blocks_count_lo; // Number of blocks reserved for superuser (see offset 80) 

45 uint32 s_free_blocks_count_lo; // Total number of unallocated blocks 

46 uint32 s_free_inodes_count; // Total number of unallocated inodes 

47 uint32 s_first_data_block; // Block number of the block containing the superblock 

48 uint32 s_log_block_size; // log2 (block size) - 10 (In other words, the number to shift 1,024 to the left by to obtain the block size) 

49 uint32 s_log_cluster_size; // log2 (fragment size) - 10. (In other words, the number to shift 1,024 to the left by to obtain the fragment size) 

50 uint32 s_blocks_per_group; // Number of blocks in each block group 

51 uint32 s_clusters_per_group; // Number of fragments in each block group 

52 uint32 s_inodes_per_group; // Number of inodes in each block group 

53 uint32 s_mtime; // Last mount time 

54 uint32 s_wtime; // Last written time 

55 uint16 s_mnt_count; // Number of times the volume has been mounted since its last consistency check 

56 uint16 s_max_mnt_count; // Number of mounts allowed before a consistency check must be done 

57 uint16 s_magic; // Ext signature (0xef53), used to help confirm the presence of Ext2 on a volume 

58 uint16 s_state; // File system state (0x1 - clean or 0x2 - has errors) 

59 uint16 s_errors; // What to do when an error is detected (ignore/remount/kernel panic) 

60 uint16 s_minor_rev_level; // Minor portion of version (combine with Major portion below to construct full version field) 

61 uint32 s_lastcheck; // time of last consistency check 

62 uint32 s_checkinterval; // Interval between forced consistency checks 

63 uint32 s_creator_os; // Operating system ID from which the filesystem on this volume was created 

64 uint32 s_rev_level; // Major portion of version (combine with Minor portion above to construct full version field) 

65 uint16 s_def_resuid; // User ID that can use reserved blocks 

66 uint16 s_def_resgid; // Group ID that can use reserved blocks 

67 } ext4_superblock_t; 

68 """ 

69 HEADER_STRUCT = "ext4_superblock_t" 

70 

71 PATTERN_MATCH_OFFSET = -MAGIC_OFFSET 

72 

73 EXTRACTOR = Command("debugfs", "-R", 'rdump / "{outdir}"', "{inpath}") 

74 

75 DOC = HandlerDoc( 

76 name="ExtFS", 

77 description="ExtFS (Ext2/Ext3/Ext4) is a family of journaling file systems commonly used in Linux-based operating systems. It supports features like large file sizes, extended attributes, and journaling for improved reliability.", 

78 handler_type=HandlerType.FILESYSTEM, 

79 vendor=None, 

80 references=[ 

81 Reference( 

82 title="Ext4 Documentation", 

83 url="https://www.kernel.org/doc/html/latest/filesystems/ext4/index.html", 

84 ), 

85 Reference( 

86 title="ExtFS Wikipedia", 

87 url="https://en.wikipedia.org/wiki/Ext4", 

88 ), 

89 ], 

90 limitations=[], 

91 ) 

92 

93 def valid_header(self, header) -> bool: 

94 if header.s_state not in [0x0, 0x1, 0x2]: 

95 logger.debug("ExtFS header state not valid", state=header.s_state) 

96 return False 

97 if header.s_errors not in [0x0, 0x1, 0x2, 0x3]: 

98 logger.debug( 

99 "ExtFS header error handling method value not valid", 

100 errors=header.s_errors, 

101 ) 

102 return False 

103 if header.s_creator_os not in [x[0] for x in OS_LIST]: 

104 logger.debug("Creator OS value not valid.", creator_os=header.s_creator_os) 

105 return False 

106 if header.s_rev_level > 2: 

107 logger.debug( 

108 "ExtFS header major version too high", rev_level=header.s_rev_level 

109 ) 

110 return False 

111 if header.s_log_block_size > 6: 

112 logger.debug( 

113 "ExtFS header s_log_block_size is too large", 

114 s_log_block_size=header.s_log_block_size, 

115 ) 

116 return False 

117 return True 

118 

119 def calculate_chunk(self, file: File, start_offset: int) -> ValidChunk | None: 

120 header = self.parse_header(file) 

121 end_offset = start_offset + ( 

122 header.s_blocks_count_lo * (EXT_BLOCK_SIZE << header.s_log_block_size) 

123 ) 

124 

125 if not self.valid_header(header): 

126 raise InvalidInputFormat("Invalid ExtFS header.") 

127 

128 return ValidChunk( 

129 start_offset=start_offset, 

130 end_offset=end_offset, 

131 )