1 // AvbHandler.cpp
2
3 #include "StdAfx.h"
4
5 #include "../../../C/CpuArch.h"
6
7 #include "../../Common/ComTry.h"
8 #include "../../Common/MyBuffer.h"
9
10 #include "../../Windows/PropVariant.h"
11
12 #include "../Common/RegisterArc.h"
13 #include "../Common/StreamUtils.h"
14
15 #include "HandlerCont.h"
16
17 #define Get32(p) GetBe32(p)
18 #define Get64(p) GetBe64(p)
19
20 #define G32(_offs_, dest) dest = Get32(p + (_offs_))
21 #define G64(_offs_, dest) dest = Get64(p + (_offs_))
22
23 using namespace NWindows;
24
25 namespace NArchive {
26
27 namespace NExt {
28 API_FUNC_IsArc IsArc_Ext_PhySize(const Byte *p, size_t size, UInt64 *phySize);
29 }
30
31 namespace NAvb {
32
AddNameToString(AString & s,const Byte * name,unsigned size,bool strictConvert)33 static void AddNameToString(AString &s, const Byte *name, unsigned size, bool strictConvert)
34 {
35 for (unsigned i = 0; i < size; i++)
36 {
37 Byte c = name[i];
38 if (c == 0)
39 return;
40 if (strictConvert && c < 32)
41 c = '_';
42 s += (char)c;
43 }
44 }
45
46 /* Maximum size of a vbmeta image - 64 KiB. */
47 #define VBMETA_MAX_SIZE (64 * 1024)
48
49 #define SIGNATURE { 'A', 'V', 'B', 'f', 0, 0, 0, 1 }
50
51 static const unsigned k_SignatureSize = 8;
52 static const Byte k_Signature[k_SignatureSize] = SIGNATURE;
53
54 // #define AVB_FOOTER_MAGIC "AVBf"
55 // #define AVB_FOOTER_MAGIC_LEN 4
56 /* The current footer version used - keep in sync with avbtool. */
57 #define AVB_FOOTER_VERSION_MAJOR 1
58
59 /* The struct used as a footer used on partitions, used to find the
60 * AvbVBMetaImageHeader struct. This struct is always stored at the
61 * end of a partition.
62 */
63 // #define AVB_FOOTER_SIZE 64
64 static const unsigned kFooterSize = 64;
65
66 struct CFooter
67 {
68 /* 0: Four bytes equal to "AVBf" (AVB_FOOTER_MAGIC). */
69 // Byte magic[AVB_FOOTER_MAGIC_LEN];
70 /* 4: The major version of the footer struct. */
71 UInt32 version_major;
72 /* 8: The minor version of the footer struct. */
73 UInt32 version_minor;
74
75 /* 12: The original size of the image on the partition. */
76 UInt64 original_image_size;
77
78 /* 20: The offset of the |AvbVBMetaImageHeader| struct. */
79 UInt64 vbmeta_offset;
80
81 /* 28: The size of the vbmeta block (header + auth + aux blocks). */
82 UInt64 vbmeta_size;
83
84 /* 36: Padding to ensure struct is size AVB_FOOTER_SIZE bytes. This
85 * must be set to zeroes.
86 */
87 Byte reserved[28];
88
ParseNArchive::NAvb::CFooter89 void Parse(const Byte *p)
90 {
91 G32 (4, version_major);
92 G32 (8, version_minor);
93 G64 (12, original_image_size);
94 G64 (20, vbmeta_offset);
95 G64 (28, vbmeta_size);
96 }
97 };
98
99
100 /* Size of the vbmeta image header. */
101 #define AVB_VBMETA_IMAGE_HEADER_SIZE 256
102
103 /* Magic for the vbmeta image header. */
104 // #define AVB_MAGIC "AVB0"
105 // #define AVB_MAGIC_LEN 4
106 /* Maximum size of the release string including the terminating NUL byte. */
107 #define AVB_RELEASE_STRING_SIZE 48
108
109 struct AvbVBMetaImageHeader
110 {
111 /* 0: Four bytes equal to "AVB0" (AVB_MAGIC). */
112 // Byte magic[AVB_MAGIC_LEN];
113
114 /* 4: The major version of libavb required for this header. */
115 UInt32 required_libavb_version_major;
116 /* 8: The minor version of libavb required for this header. */
117 UInt32 required_libavb_version_minor;
118
119 /* 12: The size of the signature block. */
120 UInt64 authentication_data_block_size;
121 /* 20: The size of the auxiliary data block. */
122 UInt64 auxiliary_data_block_size;
123
124 /* 28: The verification algorithm used, see |AvbAlgorithmType| enum. */
125 UInt32 algorithm_type;
126
127 /* 32: Offset into the "Authentication data" block of hash data. */
128 UInt64 hash_offset;
129 /* 40: Length of the hash data. */
130 UInt64 hash_size;
131
132 /* 48: Offset into the "Authentication data" block of signature data. */
133 UInt64 signature_offset;
134 /* 56: Length of the signature data. */
135 UInt64 signature_size;
136
137 /* 64: Offset into the "Auxiliary data" block of public key data. */
138 UInt64 public_key_offset;
139 /* 72: Length of the public key data. */
140 UInt64 public_key_size;
141
142 /* 80: Offset into the "Auxiliary data" block of public key metadata. */
143 UInt64 public_key_metadata_offset;
144 /* 88: Length of the public key metadata. Must be set to zero if there
145 * is no public key metadata.
146 */
147 UInt64 public_key_metadata_size;
148
149 /* 96: Offset into the "Auxiliary data" block of descriptor data. */
150 UInt64 descriptors_offset;
151 /* 104: Length of descriptor data. */
152 UInt64 descriptors_size;
153
154 /* 112: The rollback index which can be used to prevent rollback to
155 * older versions.
156 */
157 UInt64 rollback_index;
158
159 /* 120: Flags from the AvbVBMetaImageFlags enumeration. This must be
160 * set to zero if the vbmeta image is not a top-level image.
161 */
162 UInt32 flags;
163
164 /* 124: The location of the rollback index defined in this header.
165 * Only valid for the main vbmeta. For chained partitions, the rollback
166 * index location must be specified in the AvbChainPartitionDescriptor
167 * and this value must be set to 0.
168 */
169 UInt32 rollback_index_location;
170
171 /* 128: The release string from avbtool, e.g. "avbtool 1.0.0" or
172 * "avbtool 1.0.0 xyz_board Git-234abde89". Is guaranteed to be NUL
173 * terminated. Applications must not make assumptions about how this
174 * string is formatted.
175 */
176 Byte release_string[AVB_RELEASE_STRING_SIZE];
177
178 /* 176: Padding to ensure struct is size AVB_VBMETA_IMAGE_HEADER_SIZE
179 * bytes. This must be set to zeroes.
180 */
181 // Byte reserved[80];
182 bool Parse(const Byte *p);
183 };
184
Parse(const Byte * p)185 bool AvbVBMetaImageHeader::Parse(const Byte *p)
186 {
187 // Byte magic[AVB_MAGIC_LEN];
188 if (Get32(p) != 0x41564230) // "AVB0"
189 return false;
190 G32 (4, required_libavb_version_major);
191 if (required_libavb_version_major != AVB_FOOTER_VERSION_MAJOR) // "AVB0"
192 return false;
193 G32 (8, required_libavb_version_minor);
194 G64 (12, authentication_data_block_size);
195 G64 (20, auxiliary_data_block_size);
196 G32 (28, algorithm_type);
197 G64 (32, hash_offset);
198 G64 (40, hash_size);
199 G64 (48, signature_offset);
200 G64 (56, signature_size);
201 G64 (64, public_key_offset);
202 G64 (72, public_key_size);
203 G64 (80, public_key_metadata_offset);
204 G64 (88, public_key_metadata_size);
205 G64 (96, descriptors_offset);
206 G64 (104, descriptors_size);
207 G64 (112, rollback_index);
208 G32 (120, flags);
209 G32 (124, rollback_index_location);
210 memcpy(release_string, p + 128, AVB_RELEASE_STRING_SIZE);
211
212 /* 176: Padding to ensure struct is size AVB_VBMETA_IMAGE_HEADER_SIZE
213 * bytes. This must be set to zeroes.
214 */
215 // Byte reserved[80];
216 return true;
217 }
218
219
220 static const unsigned k_Descriptor_Size = 16;
221
222 enum AvbDescriptorTag
223 {
224 AVB_DESCRIPTOR_TAG_PROPERTY,
225 AVB_DESCRIPTOR_TAG_HASHTREE,
226 AVB_DESCRIPTOR_TAG_HASH,
227 AVB_DESCRIPTOR_TAG_KERNEL_CMDLINE,
228 AVB_DESCRIPTOR_TAG_CHAIN_PARTITION
229 };
230
231 struct AvbDescriptor
232 {
233 UInt64 Tag;
234 UInt64 Size;
235
ParseNArchive::NAvb::AvbDescriptor236 void Parse(const Byte *p)
237 {
238 G64 (0, Tag);
239 G64 (8, Size);
240 }
241 };
242
243
244 enum AvbHashtreeDescriptorFlags
245 {
246 AVB_HASHTREE_DESCRIPTOR_FLAGS_DO_NOT_USE_AB = (1 << 0),
247 AVB_HASHTREE_DESCRIPTOR_FLAGS_CHECK_AT_MOST_ONCE = (1 << 1)
248 };
249
250 /* A descriptor containing information about a dm-verity hashtree.
251 *
252 * Hash-trees are used to verify large partitions typically containing
253 * file systems. See
254 * https://gitlab.com/cryptsetup/cryptsetup/wikis/DMVerity for more
255 * information about dm-verity.
256 *
257 * Following this struct are |partition_name_len| bytes of the
258 * partition name (UTF-8 encoded), |salt_len| bytes of salt, and then
259 * |root_digest_len| bytes of the root digest.
260 *
261 * The |reserved| field is for future expansion and must be set to NUL
262 * bytes.
263 *
264 * Changes in v1.1:
265 * - flags field is added which supports AVB_HASHTREE_DESCRIPTOR_FLAGS_USE_AB
266 * - digest_len may be zero, which indicates the use of a persistent digest
267 */
268
269 static const unsigned k_Hashtree_Size_Min = 164;
270
271 struct AvbHashtreeDescriptor
272 {
273 UInt32 dm_verity_version;
274 UInt64 image_size;
275 UInt64 tree_offset;
276 UInt64 tree_size;
277 UInt32 data_block_size;
278 UInt32 hash_block_size;
279 UInt32 fec_num_roots;
280 UInt64 fec_offset;
281 UInt64 fec_size;
282 Byte hash_algorithm[32];
283 UInt32 partition_name_len;
284 UInt32 salt_len;
285 UInt32 root_digest_len;
286 UInt32 flags;
287 Byte reserved[60];
ParseNArchive::NAvb::AvbHashtreeDescriptor288 void Parse(const Byte *p)
289 {
290 G32 (0, dm_verity_version);
291 G64 (4, image_size);
292 G64 (12, tree_offset);
293 G64 (20, tree_size);
294 G32 (28, data_block_size);
295 G32 (32, hash_block_size);
296 G32 (36, fec_num_roots);
297 G64 (40, fec_offset);
298 G64 (48, fec_size);
299 memcpy(hash_algorithm, p + 56, 32);
300 G32 (88, partition_name_len);
301 G32 (92, salt_len);
302 G32 (96, root_digest_len);
303 G32 (100, flags);
304 }
305 };
306
307 static const unsigned k_PropertyDescriptor_Size_Min = 16;
308
309 struct AvbPropertyDescriptor
310 {
311 UInt64 key_num_bytes;
312 UInt64 value_num_bytes;
313
ParseNArchive::NAvb::AvbPropertyDescriptor314 void Parse(const Byte *p)
315 {
316 G64 (0, key_num_bytes);
317 G64 (8, value_num_bytes);
318 }
319 };
320
321 Z7_class_CHandler_final: public CHandlerCont
322 {
323 Z7_IFACE_COM7_IMP(IInArchive_Cont)
324
325 // UInt64 _startOffset;
326 UInt64 _phySize;
327
328 CFooter Footer;
329 AString Name;
330 const char *Ext;
331
332 HRESULT Open2(IInStream *stream);
333
334 virtual int GetItem_ExtractInfo(UInt32 index, UInt64 &pos, UInt64 &size) const Z7_override
335 {
336 if (index != 0)
337 return NExtract::NOperationResult::kUnavailable;
338 // pos = _startOffset;
339 pos = 0;
340 size = Footer.original_image_size;
341 return NExtract::NOperationResult::kOK;
342 }
343 };
344
345
346 HRESULT CHandler::Open2(IInStream *stream)
347 {
348 UInt64 fileSize;
349 {
350 Byte buf[kFooterSize];
351 RINOK(InStream_GetSize_SeekToEnd(stream, fileSize))
352 if (fileSize < kFooterSize)
353 return S_FALSE;
354 RINOK(InStream_SeekSet(stream, fileSize - kFooterSize))
355 RINOK(ReadStream_FALSE(stream, buf, kFooterSize))
356 if (memcmp(buf, k_Signature, k_SignatureSize) != 0)
357 return S_FALSE;
358 Footer.Parse(buf);
359 if (Footer.vbmeta_size > VBMETA_MAX_SIZE ||
360 Footer.vbmeta_size < AVB_VBMETA_IMAGE_HEADER_SIZE)
361 return S_FALSE;
362 for (unsigned i = 36; i < kFooterSize; i++)
363 if (buf[i] != 0)
364 return S_FALSE;
365 }
366 {
367 CByteBuffer buf;
368 buf.Alloc((size_t)Footer.vbmeta_size);
369 RINOK(InStream_SeekSet(stream, Footer.vbmeta_offset))
370 RINOK(ReadStream_FALSE(stream, buf, (size_t)Footer.vbmeta_size))
371
372 AvbVBMetaImageHeader meta;
373 if (!meta.Parse(buf))
374 return S_FALSE;
375
376 unsigned offset = (unsigned)AVB_VBMETA_IMAGE_HEADER_SIZE;
377 unsigned rem = (unsigned)(Footer.vbmeta_size - offset);
378
379 if (meta.authentication_data_block_size != 0)
380 {
381 if (rem < meta.authentication_data_block_size)
382 return S_FALSE;
383 const unsigned u = (unsigned)meta.authentication_data_block_size;
384 offset += u;
385 rem -= u;
386 }
387
388 if (rem < meta.descriptors_offset ||
389 rem - meta.descriptors_offset < meta.descriptors_size)
390 return S_FALSE;
391 rem = (unsigned)meta.descriptors_size;
392 while (rem != 0)
393 {
394 if (rem < k_Descriptor_Size)
395 return S_FALSE;
396 AvbDescriptor desc;
397 desc.Parse(buf + offset);
398 offset += k_Descriptor_Size;
399 rem -= k_Descriptor_Size;
400 if (desc.Size > rem)
401 return S_FALSE;
402 const unsigned descSize = (unsigned)desc.Size;
403 if (desc.Tag == AVB_DESCRIPTOR_TAG_HASHTREE)
404 {
405 if (descSize < k_Hashtree_Size_Min)
406 return S_FALSE;
407 AvbHashtreeDescriptor ht;
408 ht.Parse(buf + offset);
409 unsigned pos = k_Hashtree_Size_Min;
410
411 if (pos + ht.partition_name_len > descSize)
412 return S_FALSE;
413 Name.Empty(); // UTF-8
414 AddNameToString(Name, buf + offset + pos, ht.partition_name_len, false);
415 pos += ht.partition_name_len;
416
417 if (pos + ht.salt_len > descSize)
418 return S_FALSE;
419 CByteBuffer salt;
420 salt.CopyFrom(buf + offset + pos, ht.salt_len);
421 pos += ht.salt_len;
422
423 if (pos + ht.root_digest_len > descSize)
424 return S_FALSE;
425 CByteBuffer digest;
426 digest.CopyFrom(buf + offset + pos, ht.root_digest_len);
427 pos += ht.root_digest_len;
428 // what is that digest?
429 }
430 else if (desc.Tag == AVB_DESCRIPTOR_TAG_PROPERTY)
431 {
432 if (descSize < k_PropertyDescriptor_Size_Min + 2)
433 return S_FALSE;
434 AvbPropertyDescriptor pt;
435 pt.Parse(buf + offset);
436 unsigned pos = k_PropertyDescriptor_Size_Min;
437
438 if (pt.key_num_bytes > descSize - pos - 1)
439 return S_FALSE;
440 AString key; // UTF-8
441 AddNameToString(key, buf + offset + pos, (unsigned)pt.key_num_bytes, false);
442 pos += (unsigned)pt.key_num_bytes + 1;
443
444 if (descSize < pos)
445 return S_FALSE;
446 if (pt.value_num_bytes > descSize - pos - 1)
447 return S_FALSE;
448 AString value; // UTF-8
449 AddNameToString(value, buf + offset + pos, (unsigned)pt.value_num_bytes, false);
450 pos += (unsigned)pt.value_num_bytes + 1;
451 }
452 offset += descSize;
453 rem -= descSize;
454 }
455
456 _phySize = fileSize;
457
458 // _startOffset = 0;
459 return S_OK;
460 }
461 }
462
463
464 Z7_COM7F_IMF(CHandler::Open(IInStream *stream,
465 const UInt64 * /* maxCheckStartPosition */,
466 IArchiveOpenCallback * /* openArchiveCallback */))
467 {
468 COM_TRY_BEGIN
469 Close();
470 try
471 {
472 if (Open2(stream) != S_OK)
473 return S_FALSE;
474 _stream = stream;
475
476 {
477 CMyComPtr<ISequentialInStream> parseStream;
478 if (GetStream(0, &parseStream) == S_OK && parseStream)
479 {
480 const size_t kParseSize = 1 << 11;
481 Byte buf[kParseSize];
482 if (ReadStream_FAIL(parseStream, buf, kParseSize) == S_OK)
483 {
484 UInt64 extSize;
485 if (NExt::IsArc_Ext_PhySize(buf, kParseSize, &extSize) == k_IsArc_Res_YES)
486 if (extSize == Footer.original_image_size)
487 Ext = "ext";
488 }
489 }
490 }
491 }
492 catch(...) { return S_FALSE; }
493 return S_OK;
494 COM_TRY_END
495 }
496
497
498 Z7_COM7F_IMF(CHandler::Close())
499 {
500 _stream.Release();
501 // _startOffset = 0;
502 _phySize = 0;
503 Ext = NULL;
504 Name.Empty();
505 return S_OK;
506 }
507
508
509 static const Byte kArcProps[] =
510 {
511 kpidName
512 };
513
514 static const Byte kProps[] =
515 {
516 kpidSize,
517 kpidPackSize,
518 };
519
520 IMP_IInArchive_Props
521 IMP_IInArchive_ArcProps
522
523
524 Z7_COM7F_IMF(CHandler::GetArchiveProperty(PROPID propID, PROPVARIANT *value))
525 {
526 COM_TRY_BEGIN
527 NCOM::CPropVariant prop;
528 switch (propID)
529 {
530 case kpidMainSubfile: prop = (UInt32)0; break;
531 case kpidPhySize: prop = _phySize; break;
532 case kpidName:
533 {
534 if (!Name.IsEmpty())
535 {
536 AString s (Name);
537 s += ".avb";
538 prop = s;
539 }
540 break;
541 }
542 }
543 prop.Detach(value);
544 return S_OK;
545 COM_TRY_END
546 }
547
548
549 Z7_COM7F_IMF(CHandler::GetProperty(UInt32 /* index */, PROPID propID, PROPVARIANT *value))
550 {
551 COM_TRY_BEGIN
552 NCOM::CPropVariant prop;
553
554 switch (propID)
555 {
556 case kpidPath:
557 {
558 if (!Name.IsEmpty())
559 {
560 AString s (Name);
561 s += '.';
562 s += Ext ? Ext : "img";
563 prop = s;
564 }
565 break;
566 }
567 case kpidPackSize:
568 case kpidSize:
569 prop = Footer.original_image_size;
570 break;
571 case kpidExtension: prop = (Ext ? Ext : "img"); break;
572 }
573
574 prop.Detach(value);
575 return S_OK;
576 COM_TRY_END
577 }
578
579
580 Z7_COM7F_IMF(CHandler::GetNumberOfItems(UInt32 *numItems))
581 {
582 *numItems = 1;
583 return S_OK;
584 }
585
586
587 REGISTER_ARC_I_NO_SIG(
588 "AVB", "avb img", NULL, 0xc0,
589 /* k_Signature, */
590 0,
591 /* NArcInfoFlags::kUseGlobalOffset | */
592 NArcInfoFlags::kBackwardOpen
593 ,
594 NULL)
595
596 }}
597