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