1 /*
2 * Copyright (C) 2018 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 <string>
18 #include <vector>
19
20 #include "android-base/logging.h"
21
22 #include "base/logging.h"
23 #include "base/os.h"
24 #include "class_linker-inl.h"
25 #include "dex/art_dex_file_loader.h"
26 #include "dex/class_accessor-inl.h"
27 #include "dex/dex_file-inl.h"
28 #include "interpreter/unstarted_runtime.h"
29 #include "mirror/class-inl.h"
30 #include "mirror/dex_cache-inl.h"
31 #include "runtime.h"
32 #include "scoped_thread_state_change-inl.h"
33 #include "verifier/class_verifier.h"
34 #include "well_known_classes.h"
35
36 #include <sys/stat.h>
37 #include "cmdline.h"
38
39 namespace art {
40
41 namespace {
42
LoadDexFile(const std::string & dex_filename,std::vector<std::unique_ptr<const DexFile>> * dex_files)43 bool LoadDexFile(const std::string& dex_filename,
44 std::vector<std::unique_ptr<const DexFile>>* dex_files) {
45 ArtDexFileLoader dex_file_loader(dex_filename);
46 std::string error_msg;
47 if (!dex_file_loader.Open(/* verify= */ true,
48 /* verify_checksum= */ true,
49 &error_msg,
50 dex_files)) {
51 LOG(ERROR) << error_msg;
52 return false;
53 }
54 return true;
55 }
56
Install(Runtime * runtime,std::vector<std::unique_ptr<const DexFile>> & in,std::vector<const DexFile * > * out)57 jobject Install(Runtime* runtime,
58 std::vector<std::unique_ptr<const DexFile>>& in,
59 std::vector<const DexFile*>* out)
60 REQUIRES_SHARED(Locks::mutator_lock_) {
61 Thread* self = Thread::Current();
62 CHECK(self != nullptr);
63
64 // Need well-known-classes.
65 WellKnownClasses::Init(self->GetJniEnv());
66 // Need a class loader. Fake that we're a compiler.
67 // Note: this will run initializers through the unstarted runtime, so make sure it's
68 // initialized.
69 interpreter::UnstartedRuntime::Initialize();
70
71 for (std::unique_ptr<const DexFile>& dex_file : in) {
72 out->push_back(dex_file.release());
73 }
74
75 ClassLinker* class_linker = runtime->GetClassLinker();
76
77 jobject class_loader = class_linker->CreatePathClassLoader(self, *out);
78
79 // Need to register dex files to get a working dex cache.
80 for (const DexFile* dex_file : *out) {
81 ObjPtr<mirror::DexCache> dex_cache = class_linker->RegisterDexFile(
82 *dex_file, self->DecodeJObject(class_loader)->AsClassLoader());
83 CHECK(dex_cache != nullptr);
84 }
85
86 return class_loader;
87 }
88
89 struct MethodVerifierArgs : public CmdlineArgs {
90 protected:
91 using Base = CmdlineArgs;
92
ParseCustomart::__anona0aac79c0111::MethodVerifierArgs93 ParseStatus ParseCustom(const char* raw_option,
94 size_t raw_option_length,
95 std::string* error_msg) override {
96 DCHECK_EQ(strlen(raw_option), raw_option_length);
97 {
98 ParseStatus base_parse = Base::ParseCustom(raw_option, raw_option_length, error_msg);
99 if (base_parse != kParseUnknownArgument) {
100 return base_parse;
101 }
102 }
103
104 std::string_view option(raw_option, raw_option_length);
105 if (option.starts_with("--dex-file=")) {
106 dex_filename_ = raw_option + strlen("--dex-file=");
107 } else if (option == "--dex-file-verifier") {
108 dex_file_verifier_ = true;
109 } else if (option == "--verbose") {
110 method_verifier_verbose_ = true;
111 } else if (option == "--verbose-debug") {
112 method_verifier_verbose_debug_ = true;
113 } else if (option.starts_with("--repetitions=")) {
114 char* end;
115 repetitions_ = strtoul(raw_option + strlen("--repetitions="), &end, 10);
116 } else if (option.starts_with("--api-level=")) {
117 char* end;
118 api_level_ = strtoul(raw_option + strlen("--api-level="), &end, 10);
119 } else {
120 return kParseUnknownArgument;
121 }
122
123 return kParseOk;
124 }
125
ParseChecksart::__anona0aac79c0111::MethodVerifierArgs126 ParseStatus ParseChecks(std::string* error_msg) override {
127 // Perform the parent checks.
128 ParseStatus parent_checks = Base::ParseChecks(error_msg);
129 if (parent_checks != kParseOk) {
130 return parent_checks;
131 }
132
133 // Perform our own checks.
134 if (dex_filename_ == nullptr) {
135 *error_msg = "--dex-filename not set";
136 return kParseError;
137 }
138
139 return kParseOk;
140 }
141
GetUsageart::__anona0aac79c0111::MethodVerifierArgs142 std::string GetUsage() const override {
143 std::string usage;
144
145 usage +=
146 "Usage: method_verifier_cmd [options] ...\n"
147 // Dex file is required.
148 " --dex-file=<file.dex>: specifies an input dex file.\n"
149 " Example: --dex-file=app.apk\n"
150 " --dex-file-verifier: only run dex file verifier.\n"
151 " --verbose: use verbose verifier mode.\n"
152 " --verbose-debug: use verbose verifier debug mode.\n"
153 " --repetitions=<count>: repeat the verification count times.\n"
154 " --api-level=<level>: use API level for verification.\n"
155 "\n";
156
157 usage += Base::GetUsage();
158
159 return usage;
160 }
161
162 public:
163 const char* dex_filename_ = nullptr;
164
165 bool dex_file_verifier_ = false;
166
167 bool method_verifier_verbose_ = false;
168 bool method_verifier_verbose_debug_ = false;
169
170 size_t repetitions_ = 0u;
171
172 uint32_t api_level_ = 0u;
173 };
174
175 struct MethodVerifierMain : public CmdlineMain<MethodVerifierArgs> {
NeedsRuntimeart::__anona0aac79c0111::MethodVerifierMain176 bool NeedsRuntime() override {
177 return true;
178 }
179
ExecuteWithoutRuntimeart::__anona0aac79c0111::MethodVerifierMain180 bool ExecuteWithoutRuntime() override {
181 LOG(FATAL) << "Unreachable";
182 UNREACHABLE();
183 }
184
ExecuteWithRuntimeart::__anona0aac79c0111::MethodVerifierMain185 bool ExecuteWithRuntime(Runtime* runtime) override {
186 CHECK(args_ != nullptr);
187
188 const size_t dex_reps = args_->dex_file_verifier_
189 // If we're focused on the dex file verifier, use the
190 // repetitions parameter.
191 ? std::max(static_cast<size_t>(1u), args_->repetitions_)
192 // Otherwise just load the dex files once.
193 : 1;
194
195 std::vector<std::unique_ptr<const DexFile>> unique_dex_files;
196 for (size_t i = 0; i != dex_reps; ++i) {
197 if (args_->dex_file_verifier_ && args_->repetitions_ != 0) {
198 LOG(INFO) << "Repetition " << (i + 1);
199 }
200 unique_dex_files.clear();
201 if (!LoadDexFile(args_->dex_filename_, &unique_dex_files)) {
202 return false;
203 }
204 }
205 if (args_->dex_file_verifier_) {
206 // We're done here.
207 return true;
208 }
209
210 ScopedObjectAccess soa(Thread::Current());
211 std::vector<const DexFile*> dex_files;
212 jobject class_loader = Install(runtime, unique_dex_files, &dex_files);
213 CHECK(class_loader != nullptr);
214
215 StackHandleScope<3> scope(soa.Self());
216 Handle<mirror::ClassLoader> h_loader = scope.NewHandle(
217 soa.Decode<mirror::ClassLoader>(class_loader));
218 MutableHandle<mirror::Class> h_klass(scope.NewHandle<mirror::Class>(nullptr));
219 MutableHandle<mirror::DexCache> h_dex_cache(scope.NewHandle<mirror::DexCache>(nullptr));
220
221 if (args_->method_verifier_verbose_) {
222 gLogVerbosity.verifier = true;
223 }
224 if (args_->method_verifier_verbose_debug_) {
225 gLogVerbosity.verifier_debug = true;
226 }
227
228 const size_t verifier_reps = std::max(static_cast<size_t>(1u), args_->repetitions_);
229
230 ClassLinker* class_linker = runtime->GetClassLinker();
231 for (size_t i = 0; i != verifier_reps; ++i) {
232 if (args_->repetitions_ != 0) {
233 LOG(INFO) << "Repetition " << (i + 1);
234 }
235 for (const DexFile* dex_file : dex_files) {
236 for (ClassAccessor accessor : dex_file->GetClasses()) {
237 const char* descriptor = accessor.GetDescriptor();
238 h_klass.Assign(class_linker->FindClass(soa.Self(), descriptor, h_loader));
239 if (h_klass == nullptr || h_klass->IsErroneous()) {
240 if (args_->repetitions_ == 0) {
241 LOG(ERROR) << "Warning: could not load " << descriptor;
242 }
243 soa.Self()->ClearException();
244 continue;
245 }
246 h_dex_cache.Assign(h_klass->GetDexCache());
247 std::string error_msg;
248 verifier::FailureKind res =
249 verifier::ClassVerifier::VerifyClass(soa.Self(),
250 /* verifier_deps= */ nullptr,
251 h_dex_cache->GetDexFile(),
252 h_klass,
253 h_dex_cache,
254 h_loader,
255 *h_klass->GetClassDef(),
256 runtime->GetCompilerCallbacks(),
257 verifier::HardFailLogMode::kLogWarning,
258 args_->api_level_,
259 &error_msg);
260 if (args_->repetitions_ == 0) {
261 LOG(INFO) << descriptor << ": " << res << " " << error_msg;
262 }
263 }
264 }
265 }
266
267 return true;
268 }
269 };
270
271 } // namespace
272
273 } // namespace art
274
main(int argc,char ** argv)275 int main(int argc, char** argv) {
276 // Output all logging to stderr.
277 android::base::SetLogger(android::base::StderrLogger);
278
279 art::MethodVerifierMain main;
280 return main.Main(argc, argv);
281 }
282