xref: /aosp_15_r20/external/lzma/CPP/7zip/Archive/AvbHandler.cpp (revision f6dc9357d832569d4d1f5d24eacdb3935a1ae8e6)
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