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