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