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
29namespace art {
30
31class DexFileVerifierTest : public CommonRuntimeTest {};
32
33static 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
58static 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
104static 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  file.reset();
119
120  // read dex file
121  ScopedObjectAccess soa(Thread::Current());
122  std::vector<const DexFile*> tmp;
123  bool success = DexFile::Open(location, location, error_msg, &tmp);
124  CHECK(success) << error_msg;
125  EXPECT_EQ(1U, tmp.size());
126  const DexFile* dex_file = tmp[0];
127  EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
128  EXPECT_TRUE(dex_file->IsReadOnly());
129  return dex_file;
130}
131
132
133// For reference.
134static const char kGoodTestDex[] =
135    "ZGV4CjAzNQDrVbyVkxX1HljTznNf95AglkUAhQuFtmKkAgAAcAAAAHhWNBIAAAAAAAAAAAQCAAAN"
136    "AAAAcAAAAAYAAACkAAAAAgAAALwAAAABAAAA1AAAAAQAAADcAAAAAQAAAPwAAACIAQAAHAEAAFoB"
137    "AABiAQAAagEAAIEBAACVAQAAqQEAAL0BAADDAQAAzgEAANEBAADVAQAA2gEAAN8BAAABAAAAAgAA"
138    "AAMAAAAEAAAABQAAAAgAAAAIAAAABQAAAAAAAAAJAAAABQAAAFQBAAAEAAEACwAAAAAAAAAAAAAA"
139    "AAAAAAoAAAABAAEADAAAAAIAAAAAAAAAAAAAAAEAAAACAAAAAAAAAAcAAAAAAAAA8wEAAAAAAAAB"
140    "AAEAAQAAAOgBAAAEAAAAcBADAAAADgACAAAAAgAAAO0BAAAIAAAAYgAAABoBBgBuIAIAEAAOAAEA"
141    "AAADAAY8aW5pdD4ABkxUZXN0OwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09i"
142    "amVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AARUZXN0AAlUZXN0"
143    "LmphdmEAAVYAAlZMAANmb28AA291dAAHcHJpbnRsbgABAAcOAAMABw54AAAAAgAAgYAEnAIBCbQC"
144    "AAAADQAAAAAAAAABAAAAAAAAAAEAAAANAAAAcAAAAAIAAAAGAAAApAAAAAMAAAACAAAAvAAAAAQA"
145    "AAABAAAA1AAAAAUAAAAEAAAA3AAAAAYAAAABAAAA/AAAAAEgAAACAAAAHAEAAAEQAAABAAAAVAEA"
146    "AAIgAAANAAAAWgEAAAMgAAACAAAA6AEAAAAgAAABAAAA8wEAAAAQAAABAAAABAIAAA==";
147
148TEST_F(DexFileVerifierTest, GoodDex) {
149  ScratchFile tmp;
150  std::string error_msg;
151  std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kGoodTestDex, tmp.GetFilename().c_str(),
152                                                       &error_msg));
153  ASSERT_TRUE(raw.get() != nullptr) << error_msg;
154}
155
156static void FixUpChecksum(byte* dex_file) {
157  DexFile::Header* header = reinterpret_cast<DexFile::Header*>(dex_file);
158  uint32_t expected_size = header->file_size_;
159  uint32_t adler_checksum = adler32(0L, Z_NULL, 0);
160  const uint32_t non_sum = sizeof(DexFile::Header::magic_) + sizeof(DexFile::Header::checksum_);
161  const byte* non_sum_ptr = dex_file + non_sum;
162  adler_checksum = adler32(adler_checksum, non_sum_ptr, expected_size - non_sum);
163  header->checksum_ = adler_checksum;
164}
165
166static const DexFile* FixChecksumAndOpen(byte* bytes, size_t length, const char* location,
167                                         std::string* error_msg) {
168  // Check data.
169  CHECK(bytes != nullptr);
170
171  // Fixup of checksum.
172  FixUpChecksum(bytes);
173
174  // write to provided file
175  std::unique_ptr<File> file(OS::CreateEmptyFile(location));
176  CHECK(file.get() != NULL);
177  if (!file->WriteFully(bytes, length)) {
178    PLOG(FATAL) << "Failed to write base64 as dex file";
179  }
180  file.reset();
181
182  // read dex file
183  ScopedObjectAccess soa(Thread::Current());
184  std::vector<const DexFile*> tmp;
185  if (!DexFile::Open(location, location, error_msg, &tmp)) {
186    return nullptr;
187  }
188  EXPECT_EQ(1U, tmp.size());
189  const DexFile* dex_file = tmp[0];
190  EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
191  EXPECT_TRUE(dex_file->IsReadOnly());
192  return dex_file;
193}
194
195static bool ModifyAndLoad(const char* location, size_t offset, uint8_t new_val,
196                                    std::string* error_msg) {
197  // Decode base64.
198  size_t length;
199  std::unique_ptr<byte[]> dex_bytes(DecodeBase64(kGoodTestDex, &length));
200  CHECK(dex_bytes.get() != NULL);
201
202  // Make modifications.
203  dex_bytes.get()[offset] = new_val;
204
205  // Fixup and load.
206  std::unique_ptr<const DexFile> file(FixChecksumAndOpen(dex_bytes.get(), length, location,
207                                                         error_msg));
208  return file.get() != nullptr;
209}
210
211TEST_F(DexFileVerifierTest, MethodId) {
212  {
213    // Class error.
214    ScratchFile tmp;
215    std::string error_msg;
216    bool success = !ModifyAndLoad(tmp.GetFilename().c_str(), 220, 0xFFU, &error_msg);
217    ASSERT_TRUE(success);
218    ASSERT_NE(error_msg.find("inter_method_id_item class_idx"), std::string::npos) << error_msg;
219  }
220
221  {
222    // Proto error.
223    ScratchFile tmp;
224    std::string error_msg;
225    bool success = !ModifyAndLoad(tmp.GetFilename().c_str(), 222, 0xFFU, &error_msg);
226    ASSERT_TRUE(success);
227    ASSERT_NE(error_msg.find("inter_method_id_item proto_idx"), std::string::npos) << error_msg;
228  }
229
230  {
231    // Name error.
232    ScratchFile tmp;
233    std::string error_msg;
234    bool success = !ModifyAndLoad(tmp.GetFilename().c_str(), 224, 0xFFU, &error_msg);
235    ASSERT_TRUE(success);
236    ASSERT_NE(error_msg.find("inter_method_id_item name_idx"), std::string::npos) << error_msg;
237  }
238}
239
240}  // namespace art
241