1 /*
2  * Copyright (C) 2011 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_verifier.h"
18 
19 #include "sys/mman.h"
20 #include "zlib.h"
21 #include <memory>
22 
23 #include "base/unix_file/fd_file.h"
24 #include "base/macros.h"
25 #include "common_runtime_test.h"
26 #include "scoped_thread_state_change.h"
27 #include "thread-inl.h"
28 
29 namespace art {
30 
31 class DexFileVerifierTest : public CommonRuntimeTest {};
32 
33 static const byte kBase64Map[256] = {
34   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
35   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
36   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
37   255, 255, 255, 255, 255, 255, 255,  62, 255, 255, 255,  63,
38   52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255,
39   255, 254, 255, 255, 255,   0,   1,   2,   3,   4,   5,   6,
40     7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  // NOLINT
41    19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255, 255,  // NOLINT
42   255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,
43    37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  // NOLINT
44    49,  50,  51, 255, 255, 255, 255, 255, 255, 255, 255, 255,  // NOLINT
45   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
46   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
47   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
48   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
49   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
50   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
51   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
52   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
53   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
54   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
55   255, 255, 255, 255
56 };
57 
DecodeBase64(const char * src,size_t * dst_size)58 static inline byte* DecodeBase64(const char* src, size_t* dst_size) {
59   std::vector<byte> tmp;
60   uint32_t t = 0, y = 0;
61   int g = 3;
62   for (size_t i = 0; src[i] != '\0'; ++i) {
63     byte c = kBase64Map[src[i] & 0xFF];
64     if (c == 255) continue;
65     // the final = symbols are read and used to trim the remaining bytes
66     if (c == 254) {
67       c = 0;
68       // prevent g < 0 which would potentially allow an overflow later
69       if (--g < 0) {
70         *dst_size = 0;
71         return nullptr;
72       }
73     } else if (g != 3) {
74       // we only allow = to be at the end
75       *dst_size = 0;
76       return nullptr;
77     }
78     t = (t << 6) | c;
79     if (++y == 4) {
80       tmp.push_back((t >> 16) & 255);
81       if (g > 1) {
82         tmp.push_back((t >> 8) & 255);
83       }
84       if (g > 2) {
85         tmp.push_back(t & 255);
86       }
87       y = t = 0;
88     }
89   }
90   if (y != 0) {
91     *dst_size = 0;
92     return nullptr;
93   }
94   std::unique_ptr<byte[]> dst(new byte[tmp.size()]);
95   if (dst_size != nullptr) {
96     *dst_size = tmp.size();
97   } else {
98     *dst_size = 0;
99   }
100   std::copy(tmp.begin(), tmp.end(), dst.get());
101   return dst.release();
102 }
103 
OpenDexFileBase64(const char * base64,const char * location,std::string * error_msg)104 static const DexFile* OpenDexFileBase64(const char* base64, const char* location,
105                                         std::string* error_msg) {
106   // decode base64
107   CHECK(base64 != NULL);
108   size_t length;
109   std::unique_ptr<byte[]> dex_bytes(DecodeBase64(base64, &length));
110   CHECK(dex_bytes.get() != NULL);
111 
112   // write to provided file
113   std::unique_ptr<File> file(OS::CreateEmptyFile(location));
114   CHECK(file.get() != NULL);
115   if (!file->WriteFully(dex_bytes.get(), length)) {
116     PLOG(FATAL) << "Failed to write base64 as dex file";
117   }
118   if (file->FlushCloseOrErase() != 0) {
119     PLOG(FATAL) << "Could not flush and close test file.";
120   }
121   file.reset();
122 
123   // read dex file
124   ScopedObjectAccess soa(Thread::Current());
125   std::vector<const DexFile*> tmp;
126   bool success = DexFile::Open(location, location, error_msg, &tmp);
127   CHECK(success) << error_msg;
128   EXPECT_EQ(1U, tmp.size());
129   const DexFile* dex_file = tmp[0];
130   EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
131   EXPECT_TRUE(dex_file->IsReadOnly());
132   return dex_file;
133 }
134 
135 
136 // For reference.
137 static const char kGoodTestDex[] =
138     "ZGV4CjAzNQDrVbyVkxX1HljTznNf95AglkUAhQuFtmKkAgAAcAAAAHhWNBIAAAAAAAAAAAQCAAAN"
139     "AAAAcAAAAAYAAACkAAAAAgAAALwAAAABAAAA1AAAAAQAAADcAAAAAQAAAPwAAACIAQAAHAEAAFoB"
140     "AABiAQAAagEAAIEBAACVAQAAqQEAAL0BAADDAQAAzgEAANEBAADVAQAA2gEAAN8BAAABAAAAAgAA"
141     "AAMAAAAEAAAABQAAAAgAAAAIAAAABQAAAAAAAAAJAAAABQAAAFQBAAAEAAEACwAAAAAAAAAAAAAA"
142     "AAAAAAoAAAABAAEADAAAAAIAAAAAAAAAAAAAAAEAAAACAAAAAAAAAAcAAAAAAAAA8wEAAAAAAAAB"
143     "AAEAAQAAAOgBAAAEAAAAcBADAAAADgACAAAAAgAAAO0BAAAIAAAAYgAAABoBBgBuIAIAEAAOAAEA"
144     "AAADAAY8aW5pdD4ABkxUZXN0OwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09i"
145     "amVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AARUZXN0AAlUZXN0"
146     "LmphdmEAAVYAAlZMAANmb28AA291dAAHcHJpbnRsbgABAAcOAAMABw54AAAAAgAAgYAEnAIBCbQC"
147     "AAAADQAAAAAAAAABAAAAAAAAAAEAAAANAAAAcAAAAAIAAAAGAAAApAAAAAMAAAACAAAAvAAAAAQA"
148     "AAABAAAA1AAAAAUAAAAEAAAA3AAAAAYAAAABAAAA/AAAAAEgAAACAAAAHAEAAAEQAAABAAAAVAEA"
149     "AAIgAAANAAAAWgEAAAMgAAACAAAA6AEAAAAgAAABAAAA8wEAAAAQAAABAAAABAIAAA==";
150 
TEST_F(DexFileVerifierTest,GoodDex)151 TEST_F(DexFileVerifierTest, GoodDex) {
152   ScratchFile tmp;
153   std::string error_msg;
154   std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kGoodTestDex, tmp.GetFilename().c_str(),
155                                                        &error_msg));
156   ASSERT_TRUE(raw.get() != nullptr) << error_msg;
157 }
158 
FixUpChecksum(byte * dex_file)159 static void FixUpChecksum(byte* dex_file) {
160   DexFile::Header* header = reinterpret_cast<DexFile::Header*>(dex_file);
161   uint32_t expected_size = header->file_size_;
162   uint32_t adler_checksum = adler32(0L, Z_NULL, 0);
163   const uint32_t non_sum = sizeof(DexFile::Header::magic_) + sizeof(DexFile::Header::checksum_);
164   const byte* non_sum_ptr = dex_file + non_sum;
165   adler_checksum = adler32(adler_checksum, non_sum_ptr, expected_size - non_sum);
166   header->checksum_ = adler_checksum;
167 }
168 
FixChecksumAndOpen(byte * bytes,size_t length,const char * location,std::string * error_msg)169 static const DexFile* FixChecksumAndOpen(byte* bytes, size_t length, const char* location,
170                                          std::string* error_msg) {
171   // Check data.
172   CHECK(bytes != nullptr);
173 
174   // Fixup of checksum.
175   FixUpChecksum(bytes);
176 
177   // write to provided file
178   std::unique_ptr<File> file(OS::CreateEmptyFile(location));
179   CHECK(file.get() != NULL);
180   if (!file->WriteFully(bytes, length)) {
181     PLOG(FATAL) << "Failed to write base64 as dex file";
182   }
183   if (file->FlushCloseOrErase() != 0) {
184     PLOG(FATAL) << "Could not flush and close test file.";
185   }
186   file.reset();
187 
188   // read dex file
189   ScopedObjectAccess soa(Thread::Current());
190   std::vector<const DexFile*> tmp;
191   if (!DexFile::Open(location, location, error_msg, &tmp)) {
192     return nullptr;
193   }
194   EXPECT_EQ(1U, tmp.size());
195   const DexFile* dex_file = tmp[0];
196   EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
197   EXPECT_TRUE(dex_file->IsReadOnly());
198   return dex_file;
199 }
200 
ModifyAndLoad(const char * location,size_t offset,uint8_t new_val,std::string * error_msg)201 static bool ModifyAndLoad(const char* location, size_t offset, uint8_t new_val,
202                                     std::string* error_msg) {
203   // Decode base64.
204   size_t length;
205   std::unique_ptr<byte[]> dex_bytes(DecodeBase64(kGoodTestDex, &length));
206   CHECK(dex_bytes.get() != NULL);
207 
208   // Make modifications.
209   dex_bytes.get()[offset] = new_val;
210 
211   // Fixup and load.
212   std::unique_ptr<const DexFile> file(FixChecksumAndOpen(dex_bytes.get(), length, location,
213                                                          error_msg));
214   return file.get() != nullptr;
215 }
216 
TEST_F(DexFileVerifierTest,MethodId)217 TEST_F(DexFileVerifierTest, MethodId) {
218   {
219     // Class error.
220     ScratchFile tmp;
221     std::string error_msg;
222     bool success = !ModifyAndLoad(tmp.GetFilename().c_str(), 220, 0xFFU, &error_msg);
223     ASSERT_TRUE(success);
224     ASSERT_NE(error_msg.find("inter_method_id_item class_idx"), std::string::npos) << error_msg;
225   }
226 
227   {
228     // Proto error.
229     ScratchFile tmp;
230     std::string error_msg;
231     bool success = !ModifyAndLoad(tmp.GetFilename().c_str(), 222, 0xFFU, &error_msg);
232     ASSERT_TRUE(success);
233     ASSERT_NE(error_msg.find("inter_method_id_item proto_idx"), std::string::npos) << error_msg;
234   }
235 
236   {
237     // Name error.
238     ScratchFile tmp;
239     std::string error_msg;
240     bool success = !ModifyAndLoad(tmp.GetFilename().c_str(), 224, 0xFFU, &error_msg);
241     ASSERT_TRUE(success);
242     ASSERT_NE(error_msg.find("inter_method_id_item name_idx"), std::string::npos) << error_msg;
243   }
244 }
245 
246 }  // namespace art
247