1 /*
2 * Copyright (C) 2017 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "dex_file_loader.h"
18
19 #include "android-base/stringprintf.h"
20
21 #include "base/stl_util.h"
22 #include "compact_dex_file.h"
23 #include "dex_file.h"
24 #include "dex_file_verifier.h"
25 #include "standard_dex_file.h"
26 #include "ziparchive/zip_archive.h"
27
28 namespace art {
29
30 namespace {
31
32 class VectorContainer : public DexFileContainer {
33 public:
VectorContainer(std::vector<uint8_t> && vector)34 explicit VectorContainer(std::vector<uint8_t>&& vector) : vector_(std::move(vector)) { }
~VectorContainer()35 ~VectorContainer() override { }
36
GetPermissions()37 int GetPermissions() override {
38 return 0;
39 }
40
IsReadOnly()41 bool IsReadOnly() override {
42 return true;
43 }
44
EnableWrite()45 bool EnableWrite() override {
46 return false;
47 }
48
DisableWrite()49 bool DisableWrite() override {
50 return false;
51 }
52
53 private:
54 std::vector<uint8_t> vector_;
55 DISALLOW_COPY_AND_ASSIGN(VectorContainer);
56 };
57
58 } // namespace
59
60 using android::base::StringPrintf;
61
62 class DexZipArchive;
63
64 class DexZipEntry {
65 public:
66 // Extract this entry to memory.
67 // Returns null on failure and sets error_msg.
Extract(std::string * error_msg)68 const std::vector<uint8_t> Extract(std::string* error_msg) {
69 std::vector<uint8_t> map(GetUncompressedLength());
70 if (map.size() == 0) {
71 DCHECK(!error_msg->empty());
72 return map;
73 }
74 const int32_t error = ExtractToMemory(handle_, zip_entry_, map.data(), map.size());
75 if (error) {
76 *error_msg = std::string(ErrorCodeString(error));
77 }
78 return map;
79 }
80
~DexZipEntry()81 virtual ~DexZipEntry() {
82 delete zip_entry_;
83 }
84
GetUncompressedLength()85 uint32_t GetUncompressedLength() {
86 return zip_entry_->uncompressed_length;
87 }
88
GetCrc32()89 uint32_t GetCrc32() {
90 return zip_entry_->crc32;
91 }
92
93 private:
DexZipEntry(ZipArchiveHandle handle,::ZipEntry * zip_entry,const std::string & entry_name)94 DexZipEntry(ZipArchiveHandle handle,
95 ::ZipEntry* zip_entry,
96 const std::string& entry_name)
97 : handle_(handle), zip_entry_(zip_entry), entry_name_(entry_name) {}
98
99 ZipArchiveHandle handle_;
100 ::ZipEntry* const zip_entry_;
101 std::string const entry_name_;
102
103 friend class DexZipArchive;
104 DISALLOW_COPY_AND_ASSIGN(DexZipEntry);
105 };
106
107 class DexZipArchive {
108 public:
109 // return new DexZipArchive instance on success, null on error.
Open(const uint8_t * base,size_t size,std::string * error_msg)110 static DexZipArchive* Open(const uint8_t* base, size_t size, std::string* error_msg) {
111 ZipArchiveHandle handle;
112 uint8_t* nonconst_base = const_cast<uint8_t*>(base);
113 const int32_t error = OpenArchiveFromMemory(nonconst_base, size, "ZipArchiveMemory", &handle);
114 if (error) {
115 *error_msg = std::string(ErrorCodeString(error));
116 CloseArchive(handle);
117 return nullptr;
118 }
119 return new DexZipArchive(handle);
120 }
121
Find(const char * name,std::string * error_msg) const122 DexZipEntry* Find(const char* name, std::string* error_msg) const {
123 DCHECK(name != nullptr);
124 // Resist the urge to delete the space. <: is a bigraph sequence.
125 std::unique_ptr< ::ZipEntry> zip_entry(new ::ZipEntry);
126 const int32_t error = FindEntry(handle_, name, zip_entry.get());
127 if (error) {
128 *error_msg = std::string(ErrorCodeString(error));
129 return nullptr;
130 }
131 return new DexZipEntry(handle_, zip_entry.release(), name);
132 }
133
~DexZipArchive()134 ~DexZipArchive() {
135 CloseArchive(handle_);
136 }
137
138
139 private:
DexZipArchive(ZipArchiveHandle handle)140 explicit DexZipArchive(ZipArchiveHandle handle) : handle_(handle) {}
141 ZipArchiveHandle handle_;
142
143 friend class DexZipEntry;
144 DISALLOW_COPY_AND_ASSIGN(DexZipArchive);
145 };
146
IsZipMagic(uint32_t magic)147 static bool IsZipMagic(uint32_t magic) {
148 return (('P' == ((magic >> 0) & 0xff)) &&
149 ('K' == ((magic >> 8) & 0xff)));
150 }
151
IsMagicValid(uint32_t magic)152 bool DexFileLoader::IsMagicValid(uint32_t magic) {
153 return IsMagicValid(reinterpret_cast<uint8_t*>(&magic));
154 }
155
IsMagicValid(const uint8_t * magic)156 bool DexFileLoader::IsMagicValid(const uint8_t* magic) {
157 return StandardDexFile::IsMagicValid(magic) ||
158 CompactDexFile::IsMagicValid(magic);
159 }
160
IsVersionAndMagicValid(const uint8_t * magic)161 bool DexFileLoader::IsVersionAndMagicValid(const uint8_t* magic) {
162 if (StandardDexFile::IsMagicValid(magic)) {
163 return StandardDexFile::IsVersionValid(magic);
164 }
165 if (CompactDexFile::IsMagicValid(magic)) {
166 return CompactDexFile::IsVersionValid(magic);
167 }
168 return false;
169 }
170
IsMultiDexLocation(const char * location)171 bool DexFileLoader::IsMultiDexLocation(const char* location) {
172 return strrchr(location, kMultiDexSeparator) != nullptr;
173 }
174
GetMultiDexClassesDexName(size_t index)175 std::string DexFileLoader::GetMultiDexClassesDexName(size_t index) {
176 return (index == 0) ? "classes.dex" : StringPrintf("classes%zu.dex", index + 1);
177 }
178
GetMultiDexLocation(size_t index,const char * dex_location)179 std::string DexFileLoader::GetMultiDexLocation(size_t index, const char* dex_location) {
180 return (index == 0)
181 ? dex_location
182 : StringPrintf("%s%cclasses%zu.dex", dex_location, kMultiDexSeparator, index + 1);
183 }
184
GetDexCanonicalLocation(const char * dex_location)185 std::string DexFileLoader::GetDexCanonicalLocation(const char* dex_location) {
186 CHECK_NE(dex_location, static_cast<const char*>(nullptr));
187 std::string base_location = GetBaseLocation(dex_location);
188 const char* suffix = dex_location + base_location.size();
189 DCHECK(suffix[0] == 0 || suffix[0] == kMultiDexSeparator);
190 #ifdef _WIN32
191 // Warning: No symbolic link processing here.
192 PLOG(WARNING) << "realpath is unsupported on Windows.";
193 #else
194 // Warning: Bionic implementation of realpath() allocates > 12KB on the stack.
195 // Do not run this code on a small stack, e.g. in signal handler.
196 UniqueCPtr<const char[]> path(realpath(base_location.c_str(), nullptr));
197 if (path != nullptr && path.get() != base_location) {
198 return std::string(path.get()) + suffix;
199 }
200 #endif
201 if (suffix[0] == 0) {
202 return base_location;
203 } else {
204 return dex_location;
205 }
206 }
207
208 // All of the implementations here should be independent of the runtime.
209 // TODO: implement all the virtual methods.
210
GetMultiDexChecksums(const char * filename ATTRIBUTE_UNUSED,std::vector<uint32_t> * checksums ATTRIBUTE_UNUSED,std::vector<std::string> * dex_locations ATTRIBUTE_UNUSED,std::string * error_msg,int zip_fd ATTRIBUTE_UNUSED,bool * zip_file_only_contains_uncompress_dex ATTRIBUTE_UNUSED) const211 bool DexFileLoader::GetMultiDexChecksums(
212 const char* filename ATTRIBUTE_UNUSED,
213 std::vector<uint32_t>* checksums ATTRIBUTE_UNUSED,
214 std::vector<std::string>* dex_locations ATTRIBUTE_UNUSED,
215 std::string* error_msg,
216 int zip_fd ATTRIBUTE_UNUSED,
217 bool* zip_file_only_contains_uncompress_dex ATTRIBUTE_UNUSED) const {
218 *error_msg = "UNIMPLEMENTED";
219 return false;
220 }
221
Open(const std::string & location,uint32_t location_checksum,std::vector<uint8_t> && memory,const OatDexFile * oat_dex_file,bool verify,bool verify_checksum,std::string * error_msg)222 std::unique_ptr<const DexFile> DexFileLoader::Open(
223 const std::string& location,
224 uint32_t location_checksum,
225 std::vector<uint8_t>&& memory,
226 const OatDexFile* oat_dex_file,
227 bool verify,
228 bool verify_checksum,
229 std::string* error_msg) {
230 auto memory_data = memory.data();
231 auto memory_size = memory.size();
232 return OpenCommon(memory_data,
233 memory_size,
234 /*data_base=*/ nullptr,
235 /*data_size=*/ 0,
236 location,
237 location_checksum,
238 oat_dex_file,
239 verify,
240 verify_checksum,
241 error_msg,
242 std::make_unique<VectorContainer>(std::move(memory)),
243 /*verify_result=*/ nullptr);
244 }
245
Open(const uint8_t * base,size_t size,const std::string & location,uint32_t location_checksum,const OatDexFile * oat_dex_file,bool verify,bool verify_checksum,std::string * error_msg,std::unique_ptr<DexFileContainer> container) const246 std::unique_ptr<const DexFile> DexFileLoader::Open(
247 const uint8_t* base,
248 size_t size,
249 const std::string& location,
250 uint32_t location_checksum,
251 const OatDexFile* oat_dex_file,
252 bool verify,
253 bool verify_checksum,
254 std::string* error_msg,
255 std::unique_ptr<DexFileContainer> container) const {
256 return OpenCommon(base,
257 size,
258 /*data_base=*/ nullptr,
259 /*data_size=*/ 0,
260 location,
261 location_checksum,
262 oat_dex_file,
263 verify,
264 verify_checksum,
265 error_msg,
266 std::move(container),
267 /*verify_result=*/ nullptr);
268 }
269
OpenWithDataSection(const uint8_t * base,size_t size,const uint8_t * data_base,size_t data_size,const std::string & location,uint32_t location_checksum,const OatDexFile * oat_dex_file,bool verify,bool verify_checksum,std::string * error_msg) const270 std::unique_ptr<const DexFile> DexFileLoader::OpenWithDataSection(
271 const uint8_t* base,
272 size_t size,
273 const uint8_t* data_base,
274 size_t data_size,
275 const std::string& location,
276 uint32_t location_checksum,
277 const OatDexFile* oat_dex_file,
278 bool verify,
279 bool verify_checksum,
280 std::string* error_msg) const {
281 return OpenCommon(base,
282 size,
283 data_base,
284 data_size,
285 location,
286 location_checksum,
287 oat_dex_file,
288 verify,
289 verify_checksum,
290 error_msg,
291 /*container=*/ nullptr,
292 /*verify_result=*/ nullptr);
293 }
294
OpenAll(const uint8_t * base,size_t size,const std::string & location,bool verify,bool verify_checksum,DexFileLoaderErrorCode * error_code,std::string * error_msg,std::vector<std::unique_ptr<const DexFile>> * dex_files) const295 bool DexFileLoader::OpenAll(
296 const uint8_t* base,
297 size_t size,
298 const std::string& location,
299 bool verify,
300 bool verify_checksum,
301 DexFileLoaderErrorCode* error_code,
302 std::string* error_msg,
303 std::vector<std::unique_ptr<const DexFile>>* dex_files) const {
304 DCHECK(dex_files != nullptr) << "DexFile::Open: out-param is nullptr";
305 uint32_t magic = *reinterpret_cast<const uint32_t*>(base);
306 if (IsZipMagic(magic)) {
307 std::unique_ptr<DexZipArchive> zip_archive(DexZipArchive::Open(base, size, error_msg));
308 if (zip_archive.get() == nullptr) {
309 DCHECK(!error_msg->empty());
310 return false;
311 }
312 return OpenAllDexFilesFromZip(*zip_archive.get(),
313 location,
314 verify,
315 verify_checksum,
316 error_code,
317 error_msg,
318 dex_files);
319 }
320 if (IsMagicValid(magic)) {
321 const DexFile::Header* dex_header = reinterpret_cast<const DexFile::Header*>(base);
322 std::unique_ptr<const DexFile> dex_file(Open(base,
323 size,
324 location,
325 dex_header->checksum_,
326 /*oat_dex_file=*/ nullptr,
327 verify,
328 verify_checksum,
329 error_msg));
330 if (dex_file.get() != nullptr) {
331 dex_files->push_back(std::move(dex_file));
332 return true;
333 } else {
334 return false;
335 }
336 }
337 *error_msg = StringPrintf("Expected valid zip or dex file");
338 return false;
339 }
340
OpenCommon(const uint8_t * base,size_t size,const uint8_t * data_base,size_t data_size,const std::string & location,uint32_t location_checksum,const OatDexFile * oat_dex_file,bool verify,bool verify_checksum,std::string * error_msg,std::unique_ptr<DexFileContainer> container,VerifyResult * verify_result)341 std::unique_ptr<DexFile> DexFileLoader::OpenCommon(const uint8_t* base,
342 size_t size,
343 const uint8_t* data_base,
344 size_t data_size,
345 const std::string& location,
346 uint32_t location_checksum,
347 const OatDexFile* oat_dex_file,
348 bool verify,
349 bool verify_checksum,
350 std::string* error_msg,
351 std::unique_ptr<DexFileContainer> container,
352 VerifyResult* verify_result) {
353 if (verify_result != nullptr) {
354 *verify_result = VerifyResult::kVerifyNotAttempted;
355 }
356 std::unique_ptr<DexFile> dex_file;
357 if (size >= sizeof(StandardDexFile::Header) && StandardDexFile::IsMagicValid(base)) {
358 if (data_size != 0) {
359 CHECK_EQ(base, data_base) << "Unsupported for standard dex";
360 }
361 dex_file.reset(new StandardDexFile(base,
362 size,
363 location,
364 location_checksum,
365 oat_dex_file,
366 std::move(container)));
367 } else if (size >= sizeof(CompactDexFile::Header) && CompactDexFile::IsMagicValid(base)) {
368 if (data_base == nullptr) {
369 // TODO: Is there a clean way to support both an explicit data section and reading the one
370 // from the header.
371 CHECK_EQ(data_size, 0u);
372 const CompactDexFile::Header* const header = CompactDexFile::Header::At(base);
373 data_base = base + header->data_off_;
374 data_size = header->data_size_;
375 }
376 dex_file.reset(new CompactDexFile(base,
377 size,
378 data_base,
379 data_size,
380 location,
381 location_checksum,
382 oat_dex_file,
383 std::move(container)));
384 // Disable verification for CompactDex input.
385 verify = false;
386 } else {
387 *error_msg = "Invalid or truncated dex file";
388 }
389 if (dex_file == nullptr) {
390 *error_msg = StringPrintf("Failed to open dex file '%s' from memory: %s", location.c_str(),
391 error_msg->c_str());
392 return nullptr;
393 }
394 if (!dex_file->Init(error_msg)) {
395 dex_file.reset();
396 return nullptr;
397 }
398 if (verify && !dex::Verify(dex_file.get(),
399 dex_file->Begin(),
400 dex_file->Size(),
401 location.c_str(),
402 verify_checksum,
403 error_msg)) {
404 if (verify_result != nullptr) {
405 *verify_result = VerifyResult::kVerifyFailed;
406 }
407 return nullptr;
408 }
409 if (verify_result != nullptr) {
410 *verify_result = VerifyResult::kVerifySucceeded;
411 }
412 return dex_file;
413 }
414
OpenOneDexFileFromZip(const DexZipArchive & zip_archive,const char * entry_name,const std::string & location,bool verify,bool verify_checksum,DexFileLoaderErrorCode * error_code,std::string * error_msg) const415 std::unique_ptr<const DexFile> DexFileLoader::OpenOneDexFileFromZip(
416 const DexZipArchive& zip_archive,
417 const char* entry_name,
418 const std::string& location,
419 bool verify,
420 bool verify_checksum,
421 DexFileLoaderErrorCode* error_code,
422 std::string* error_msg) const {
423 CHECK(!location.empty());
424 std::unique_ptr<DexZipEntry> zip_entry(zip_archive.Find(entry_name, error_msg));
425 if (zip_entry == nullptr) {
426 *error_code = DexFileLoaderErrorCode::kEntryNotFound;
427 return nullptr;
428 }
429 if (zip_entry->GetUncompressedLength() == 0) {
430 *error_msg = StringPrintf("Dex file '%s' has zero length", location.c_str());
431 *error_code = DexFileLoaderErrorCode::kDexFileError;
432 return nullptr;
433 }
434
435 std::vector<uint8_t> map(zip_entry->Extract(error_msg));
436 if (map.size() == 0) {
437 *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", entry_name, location.c_str(),
438 error_msg->c_str());
439 *error_code = DexFileLoaderErrorCode::kExtractToMemoryError;
440 return nullptr;
441 }
442 VerifyResult verify_result;
443 auto map_data = map.data();
444 auto map_size = map.size();
445 std::unique_ptr<const DexFile> dex_file = OpenCommon(
446 map_data,
447 map_size,
448 /*data_base=*/ nullptr,
449 /*data_size=*/ 0u,
450 location,
451 zip_entry->GetCrc32(),
452 /*oat_dex_file=*/ nullptr,
453 verify,
454 verify_checksum,
455 error_msg,
456 std::make_unique<VectorContainer>(std::move(map)),
457 &verify_result);
458 if (verify_result != VerifyResult::kVerifySucceeded) {
459 if (verify_result == VerifyResult::kVerifyNotAttempted) {
460 *error_code = DexFileLoaderErrorCode::kDexFileError;
461 } else {
462 *error_code = DexFileLoaderErrorCode::kVerifyError;
463 }
464 return nullptr;
465 }
466 *error_code = DexFileLoaderErrorCode::kNoError;
467 return dex_file;
468 }
469
470 // Technically we do not have a limitation with respect to the number of dex files that can be in a
471 // multidex APK. However, it's bad practice, as each dex file requires its own tables for symbols
472 // (types, classes, methods, ...) and dex caches. So warn the user that we open a zip with what
473 // seems an excessive number.
474 static constexpr size_t kWarnOnManyDexFilesThreshold = 100;
475
OpenAllDexFilesFromZip(const DexZipArchive & zip_archive,const std::string & location,bool verify,bool verify_checksum,DexFileLoaderErrorCode * error_code,std::string * error_msg,std::vector<std::unique_ptr<const DexFile>> * dex_files) const476 bool DexFileLoader::OpenAllDexFilesFromZip(
477 const DexZipArchive& zip_archive,
478 const std::string& location,
479 bool verify,
480 bool verify_checksum,
481 DexFileLoaderErrorCode* error_code,
482 std::string* error_msg,
483 std::vector<std::unique_ptr<const DexFile>>* dex_files) const {
484 DCHECK(dex_files != nullptr) << "DexFile::OpenFromZip: out-param is nullptr";
485 std::unique_ptr<const DexFile> dex_file(OpenOneDexFileFromZip(zip_archive,
486 kClassesDex,
487 location,
488 verify,
489 verify_checksum,
490 error_code,
491 error_msg));
492 if (*error_code != DexFileLoaderErrorCode::kNoError) {
493 return false;
494 } else {
495 // Had at least classes.dex.
496 dex_files->push_back(std::move(dex_file));
497
498 // Now try some more.
499
500 // We could try to avoid std::string allocations by working on a char array directly. As we
501 // do not expect a lot of iterations, this seems too involved and brittle.
502
503 for (size_t i = 1; ; ++i) {
504 std::string name = GetMultiDexClassesDexName(i);
505 std::string fake_location = GetMultiDexLocation(i, location.c_str());
506 std::unique_ptr<const DexFile> next_dex_file(OpenOneDexFileFromZip(zip_archive,
507 name.c_str(),
508 fake_location,
509 verify,
510 verify_checksum,
511 error_code,
512 error_msg));
513 if (next_dex_file.get() == nullptr) {
514 if (*error_code != DexFileLoaderErrorCode::kEntryNotFound) {
515 LOG(WARNING) << "Zip open failed: " << *error_msg;
516 }
517 break;
518 } else {
519 dex_files->push_back(std::move(next_dex_file));
520 }
521
522 if (i == kWarnOnManyDexFilesThreshold) {
523 LOG(WARNING) << location << " has in excess of " << kWarnOnManyDexFilesThreshold
524 << " dex files. Please consider coalescing and shrinking the number to "
525 " avoid runtime overhead.";
526 }
527
528 if (i == std::numeric_limits<size_t>::max()) {
529 LOG(ERROR) << "Overflow in number of dex files!";
530 break;
531 }
532 }
533
534 return true;
535 }
536 }
537 } // namespace art
538