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

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

110 statements  

1from pathlib import Path 

2 

3from structlog import get_logger 

4 

5from unblob.extractors import Command 

6 

7from ...file_utils import Endian, StructParser, get_endian, round_up 

8from ...models import ( 

9 Extractor, 

10 File, 

11 HandlerDoc, 

12 HandlerType, 

13 HexString, 

14 Reference, 

15 StructHandler, 

16 ValidChunk, 

17) 

18 

19logger = get_logger() 

20 

21PAD_SIZES = [4_096, 1_024] 

22 

23 

24class SquashFSExtractor(Extractor): 

25 EXECUTABLE = "sasquatch" 

26 V4BE_EXECUTABLE = "sasquatch-v4be" 

27 

28 def __init__(self, version: int, big_endian_magic: int): 

29 self.version = version 

30 self.big_endian_magic = big_endian_magic 

31 

32 def extract(self, inpath: Path, outdir: Path): 

33 with File.from_path(inpath) as file: 

34 endian = get_endian(file, self.big_endian_magic) 

35 

36 commands_args = [] 

37 executable = self.EXECUTABLE 

38 

39 match endian, self.version: 

40 case Endian.BIG, 4: 

41 executable = self.V4BE_EXECUTABLE 

42 struct_parser = StructParser(SquashFSv4LEHandler.C_DEFINITIONS) 

43 with File.from_path(inpath) as f: 

44 header = struct_parser.parse( 

45 SquashFSv4LEHandler.HEADER_STRUCT, f, Endian.BIG 

46 ) 

47 # see https://raw.githubusercontent.com/Freetz/freetz/master/tools/make/squashfs4-host-be/AVM-BE-format.txt 

48 is_avm = header.bytes_used == header.mkfs_time 

49 if not is_avm: 

50 commands_args.append("-be") 

51 case Endian.BIG, _: 

52 commands_args.append("-be") 

53 case Endian.LITTLE, _: 

54 commands_args.append("-le") 

55 

56 commands_args.extend( 

57 [ 

58 "-no-exit-code", 

59 "-f", 

60 "-d", 

61 "{outdir}", 

62 "{inpath}", 

63 ] 

64 ) 

65 extractor = Command(executable, *commands_args) 

66 extractor.extract(inpath, outdir) 

67 

68 def get_dependencies(self) -> list[str]: 

69 return [self.EXECUTABLE, self.V4BE_EXECUTABLE] 

70 

71 

72class _SquashFSBase(StructHandler): 

73 BIG_ENDIAN_MAGIC = 0x73_71_73_68 

74 

75 EXTRACTOR = SquashFSExtractor(3, 0x73_71_73_68) 

76 

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

78 file.seek(start_offset) 

79 endian = get_endian(file, self.BIG_ENDIAN_MAGIC) 

80 header = self.parse_header(file, endian) 

81 

82 end_of_data_offset = (start_offset + header.bytes_used) & 0xFF_FF_FF_FF 

83 file.seek(end_of_data_offset) 

84 padding = file.read( 

85 round_up(header.bytes_used, max(PAD_SIZES)) - header.bytes_used 

86 ) 

87 

88 for pad_size in sorted(PAD_SIZES, reverse=True): 

89 size = round_up(header.bytes_used, pad_size) 

90 padding_length = size - header.bytes_used 

91 

92 if padding.startswith(b"\00" * padding_length): 

93 end_offset = start_offset + size 

94 return ValidChunk(start_offset=start_offset, end_offset=end_offset) 

95 

96 return ValidChunk( 

97 start_offset=start_offset, end_offset=start_offset + header.bytes_used 

98 ) 

99 

100 

101class SquashFSv1Handler(_SquashFSBase): 

102 NAME = "squashfs_v1" 

103 

104 PATTERNS = [ 

105 HexString( 

106 """ 

107 // 00000000 73 71 73 68 00 00 00 03 00 00 00 00 00 00 00 00 |sqsh............| 

108 // 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 |................| 

109 // squashfs_v1_magic_be 

110 73 71 73 68 [24] 00 01 

111 """ 

112 ), 

113 HexString( 

114 """ 

115 // 00000000 68 73 71 73 03 00 00 00 00 00 00 00 00 00 00 00 |hsqs............| 

116 // 00000010 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 |................| 

117 // squashfs_v1_magic_le 

118 68 73 71 73 [24] 01 00 

119 """ 

120 ), 

121 ] 

122 

123 C_DEFINITIONS = r""" 

124 typedef struct squashfs_super_block 

125 { 

126 char s_magic[4]; 

127 uint32 inodes; 

128 uint32 bytes_used; 

129 uint32 uid_start; 

130 uint32 guid_start; 

131 uint32 inode_table_start; 

132 uint32 directory_table_start; 

133 uint16 s_major; 

134 uint16 s_minor; 

135 } squashfs_super_block_t; 

136 """ 

137 HEADER_STRUCT = "squashfs_super_block_t" 

138 

139 DOC = HandlerDoc( 

140 name="SquashFS (v1)", 

141 description="SquashFS version 1 is a compressed, read-only file system format designed for minimal storage usage. It is commonly used in embedded systems and early Linux distributions.", 

142 handler_type=HandlerType.FILESYSTEM, 

143 vendor=None, 

144 references=[ 

145 Reference( 

146 title="SquashFS Documentation", 

147 url="https://dr-emann.github.io/squashfs/", 

148 ), 

149 Reference( 

150 title="SquashFS Wikipedia", 

151 url="https://en.wikipedia.org/wiki/SquashFS", 

152 ), 

153 ], 

154 limitations=[], 

155 ) 

156 

157 

158class SquashFSv2Handler(SquashFSv1Handler): 

159 NAME = "squashfs_v2" 

160 

161 PATTERNS = [ 

162 HexString( 

163 """ 

164 // 00000000 73 71 73 68 00 00 00 03 00 00 00 00 00 00 00 00 |sqsh............| 

165 // 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 |................| 

166 // squashfs_v2_magic_be 

167 73 71 73 68 [24] 00 02 

168 """ 

169 ), 

170 HexString( 

171 """ 

172 // 00000000 68 73 71 73 03 00 00 00 00 00 00 00 00 00 00 00 |hsqs............| 

173 // 00000010 00 00 00 00 00 00 00 00 00 00 00 00 02 00 00 00 |................| 

174 // squashfs_v2_magic_le 

175 68 73 71 73 [24] 02 00 

176 """ 

177 ), 

178 ] 

179 

180 DOC = HandlerDoc( 

181 name="SquashFS (v2)", 

182 description="SquashFS version 2 is a compressed, read-only file system format designed for minimal storage usage. It builds upon version 1 with additional features and improvements for embedded systems and Linux distributions.", 

183 handler_type=HandlerType.FILESYSTEM, 

184 vendor=None, 

185 references=[ 

186 Reference( 

187 title="SquashFS Documentation", 

188 url="https://dr-emann.github.io/squashfs/", 

189 ), 

190 Reference( 

191 title="SquashFS Wikipedia", 

192 url="https://en.wikipedia.org/wiki/SquashFS", 

193 ), 

194 ], 

195 limitations=[], 

196 ) 

197 

198 

199class SquashFSv2NonStandardHandler(SquashFSv2Handler): 

200 NAME = "squashfs_v2_nonstandard" 

201 

202 BIG_ENDIAN_MAGIC = 0x73_71_6C_7A 

203 

204 EXTRACTOR = SquashFSExtractor(2, 0x73_71_6C_7A) 

205 

206 PATTERNS = [ 

207 HexString( 

208 """ 

209 // 00000000 73 71 6c 7a 00 00 00 05 00 00 00 00 00 00 00 00 |sqlz............| 

210 // 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 02 00 01 |................| 

211 // squashfs_v2_magic_non_standard_be 

212 73 71 6c 7a [24] 00 02 

213 """ 

214 ), 

215 HexString( 

216 """ 

217 // 00000000 7a 6c 71 73 05 00 00 00 00 00 00 00 00 00 00 00 |zlqs............| 

218 // 00000010 00 00 00 00 00 00 00 00 00 00 00 00 02 00 01 00 |................| 

219 // squashfs_v2_magic_non_standard_le 

220 7a 6c 71 73 [24] 02 00 

221 """ 

222 ), 

223 ] 

224 

225 DOC = HandlerDoc( 

226 name="SquashFS (v2-non-standard)", 

227 description="SquashFS version 2 is a compressed, read-only file system format designed for minimal storage usage. It is commonly used in embedded systems and early Linux distributions.", 

228 handler_type=HandlerType.FILESYSTEM, 

229 vendor=None, 

230 references=[ 

231 Reference( 

232 title="SquashFS Documentation", 

233 url="https://dr-emann.github.io/squashfs/", 

234 ), 

235 Reference( 

236 title="SquashFS Wikipedia", 

237 url="https://en.wikipedia.org/wiki/SquashFS", 

238 ), 

239 ], 

240 limitations=[], 

241 ) 

242 

243 

244class SquashFSv3Handler(_SquashFSBase): 

245 NAME = "squashfs_v3" 

246 

247 PATTERNS = [ 

248 HexString( 

249 """ 

250 // 00000000 73 71 73 68 00 00 00 03 00 00 00 00 00 00 00 00 |sqsh............| 

251 // 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 03 00 00 |................| 

252 // squashfs_v3_magic_be 

253 73 71 73 68 [24] 00 03 

254 """ 

255 ), 

256 HexString( 

257 """ 

258 // 00000000 68 73 71 73 03 00 00 00 00 00 00 00 00 00 00 00 |hsqs............| 

259 // 00000010 00 00 00 00 00 00 00 00 00 00 00 00 03 00 00 00 |................| 

260 // squashfs_v3_magic_le 

261 68 73 71 73 [24] 03 00 

262 """ 

263 ), 

264 ] 

265 

266 DOC = HandlerDoc( 

267 name="SquashFS (v3)", 

268 description="SquashFS version 3 is a compressed, read-only file system format designed for minimal storage usage. It is widely used in embedded systems and Linux distributions for efficient storage and fast access.", 

269 handler_type=HandlerType.FILESYSTEM, 

270 vendor=None, 

271 references=[ 

272 Reference( 

273 title="SquashFS Documentation", 

274 url="https://dr-emann.github.io/squashfs/", 

275 ), 

276 Reference( 

277 title="SquashFS Wikipedia", 

278 url="https://en.wikipedia.org/wiki/SquashFS", 

279 ), 

280 ], 

281 limitations=[], 

282 ) 

283 

284 C_DEFINITIONS = r""" 

285 typedef struct squashfs3_super_block 

286 { 

287 char s_magic[4]; 

288 uint32 inodes; 

289 uint32 bytes_used_2; 

290 uint32 uid_start_2; 

291 uint32 guid_start_2; 

292 uint32 inode_table_start_2; 

293 uint32 directory_table_start_2; 

294 uint16 s_major; 

295 uint16 s_minor; 

296 uint16 block_size_1; 

297 uint16 block_log; 

298 uint8 flags; 

299 uint8 no_uids; 

300 uint8 no_guids; 

301 uint32 mkfs_time /* time of filesystem creation */; 

302 uint64 root_inode; 

303 uint32 block_size; 

304 uint32 fragments; 

305 uint32 fragment_table_start_2; 

306 uint64 bytes_used; 

307 uint64 uid_start; 

308 uint64 guid_start; 

309 uint64 inode_table_start; 

310 uint64 directory_table_start; 

311 uint64 fragment_table_start; 

312 uint64 lookup_table_start; 

313 } squashfs3_super_block_t; 

314 """ 

315 HEADER_STRUCT = "squashfs3_super_block_t" 

316 

317 

318class SquashFSv3DDWRTHandler(SquashFSv3Handler): 

319 NAME = "squashfs_v3_ddwrt" 

320 

321 BIG_ENDIAN_MAGIC = 0x74_71_73_68 

322 

323 EXTRACTOR = SquashFSExtractor(3, 0x74_71_73_68) 

324 

325 PATTERNS = [ 

326 HexString( 

327 """ 

328 // 00000000 68 73 71 74 21 02 00 00 00 00 00 00 00 00 00 00 |hsqt!...........| 

329 // 00000010 00 00 00 00 00 00 00 00 50 02 00 00 03 00 00 00 |........P.......| 

330 // squashfs_v3_magic_ddwrt_le 

331 68 73 71 74 [24] 03 00 

332 """ 

333 ), 

334 HexString( 

335 """ 

336 // 00000000 74 71 73 68 00 00 00 05 00 00 00 00 00 00 00 00 |tqsh............| 

337 // 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 03 00 01 |................| 

338 // squashfs_v3_magic_ddwrt_be 

339 74 71 73 68 [24] 00 03 

340 """ 

341 ), 

342 ] 

343 

344 DOC = HandlerDoc( 

345 name="SquashFS (v3-DDWRT)", 

346 description="SquashFS version 3 DD-WRT is a variant of the SquashFS v3 format used in DD-WRT firmware. It features a unique magic number and may include specific optimizations for embedded systems.", 

347 handler_type=HandlerType.FILESYSTEM, 

348 vendor="DDWRT", 

349 references=[ 

350 Reference( 

351 title="SquashFS Documentation", 

352 url="https://dr-emann.github.io/squashfs/", 

353 ), 

354 Reference( 

355 title="SquashFS Wikipedia", 

356 url="https://en.wikipedia.org/wiki/SquashFS", 

357 ), 

358 ], 

359 limitations=[], 

360 ) 

361 

362 

363class SquashFSv3BroadcomHandler(SquashFSv3Handler): 

364 NAME = "squashfs_v3_broadcom" 

365 

366 BIG_ENDIAN_MAGIC = 0x71_73_68_73 

367 

368 EXTRACTOR = SquashFSExtractor(3, 0x71_73_68_73) 

369 

370 PATTERNS = [ 

371 HexString( 

372 """ 

373 // 00000000 73 68 73 71 0f 05 00 00 c8 a9 00 01 00 00 00 bc |shsq............| 

374 // 00000010 1f 2d 00 a2 d0 2b 00 bf 79 2e 00 65 03 00 00 00 |.-...+..y..e....| 

375 // squashfs_v3_magic_broadcom_le 

376 73 68 73 71 [24] 03 00 

377 """ 

378 ), 

379 HexString( 

380 """ 

381 // 00000000 71 73 68 73 0f 05 00 00 c8 a9 00 01 00 00 00 bc |qshs............| 

382 // 00000010 1f 2d 00 a2 d0 2b 00 bf 79 2e 00 65 00 03 00 00 |.-...+..y..e....| 

383 // squashfs_v3_magic_broadcom_be 

384 71 73 68 73 [24] 00 03 

385 

386 """ 

387 ), 

388 ] 

389 

390 DOC = HandlerDoc( 

391 name="SquashFS (v3-Broadcom)", 

392 description="SquashFS version 3 Broadcom is a variant of the SquashFS v3 format used in Broadcom firmware. It features a unique magic number and may include specific optimizations for Broadcom devices.", 

393 handler_type=HandlerType.FILESYSTEM, 

394 vendor="Broadcom", 

395 references=[ 

396 Reference( 

397 title="SquashFS Documentation", 

398 url="https://dr-emann.github.io/squashfs/", 

399 ), 

400 Reference( 

401 title="SquashFS Wikipedia", 

402 url="https://en.wikipedia.org/wiki/SquashFS", 

403 ), 

404 ], 

405 limitations=[], 

406 ) 

407 

408 

409class SquashFSv3NSHandler(SquashFSv3Handler): 

410 NAME = "squashfs_v3_nonstandard" 

411 

412 BIG_ENDIAN_MAGIC = 0x73_71_6C_7A 

413 

414 EXTRACTOR = SquashFSExtractor(3, 0x73_71_6C_7A) 

415 

416 PATTERNS = [ 

417 HexString( 

418 """ 

419 // 00000000 7a 6c 71 73 00 00 04 df 57 00 17 95 46 00 19 ed |zlqs....W...F...| 

420 // 00000010 20 08 04 8e 02 40 01 06 c9 02 16 00 00 03 00 01 | ....@..........| 

421 // squashfs_v3_magic_nonstandard_le 

422 7A 6c 71 73 [24] 03 00 

423 """ 

424 ), 

425 HexString( 

426 """ 

427 // 00000000 73 71 6c 7a 00 00 04 df 57 00 17 95 46 00 19 ed |sqlz....W...F...| 

428 // 00000010 20 08 04 8e 02 40 01 06 c9 02 16 00 00 03 00 01 | ....@..........| 

429 // squashfs_v3_magic_nonstandard_be 

430 73 71 6c 7A [24] 00 03 

431 """ 

432 ), 

433 ] 

434 

435 DOC = HandlerDoc( 

436 name="SquashFS (v3-non-standard)", 

437 description="SquashFS version 3 is a compressed, read-only file system format designed for minimal storage usage. It is widely used in embedded systems and Linux distributions for efficient storage and fast access.", 

438 handler_type=HandlerType.FILESYSTEM, 

439 vendor="unknown", 

440 references=[ 

441 Reference( 

442 title="SquashFS Documentation", 

443 url="https://dr-emann.github.io/squashfs/", 

444 ), 

445 Reference( 

446 title="SquashFS Wikipedia", 

447 url="https://en.wikipedia.org/wiki/SquashFS", 

448 ), 

449 ], 

450 limitations=[], 

451 ) 

452 

453 

454class SquashFSv4LEHandler(_SquashFSBase): 

455 NAME = "squashfs_v4_le" 

456 

457 PATTERNS = [ 

458 HexString( 

459 """ 

460 // 00000000 68 73 71 73 03 00 00 00 00 c1 9c 61 00 00 02 00 |hsqs.......a....| 

461 // 00000010 01 00 00 00 01 00 11 00 c0 00 01 00 04 00 00 00 |................| 

462 // squashfs_v4_magic_le 

463 68 73 71 73 [24] 04 00 

464 """ 

465 ), 

466 ] 

467 

468 C_DEFINITIONS = r""" 

469 typedef struct squashfs4_super_block 

470 { 

471 char s_magic[4]; 

472 uint32 inodes; 

473 uint32 mkfs_time /* time of filesystem creation */; 

474 uint32 block_size; 

475 uint32 fragments; 

476 uint16 compression; 

477 uint16 block_log; 

478 uint16 flags; 

479 uint16 no_ids; 

480 uint16 s_major; 

481 uint16 s_minor; 

482 uint64 root_inode; 

483 uint64 bytes_used; 

484 uint64 id_table_start; 

485 uint64 xattr_id_table_start; 

486 uint64 inode_table_start; 

487 uint64 directory_table_start; 

488 uint64 fragment_table_start; 

489 uint64 lookup_table_start; 

490 } squashfs4_super_block_t; 

491 """ 

492 HEADER_STRUCT = "squashfs4_super_block_t" 

493 

494 DOC = HandlerDoc( 

495 name="SquashFS (v4-LE)", 

496 description="SquashFS version 4 is a compressed, read-only file system format designed for minimal storage usage and fast access. It is widely used in embedded systems and Linux distributions for efficient storage management.", 

497 handler_type=HandlerType.FILESYSTEM, 

498 vendor=None, 

499 references=[ 

500 Reference( 

501 title="SquashFS Documentation", 

502 url="https://dr-emann.github.io/squashfs/", 

503 ), 

504 Reference( 

505 title="SquashFS Wikipedia", 

506 url="https://en.wikipedia.org/wiki/SquashFS", 

507 ), 

508 ], 

509 limitations=[], 

510 ) 

511 

512 

513class SquashFSv4BEHandler(SquashFSv4LEHandler): 

514 NAME = "squashfs_v4_be" 

515 

516 PATTERNS = [ 

517 HexString( 

518 """ 

519 // 00000000 73 71 73 68 03 00 00 00 00 c1 9c 61 00 00 02 00 |sqsh.......a....| 

520 // 00000010 01 00 00 00 01 00 11 00 c0 00 01 00 04 00 00 00 |................| 

521 // squashfs_v4_magic_be 

522 73 71 73 68 [24] 00 04 

523 """ 

524 ), 

525 ] 

526 

527 EXTRACTOR = SquashFSExtractor(4, 0x73_71_73_68) 

528 

529 DOC = HandlerDoc( 

530 name="SquashFS (v4-BE)", 

531 description="SquashFS version 4 is a compressed, read-only file system format designed for minimal storage usage and fast access. It supports both big-endian and little-endian formats and is widely used in embedded systems and Linux distributions.", 

532 handler_type=HandlerType.FILESYSTEM, 

533 vendor=None, 

534 references=[ 

535 Reference( 

536 title="SquashFS Documentation", 

537 url="https://dr-emann.github.io/squashfs/", 

538 ), 

539 Reference( 

540 title="SquashFS Wikipedia", 

541 url="https://en.wikipedia.org/wiki/SquashFS", 

542 ), 

543 ], 

544 limitations=[], 

545 ) 

546 

547 

548class SquashFSv4BroadcomHandler(SquashFSv4LEHandler): 

549 NAME = "squashfs_v4_broadcom" 

550 

551 BIG_ENDIAN_MAGIC = 0x71_73_68_73 

552 

553 EXTRACTOR = SquashFSExtractor(4, 0x71_73_68_73) 

554 

555 PATTERNS = [ 

556 HexString( 

557 """ 

558 // 00000000 71 73 68 73 00 00 00 05 62 1f 5e 09 00 02 00 00 |qshs....b.^.....| 

559 // 00000010 00 00 00 01 00 01 00 11 00 c0 00 01 00 04 00 00 |................| 

560 // squashfs_v4_magic_broadcom_be 

561 71 73 68 73 [24] 00 04 

562 """ 

563 ), 

564 HexString( 

565 """ 

566 // 00000000 73 68 73 71 03 00 00 00 00 c1 9c 61 00 00 02 00 |shsq.......a....| 

567 // 00000010 01 00 00 00 01 00 11 00 c0 00 01 00 04 00 00 00 |................| 

568 // squashfs_v4_magic_broadcom_le 

569 73 68 73 71 [24] 04 00 

570 """ 

571 ), 

572 ] 

573 

574 DOC = HandlerDoc( 

575 name="SquashFS (v4-broadcom)", 

576 description="SquashFS version 4 is a compressed, read-only file system format designed for minimal storage usage. It is widely used in embedded systems and Linux distributions for efficient storage and fast access.", 

577 handler_type=HandlerType.FILESYSTEM, 

578 vendor="Broadcom", 

579 references=[ 

580 Reference( 

581 title="SquashFS Documentation", 

582 url="https://dr-emann.github.io/squashfs/", 

583 ), 

584 Reference( 

585 title="SquashFS Wikipedia", 

586 url="https://en.wikipedia.org/wiki/SquashFS", 

587 ), 

588 ], 

589 limitations=[], 

590 )