xref: /aosp_15_r20/system/apex/apexd/apex_file.cpp (revision 33f3758387333dbd2962d7edbd98681940d895da)
1*33f37583SAndroid Build Coastguard Worker /*
2*33f37583SAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*33f37583SAndroid Build Coastguard Worker  *
4*33f37583SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*33f37583SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*33f37583SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*33f37583SAndroid Build Coastguard Worker  *
8*33f37583SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*33f37583SAndroid Build Coastguard Worker  *
10*33f37583SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*33f37583SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*33f37583SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*33f37583SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*33f37583SAndroid Build Coastguard Worker  * limitations under the License.
15*33f37583SAndroid Build Coastguard Worker  */
16*33f37583SAndroid Build Coastguard Worker 
17*33f37583SAndroid Build Coastguard Worker #include "apex_file.h"
18*33f37583SAndroid Build Coastguard Worker 
19*33f37583SAndroid Build Coastguard Worker #include <android-base/file.h>
20*33f37583SAndroid Build Coastguard Worker #include <android-base/logging.h>
21*33f37583SAndroid Build Coastguard Worker #include <android-base/scopeguard.h>
22*33f37583SAndroid Build Coastguard Worker #include <android-base/strings.h>
23*33f37583SAndroid Build Coastguard Worker #include <android-base/unique_fd.h>
24*33f37583SAndroid Build Coastguard Worker #include <fcntl.h>
25*33f37583SAndroid Build Coastguard Worker #include <libavb/libavb.h>
26*33f37583SAndroid Build Coastguard Worker #include <sys/stat.h>
27*33f37583SAndroid Build Coastguard Worker #include <sys/types.h>
28*33f37583SAndroid Build Coastguard Worker #include <unistd.h>
29*33f37583SAndroid Build Coastguard Worker #include <ziparchive/zip_archive.h>
30*33f37583SAndroid Build Coastguard Worker 
31*33f37583SAndroid Build Coastguard Worker #include <filesystem>
32*33f37583SAndroid Build Coastguard Worker #include <fstream>
33*33f37583SAndroid Build Coastguard Worker #include <span>
34*33f37583SAndroid Build Coastguard Worker 
35*33f37583SAndroid Build Coastguard Worker #include "apex_constants.h"
36*33f37583SAndroid Build Coastguard Worker #include "apexd_utils.h"
37*33f37583SAndroid Build Coastguard Worker #include "apexd_verity.h"
38*33f37583SAndroid Build Coastguard Worker 
39*33f37583SAndroid Build Coastguard Worker using android::base::borrowed_fd;
40*33f37583SAndroid Build Coastguard Worker using android::base::ErrnoError;
41*33f37583SAndroid Build Coastguard Worker using android::base::Error;
42*33f37583SAndroid Build Coastguard Worker using android::base::ReadFullyAtOffset;
43*33f37583SAndroid Build Coastguard Worker using android::base::RemoveFileIfExists;
44*33f37583SAndroid Build Coastguard Worker using android::base::Result;
45*33f37583SAndroid Build Coastguard Worker using android::base::unique_fd;
46*33f37583SAndroid Build Coastguard Worker using ::apex::proto::ApexManifest;
47*33f37583SAndroid Build Coastguard Worker 
48*33f37583SAndroid Build Coastguard Worker namespace android {
49*33f37583SAndroid Build Coastguard Worker namespace apex {
50*33f37583SAndroid Build Coastguard Worker namespace {
51*33f37583SAndroid Build Coastguard Worker 
52*33f37583SAndroid Build Coastguard Worker constexpr const char* kImageFilename = "apex_payload.img";
53*33f37583SAndroid Build Coastguard Worker constexpr const char* kCompressedApexFilename = "original_apex";
54*33f37583SAndroid Build Coastguard Worker constexpr const char* kBundledPublicKeyFilename = "apex_pubkey";
55*33f37583SAndroid Build Coastguard Worker 
56*33f37583SAndroid Build Coastguard Worker struct FsMagic {
57*33f37583SAndroid Build Coastguard Worker   const char* type;
58*33f37583SAndroid Build Coastguard Worker   int32_t offset;
59*33f37583SAndroid Build Coastguard Worker   int16_t len;
60*33f37583SAndroid Build Coastguard Worker   const char* magic;
61*33f37583SAndroid Build Coastguard Worker };
62*33f37583SAndroid Build Coastguard Worker constexpr const FsMagic kFsType[] = {{"f2fs", 1024, 4, "\x10\x20\xf5\xf2"},
63*33f37583SAndroid Build Coastguard Worker                                      {"ext4", 1024 + 0x38, 2, "\123\357"},
64*33f37583SAndroid Build Coastguard Worker                                      {"erofs", 1024, 4, "\xe2\xe1\xf5\xe0"}};
65*33f37583SAndroid Build Coastguard Worker 
RetrieveFsType(borrowed_fd fd,uint32_t image_offset)66*33f37583SAndroid Build Coastguard Worker Result<std::string> RetrieveFsType(borrowed_fd fd, uint32_t image_offset) {
67*33f37583SAndroid Build Coastguard Worker   for (const auto& fs : kFsType) {
68*33f37583SAndroid Build Coastguard Worker     char buf[fs.len];
69*33f37583SAndroid Build Coastguard Worker     if (!ReadFullyAtOffset(fd, buf, fs.len, image_offset + fs.offset)) {
70*33f37583SAndroid Build Coastguard Worker       return ErrnoError() << "Couldn't read filesystem magic";
71*33f37583SAndroid Build Coastguard Worker     }
72*33f37583SAndroid Build Coastguard Worker     if (memcmp(buf, fs.magic, fs.len) == 0) {
73*33f37583SAndroid Build Coastguard Worker       return std::string(fs.type);
74*33f37583SAndroid Build Coastguard Worker     }
75*33f37583SAndroid Build Coastguard Worker   }
76*33f37583SAndroid Build Coastguard Worker   return Error() << "Couldn't find filesystem magic";
77*33f37583SAndroid Build Coastguard Worker }
78*33f37583SAndroid Build Coastguard Worker 
79*33f37583SAndroid Build Coastguard Worker }  // namespace
80*33f37583SAndroid Build Coastguard Worker 
Open(const std::string & path)81*33f37583SAndroid Build Coastguard Worker Result<ApexFile> ApexFile::Open(const std::string& path) {
82*33f37583SAndroid Build Coastguard Worker   std::optional<uint32_t> image_offset;
83*33f37583SAndroid Build Coastguard Worker   std::optional<size_t> image_size;
84*33f37583SAndroid Build Coastguard Worker   std::string manifest_content;
85*33f37583SAndroid Build Coastguard Worker   std::string pubkey;
86*33f37583SAndroid Build Coastguard Worker   std::optional<std::string> fs_type;
87*33f37583SAndroid Build Coastguard Worker   ZipEntry entry;
88*33f37583SAndroid Build Coastguard Worker 
89*33f37583SAndroid Build Coastguard Worker   unique_fd fd(open(path.c_str(), O_RDONLY | O_BINARY | O_CLOEXEC));
90*33f37583SAndroid Build Coastguard Worker   if (fd < 0) {
91*33f37583SAndroid Build Coastguard Worker     return ErrnoError() << "Failed to open package " << path << ": "
92*33f37583SAndroid Build Coastguard Worker                         << "I/O error";
93*33f37583SAndroid Build Coastguard Worker   }
94*33f37583SAndroid Build Coastguard Worker 
95*33f37583SAndroid Build Coastguard Worker   ZipArchiveHandle handle;
96*33f37583SAndroid Build Coastguard Worker   auto handle_guard =
97*33f37583SAndroid Build Coastguard Worker       android::base::make_scope_guard([&handle] { CloseArchive(handle); });
98*33f37583SAndroid Build Coastguard Worker   int ret = OpenArchiveFd(fd.get(), path.c_str(), &handle,
99*33f37583SAndroid Build Coastguard Worker                           /*assume_ownership=*/false);
100*33f37583SAndroid Build Coastguard Worker   if (ret < 0) {
101*33f37583SAndroid Build Coastguard Worker     return Error() << "Failed to open package " << path << ": "
102*33f37583SAndroid Build Coastguard Worker                    << ErrorCodeString(ret);
103*33f37583SAndroid Build Coastguard Worker   }
104*33f37583SAndroid Build Coastguard Worker 
105*33f37583SAndroid Build Coastguard Worker   bool is_compressed = true;
106*33f37583SAndroid Build Coastguard Worker   ret = FindEntry(handle, kCompressedApexFilename, &entry);
107*33f37583SAndroid Build Coastguard Worker   if (ret < 0) {
108*33f37583SAndroid Build Coastguard Worker     is_compressed = false;
109*33f37583SAndroid Build Coastguard Worker   }
110*33f37583SAndroid Build Coastguard Worker 
111*33f37583SAndroid Build Coastguard Worker   if (!is_compressed) {
112*33f37583SAndroid Build Coastguard Worker     // Locate the mountable image within the zipfile and store offset and size.
113*33f37583SAndroid Build Coastguard Worker     ret = FindEntry(handle, kImageFilename, &entry);
114*33f37583SAndroid Build Coastguard Worker     if (ret < 0) {
115*33f37583SAndroid Build Coastguard Worker       return Error() << "Could not find entry \"" << kImageFilename
116*33f37583SAndroid Build Coastguard Worker                      << "\" or \"" << kCompressedApexFilename
117*33f37583SAndroid Build Coastguard Worker                      << "\" in package " << path << ": "
118*33f37583SAndroid Build Coastguard Worker                      << ErrorCodeString(ret);
119*33f37583SAndroid Build Coastguard Worker     }
120*33f37583SAndroid Build Coastguard Worker     image_offset = entry.offset;
121*33f37583SAndroid Build Coastguard Worker     image_size = entry.uncompressed_length;
122*33f37583SAndroid Build Coastguard Worker 
123*33f37583SAndroid Build Coastguard Worker     auto fs_type_result = RetrieveFsType(fd, image_offset.value());
124*33f37583SAndroid Build Coastguard Worker     if (!fs_type_result.ok()) {
125*33f37583SAndroid Build Coastguard Worker       return Error() << "Failed to retrieve filesystem type for " << path
126*33f37583SAndroid Build Coastguard Worker                      << ": " << fs_type_result.error();
127*33f37583SAndroid Build Coastguard Worker     }
128*33f37583SAndroid Build Coastguard Worker     fs_type = std::move(*fs_type_result);
129*33f37583SAndroid Build Coastguard Worker   }
130*33f37583SAndroid Build Coastguard Worker 
131*33f37583SAndroid Build Coastguard Worker   ret = FindEntry(handle, kManifestFilenamePb, &entry);
132*33f37583SAndroid Build Coastguard Worker   if (ret < 0) {
133*33f37583SAndroid Build Coastguard Worker     return Error() << "Could not find entry \"" << kManifestFilenamePb
134*33f37583SAndroid Build Coastguard Worker                    << "\" in package " << path << ": " << ErrorCodeString(ret);
135*33f37583SAndroid Build Coastguard Worker   }
136*33f37583SAndroid Build Coastguard Worker 
137*33f37583SAndroid Build Coastguard Worker   uint32_t length = entry.uncompressed_length;
138*33f37583SAndroid Build Coastguard Worker   manifest_content.resize(length, '\0');
139*33f37583SAndroid Build Coastguard Worker   ret = ExtractToMemory(handle, &entry,
140*33f37583SAndroid Build Coastguard Worker                         reinterpret_cast<uint8_t*>(&(manifest_content)[0]),
141*33f37583SAndroid Build Coastguard Worker                         length);
142*33f37583SAndroid Build Coastguard Worker   if (ret != 0) {
143*33f37583SAndroid Build Coastguard Worker     return Error() << "Failed to extract manifest from package " << path << ": "
144*33f37583SAndroid Build Coastguard Worker                    << ErrorCodeString(ret);
145*33f37583SAndroid Build Coastguard Worker   }
146*33f37583SAndroid Build Coastguard Worker 
147*33f37583SAndroid Build Coastguard Worker   ret = FindEntry(handle, kBundledPublicKeyFilename, &entry);
148*33f37583SAndroid Build Coastguard Worker   if (ret >= 0) {
149*33f37583SAndroid Build Coastguard Worker     length = entry.uncompressed_length;
150*33f37583SAndroid Build Coastguard Worker     pubkey.resize(length, '\0');
151*33f37583SAndroid Build Coastguard Worker     ret = ExtractToMemory(handle, &entry,
152*33f37583SAndroid Build Coastguard Worker                           reinterpret_cast<uint8_t*>(&(pubkey)[0]), length);
153*33f37583SAndroid Build Coastguard Worker     if (ret != 0) {
154*33f37583SAndroid Build Coastguard Worker       return Error() << "Failed to extract public key from package " << path
155*33f37583SAndroid Build Coastguard Worker                      << ": " << ErrorCodeString(ret);
156*33f37583SAndroid Build Coastguard Worker     }
157*33f37583SAndroid Build Coastguard Worker   }
158*33f37583SAndroid Build Coastguard Worker 
159*33f37583SAndroid Build Coastguard Worker   Result<ApexManifest> manifest = ParseManifest(manifest_content);
160*33f37583SAndroid Build Coastguard Worker   if (!manifest.ok()) {
161*33f37583SAndroid Build Coastguard Worker     return manifest.error();
162*33f37583SAndroid Build Coastguard Worker   }
163*33f37583SAndroid Build Coastguard Worker 
164*33f37583SAndroid Build Coastguard Worker   if (is_compressed && manifest->providesharedapexlibs()) {
165*33f37583SAndroid Build Coastguard Worker     return Error() << "Apex providing sharedlibs shouldn't be compressed";
166*33f37583SAndroid Build Coastguard Worker   }
167*33f37583SAndroid Build Coastguard Worker 
168*33f37583SAndroid Build Coastguard Worker   // b/179211712 the stored path should be the realpath, otherwise the path we
169*33f37583SAndroid Build Coastguard Worker   // get by scanning the directory would be different from the path we get
170*33f37583SAndroid Build Coastguard Worker   // by reading /proc/mounts, if the apex file is on a symlink dir.
171*33f37583SAndroid Build Coastguard Worker   std::string realpath;
172*33f37583SAndroid Build Coastguard Worker   if (!android::base::Realpath(path, &realpath)) {
173*33f37583SAndroid Build Coastguard Worker     return ErrnoError() << "can't get realpath of " << path;
174*33f37583SAndroid Build Coastguard Worker   }
175*33f37583SAndroid Build Coastguard Worker 
176*33f37583SAndroid Build Coastguard Worker   return ApexFile(realpath, image_offset, image_size, std::move(*manifest),
177*33f37583SAndroid Build Coastguard Worker                   pubkey, fs_type, is_compressed);
178*33f37583SAndroid Build Coastguard Worker }
179*33f37583SAndroid Build Coastguard Worker 
180*33f37583SAndroid Build Coastguard Worker // AVB-related code.
181*33f37583SAndroid Build Coastguard Worker 
182*33f37583SAndroid Build Coastguard Worker namespace {
183*33f37583SAndroid Build Coastguard Worker 
184*33f37583SAndroid Build Coastguard Worker static constexpr int kVbMetaMaxSize = 64 * 1024;
185*33f37583SAndroid Build Coastguard Worker 
GetSalt(const AvbHashtreeDescriptor & desc,const uint8_t * trailing_data)186*33f37583SAndroid Build Coastguard Worker std::string GetSalt(const AvbHashtreeDescriptor& desc,
187*33f37583SAndroid Build Coastguard Worker                     const uint8_t* trailing_data) {
188*33f37583SAndroid Build Coastguard Worker   const uint8_t* desc_salt = trailing_data + desc.partition_name_len;
189*33f37583SAndroid Build Coastguard Worker 
190*33f37583SAndroid Build Coastguard Worker   return BytesToHex(desc_salt, desc.salt_len);
191*33f37583SAndroid Build Coastguard Worker }
192*33f37583SAndroid Build Coastguard Worker 
GetDigest(const AvbHashtreeDescriptor & desc,const uint8_t * trailing_data)193*33f37583SAndroid Build Coastguard Worker std::string GetDigest(const AvbHashtreeDescriptor& desc,
194*33f37583SAndroid Build Coastguard Worker                       const uint8_t* trailing_data) {
195*33f37583SAndroid Build Coastguard Worker   const uint8_t* desc_digest =
196*33f37583SAndroid Build Coastguard Worker       trailing_data + desc.partition_name_len + desc.salt_len;
197*33f37583SAndroid Build Coastguard Worker 
198*33f37583SAndroid Build Coastguard Worker   return BytesToHex(desc_digest, desc.root_digest_len);
199*33f37583SAndroid Build Coastguard Worker }
200*33f37583SAndroid Build Coastguard Worker 
GetAvbFooter(const ApexFile & apex,const unique_fd & fd)201*33f37583SAndroid Build Coastguard Worker Result<std::unique_ptr<AvbFooter>> GetAvbFooter(const ApexFile& apex,
202*33f37583SAndroid Build Coastguard Worker                                                 const unique_fd& fd) {
203*33f37583SAndroid Build Coastguard Worker   std::array<uint8_t, AVB_FOOTER_SIZE> footer_data;
204*33f37583SAndroid Build Coastguard Worker   auto footer = std::make_unique<AvbFooter>();
205*33f37583SAndroid Build Coastguard Worker 
206*33f37583SAndroid Build Coastguard Worker   // The AVB footer is located in the last part of the image
207*33f37583SAndroid Build Coastguard Worker   if (!apex.GetImageOffset() || !apex.GetImageSize()) {
208*33f37583SAndroid Build Coastguard Worker     return Error() << "Cannot check avb footer without image offset and size";
209*33f37583SAndroid Build Coastguard Worker   }
210*33f37583SAndroid Build Coastguard Worker   off_t offset = apex.GetImageSize().value() + apex.GetImageOffset().value() -
211*33f37583SAndroid Build Coastguard Worker                  AVB_FOOTER_SIZE;
212*33f37583SAndroid Build Coastguard Worker   int ret = lseek(fd, offset, SEEK_SET);
213*33f37583SAndroid Build Coastguard Worker   if (ret == -1) {
214*33f37583SAndroid Build Coastguard Worker     return ErrnoError() << "Couldn't seek to AVB footer";
215*33f37583SAndroid Build Coastguard Worker   }
216*33f37583SAndroid Build Coastguard Worker 
217*33f37583SAndroid Build Coastguard Worker   ret = read(fd, footer_data.data(), AVB_FOOTER_SIZE);
218*33f37583SAndroid Build Coastguard Worker   if (ret != AVB_FOOTER_SIZE) {
219*33f37583SAndroid Build Coastguard Worker     return ErrnoError() << "Couldn't read AVB footer";
220*33f37583SAndroid Build Coastguard Worker   }
221*33f37583SAndroid Build Coastguard Worker 
222*33f37583SAndroid Build Coastguard Worker   if (!avb_footer_validate_and_byteswap((const AvbFooter*)footer_data.data(),
223*33f37583SAndroid Build Coastguard Worker                                         footer.get())) {
224*33f37583SAndroid Build Coastguard Worker     return Error() << "AVB footer verification failed.";
225*33f37583SAndroid Build Coastguard Worker   }
226*33f37583SAndroid Build Coastguard Worker 
227*33f37583SAndroid Build Coastguard Worker   LOG(VERBOSE) << "AVB footer verification successful.";
228*33f37583SAndroid Build Coastguard Worker   return footer;
229*33f37583SAndroid Build Coastguard Worker }
230*33f37583SAndroid Build Coastguard Worker 
CompareKeys(const uint8_t * key,size_t length,const std::string & public_key_content)231*33f37583SAndroid Build Coastguard Worker bool CompareKeys(const uint8_t* key, size_t length,
232*33f37583SAndroid Build Coastguard Worker                  const std::string& public_key_content) {
233*33f37583SAndroid Build Coastguard Worker   return public_key_content.length() == length &&
234*33f37583SAndroid Build Coastguard Worker          memcmp(&public_key_content[0], key, length) == 0;
235*33f37583SAndroid Build Coastguard Worker }
236*33f37583SAndroid Build Coastguard Worker 
237*33f37583SAndroid Build Coastguard Worker // Verifies correctness of vbmeta and returns public key it was signed with.
VerifyVbMetaSignature(const ApexFile & apex,const uint8_t * data,size_t length)238*33f37583SAndroid Build Coastguard Worker Result<std::span<const uint8_t>> VerifyVbMetaSignature(const ApexFile& apex,
239*33f37583SAndroid Build Coastguard Worker                                                        const uint8_t* data,
240*33f37583SAndroid Build Coastguard Worker                                                        size_t length) {
241*33f37583SAndroid Build Coastguard Worker   const uint8_t* pk;
242*33f37583SAndroid Build Coastguard Worker   size_t pk_len;
243*33f37583SAndroid Build Coastguard Worker   AvbVBMetaVerifyResult res;
244*33f37583SAndroid Build Coastguard Worker 
245*33f37583SAndroid Build Coastguard Worker   res = avb_vbmeta_image_verify(data, length, &pk, &pk_len);
246*33f37583SAndroid Build Coastguard Worker   switch (res) {
247*33f37583SAndroid Build Coastguard Worker     case AVB_VBMETA_VERIFY_RESULT_OK:
248*33f37583SAndroid Build Coastguard Worker       break;
249*33f37583SAndroid Build Coastguard Worker     case AVB_VBMETA_VERIFY_RESULT_OK_NOT_SIGNED:
250*33f37583SAndroid Build Coastguard Worker     case AVB_VBMETA_VERIFY_RESULT_HASH_MISMATCH:
251*33f37583SAndroid Build Coastguard Worker     case AVB_VBMETA_VERIFY_RESULT_SIGNATURE_MISMATCH:
252*33f37583SAndroid Build Coastguard Worker       return Error() << "Error verifying " << apex.GetPath() << ": "
253*33f37583SAndroid Build Coastguard Worker                      << avb_vbmeta_verify_result_to_string(res);
254*33f37583SAndroid Build Coastguard Worker     case AVB_VBMETA_VERIFY_RESULT_INVALID_VBMETA_HEADER:
255*33f37583SAndroid Build Coastguard Worker       return Error() << "Error verifying " << apex.GetPath() << ": "
256*33f37583SAndroid Build Coastguard Worker                      << "invalid vbmeta header";
257*33f37583SAndroid Build Coastguard Worker     case AVB_VBMETA_VERIFY_RESULT_UNSUPPORTED_VERSION:
258*33f37583SAndroid Build Coastguard Worker       return Error() << "Error verifying " << apex.GetPath() << ": "
259*33f37583SAndroid Build Coastguard Worker                      << "unsupported version";
260*33f37583SAndroid Build Coastguard Worker     default:
261*33f37583SAndroid Build Coastguard Worker       return Error() << "Unknown vmbeta_image_verify return value : " << res;
262*33f37583SAndroid Build Coastguard Worker   }
263*33f37583SAndroid Build Coastguard Worker 
264*33f37583SAndroid Build Coastguard Worker   return std::span<const uint8_t>(pk, pk_len);
265*33f37583SAndroid Build Coastguard Worker }
266*33f37583SAndroid Build Coastguard Worker 
VerifyVbMeta(const ApexFile & apex,const unique_fd & fd,const AvbFooter & footer,const std::string & public_key)267*33f37583SAndroid Build Coastguard Worker Result<std::unique_ptr<uint8_t[]>> VerifyVbMeta(const ApexFile& apex,
268*33f37583SAndroid Build Coastguard Worker                                                 const unique_fd& fd,
269*33f37583SAndroid Build Coastguard Worker                                                 const AvbFooter& footer,
270*33f37583SAndroid Build Coastguard Worker                                                 const std::string& public_key) {
271*33f37583SAndroid Build Coastguard Worker   if (footer.vbmeta_size > kVbMetaMaxSize) {
272*33f37583SAndroid Build Coastguard Worker     return Errorf("VbMeta size in footer exceeds kVbMetaMaxSize.");
273*33f37583SAndroid Build Coastguard Worker   }
274*33f37583SAndroid Build Coastguard Worker 
275*33f37583SAndroid Build Coastguard Worker   if (!apex.GetImageOffset()) {
276*33f37583SAndroid Build Coastguard Worker     return Error() << "Cannot check VbMeta size without image offset";
277*33f37583SAndroid Build Coastguard Worker   }
278*33f37583SAndroid Build Coastguard Worker 
279*33f37583SAndroid Build Coastguard Worker   off_t offset = apex.GetImageOffset().value() + footer.vbmeta_offset;
280*33f37583SAndroid Build Coastguard Worker   std::unique_ptr<uint8_t[]> vbmeta_buf(new uint8_t[footer.vbmeta_size]);
281*33f37583SAndroid Build Coastguard Worker 
282*33f37583SAndroid Build Coastguard Worker   if (!ReadFullyAtOffset(fd, vbmeta_buf.get(), footer.vbmeta_size, offset)) {
283*33f37583SAndroid Build Coastguard Worker     return ErrnoError() << "Couldn't read AVB meta-data";
284*33f37583SAndroid Build Coastguard Worker   }
285*33f37583SAndroid Build Coastguard Worker 
286*33f37583SAndroid Build Coastguard Worker   Result<std::span<const uint8_t>> st =
287*33f37583SAndroid Build Coastguard Worker       VerifyVbMetaSignature(apex, vbmeta_buf.get(), footer.vbmeta_size);
288*33f37583SAndroid Build Coastguard Worker   if (!st.ok()) {
289*33f37583SAndroid Build Coastguard Worker     return st.error();
290*33f37583SAndroid Build Coastguard Worker   }
291*33f37583SAndroid Build Coastguard Worker 
292*33f37583SAndroid Build Coastguard Worker   if (!CompareKeys(st->data(), st->size(), public_key)) {
293*33f37583SAndroid Build Coastguard Worker     return Error() << "Error verifying " << apex.GetPath() << " : "
294*33f37583SAndroid Build Coastguard Worker                    << "public key doesn't match the pre-installed one";
295*33f37583SAndroid Build Coastguard Worker   }
296*33f37583SAndroid Build Coastguard Worker 
297*33f37583SAndroid Build Coastguard Worker   return vbmeta_buf;
298*33f37583SAndroid Build Coastguard Worker }
299*33f37583SAndroid Build Coastguard Worker 
FindDescriptor(uint8_t * vbmeta_data,size_t vbmeta_size)300*33f37583SAndroid Build Coastguard Worker Result<const AvbHashtreeDescriptor*> FindDescriptor(uint8_t* vbmeta_data,
301*33f37583SAndroid Build Coastguard Worker                                                     size_t vbmeta_size) {
302*33f37583SAndroid Build Coastguard Worker   const AvbDescriptor** descriptors;
303*33f37583SAndroid Build Coastguard Worker   size_t num_descriptors;
304*33f37583SAndroid Build Coastguard Worker 
305*33f37583SAndroid Build Coastguard Worker   descriptors =
306*33f37583SAndroid Build Coastguard Worker       avb_descriptor_get_all(vbmeta_data, vbmeta_size, &num_descriptors);
307*33f37583SAndroid Build Coastguard Worker 
308*33f37583SAndroid Build Coastguard Worker   // avb_descriptor_get_all() returns an internally allocated array
309*33f37583SAndroid Build Coastguard Worker   // of pointers and it needs to be avb_free()ed after using it.
310*33f37583SAndroid Build Coastguard Worker   auto guard = android::base::ScopeGuard(std::bind(avb_free, descriptors));
311*33f37583SAndroid Build Coastguard Worker 
312*33f37583SAndroid Build Coastguard Worker   for (size_t i = 0; i < num_descriptors; i++) {
313*33f37583SAndroid Build Coastguard Worker     AvbDescriptor desc;
314*33f37583SAndroid Build Coastguard Worker     if (!avb_descriptor_validate_and_byteswap(descriptors[i], &desc)) {
315*33f37583SAndroid Build Coastguard Worker       return Errorf("Couldn't validate AvbDescriptor.");
316*33f37583SAndroid Build Coastguard Worker     }
317*33f37583SAndroid Build Coastguard Worker 
318*33f37583SAndroid Build Coastguard Worker     if (desc.tag != AVB_DESCRIPTOR_TAG_HASHTREE) {
319*33f37583SAndroid Build Coastguard Worker       // Ignore other descriptors
320*33f37583SAndroid Build Coastguard Worker       continue;
321*33f37583SAndroid Build Coastguard Worker     }
322*33f37583SAndroid Build Coastguard Worker 
323*33f37583SAndroid Build Coastguard Worker     // Check that hashtree descriptor actually fits into memory.
324*33f37583SAndroid Build Coastguard Worker     const uint8_t* vbmeta_end = vbmeta_data + vbmeta_size;
325*33f37583SAndroid Build Coastguard Worker     if ((uint8_t*)descriptors[i] + sizeof(AvbHashtreeDescriptor) > vbmeta_end) {
326*33f37583SAndroid Build Coastguard Worker       return Errorf("Invalid length for AvbHashtreeDescriptor");
327*33f37583SAndroid Build Coastguard Worker     }
328*33f37583SAndroid Build Coastguard Worker     return (const AvbHashtreeDescriptor*)descriptors[i];
329*33f37583SAndroid Build Coastguard Worker   }
330*33f37583SAndroid Build Coastguard Worker 
331*33f37583SAndroid Build Coastguard Worker   return Errorf("Couldn't find any AVB hashtree descriptors.");
332*33f37583SAndroid Build Coastguard Worker }
333*33f37583SAndroid Build Coastguard Worker 
VerifyDescriptor(const AvbHashtreeDescriptor * desc)334*33f37583SAndroid Build Coastguard Worker Result<std::unique_ptr<AvbHashtreeDescriptor>> VerifyDescriptor(
335*33f37583SAndroid Build Coastguard Worker     const AvbHashtreeDescriptor* desc) {
336*33f37583SAndroid Build Coastguard Worker   auto verified_desc = std::make_unique<AvbHashtreeDescriptor>();
337*33f37583SAndroid Build Coastguard Worker 
338*33f37583SAndroid Build Coastguard Worker   if (!avb_hashtree_descriptor_validate_and_byteswap(desc,
339*33f37583SAndroid Build Coastguard Worker                                                      verified_desc.get())) {
340*33f37583SAndroid Build Coastguard Worker     return Errorf("Couldn't validate AvbDescriptor.");
341*33f37583SAndroid Build Coastguard Worker   }
342*33f37583SAndroid Build Coastguard Worker 
343*33f37583SAndroid Build Coastguard Worker   return verified_desc;
344*33f37583SAndroid Build Coastguard Worker }
345*33f37583SAndroid Build Coastguard Worker 
346*33f37583SAndroid Build Coastguard Worker }  // namespace
347*33f37583SAndroid Build Coastguard Worker 
VerifyApexVerity(const std::string & public_key) const348*33f37583SAndroid Build Coastguard Worker Result<ApexVerityData> ApexFile::VerifyApexVerity(
349*33f37583SAndroid Build Coastguard Worker     const std::string& public_key) const {
350*33f37583SAndroid Build Coastguard Worker   if (IsCompressed()) {
351*33f37583SAndroid Build Coastguard Worker     return Error() << "Cannot verify ApexVerity of compressed APEX";
352*33f37583SAndroid Build Coastguard Worker   }
353*33f37583SAndroid Build Coastguard Worker 
354*33f37583SAndroid Build Coastguard Worker   ApexVerityData verity_data;
355*33f37583SAndroid Build Coastguard Worker 
356*33f37583SAndroid Build Coastguard Worker   unique_fd fd(open(GetPath().c_str(), O_RDONLY | O_CLOEXEC));
357*33f37583SAndroid Build Coastguard Worker   if (fd.get() == -1) {
358*33f37583SAndroid Build Coastguard Worker     return ErrnoError() << "Failed to open " << GetPath();
359*33f37583SAndroid Build Coastguard Worker   }
360*33f37583SAndroid Build Coastguard Worker 
361*33f37583SAndroid Build Coastguard Worker   Result<std::unique_ptr<AvbFooter>> footer = GetAvbFooter(*this, fd);
362*33f37583SAndroid Build Coastguard Worker   if (!footer.ok()) {
363*33f37583SAndroid Build Coastguard Worker     return footer.error();
364*33f37583SAndroid Build Coastguard Worker   }
365*33f37583SAndroid Build Coastguard Worker 
366*33f37583SAndroid Build Coastguard Worker   Result<std::unique_ptr<uint8_t[]>> vbmeta_data =
367*33f37583SAndroid Build Coastguard Worker       VerifyVbMeta(*this, fd, **footer, public_key);
368*33f37583SAndroid Build Coastguard Worker   if (!vbmeta_data.ok()) {
369*33f37583SAndroid Build Coastguard Worker     return vbmeta_data.error();
370*33f37583SAndroid Build Coastguard Worker   }
371*33f37583SAndroid Build Coastguard Worker 
372*33f37583SAndroid Build Coastguard Worker   Result<const AvbHashtreeDescriptor*> descriptor =
373*33f37583SAndroid Build Coastguard Worker       FindDescriptor(vbmeta_data->get(), (*footer)->vbmeta_size);
374*33f37583SAndroid Build Coastguard Worker   if (!descriptor.ok()) {
375*33f37583SAndroid Build Coastguard Worker     return descriptor.error();
376*33f37583SAndroid Build Coastguard Worker   }
377*33f37583SAndroid Build Coastguard Worker 
378*33f37583SAndroid Build Coastguard Worker   Result<std::unique_ptr<AvbHashtreeDescriptor>> verified_descriptor =
379*33f37583SAndroid Build Coastguard Worker       VerifyDescriptor(*descriptor);
380*33f37583SAndroid Build Coastguard Worker   if (!verified_descriptor.ok()) {
381*33f37583SAndroid Build Coastguard Worker     return verified_descriptor.error();
382*33f37583SAndroid Build Coastguard Worker   }
383*33f37583SAndroid Build Coastguard Worker   verity_data.desc = std::move(*verified_descriptor);
384*33f37583SAndroid Build Coastguard Worker 
385*33f37583SAndroid Build Coastguard Worker   // This area is now safe to access, because we just verified it
386*33f37583SAndroid Build Coastguard Worker   const uint8_t* trailing_data =
387*33f37583SAndroid Build Coastguard Worker       (const uint8_t*)*descriptor + sizeof(AvbHashtreeDescriptor);
388*33f37583SAndroid Build Coastguard Worker   verity_data.hash_algorithm =
389*33f37583SAndroid Build Coastguard Worker       reinterpret_cast<const char*>((*descriptor)->hash_algorithm);
390*33f37583SAndroid Build Coastguard Worker   verity_data.salt = GetSalt(*verity_data.desc, trailing_data);
391*33f37583SAndroid Build Coastguard Worker   verity_data.root_digest = GetDigest(*verity_data.desc, trailing_data);
392*33f37583SAndroid Build Coastguard Worker 
393*33f37583SAndroid Build Coastguard Worker   return verity_data;
394*33f37583SAndroid Build Coastguard Worker }
395*33f37583SAndroid Build Coastguard Worker 
Decompress(const std::string & dest_path) const396*33f37583SAndroid Build Coastguard Worker Result<void> ApexFile::Decompress(const std::string& dest_path) const {
397*33f37583SAndroid Build Coastguard Worker   const std::string& src_path = GetPath();
398*33f37583SAndroid Build Coastguard Worker 
399*33f37583SAndroid Build Coastguard Worker   LOG(INFO) << "Decompressing" << src_path << " to " << dest_path;
400*33f37583SAndroid Build Coastguard Worker 
401*33f37583SAndroid Build Coastguard Worker   // We should decompress compressed APEX files only
402*33f37583SAndroid Build Coastguard Worker   if (!IsCompressed()) {
403*33f37583SAndroid Build Coastguard Worker     return ErrnoError() << "Cannot decompress an uncompressed APEX";
404*33f37583SAndroid Build Coastguard Worker   }
405*33f37583SAndroid Build Coastguard Worker 
406*33f37583SAndroid Build Coastguard Worker   // Get file descriptor of the compressed apex file
407*33f37583SAndroid Build Coastguard Worker   unique_fd src_fd(open(src_path.c_str(), O_RDONLY | O_CLOEXEC));
408*33f37583SAndroid Build Coastguard Worker   if (src_fd.get() == -1) {
409*33f37583SAndroid Build Coastguard Worker     return ErrnoError() << "Failed to open compressed APEX " << GetPath();
410*33f37583SAndroid Build Coastguard Worker   }
411*33f37583SAndroid Build Coastguard Worker 
412*33f37583SAndroid Build Coastguard Worker   // Open it as a zip file
413*33f37583SAndroid Build Coastguard Worker   ZipArchiveHandle handle;
414*33f37583SAndroid Build Coastguard Worker   int ret = OpenArchiveFd(src_fd.get(), src_path.c_str(), &handle, false);
415*33f37583SAndroid Build Coastguard Worker   if (ret < 0) {
416*33f37583SAndroid Build Coastguard Worker     return Error() << "Failed to open package " << src_path << ": "
417*33f37583SAndroid Build Coastguard Worker                    << ErrorCodeString(ret);
418*33f37583SAndroid Build Coastguard Worker   }
419*33f37583SAndroid Build Coastguard Worker   auto handle_guard =
420*33f37583SAndroid Build Coastguard Worker       android::base::make_scope_guard([&handle] { CloseArchive(handle); });
421*33f37583SAndroid Build Coastguard Worker 
422*33f37583SAndroid Build Coastguard Worker   // Find the original apex file inside the zip and extract to dest
423*33f37583SAndroid Build Coastguard Worker   ZipEntry entry;
424*33f37583SAndroid Build Coastguard Worker   ret = FindEntry(handle, kCompressedApexFilename, &entry);
425*33f37583SAndroid Build Coastguard Worker   if (ret < 0) {
426*33f37583SAndroid Build Coastguard Worker     return Error() << "Could not find entry \"" << kCompressedApexFilename
427*33f37583SAndroid Build Coastguard Worker                    << "\" in package " << src_path << ": "
428*33f37583SAndroid Build Coastguard Worker                    << ErrorCodeString(ret);
429*33f37583SAndroid Build Coastguard Worker   }
430*33f37583SAndroid Build Coastguard Worker 
431*33f37583SAndroid Build Coastguard Worker   // Open destination file descriptor
432*33f37583SAndroid Build Coastguard Worker   unique_fd dest_fd(
433*33f37583SAndroid Build Coastguard Worker       open(dest_path.c_str(), O_WRONLY | O_CLOEXEC | O_CREAT | O_EXCL, 0644));
434*33f37583SAndroid Build Coastguard Worker   if (dest_fd.get() == -1) {
435*33f37583SAndroid Build Coastguard Worker     return ErrnoError() << "Failed to open decompression destination "
436*33f37583SAndroid Build Coastguard Worker                         << dest_path.c_str();
437*33f37583SAndroid Build Coastguard Worker   }
438*33f37583SAndroid Build Coastguard Worker 
439*33f37583SAndroid Build Coastguard Worker   // Prepare a guard that deletes the extracted file if anything goes wrong
440*33f37583SAndroid Build Coastguard Worker   auto decompressed_guard = android::base::make_scope_guard(
441*33f37583SAndroid Build Coastguard Worker       [&dest_path] { RemoveFileIfExists(dest_path); });
442*33f37583SAndroid Build Coastguard Worker 
443*33f37583SAndroid Build Coastguard Worker   // Extract the original_apex to dest_path
444*33f37583SAndroid Build Coastguard Worker   ret = ExtractEntryToFile(handle, &entry, dest_fd.get());
445*33f37583SAndroid Build Coastguard Worker   if (ret < 0) {
446*33f37583SAndroid Build Coastguard Worker     return Error() << "Could not decompress to file " << dest_path << " "
447*33f37583SAndroid Build Coastguard Worker                    << ErrorCodeString(ret);
448*33f37583SAndroid Build Coastguard Worker   }
449*33f37583SAndroid Build Coastguard Worker 
450*33f37583SAndroid Build Coastguard Worker   // Verification complete. Accept the decompressed file
451*33f37583SAndroid Build Coastguard Worker   decompressed_guard.Disable();
452*33f37583SAndroid Build Coastguard Worker   LOG(VERBOSE) << "Decompressed " << src_path << " to " << dest_path;
453*33f37583SAndroid Build Coastguard Worker 
454*33f37583SAndroid Build Coastguard Worker   return {};
455*33f37583SAndroid Build Coastguard Worker }
456*33f37583SAndroid Build Coastguard Worker 
457*33f37583SAndroid Build Coastguard Worker }  // namespace apex
458*33f37583SAndroid Build Coastguard Worker }  // namespace android
459