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 #ifndef ART_LIBDEXFILE_DEX_DEX_FILE_LOADER_H_
18 #define ART_LIBDEXFILE_DEX_DEX_FILE_LOADER_H_
19 
20 #include <cstdint>
21 #include <functional>
22 #include <memory>
23 #include <optional>
24 #include <string>
25 #include <string_view>
26 #include <vector>
27 
28 #include "base/os.h"
29 #include "base/unix_file/fd_file.h"
30 #include "dex_file.h"
31 
32 namespace art {
33 
34 class MemMap;
35 class OatDexFile;
36 class ZipArchive;
37 
38 enum class DexFileLoaderErrorCode {
39   kNoError,
40   kEntryNotFound,
41   kExtractToMemoryError,
42   kDexFileError,
43   kMakeReadOnlyError,
44   kVerifyError
45 };
46 
47 // Class that is used to open dex files and deal with corresponding multidex and location logic.
48 class DexFileLoader {
49  public:
50   // name of the DexFile entry within a zip archive
51   static constexpr const char* kClassesDex = "classes.dex";
52 
53   // The separator character in MultiDex locations.
54   static constexpr char kMultiDexSeparator = '!';
55 
56   // Return true if the magic is valid for dex or cdex.
57   static bool IsMagicValid(uint32_t magic);
58   static bool IsMagicValid(const uint8_t* magic);
59 
60   // Return true if the corresponding version and magic is valid.
61   static bool IsVersionAndMagicValid(const uint8_t* magic);
62 
63   // Check whether a location denotes a multidex dex file. This is a very simple check: returns
64   // whether the string contains the separator character.
65   static bool IsMultiDexLocation(std::string_view location);
66 
67   // Return the name of the index-th classes.dex in a multidex zip file. This is classes.dex for
68   // index == 0, and classes{index + 1}.dex else.
69   static std::string GetMultiDexClassesDexName(size_t index);
70 
71   // Return the (possibly synthetic) dex location for a multidex entry. This is dex_location for
72   // index == 0, and dex_location + multi-dex-separator + GetMultiDexClassesDexName(index) else.
73   static std::string GetMultiDexLocation(size_t index, const char* dex_location);
74 
75   // Returns combined checksum of one or more dex files (one checksum for the whole multidex set).
76   //
77   // This uses the source path provided to DexFileLoader constructor.
78   //
79   // Returns false on error.  Sets *checksum to nullopt for an empty set.
80   bool GetMultiDexChecksum(/*out*/ std::optional<uint32_t>* checksum,
81                            /*out*/ std::string* error_msg,
82                            /*out*/ bool* only_contains_uncompressed_dex = nullptr);
83 
84   // Returns combined checksum of one or more dex files (one checksum for the whole multidex set).
85   //
86   // This uses already open dex files.
87   //
88   // It starts iteration at index 'i', which must be a primary dex file,
89   // and it sets 'i' to the next primary dex file or to end of the array.
90   template <typename DexFilePtrVector>  // array|vector<unique_ptr|DexFile|OatDexFile*>.
GetMultiDexChecksum(const DexFilePtrVector & dex_files,size_t * i)91   static uint32_t GetMultiDexChecksum(const DexFilePtrVector& dex_files,
92                                       /*inout*/ size_t* i) {
93     CHECK_LT(*i, dex_files.size()) << "No dex files";
94     std::optional<uint32_t> checksum;
95     for (; *i < dex_files.size(); ++(*i)) {
96       const auto* dex_file = &*dex_files[*i];
97       bool is_primary_dex = !IsMultiDexLocation(dex_file->GetLocation());
98       if (!checksum.has_value()) {                         // First dex file.
99         CHECK(is_primary_dex) << dex_file->GetLocation();  // Expect primary dex.
100       } else if (is_primary_dex) {                         // Later dex file.
101         break;  // Found another primary dex file, terminate iteration.
102       }
103       if (!is_primary_dex && dex_file->GetDexVersion() >= DexFile::kDexContainerVersion) {
104         if (dex_file->GetLocationChecksum() == dex_files[*i - 1]->GetLocationChecksum() + 1) {
105           continue;
106         }
107       }
108       checksum = checksum.value_or(kEmptyMultiDexChecksum) ^ dex_file->GetLocationChecksum();
109     }
110     CHECK(checksum.has_value());
111     return checksum.value();
112   }
113 
114   // Calculate checksum of dex files in a vector, starting at index 0.
115   // It will CHECK that the whole vector is consumed (i.e. there is just one primary dex file).
116   template <typename DexFilePtrVector>
GetMultiDexChecksum(const DexFilePtrVector & dex_files)117   static uint32_t GetMultiDexChecksum(const DexFilePtrVector& dex_files) {
118     size_t i = 0;
119     uint32_t checksum = GetMultiDexChecksum(dex_files, &i);
120     CHECK_EQ(i, dex_files.size());
121     return checksum;
122   }
123 
124   // Non-zero initial value for multi-dex to catch bugs if multi-dex checksum is compared
125   // directly to DexFile::GetLocationChecksum without going through GetMultiDexChecksum.
126   static constexpr uint32_t kEmptyMultiDexChecksum = 1;
127 
128   // Returns the canonical form of the given dex location.
129   //
130   // There are different flavors of "dex locations" as follows:
131   // the file name of a dex file:
132   //     The actual file path that the dex file has on disk.
133   // dex_location:
134   //     This acts as a key for the class linker to know which dex file to load.
135   //     It may correspond to either an old odex file or a particular dex file
136   //     inside an oat file. In the first case it will also match the file name
137   //     of the dex file. In the second case (oat) it will include the file name
138   //     and possibly some multidex annotation to uniquely identify it.
139   // canonical_dex_location:
140   //     the dex_location where its file name part has been made canonical.
141   static std::string GetDexCanonicalLocation(const char* dex_location);
142 
143   // For normal dex files, location and base location coincide. If a dex file is part of a multidex
144   // archive, the base location is the name of the originating jar/apk, stripped of any internal
145   // classes*.dex path.
GetBaseLocation(const char * location)146   static std::string GetBaseLocation(const char* location) {
147     const char* pos = strrchr(location, kMultiDexSeparator);
148     return (pos == nullptr) ? location : std::string(location, pos - location);
149   }
150 
GetBaseLocation(const std::string & location)151   static std::string GetBaseLocation(const std::string& location) {
152     return GetBaseLocation(location.c_str());
153   }
154 
155   // Returns the '!classes*.dex' part of the dex location. Returns an empty
156   // string if there is no multidex suffix for the given location.
157   // The kMultiDexSeparator is included in the returned suffix.
GetMultiDexSuffix(const std::string & location)158   static std::string GetMultiDexSuffix(const std::string& location) {
159     size_t pos = location.rfind(kMultiDexSeparator);
160     return (pos == std::string::npos) ? std::string() : location.substr(pos);
161   }
162 
DexFileLoader(const char * filename,const File * file,const std::string & location)163   DexFileLoader(const char* filename, const File* file, const std::string& location)
164       : filename_(filename), file_(file), location_(location) {
165     CHECK(file != nullptr);  // Must be non-null, but may be invalid.
166   }
167 
DexFileLoader(std::shared_ptr<DexFileContainer> container,const std::string & location)168   DexFileLoader(std::shared_ptr<DexFileContainer> container, const std::string& location)
169       : root_container_(std::move(container)), location_(location) {
170     CHECK(root_container_ != nullptr);
171   }
172 
173   DexFileLoader(const uint8_t* base, size_t size, const std::string& location);
174 
175   DexFileLoader(std::vector<uint8_t>&& memory, const std::string& location);
176 
177   DexFileLoader(MemMap&& mem_map, const std::string& location);
178 
DexFileLoader(File * file,const std::string & location)179   DexFileLoader(File* file, const std::string& location)
180       : DexFileLoader(/*filename=*/location.c_str(), file, location) {}
181 
DexFileLoader(const char * filename,const std::string & location)182   DexFileLoader(const char* filename, const std::string& location)
183       : DexFileLoader(filename, /*file=*/&kInvalidFile, location) {}
184 
DexFileLoader(const std::string & location)185   explicit DexFileLoader(const std::string& location)
186       : DexFileLoader(location.c_str(), /*file=*/&kInvalidFile, location) {}
187 
~DexFileLoader()188   virtual ~DexFileLoader() {}
189 
190   // Open singe dex file at the given offset within the container (usually 0).
191   // This intentionally ignores all other dex files in the container
192   std::unique_ptr<const DexFile> OpenOne(size_t header_offset,
193                                          uint32_t location_checksum,
194                                          const OatDexFile* oat_dex_file,
195                                          bool verify,
196                                          bool verify_checksum,
197                                          std::string* error_msg);
198 
199   // Open single dex file (starting at offset 0 of the container).
200   // It expects only single dex file to be present and will fail otherwise.
Open(uint32_t location_checksum,const OatDexFile * oat_dex_file,bool verify,bool verify_checksum,std::string * error_msg)201   std::unique_ptr<const DexFile> Open(uint32_t location_checksum,
202                                       const OatDexFile* oat_dex_file,
203                                       bool verify,
204                                       bool verify_checksum,
205                                       std::string* error_msg) {
206     std::unique_ptr<const DexFile> dex_file = OpenOne(
207         /*header_offset=*/0, location_checksum, oat_dex_file, verify, verify_checksum, error_msg);
208     // This API returns only singe DEX file, so check there is just single dex in the container.
209     CHECK(dex_file == nullptr || dex_file->IsDexContainerLastEntry()) << location_;
210     return dex_file;
211   }
212 
Open(uint32_t location_checksum,bool verify,bool verify_checksum,std::string * error_msg)213   std::unique_ptr<const DexFile> Open(uint32_t location_checksum,
214                                       bool verify,
215                                       bool verify_checksum,
216                                       std::string* error_msg) {
217     return Open(location_checksum,
218                 /*oat_dex_file=*/nullptr,
219                 verify,
220                 verify_checksum,
221                 error_msg);
222   }
223 
224   // Opens all dex files, guessing the container format based on file magic.
225   bool Open(bool verify,
226             bool verify_checksum,
227             bool allow_no_dex_files,
228             DexFileLoaderErrorCode* error_code,
229             std::string* error_msg,
230             std::vector<std::unique_ptr<const DexFile>>* dex_files);
231 
Open(bool verify,bool verify_checksum,DexFileLoaderErrorCode * error_code,std::string * error_msg,std::vector<std::unique_ptr<const DexFile>> * dex_files)232   bool Open(bool verify,
233             bool verify_checksum,
234             DexFileLoaderErrorCode* error_code,
235             std::string* error_msg,
236             std::vector<std::unique_ptr<const DexFile>>* dex_files) {
237     return Open(verify,
238                 verify_checksum,
239                 /*allow_no_dex_files=*/false,
240                 error_code,
241                 error_msg,
242                 dex_files);
243   }
244 
Open(bool verify,bool verify_checksum,bool allow_no_dex_files,std::string * error_msg,std::vector<std::unique_ptr<const DexFile>> * dex_files)245   bool Open(bool verify,
246             bool verify_checksum,
247             bool allow_no_dex_files,
248             std::string* error_msg,
249             std::vector<std::unique_ptr<const DexFile>>* dex_files) {
250     DexFileLoaderErrorCode error_code;
251     return Open(verify, verify_checksum, allow_no_dex_files, &error_code, error_msg, dex_files);
252   }
253 
Open(bool verify,bool verify_checksum,std::string * error_msg,std::vector<std::unique_ptr<const DexFile>> * dex_files)254   bool Open(bool verify,
255             bool verify_checksum,
256             std::string* error_msg,
257             std::vector<std::unique_ptr<const DexFile>>* dex_files) {
258     DexFileLoaderErrorCode error_code;
259     return Open(verify,
260                 verify_checksum,
261                 /*allow_no_dex_files=*/false,
262                 &error_code,
263                 error_msg,
264                 dex_files);
265   }
266 
267  protected:
268   static const File kInvalidFile;  // Used for "no file descriptor" (-1).
269 
270   bool InitAndReadMagic(size_t header_offset, uint32_t* magic, std::string* error_msg);
271 
272   // Ensure we have root container.  If we are backed by a file, memory-map it.
273   // We can only do this for dex files since zip files might be too big to map.
274   bool MapRootContainer(std::string* error_msg);
275 
276   static std::unique_ptr<DexFile> OpenCommon(std::shared_ptr<DexFileContainer> container,
277                                              const uint8_t* base,
278                                              size_t size,
279                                              const std::string& location,
280                                              std::optional<uint32_t> location_checksum,
281                                              const OatDexFile* oat_dex_file,
282                                              bool verify,
283                                              bool verify_checksum,
284                                              std::string* error_msg,
285                                              DexFileLoaderErrorCode* error_code);
286 
287   // Old signature preserved for app-compat.
288   std::unique_ptr<const DexFile> Open(const uint8_t* base,
289                                       size_t size,
290                                       const std::string& location,
291                                       uint32_t location_checksum,
292                                       const OatDexFile* oat_dex_file,
293                                       bool verify,
294                                       bool verify_checksum,
295                                       std::string* error_msg,
296                                       std::unique_ptr<DexFileContainer> container) const;
297 
298   // Old signature preserved for app-compat.
299   enum VerifyResult {};
300   static std::unique_ptr<DexFile> OpenCommon(const uint8_t* base,
301                                              size_t size,
302                                              const uint8_t* data_base,
303                                              size_t data_size,
304                                              const std::string& location,
305                                              uint32_t location_checksum,
306                                              const OatDexFile* oat_dex_file,
307                                              bool verify,
308                                              bool verify_checksum,
309                                              std::string* error_msg,
310                                              std::unique_ptr<DexFileContainer> container,
311                                              VerifyResult* verify_result);
312 
313   // Open .dex files from the entry_name in a zip archive.
314   bool OpenFromZipEntry(const ZipArchive& zip_archive,
315                         const char* entry_name,
316                         const std::string& location,
317                         bool verify,
318                         bool verify_checksum,
319                         /*inout*/ size_t* multidex_count,
320                         /*out*/ DexFileLoaderErrorCode* error_code,
321                         /*out*/ std::string* error_msg,
322                         /*out*/ std::vector<std::unique_ptr<const DexFile>>* dex_files) const;
323 
324   // The DexFileLoader can be backed either by file or by memory (i.e. DexFileContainer).
325   // We can not just mmap the file since APKs might be unreasonably large for 32-bit system.
326   std::string filename_;
327   const File* file_ = &kInvalidFile;
328   std::optional<File> owned_file_;  // May be used as backing storage for 'file_'.
329   std::shared_ptr<DexFileContainer> root_container_;
330 
331   // The full absolute path to the dex file, if it was loaded from disk.
332   //
333   // Can also be a path to a multidex container (typically apk), followed by
334   // kMultiDexSeparator and the file inside the container.
335   //
336   // On host this may not be an absolute path.
337   //
338   // On device libnativeloader uses this to determine the location of the java
339   // package or shared library, which decides where to load native libraries
340   // from.
341   const std::string location_;
342 };
343 
344 }  // namespace art
345 
346 #endif  // ART_LIBDEXFILE_DEX_DEX_FILE_LOADER_H_
347