1 /*
2 * The Sleuth Kit
3 *
4 * Brian Carrier [carrier <at> sleuthkit [dot] org]
5 * Copyright (c) 2019-2020 Brian Carrier. All Rights reserved
6 * Copyright (c) 2018-2019 BlackBag Technologies. All Rights reserved
7 *
8 * This software is distributed under the Common Public License 1.0
9 */
10 #include "../util/crypto.hpp"
11 #include "apfs_fs.hpp"
12 #include "tsk_apfs.hpp"
13
14 #include <cstring>
15
16 // MSVC doesn't define ffs/ffsll.
17 #ifdef _MSC_VER
18 #include <intrin.h>
19
20 #ifdef _M_X64 // 64-bit
21 #pragma intrinsic(_BitScanForward64)
lsbset(unsigned __int64 x)22 static __forceinline int lsbset(unsigned __int64 x) {
23 unsigned long i;
24
25 if (_BitScanForward64(&i, x)) {
26 return i + 1;
27 }
28
29 return 0;
30 }
31 #else // 32-bit
32 #pragma intrinsic(_BitScanForward)
lsbset(long x)33 static __forceinline int lsbset(long x) {
34 unsigned long i;
35
36 if (_BitScanForward(&i, x)) {
37 return i + 1;
38 }
39 return 0;
40 }
41 #endif // _M_X64
42
43 #else // gcc or clang
44
45 #ifdef __x86_64__
46 #define lsbset(x) __builtin_ffsll(x)
47 #else // 32-bit
48 #define lsbset(x) __builtin_ffs(x)
49 #endif // __x86_64__
50
51 #endif // _MSC_VER
52
53 class wrapped_key_parser {
54 // TODO(JTS): This code assume a well-formed input. It needs some sanity
55 // checking!
56
57 using tag = uint8_t;
58 using view = span<const uint8_t>;
59
60 const uint8_t* _data;
61
get_length(const uint8_t ** pos) const62 size_t get_length(const uint8_t** pos) const noexcept {
63 auto data = *pos;
64
65 size_t len = *data++;
66
67 if (len & 0x80) {
68 len = 0;
69 auto enc_len = len & 0x7F;
70 while (enc_len--) {
71 len <<= 8;
72 len |= *data++;
73 }
74 }
75
76 *pos = data;
77 return len;
78 }
79
get_tag(tag t) const80 const view get_tag(tag t) const noexcept {
81 auto data = _data;
82
83 while (true) {
84 const auto tag = *data++;
85 const auto len = get_length(&data);
86
87 if (tag == t) {
88 return {data, len};
89 }
90
91 data += len;
92 }
93 }
94
95 // Needed for the recursive variadic to compile, but should never be
96 // called. TODO(JTS): Use constexpr if when we enforce C++17
get_data(void) const97 const view get_data(void) const {
98 throw std::logic_error("this should be unreachable");
99 }
100
101 public:
wrapped_key_parser(const void * data)102 wrapped_key_parser(const void* data) noexcept : _data{(const uint8_t*)data} {}
103
104 template <typename... Args>
get_data(tag t,Args...args) const105 const view get_data(tag t, Args... args) const noexcept {
106 const auto data = get_tag(t);
107
108 if (sizeof...(args) == 0 || !data.valid()) {
109 return data;
110 }
111
112 return wrapped_key_parser{data.data()}.get_data(args...);
113 }
114
115 template <typename... Args>
get_number(tag t,Args...args) const116 uint64_t get_number(tag t, Args... args) const noexcept {
117 const auto data = get_data(t, args...);
118
119 uint64_t n = 0;
120 for (auto p = data.data(); p < data.data() + data.count(); p++) {
121 n <<= 8;
122 n |= *p;
123 }
124
125 return n;
126 }
127 };
128
APFSBlock(const APFSPool & pool,const apfs_block_num block_num)129 APFSBlock::APFSBlock(const APFSPool& pool, const apfs_block_num block_num)
130 : _storage{}, _pool{pool}, _block_num{block_num} {
131 const auto sz =
132 pool.read(block_num * APFS_BLOCK_SIZE, _storage.data(), APFS_BLOCK_SIZE);
133 if (sz != APFS_BLOCK_SIZE) {
134 throw std::runtime_error("could not read APFSBlock");
135 }
136 }
137
decrypt(const uint8_t * key,const uint8_t * key2)138 void APFSBlock::decrypt(const uint8_t* key, const uint8_t* key2) noexcept {
139 #ifdef HAVE_LIBOPENSSL
140 // If the data is encrypted via the T2 chip, we can't decrypt it. This means
141 // that if the data wasn't decrypted at acquisition time, then processing will
142 // likely fail. Either way, there is no need to decrypt.
143 if (_pool.hardware_crypto()) {
144 return;
145 }
146
147 aes_xts_decryptor dec{ aes_xts_decryptor::AES_128, key, key2,
148 APFS_CRYPTO_SW_BLKSIZE };
149
150 dec.decrypt_buffer(_storage.data(), _storage.size(),
151 _block_num * APFS_BLOCK_SIZE);
152 #else
153 return;
154 #endif
155 }
156
dump() const157 void APFSBlock::dump() const noexcept {
158 // Dump contents of block to stdout for debugging
159 for (const auto byte : _storage) {
160 putchar(byte);
161 }
162 }
163
validate_checksum() const164 bool APFSObject::validate_checksum() const noexcept {
165 if (obj()->cksum == std::numeric_limits<uint64_t>::max()) {
166 return false;
167 }
168
169 // Calculate the checksum using the modified fletcher's algorithm
170 const auto checksum = [&]() -> uint64_t {
171 const auto data =
172 reinterpret_cast<const uint32_t*>(_storage.data() + sizeof(uint64_t));
173 const auto len = (_storage.size() - sizeof(uint64_t)) / sizeof(uint32_t);
174
175 constexpr uint64_t mod = std::numeric_limits<uint32_t>::max();
176
177 uint64_t sum1{0};
178 uint64_t sum2{0};
179
180 for (size_t i = 0; i < len; i++) {
181 sum1 = (sum1 + data[i]) % mod;
182 sum2 = (sum2 + sum1) % mod;
183 }
184
185 const auto ck_low = mod - ((sum1 + sum2) % mod);
186 const auto ck_high = mod - ((sum1 + ck_low) % mod);
187
188 return (ck_high << 32) | ck_low;
189 }();
190
191 // Compare calculated checksum with the value in the object header
192 return (checksum == obj()->cksum);
193 }
194
APFSSuperblock(const APFSPool & pool,const apfs_block_num block_num)195 APFSSuperblock::APFSSuperblock(const APFSPool& pool,
196 const apfs_block_num block_num)
197 : APFSObject(pool, block_num), _spaceman{} {
198 if (obj_type() != APFS_OBJ_TYPE_SUPERBLOCK) {
199 throw std::runtime_error("APFSSuperblock: invalid object type");
200 }
201
202 if (sb()->magic != APFS_NXSUPERBLOCK_MAGIC) {
203 throw std::runtime_error("APFSSuperblock: invalid magic");
204 }
205
206 if (bit_is_set(sb()->incompatible_features, APFS_NXSB_INCOMPAT_VERSION1)) {
207 throw std::runtime_error(
208 "APFSSuperblock: Pre-release versions of APFS are not supported");
209 }
210
211 if (bit_is_set(sb()->incompatible_features, APFS_NXSB_INCOMPAT_FUSION)) {
212 if (tsk_verbose) {
213 tsk_fprintf(stderr,
214 "WARNING: APFS fusion drives may not be fully supported\n");
215 }
216 }
217
218 if (block_size() != APFS_BLOCK_SIZE) {
219 throw std::runtime_error(
220 "APFSSuperblock: invalid or unsupported block size");
221 }
222 }
223
volume_blocks() const224 const std::vector<apfs_block_num> APFSSuperblock::volume_blocks() const {
225 std::vector<apfs_block_num> vec{};
226
227 const auto root = omap().root<APFSObjectBtreeNode>();
228
229 for (const auto& e : root.entries()) {
230 vec.emplace_back(e.value->paddr);
231 }
232
233 return vec;
234 }
235
sm_bitmap_blocks() const236 const std::vector<apfs_block_num> APFSSuperblock::sm_bitmap_blocks() const {
237 const auto entries = spaceman().bm_entries();
238
239 std::vector<apfs_block_num> v{};
240 v.reserve(entries.size());
241
242 for (const auto& entry : entries) {
243 if (entry.bm_block != 0) {
244 v.emplace_back(entry.bm_block);
245 }
246 }
247
248 return v;
249 }
250
volume_oids() const251 const std::vector<uint64_t> APFSSuperblock::volume_oids() const {
252 std::vector<uint64_t> v{};
253
254 for (auto i = 0U; i < sb()->max_fs_count; i++) {
255 const auto oid = sb()->fs_oids[i];
256
257 if (oid == 0) {
258 break;
259 }
260
261 v.emplace_back(oid);
262 }
263
264 return v;
265 }
266
checkpoint_desc_block() const267 apfs_block_num APFSSuperblock::checkpoint_desc_block() const {
268 for (auto i = 0U; i < sb()->chkpt_desc_block_count; i++) {
269 const auto block_num = sb()->chkpt_desc_base_addr + i;
270 const auto block = APFSObject(_pool, block_num);
271
272 if (!block.validate_checksum()) {
273 if (tsk_verbose) {
274 tsk_fprintf(stderr,
275 "APFSSuperblock::checkpoint_desc_block: Block %lld did not "
276 "validate.\n",
277 block_num);
278 }
279 continue;
280 }
281
282 if (block.xid() == xid() &&
283 block.obj_type() == APFS_OBJ_TYPE_CHECKPOINT_DESC) {
284 return block_num;
285 }
286 }
287
288 // We didn't find anything so return 0;
289 return 0;
290 }
291
spaceman() const292 const APFSSpaceman& APFSSuperblock::spaceman() const {
293 if (_spaceman != nullptr) {
294 return *_spaceman;
295 }
296
297 #ifdef TSK_MULTITHREAD_LIB
298 // Since this function is const, and const methods generally are assumed to be
299 // thread safe, we ideally want to it be thread safe so multiple threads
300 // aren't trying to initialize at the same time.
301 std::lock_guard<std::mutex> lock{_spaceman_init_lock};
302
303 // Check again to make sure someone else didn't already beat us to this.
304 if (_spaceman != nullptr) {
305 return *_spaceman;
306 }
307 #endif
308
309 const APFSCheckpointMap cd{_pool, checkpoint_desc_block()};
310
311 _spaceman = std::make_unique<APFSSpaceman>(
312 _pool, cd.get_object_block(sb()->spaceman_oid, APFS_OBJ_TYPE_SPACEMAN));
313
314 return *_spaceman;
315 }
316
keybag() const317 APFSSuperblock::Keybag APFSSuperblock::keybag() const {
318 if (sb()->keylocker.start_paddr == 0) {
319 throw std::runtime_error("no keybag found");
320 }
321
322 return {(*this)};
323 }
324
APFSOmap(const APFSPool & pool,const apfs_block_num block_num)325 APFSOmap::APFSOmap(const APFSPool& pool, const apfs_block_num block_num)
326 : APFSObject(pool, block_num) {
327 if (obj_type() != APFS_OBJ_TYPE_OMAP) {
328 throw std::runtime_error("APFSOmap: invalid object type");
329 }
330 }
331
APFSFileSystem(const APFSPool & pool,const apfs_block_num block_num)332 APFSFileSystem::APFSFileSystem(const APFSPool& pool,
333 const apfs_block_num block_num)
334 : APFSObject(pool, block_num) {
335 if (obj_type() != APFS_OBJ_TYPE_FS) {
336 throw std::runtime_error("APFSFileSystem: invalid object type");
337 }
338
339 if (fs()->magic != APFS_FS_MAGIC) {
340 throw std::runtime_error("APFSFileSystem: invalid magic");
341 }
342
343 if (encrypted() && pool.hardware_crypto() == false) {
344 init_crypto_info();
345 }
346 }
347
wrapped_kek(Guid && id,const std::unique_ptr<uint8_t[]> & kp)348 APFSFileSystem::wrapped_kek::wrapped_kek(Guid&& id,
349 const std::unique_ptr<uint8_t[]>& kp)
350 : uuid{std::forward<Guid>(id)} {
351 // Parse KEK
352 wrapped_key_parser wp{kp.get()};
353
354 // Get flags
355 flags = wp.get_number(0x30, 0xA3, 0x82);
356
357 // Get wrapped KEK
358 auto kek_data = wp.get_data(0x30, 0xA3, 0x83);
359 if (kek_data.count() != sizeof(data)) {
360 throw std::runtime_error("invalid KEK size");
361 }
362 std::memcpy(data, kek_data.data(), sizeof(data));
363
364 // Get iterations
365 iterations = wp.get_number(0x30, 0xA3, 0x84);
366
367 // Get salt
368 kek_data = wp.get_data(0x30, 0xA3, 0x85);
369 if (kek_data.count() != sizeof(salt)) {
370 throw std::runtime_error("invalid salt size");
371 }
372 std::memcpy(salt, kek_data.data(), sizeof(salt));
373 }
374
APFSFileSystem(const APFSPool & pool,const apfs_block_num block_num,const std::string & password)375 APFSFileSystem::APFSFileSystem(const APFSPool& pool,
376 const apfs_block_num block_num,
377 const std::string& password)
378 : APFSFileSystem(pool, block_num) {
379 if (encrypted()) {
380 unlock(password);
381 }
382 }
383
384 // These are the known special recovery UUIDs. The ones that are commented out
385 // are currently supported.
386 static const auto unsupported_recovery_keys = {
387 Guid{"c064ebc6-0000-11aa-aa11-00306543ecac"}, // Institutional Recovery
388 Guid{"2fa31400-baff-4de7-ae2a-c3aa6e1fd340"}, // Institutional User
389 // Guid{"ebc6C064-0000-11aa-aa11-00306543ecac"}, // Personal Recovery
390 Guid{"64c0c6eb-0000-11aa-aa11-00306543ecac"}, // iCould Recovery
391 Guid{"ec1c2ad9-b618-4ed6-bd8d-50f361c27507"}, // iCloud User
392 };
393
init_crypto_info()394 void APFSFileSystem::init_crypto_info() {
395 try {
396
397 // Get container keybag
398 const auto container_kb = _pool.nx()->keybag();
399
400 auto data = container_kb.get_key(uuid(), APFS_KB_TYPE_VOLUME_KEY);
401 if (data == nullptr) {
402 throw std::runtime_error(
403 "APFSFileSystem: can not find volume encryption key");
404 }
405
406 wrapped_key_parser wp{ data.get() };
407
408 // Get Wrapped VEK
409 auto kek_data = wp.get_data(0x30, 0xA3, 0x83);
410 if (kek_data.count() != sizeof(_crypto.wrapped_vek)) {
411 throw std::runtime_error("invalid VEK size");
412 }
413 std::memcpy(_crypto.wrapped_vek, kek_data.data(),
414 sizeof(_crypto.wrapped_vek));
415
416 // Get VEK Flags
417 _crypto.vek_flags = wp.get_number(0x30, 0xA3, 0x82);
418
419 // Get VEK UUID
420 kek_data = wp.get_data(0x30, 0xA3, 0x81);
421 if (kek_data.count() != sizeof(_crypto.vek_uuid)) {
422 throw std::runtime_error("invalid UUID size");
423 }
424 std::memcpy(_crypto.vek_uuid, kek_data.data(), sizeof(_crypto.vek_uuid));
425
426 data = container_kb.get_key(uuid(), APFS_KB_TYPE_UNLOCK_RECORDS);
427 if (data == nullptr) {
428 throw std::runtime_error(
429 "APFSFileSystem: can not find volume recovery key");
430 }
431
432 const auto rec =
433 reinterpret_cast<const apfs_volrec_keybag_value*>(data.get());
434
435 if (rec->num_blocks != 1) {
436 throw std::runtime_error(
437 "only single block keybags are currently supported");
438 }
439
440 _crypto.recs_block_num = rec->start_block;
441
442 Keybag recs{ (*this), _crypto.recs_block_num };
443
444 data = recs.get_key(uuid(), APFS_KB_TYPE_PASSPHRASE_HINT);
445
446 if (data != nullptr) {
447 _crypto.password_hint = std::string((const char*)data.get());
448 }
449
450 // Get KEKs
451 auto keks = recs.get_keys();
452 if (keks.empty()) {
453 throw std::runtime_error("could not find any KEKs");
454 }
455
456 for (auto& k : keks) {
457 if (k.type != APFS_KB_TYPE_UNLOCK_RECORDS) {
458 continue;
459 }
460
461 if (std::find(unsupported_recovery_keys.begin(),
462 unsupported_recovery_keys.end(),
463 k.uuid) != unsupported_recovery_keys.end()) {
464 // Skip unparsable recovery KEKs
465 if (tsk_verbose) {
466 tsk_fprintf(stderr, "apfs: skipping unsupported KEK type: %s\n",
467 k.uuid.str().c_str());
468 }
469 continue;
470 }
471
472 _crypto.wrapped_keks.emplace_back(wrapped_kek{ std::move(k.uuid), k.data });
473 }
474 }
475 catch (std::exception& e) {
476 if (tsk_verbose) {
477 tsk_fprintf(stderr, "APFSFileSystem::init_crypto_info: %s", e.what());
478 }
479 }
480 }
481
unlock(const std::string & password)482 bool APFSFileSystem::unlock(const std::string& password) noexcept {
483 #ifdef HAVE_LIBOPENSSL
484 if (_crypto.unlocked) {
485 // Already unlocked
486 return true;
487 }
488
489 // TODO(JTS): If bits 32:16 are set to 1, some other sort of KEK decryption is
490 // used (see _fv_decrypt_vek in AppleKeyStore).
491 if (_crypto.unk16()) {
492 if (tsk_verbose) {
493 tsk_fprintf(stderr,
494 "apfs: UNK16 is set in VEK. Decryption will likely fail.\n");
495 }
496 }
497
498 // Check the password against all possible KEKs
499 for (const auto& wk : _crypto.wrapped_keks) {
500 // If the 57th bit of the KEK flags is set, then the kek is a CoreStorage
501 // KEK
502 const auto kek_len = (wk.cs()) ? 0x10 : 0x20;
503
504 // TODO(JTS): If the 56th bit of the KEK flags is set, some sort of hardware
505 // decryption is needed
506 if (wk.hw_crypt()) {
507 if (tsk_verbose) {
508 tsk_fprintf(
509 stderr,
510 "apfs: hardware decryption is not yet supported. KEK decryption "
511 "will likely fail\n");
512 }
513 }
514
515 const auto user_key = pbkdf2_hmac_sha256(password, wk.salt, sizeof(wk.salt),
516 wk.iterations, kek_len);
517 if (user_key == nullptr) {
518 if (tsk_verbose) {
519 tsk_fprintf(stderr, "apfs: can not generate user key\n");
520 }
521 continue;
522 }
523
524 const auto kek =
525 rfc3394_key_unwrap(user_key.get(), kek_len, wk.data, kek_len + 8);
526 if (kek == nullptr) {
527 if (tsk_verbose) {
528 tsk_fprintf(stderr,
529 "apfs: KEK %s can not be unwrapped with given password\n",
530 wk.uuid.str().c_str());
531 }
532 continue;
533 }
534
535 // If the 57th bit of the VEK flags is set, then the VEK is a
536 // CoreStorage VEK
537 const auto vek_len = (_crypto.cs()) ? 0x10 : 0x20;
538
539 // If a 128 bit VEK is wrapped with a 256 bit KEK then only the first 128
540 // bits of the KEK are used.
541 const auto vek = rfc3394_key_unwrap(kek.get(), std::min(kek_len, vek_len),
542 _crypto.wrapped_vek, vek_len + 8);
543 if (vek == nullptr) {
544 if (tsk_verbose) {
545 tsk_fprintf(stderr, "apfs: failed to unwrap VEK\n");
546 }
547 continue;
548 }
549
550 _crypto.password = password;
551 std::memcpy(_crypto.vek, vek.get(), vek_len);
552
553 if (_crypto.cs()) {
554 // For volumes that were converted from CoreStorage, the tweak is the
555 // first 128-bits of SHA256(vek + vekuuid)
556 std::memcpy(_crypto.vek + 0x10, _crypto.vek_uuid,
557 sizeof(_crypto.vek_uuid));
558
559 const auto hash = hash_buffer_sha256(_crypto.vek, sizeof(_crypto.vek));
560
561 std::memcpy(_crypto.vek + 0x10, hash.get(), 0x10);
562 }
563
564 _crypto.unlocked = true;
565
566 return true;
567 }
568
569 return false;
570 #else
571 if (tsk_verbose) {
572 tsk_fprintf(stderr, "apfs: crypto library not loaded\n");
573 }
574 return false;
575 #endif
576 }
577
unmount_log() const578 const std::vector<APFSFileSystem::unmount_log_t> APFSFileSystem::unmount_log()
579 const {
580 std::vector<unmount_log_t> v{};
581
582 for (auto i = 0; i < 8; i++) {
583 const auto& log = fs()->unmount_logs[i];
584
585 if (log.timestamp == 0) {
586 return v;
587 }
588
589 v.emplace_back(
590 unmount_log_t{log.timestamp, log.kext_ver_str, log.last_xid});
591 }
592
593 return v;
594 }
595
snapshots() const596 const std::vector<APFSFileSystem::snapshot_t> APFSFileSystem::snapshots()
597 const {
598 std::vector<snapshot_t> v{};
599
600 const APFSSnapshotMetaBtreeNode snap_tree{_pool, fs()->snap_meta_tree_oid};
601
602 struct key_type {
603 uint64_t xid_and_type;
604
605 inline uint64_t snap_xid() const noexcept {
606 return bitfield_value(xid_and_type, 60, 0);
607 }
608
609 inline uint64_t type() const noexcept {
610 return bitfield_value(xid_and_type, 4, 60);
611 }
612 };
613
614 using value_type = apfs_snap_metadata;
615
616 std::for_each(snap_tree.begin(), snap_tree.end(), [&](const auto& entry) {
617 const auto key = entry.key.template as<key_type>();
618 const auto value = entry.value.template as<value_type>();
619
620 if (key->type() != APFS_JOBJTYPE_SNAP_METADATA) {
621 return;
622 }
623
624 v.emplace_back(snapshot_t{
625 {value->name, value->name_length - 1U}, // name
626 value->create_time, // timestamp
627 key->snap_xid(), // snap_xid
628 (value->extentref_tree_oid == 0), // dataless
629 });
630 });
631
632 return v;
633 }
634
root_jobj_tree() const635 APFSJObjTree APFSFileSystem::root_jobj_tree() const {
636 return {_pool, omap_root(), rdo(), crypto_info()};
637 }
638
omap_root() const639 apfs_block_num APFSFileSystem::omap_root() const {
640 return APFSOmap{_pool, fs()->omap_oid}.root_block();
641 }
642
APFSJObjBtreeNode(const APFSObjectBtreeNode * obj_root,apfs_block_num block_num,const uint8_t * key)643 APFSJObjBtreeNode::APFSJObjBtreeNode(const APFSObjectBtreeNode* obj_root,
644 apfs_block_num block_num,
645 const uint8_t* key)
646 #ifdef HAVE_LIBOPENSSL
647 : APFSBtreeNode(obj_root->pool(), block_num, key), _obj_root{obj_root} {
648 #else
649 : APFSBtreeNode(obj_root->pool(), block_num, nullptr), _obj_root{ obj_root } {
650 #endif
651 if (subtype() != APFS_OBJ_TYPE_FSTREE) {
652 throw std::runtime_error("APFSJObjBtreeNode: invalid subtype");
653 }
654 }
655
656
find(uint64_t oid) const657 APFSObjectBtreeNode::iterator APFSObjectBtreeNode::find(uint64_t oid) const {
658 return APFSBtreeNode::find(
659 oid, [xid = this->_xid](const auto& key,
660 const auto oid) noexcept->int64_t {
661 if ((key->oid == oid) && (key->xid > xid)) {
662 return key->xid - xid;
663 }
664
665 return (key->oid - oid);
666 });
667 }
668
APFSObjectBtreeNode(const APFSPool & pool,apfs_block_num block_num)669 APFSObjectBtreeNode::APFSObjectBtreeNode(const APFSPool& pool,
670 apfs_block_num block_num)
671 : APFSBtreeNode(pool, block_num), _xid{xid()} {
672 if (subtype() != APFS_OBJ_TYPE_OMAP) {
673 throw std::runtime_error("APFSObjectBtreeNode: invalid subtype");
674 }
675 }
676
APFSObjectBtreeNode(const APFSPool & pool,apfs_block_num block_num,uint64_t snap_xid)677 APFSObjectBtreeNode::APFSObjectBtreeNode(const APFSPool& pool,
678 apfs_block_num block_num,
679 uint64_t snap_xid)
680 : APFSBtreeNode(pool, block_num), _xid{snap_xid} {
681 if (subtype() != APFS_OBJ_TYPE_OMAP) {
682 throw std::runtime_error("APFSObjectBtreeNode: invalid subtype");
683 }
684 }
685
APFSSnapshotMetaBtreeNode(const APFSPool & pool,apfs_block_num block_num)686 APFSSnapshotMetaBtreeNode::APFSSnapshotMetaBtreeNode(const APFSPool& pool,
687 apfs_block_num block_num)
688 : APFSBtreeNode(pool, block_num) {
689 if (subtype() != APFS_OBJ_TYPE_SNAPMETATREE) {
690 throw std::runtime_error("APFSSnapshotMetaBtreeNode: invalid subtype");
691 }
692 }
693
APFSExtentRefBtreeNode(const APFSPool & pool,apfs_block_num block_num)694 APFSExtentRefBtreeNode::APFSExtentRefBtreeNode(const APFSPool& pool,
695 apfs_block_num block_num)
696 : APFSBtreeNode(pool, block_num) {
697 if (subtype() != APFS_OBJ_TYPE_BLOCKREFTREE) {
698 throw std::runtime_error("APFSExtentRefBtreeNode: invalid subtype");
699 }
700 }
701
APFSCheckpointMap(const APFSPool & pool,const apfs_block_num block_num)702 APFSCheckpointMap::APFSCheckpointMap(const APFSPool& pool,
703 const apfs_block_num block_num)
704 : APFSObject(pool, block_num) {
705 if (obj_type() != APFS_OBJ_TYPE_CHECKPOINT_DESC) {
706 throw std::runtime_error("APFSCheckpointMap: invalid object type");
707 }
708 }
709
get_object_block(uint64_t oid,APFS_OBJ_TYPE_ENUM type) const710 apfs_block_num APFSCheckpointMap::get_object_block(
711 uint64_t oid, APFS_OBJ_TYPE_ENUM type) const {
712 const auto entries = map()->entries;
713
714 for (auto i = 0U; i < map()->count; i++) {
715 const auto& entry = entries[i];
716
717 if (entry.oid == oid && entry.type == type) {
718 return entry.paddr;
719 }
720 }
721
722 // Not found
723 throw std::runtime_error(
724 "APFSCheckpointMap::get_object_block: object not found");
725 }
726
APFSSpaceman(const APFSPool & pool,const apfs_block_num block_num)727 APFSSpaceman::APFSSpaceman(const APFSPool& pool, const apfs_block_num block_num)
728 : APFSObject(pool, block_num), _bm_entries{} {
729 if (obj_type() != APFS_OBJ_TYPE_SPACEMAN) {
730 throw std::runtime_error("APFSSpaceman: invalid object type");
731 }
732 }
733
bm_entries() const734 const std::vector<APFSSpacemanCIB::bm_entry>& APFSSpaceman::bm_entries() const {
735 if (!_bm_entries.empty()) {
736 return _bm_entries;
737 }
738
739 #ifdef TSK_MULTITHREAD_LIB
740 // Since this function is const, and const methods generally are assumed to be
741 // thread safe, we ideally want to it be thread safe so multiple threads
742 // aren't trying to initialize at the same time.
743 std::lock_guard<std::mutex> lock{_bm_entries_init_lock};
744
745 // Check again to make sure someone else didn't already beat us to this.
746 if (!_bm_entries.empty()) {
747 return _bm_entries;
748 }
749
750 // Our above checks would not prevent someone from accessing the member while
751 // the initialization is in progress, so let's initialize a temporary and them
752 // move it into the member instead.
753 decltype(_bm_entries) bm_entries{};
754 #else
755 // There's no possibility for contention, so let's just initialize the member
756 // directly so that we can save the move.
757 auto& bm_entries = _bm_entries;
758 #endif
759
760 bm_entries.reserve(sm()->devs[APFS_SD_MAIN].cib_count);
761
762 const auto cib_blocks = [&] {
763 std::vector<apfs_block_num> v{};
764 v.reserve(sm()->devs[APFS_SD_MAIN].cib_count);
765
766 const auto entries = this->entries();
767
768 // Is the next level cib?
769 if (sm()->devs[APFS_SD_MAIN].cab_count == 0) {
770 // Our entires contain the cib blocks
771 for (auto i = 0U; i < sm()->devs[APFS_SD_MAIN].cib_count; i++) {
772 v.emplace_back(entries[i]);
773 }
774
775 return v;
776 }
777
778 // The next level is cab, not cib so we need to recurse them
779 for (auto i = 0U; i < sm()->devs[APFS_SD_MAIN].cab_count; i++) {
780 const APFSSpacemanCAB cab(_pool, entries[i]);
781 const auto cab_entries = cab.cib_blocks();
782
783 // Append the blocks to the vector
784 std::copy(cab_entries.begin(), cab_entries.end(), std::back_inserter(v));
785 }
786
787 return v;
788 }();
789
790 for (const auto block : cib_blocks) {
791 const APFSSpacemanCIB cib(_pool, block);
792
793 const auto entries = cib.bm_entries();
794
795 // Append the entries to the vector
796 std::copy(entries.begin(), entries.end(), std::back_inserter(bm_entries));
797 }
798
799 // Sort the entries by offset
800 std::sort(bm_entries.begin(), bm_entries.end(),
801 [](const auto& a, const auto& b) { return (a.offset < b.offset); });
802
803 #ifdef TSK_MULTITHREAD_LIB
804 // Now that we're fully initialized we can now move our initialized vector
805 // into the member to signal that we're ready for access.
806 _bm_entries = std::move(bm_entries);
807 #endif
808
809 return _bm_entries;
810 }
811
unallocated_ranges() const812 const std::vector<APFSSpaceman::range> APFSSpaceman::unallocated_ranges()
813 const {
814 std::vector<range> v{};
815
816 for (const auto& entry : bm_entries()) {
817 if (entry.free_blocks == 0) {
818 // No free ranges to add
819 continue;
820 }
821
822 if (entry.total_blocks == entry.free_blocks) {
823 // The entire bitmap block is free
824 if (!v.empty() &&
825 v.back().start_block + v.back().num_blocks == entry.offset) {
826 // We're within the same range as the last one, so just update the
827 // count
828 v.back().num_blocks += entry.free_blocks;
829 } else {
830 // We're not contiguous with the last range, so add a new one
831 v.emplace_back(range{entry.offset, entry.free_blocks});
832 }
833 continue;
834 }
835
836 // We've got to enumerate the bitmap block for it's ranges
837 const auto ranges = APFSBitmapBlock{_pool, entry}.unallocated_ranges();
838
839 // TODO(JTS): We could possibly de-duplicate the first range if it's
840 // contiguous with the last range, but the overhead might outweigh the
841 // convenience
842 std::copy(ranges.begin(), ranges.end(), std::back_inserter(v));
843 }
844
845 return v;
846 }
847
APFSSpacemanCIB(const APFSPool & pool,const apfs_block_num block_num)848 APFSSpacemanCIB::APFSSpacemanCIB(const APFSPool& pool,
849 const apfs_block_num block_num)
850 : APFSObject(pool, block_num) {
851 if (obj_type() != APFS_OBJ_TYPE_SPACEMAN_CIB) {
852 throw std::runtime_error("APFSSpacemanCIB: invalid object type");
853 }
854 }
855
bm_entries() const856 const std::vector<APFSSpacemanCIB::bm_entry> APFSSpacemanCIB::bm_entries()
857 const {
858 std::vector<bm_entry> v{};
859 v.reserve(cib()->entry_count);
860
861 const auto entries = cib()->entries;
862 for (auto i = 0U; i < cib()->entry_count; i++) {
863 const auto& entry = entries[i];
864 v.emplace_back(bm_entry{entry.addr, entry.block_count, entry.free_count,
865 entry.bm_addr});
866 }
867
868 return v;
869 }
870
APFSSpacemanCAB(const APFSPool & pool,const apfs_block_num block_num)871 APFSSpacemanCAB::APFSSpacemanCAB(const APFSPool& pool,
872 const apfs_block_num block_num)
873 : APFSObject(pool, block_num) {
874 if (obj_type() != APFS_OBJ_TYPE_SPACEMAN_CAB) {
875 throw std::runtime_error("APFSSpacemanCAB: invalid object type");
876 }
877 }
878
cib_blocks() const879 const std::vector<apfs_block_num> APFSSpacemanCAB::cib_blocks() const {
880 std::vector<apfs_block_num> v{};
881 v.reserve(cib_count());
882
883 const auto entries = cab()->cib_blocks;
884
885 for (auto i = 0U; i < cib_count(); i++) {
886 v.emplace_back(entries[i]);
887 }
888
889 return v;
890 }
891
APFSBitmapBlock(const APFSPool & pool,const APFSSpacemanCIB::bm_entry & entry)892 APFSBitmapBlock::APFSBitmapBlock(const APFSPool& pool,
893 const APFSSpacemanCIB::bm_entry& entry)
894 : APFSBlock(pool, entry.bm_block), _entry{entry} {}
895
next()896 uint32_t APFSBitmapBlock::next() noexcept {
897 while (!done()) {
898 // Calculate the index of the bit to be evaluated.
899 const auto i = _hint % cached_bits;
900
901 // If we're evaluating the first bit then we need to cache the next set
902 // from the array.
903 if (i == 0) {
904 cache_next();
905
906 // If there are no set bits then there's nothing to scan for, so let's
907 // try again with the next set of bits.
908 if (_cache == 0) {
909 _hint += cached_bits;
910 continue;
911 }
912 }
913
914 // Mask the fetched value and count the number of trailing zero bits.
915 const auto c = lsbset((_cache >> i) << i);
916
917 // If c is non-zero then there are set bits.
918 if (c != 0) {
919 // There are set bits. We just need to make sure that they're within
920 // the range we're scanning for.
921
922 // Adjust the hint for the next call
923 _hint += c - i;
924
925 // Check to see if we're still in range
926 if (_hint - 1 < _entry.total_blocks) {
927 return _hint - 1;
928 }
929
930 // The hit is outside of our scanned range
931 return no_bits_left;
932 }
933
934 // There are no set bits, so we need to adjust the hint to the next set of
935 // bits and try again.
936 _hint += cached_bits - i;
937 }
938
939 return no_bits_left;
940 }
941
unallocated_ranges()942 const std::vector<APFSSpaceman::range> APFSBitmapBlock::unallocated_ranges() {
943 // Check for special case where all blocks are allocated
944 if (_entry.free_blocks == 0) {
945 return {};
946 }
947
948 // Check for special cases where all blocks are free
949 if (_entry.free_blocks == _entry.total_blocks) {
950 return {{_entry.offset, _entry.total_blocks}};
951 }
952
953 reset();
954 _mode = mode::unset;
955
956 std::vector<APFSSpaceman::range> v{};
957
958 while (!done()) {
959 // Get the start of the range.
960 const auto s = next();
961
962 // If there's no start then we're done.
963 if (s == no_bits_left) {
964 break;
965 }
966
967 // Toggle the scan mode to look for the next type of bit.
968 toggle_mode();
969
970 // Get the end of the range.
971 auto e = next();
972
973 // If there's no end then we set the end of the range to the end of the
974 // bitmap.
975 if (e == no_bits_left) {
976 e = _entry.total_blocks;
977 }
978
979 // Add the range description to the vector.
980 v.emplace_back(APFSSpaceman::range{s + _entry.offset, e - s});
981
982 // Toggle the scan mode for the next scan.
983 toggle_mode();
984 }
985
986 return v;
987 }
988
APFSKeybag(const APFSPool & pool,const apfs_block_num block_num,const uint8_t * key,const uint8_t * key2)989 APFSKeybag::APFSKeybag(const APFSPool& pool, const apfs_block_num block_num,
990 const uint8_t* key, const uint8_t* key2)
991 : APFSObject(pool, block_num) {
992 decrypt(key, key2);
993
994 if (!validate_checksum()) {
995 throw std::runtime_error("keybag did not decrypt properly");
996 }
997
998 if (kb()->version != 2) {
999 throw std::runtime_error("keybag version not supported");
1000 }
1001 }
1002
get_key(const Guid & uuid,uint16_t type) const1003 std::unique_ptr<uint8_t[]> APFSKeybag::get_key(const Guid& uuid,
1004 uint16_t type) const {
1005 if (kb()->num_entries == 0) {
1006 return nullptr;
1007 }
1008
1009 // First key is immediately after the header
1010 auto next_key = kb()->first_key;
1011
1012 for (auto i = 0U; i < kb()->num_entries; i++) {
1013 if (next_key->type == type &&
1014 std::memcmp(next_key->uuid, uuid.bytes().data(), 16) == 0) {
1015 // We've found a matching key. Copy it's data to a pointer and return it.
1016 const auto data = reinterpret_cast<const uint8_t*>(next_key + 1);
1017
1018 // We're padding the data with an extra byte so we can null-terminate
1019 // any data strings. There might be a better way.
1020 auto dp = std::make_unique<uint8_t[]>(next_key->length + 1);
1021
1022 std::memcpy(dp.get(), data, next_key->length);
1023
1024 return dp;
1025 }
1026
1027 // Calculate address of next key (ensuring alignment)
1028
1029 const auto nk_addr =
1030 (uintptr_t)next_key +
1031 ((sizeof(*next_key) + next_key->length + 0x0F) & ~0x0FULL);
1032
1033 next_key = reinterpret_cast<const apfs_keybag_key*>(nk_addr);
1034 }
1035
1036 // Not Found
1037 return nullptr;
1038 }
1039
get_keys() const1040 std::vector<APFSKeybag::key> APFSKeybag::get_keys() const {
1041 std::vector<key> keys;
1042
1043 // First key is immediately after the header
1044 auto next_key = kb()->first_key;
1045
1046 for (auto i = 0U; i < kb()->num_entries; i++) {
1047 const auto data = reinterpret_cast<const uint8_t*>(next_key + 1);
1048
1049 // We're padding the data with an extra byte so we can null-terminate
1050 // any data strings. There might be a better way.
1051 auto dp = std::make_unique<uint8_t[]>(next_key->length + 1);
1052
1053 std::memcpy(dp.get(), data, next_key->length);
1054
1055 keys.emplace_back(key{{next_key->uuid}, std::move(dp), next_key->type});
1056
1057 // Calculate address of next key (ensuring alignment)
1058 const auto nk_addr =
1059 (uintptr_t)next_key +
1060 ((sizeof(*next_key) + next_key->length + 0x0F) & ~0x0FULL);
1061
1062 next_key = reinterpret_cast<const apfs_keybag_key*>(nk_addr);
1063 }
1064
1065 return keys;
1066 }
1067
Keybag(const APFSSuperblock & sb)1068 APFSSuperblock::Keybag::Keybag(const APFSSuperblock& sb)
1069 : APFSKeybag(sb.pool(), sb.sb()->keylocker.start_paddr, sb.sb()->uuid,
1070 sb.sb()->uuid) {
1071 if (obj_type_and_flags() != APFS_OBJ_TYPE_CONTAINER_KEYBAG) {
1072 throw std::runtime_error("APFSSuperblock::Keybag: invalid object type");
1073 }
1074
1075 if (sb.sb()->keylocker.block_count != 1) {
1076 throw std::runtime_error("only single block keybags are supported");
1077 }
1078 }
1079
find(apfs_block_num block) const1080 APFSExtentRefBtreeNode::iterator APFSExtentRefBtreeNode::find(
1081 apfs_block_num block) const {
1082 return APFSBtreeNode::find(
1083 block, [](const auto& key, const auto block) noexcept->int64_t {
1084 return key.template as<APFSPhysicalExtentKey>()->start_block() - block;
1085 });
1086 }
1087
Keybag(const APFSFileSystem & vol,apfs_block_num block_num)1088 APFSFileSystem::Keybag::Keybag(const APFSFileSystem& vol,
1089 apfs_block_num block_num)
1090 : APFSKeybag(vol.pool(), block_num, vol.fs()->uuid, vol.fs()->uuid) {
1091 if (obj_type_and_flags() != APFS_OBJ_TYPE_VOLUME_RECOVERY_KEYBAG) {
1092 throw std::runtime_error("APFSFileSystem::Keybag: invalid object type");
1093 }
1094 }
1095