1*d57664e9SAndroid Build Coastguard Worker /*
2*d57664e9SAndroid Build Coastguard Worker * Copyright (C) 2019 The Android Open Source Project
3*d57664e9SAndroid Build Coastguard Worker *
4*d57664e9SAndroid Build Coastguard Worker * Licensed under the Apache License, Version 2.0 (the "License");
5*d57664e9SAndroid Build Coastguard Worker * you may not use this file except in compliance with the License.
6*d57664e9SAndroid Build Coastguard Worker * You may obtain a copy of the License at
7*d57664e9SAndroid Build Coastguard Worker *
8*d57664e9SAndroid Build Coastguard Worker * http://www.apache.org/licenses/LICENSE-2.0
9*d57664e9SAndroid Build Coastguard Worker *
10*d57664e9SAndroid Build Coastguard Worker * Unless required by applicable law or agreed to in writing, software
11*d57664e9SAndroid Build Coastguard Worker * distributed under the License is distributed on an "AS IS" BASIS,
12*d57664e9SAndroid Build Coastguard Worker * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*d57664e9SAndroid Build Coastguard Worker * See the License for the specific language governing permissions and
14*d57664e9SAndroid Build Coastguard Worker * limitations under the License.
15*d57664e9SAndroid Build Coastguard Worker */
16*d57664e9SAndroid Build Coastguard Worker
17*d57664e9SAndroid Build Coastguard Worker #include <cstring>
18*d57664e9SAndroid Build Coastguard Worker #include <iostream>
19*d57664e9SAndroid Build Coastguard Worker #include <memory>
20*d57664e9SAndroid Build Coastguard Worker #include <sstream>
21*d57664e9SAndroid Build Coastguard Worker
22*d57664e9SAndroid Build Coastguard Worker #include <unistd.h>
23*d57664e9SAndroid Build Coastguard Worker
24*d57664e9SAndroid Build Coastguard Worker #include <jni.h>
25*d57664e9SAndroid Build Coastguard Worker
26*d57664e9SAndroid Build Coastguard Worker #include <jvmti.h>
27*d57664e9SAndroid Build Coastguard Worker
28*d57664e9SAndroid Build Coastguard Worker #include <android-base/file.h>
29*d57664e9SAndroid Build Coastguard Worker #include <android-base/logging.h>
30*d57664e9SAndroid Build Coastguard Worker #include <android-base/macros.h>
31*d57664e9SAndroid Build Coastguard Worker #include <android-base/strings.h>
32*d57664e9SAndroid Build Coastguard Worker #include <android-base/unique_fd.h>
33*d57664e9SAndroid Build Coastguard Worker
34*d57664e9SAndroid Build Coastguard Worker #include <fcntl.h>
35*d57664e9SAndroid Build Coastguard Worker #include <sys/stat.h>
36*d57664e9SAndroid Build Coastguard Worker #include <sys/wait.h>
37*d57664e9SAndroid Build Coastguard Worker
38*d57664e9SAndroid Build Coastguard Worker #include <nativehelper/scoped_utf_chars.h>
39*d57664e9SAndroid Build Coastguard Worker
40*d57664e9SAndroid Build Coastguard Worker // We need dladdr.
41*d57664e9SAndroid Build Coastguard Worker #if !defined(__APPLE__) && !defined(_WIN32)
42*d57664e9SAndroid Build Coastguard Worker #ifndef _GNU_SOURCE
43*d57664e9SAndroid Build Coastguard Worker #define _GNU_SOURCE
44*d57664e9SAndroid Build Coastguard Worker #define DEFINED_GNU_SOURCE
45*d57664e9SAndroid Build Coastguard Worker #endif
46*d57664e9SAndroid Build Coastguard Worker #include <dlfcn.h>
47*d57664e9SAndroid Build Coastguard Worker #ifdef DEFINED_GNU_SOURCE
48*d57664e9SAndroid Build Coastguard Worker #undef _GNU_SOURCE
49*d57664e9SAndroid Build Coastguard Worker #undef DEFINED_GNU_SOURCE
50*d57664e9SAndroid Build Coastguard Worker #endif
51*d57664e9SAndroid Build Coastguard Worker #endif
52*d57664e9SAndroid Build Coastguard Worker
53*d57664e9SAndroid Build Coastguard Worker // Slicer's headers have code that triggers these warnings. b/65298177
54*d57664e9SAndroid Build Coastguard Worker #pragma clang diagnostic push
55*d57664e9SAndroid Build Coastguard Worker #pragma clang diagnostic ignored "-Wunused-parameter"
56*d57664e9SAndroid Build Coastguard Worker #pragma clang diagnostic ignored "-Wsign-compare"
57*d57664e9SAndroid Build Coastguard Worker
58*d57664e9SAndroid Build Coastguard Worker #include <slicer/dex_ir.h>
59*d57664e9SAndroid Build Coastguard Worker #include <slicer/code_ir.h>
60*d57664e9SAndroid Build Coastguard Worker #include <slicer/dex_bytecode.h>
61*d57664e9SAndroid Build Coastguard Worker #include <slicer/dex_ir_builder.h>
62*d57664e9SAndroid Build Coastguard Worker #include <slicer/writer.h>
63*d57664e9SAndroid Build Coastguard Worker #include <slicer/reader.h>
64*d57664e9SAndroid Build Coastguard Worker
65*d57664e9SAndroid Build Coastguard Worker #pragma clang diagnostic pop
66*d57664e9SAndroid Build Coastguard Worker
67*d57664e9SAndroid Build Coastguard Worker namespace {
68*d57664e9SAndroid Build Coastguard Worker
69*d57664e9SAndroid Build Coastguard Worker JavaVM* gJavaVM = nullptr;
70*d57664e9SAndroid Build Coastguard Worker bool gForkCrash = false;
71*d57664e9SAndroid Build Coastguard Worker bool gJavaCrash = false;
72*d57664e9SAndroid Build Coastguard Worker
73*d57664e9SAndroid Build Coastguard Worker // Converts a class name to a type descriptor
74*d57664e9SAndroid Build Coastguard Worker // (ex. "java.lang.String" to "Ljava/lang/String;")
classNameToDescriptor(const char * className)75*d57664e9SAndroid Build Coastguard Worker std::string classNameToDescriptor(const char* className) {
76*d57664e9SAndroid Build Coastguard Worker std::stringstream ss;
77*d57664e9SAndroid Build Coastguard Worker ss << "L";
78*d57664e9SAndroid Build Coastguard Worker for (auto p = className; *p != '\0'; ++p) {
79*d57664e9SAndroid Build Coastguard Worker ss << (*p == '.' ? '/' : *p);
80*d57664e9SAndroid Build Coastguard Worker }
81*d57664e9SAndroid Build Coastguard Worker ss << ";";
82*d57664e9SAndroid Build Coastguard Worker return ss.str();
83*d57664e9SAndroid Build Coastguard Worker }
84*d57664e9SAndroid Build Coastguard Worker
85*d57664e9SAndroid Build Coastguard Worker using namespace dex;
86*d57664e9SAndroid Build Coastguard Worker using namespace lir;
87*d57664e9SAndroid Build Coastguard Worker
88*d57664e9SAndroid Build Coastguard Worker class Transformer {
89*d57664e9SAndroid Build Coastguard Worker public:
Transformer(std::shared_ptr<ir::DexFile> dexIr)90*d57664e9SAndroid Build Coastguard Worker explicit Transformer(std::shared_ptr<ir::DexFile> dexIr) : dexIr_(dexIr) {}
91*d57664e9SAndroid Build Coastguard Worker
transform()92*d57664e9SAndroid Build Coastguard Worker bool transform() {
93*d57664e9SAndroid Build Coastguard Worker bool classModified = false;
94*d57664e9SAndroid Build Coastguard Worker
95*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<ir::Builder> builder;
96*d57664e9SAndroid Build Coastguard Worker
97*d57664e9SAndroid Build Coastguard Worker for (auto& method : dexIr_->encoded_methods) {
98*d57664e9SAndroid Build Coastguard Worker // Do not look into abstract/bridge/native/synthetic methods.
99*d57664e9SAndroid Build Coastguard Worker if ((method->access_flags & (kAccAbstract | kAccBridge | kAccNative | kAccSynthetic))
100*d57664e9SAndroid Build Coastguard Worker != 0) {
101*d57664e9SAndroid Build Coastguard Worker continue;
102*d57664e9SAndroid Build Coastguard Worker }
103*d57664e9SAndroid Build Coastguard Worker
104*d57664e9SAndroid Build Coastguard Worker struct HookVisitor: public Visitor {
105*d57664e9SAndroid Build Coastguard Worker HookVisitor(Transformer* transformer, CodeIr* c_ir)
106*d57664e9SAndroid Build Coastguard Worker : transformer(transformer), cIr(c_ir) {
107*d57664e9SAndroid Build Coastguard Worker }
108*d57664e9SAndroid Build Coastguard Worker
109*d57664e9SAndroid Build Coastguard Worker bool Visit(Bytecode* bytecode) override {
110*d57664e9SAndroid Build Coastguard Worker if (bytecode->opcode == OP_MONITOR_ENTER) {
111*d57664e9SAndroid Build Coastguard Worker insertHook(bytecode, true,
112*d57664e9SAndroid Build Coastguard Worker reinterpret_cast<VReg*>(bytecode->operands[0])->reg);
113*d57664e9SAndroid Build Coastguard Worker return true;
114*d57664e9SAndroid Build Coastguard Worker }
115*d57664e9SAndroid Build Coastguard Worker if (bytecode->opcode == OP_MONITOR_EXIT) {
116*d57664e9SAndroid Build Coastguard Worker insertHook(bytecode, false,
117*d57664e9SAndroid Build Coastguard Worker reinterpret_cast<VReg*>(bytecode->operands[0])->reg);
118*d57664e9SAndroid Build Coastguard Worker return true;
119*d57664e9SAndroid Build Coastguard Worker }
120*d57664e9SAndroid Build Coastguard Worker return false;
121*d57664e9SAndroid Build Coastguard Worker }
122*d57664e9SAndroid Build Coastguard Worker
123*d57664e9SAndroid Build Coastguard Worker void insertHook(lir::Instruction* before, bool pre, u4 reg) {
124*d57664e9SAndroid Build Coastguard Worker transformer->preparePrePost();
125*d57664e9SAndroid Build Coastguard Worker transformer->addCall(cIr, before, OP_INVOKE_STATIC_RANGE,
126*d57664e9SAndroid Build Coastguard Worker transformer->hookType_, pre ? "preLock" : "postLock",
127*d57664e9SAndroid Build Coastguard Worker transformer->voidType_, transformer->objectType_, reg);
128*d57664e9SAndroid Build Coastguard Worker myModified = true;
129*d57664e9SAndroid Build Coastguard Worker }
130*d57664e9SAndroid Build Coastguard Worker
131*d57664e9SAndroid Build Coastguard Worker Transformer* transformer;
132*d57664e9SAndroid Build Coastguard Worker CodeIr* cIr;
133*d57664e9SAndroid Build Coastguard Worker bool myModified = false;
134*d57664e9SAndroid Build Coastguard Worker };
135*d57664e9SAndroid Build Coastguard Worker
136*d57664e9SAndroid Build Coastguard Worker CodeIr c(method.get(), dexIr_);
137*d57664e9SAndroid Build Coastguard Worker bool methodModified = false;
138*d57664e9SAndroid Build Coastguard Worker
139*d57664e9SAndroid Build Coastguard Worker HookVisitor visitor(this, &c);
140*d57664e9SAndroid Build Coastguard Worker for (auto it = c.instructions.begin(); it != c.instructions.end(); ++it) {
141*d57664e9SAndroid Build Coastguard Worker lir::Instruction* fi = *it;
142*d57664e9SAndroid Build Coastguard Worker fi->Accept(&visitor);
143*d57664e9SAndroid Build Coastguard Worker }
144*d57664e9SAndroid Build Coastguard Worker methodModified |= visitor.myModified;
145*d57664e9SAndroid Build Coastguard Worker
146*d57664e9SAndroid Build Coastguard Worker if (methodModified) {
147*d57664e9SAndroid Build Coastguard Worker classModified = true;
148*d57664e9SAndroid Build Coastguard Worker c.Assemble();
149*d57664e9SAndroid Build Coastguard Worker }
150*d57664e9SAndroid Build Coastguard Worker }
151*d57664e9SAndroid Build Coastguard Worker
152*d57664e9SAndroid Build Coastguard Worker return classModified;
153*d57664e9SAndroid Build Coastguard Worker }
154*d57664e9SAndroid Build Coastguard Worker
155*d57664e9SAndroid Build Coastguard Worker private:
preparePrePost()156*d57664e9SAndroid Build Coastguard Worker void preparePrePost() {
157*d57664e9SAndroid Build Coastguard Worker // Insert "void LockHook.(pre|post)(Object o)."
158*d57664e9SAndroid Build Coastguard Worker
159*d57664e9SAndroid Build Coastguard Worker prepareBuilder();
160*d57664e9SAndroid Build Coastguard Worker
161*d57664e9SAndroid Build Coastguard Worker if (voidType_ == nullptr) {
162*d57664e9SAndroid Build Coastguard Worker voidType_ = builder_->GetType("V");
163*d57664e9SAndroid Build Coastguard Worker }
164*d57664e9SAndroid Build Coastguard Worker if (hookType_ == nullptr) {
165*d57664e9SAndroid Build Coastguard Worker hookType_ = builder_->GetType("Lcom/android/lock_checker/LockHook;");
166*d57664e9SAndroid Build Coastguard Worker }
167*d57664e9SAndroid Build Coastguard Worker if (objectType_ == nullptr) {
168*d57664e9SAndroid Build Coastguard Worker objectType_ = builder_->GetType("Ljava/lang/Object;");
169*d57664e9SAndroid Build Coastguard Worker }
170*d57664e9SAndroid Build Coastguard Worker }
171*d57664e9SAndroid Build Coastguard Worker
prepareBuilder()172*d57664e9SAndroid Build Coastguard Worker void prepareBuilder() {
173*d57664e9SAndroid Build Coastguard Worker if (builder_ == nullptr) {
174*d57664e9SAndroid Build Coastguard Worker builder_ = std::unique_ptr<ir::Builder>(new ir::Builder(dexIr_));
175*d57664e9SAndroid Build Coastguard Worker }
176*d57664e9SAndroid Build Coastguard Worker }
177*d57664e9SAndroid Build Coastguard Worker
addInst(CodeIr * cIr,lir::Instruction * instructionAfter,Opcode opcode,const std::list<Operand * > & operands)178*d57664e9SAndroid Build Coastguard Worker static void addInst(CodeIr* cIr, lir::Instruction* instructionAfter, Opcode opcode,
179*d57664e9SAndroid Build Coastguard Worker const std::list<Operand*>& operands) {
180*d57664e9SAndroid Build Coastguard Worker auto instruction = cIr->Alloc<Bytecode>();
181*d57664e9SAndroid Build Coastguard Worker
182*d57664e9SAndroid Build Coastguard Worker instruction->opcode = opcode;
183*d57664e9SAndroid Build Coastguard Worker
184*d57664e9SAndroid Build Coastguard Worker for (auto it = operands.begin(); it != operands.end(); it++) {
185*d57664e9SAndroid Build Coastguard Worker instruction->operands.push_back(*it);
186*d57664e9SAndroid Build Coastguard Worker }
187*d57664e9SAndroid Build Coastguard Worker
188*d57664e9SAndroid Build Coastguard Worker cIr->instructions.InsertBefore(instructionAfter, instruction);
189*d57664e9SAndroid Build Coastguard Worker }
190*d57664e9SAndroid Build Coastguard Worker
addCall(CodeIr * cIr,lir::Instruction * instructionAfter,Opcode opcode,ir::Type * type,const char * methodName,ir::Type * returnType,const std::vector<ir::Type * > & types,const std::list<int> & regs)191*d57664e9SAndroid Build Coastguard Worker void addCall(CodeIr* cIr, lir::Instruction* instructionAfter, Opcode opcode, ir::Type* type,
192*d57664e9SAndroid Build Coastguard Worker const char* methodName, ir::Type* returnType,
193*d57664e9SAndroid Build Coastguard Worker const std::vector<ir::Type*>& types, const std::list<int>& regs) {
194*d57664e9SAndroid Build Coastguard Worker auto proto = builder_->GetProto(returnType, builder_->GetTypeList(types));
195*d57664e9SAndroid Build Coastguard Worker auto method = builder_->GetMethodDecl(builder_->GetAsciiString(methodName), proto, type);
196*d57664e9SAndroid Build Coastguard Worker
197*d57664e9SAndroid Build Coastguard Worker VRegList* paramRegs = cIr->Alloc<VRegList>();
198*d57664e9SAndroid Build Coastguard Worker for (auto it = regs.begin(); it != regs.end(); it++) {
199*d57664e9SAndroid Build Coastguard Worker paramRegs->registers.push_back(*it);
200*d57664e9SAndroid Build Coastguard Worker }
201*d57664e9SAndroid Build Coastguard Worker
202*d57664e9SAndroid Build Coastguard Worker addInst(cIr, instructionAfter, opcode,
203*d57664e9SAndroid Build Coastguard Worker { paramRegs, cIr->Alloc<Method>(method, method->orig_index) });
204*d57664e9SAndroid Build Coastguard Worker }
205*d57664e9SAndroid Build Coastguard Worker
addCall(CodeIr * cIr,lir::Instruction * instructionAfter,Opcode opcode,ir::Type * type,const char * methodName,ir::Type * returnType,ir::Type * paramType,u4 paramVReg)206*d57664e9SAndroid Build Coastguard Worker void addCall(CodeIr* cIr, lir::Instruction* instructionAfter, Opcode opcode, ir::Type* type,
207*d57664e9SAndroid Build Coastguard Worker const char* methodName, ir::Type* returnType, ir::Type* paramType,
208*d57664e9SAndroid Build Coastguard Worker u4 paramVReg) {
209*d57664e9SAndroid Build Coastguard Worker auto proto = builder_->GetProto(returnType, builder_->GetTypeList( { paramType }));
210*d57664e9SAndroid Build Coastguard Worker auto method = builder_->GetMethodDecl(builder_->GetAsciiString(methodName), proto, type);
211*d57664e9SAndroid Build Coastguard Worker
212*d57664e9SAndroid Build Coastguard Worker VRegRange* args = cIr->Alloc<VRegRange>(paramVReg, 1);
213*d57664e9SAndroid Build Coastguard Worker
214*d57664e9SAndroid Build Coastguard Worker addInst(cIr, instructionAfter, opcode,
215*d57664e9SAndroid Build Coastguard Worker { args, cIr->Alloc<Method>(method, method->orig_index) });
216*d57664e9SAndroid Build Coastguard Worker }
217*d57664e9SAndroid Build Coastguard Worker
218*d57664e9SAndroid Build Coastguard Worker std::shared_ptr<ir::DexFile> dexIr_;
219*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<ir::Builder> builder_;
220*d57664e9SAndroid Build Coastguard Worker
221*d57664e9SAndroid Build Coastguard Worker ir::Type* voidType_ = nullptr;
222*d57664e9SAndroid Build Coastguard Worker ir::Type* hookType_ = nullptr;
223*d57664e9SAndroid Build Coastguard Worker ir::Type* objectType_ = nullptr;
224*d57664e9SAndroid Build Coastguard Worker };
225*d57664e9SAndroid Build Coastguard Worker
maybeTransform(const char * name,size_t classDataLen,const unsigned char * classData,dex::Writer::Allocator * allocator)226*d57664e9SAndroid Build Coastguard Worker std::pair<dex::u1*, size_t> maybeTransform(const char* name, size_t classDataLen,
227*d57664e9SAndroid Build Coastguard Worker const unsigned char* classData, dex::Writer::Allocator* allocator) {
228*d57664e9SAndroid Build Coastguard Worker // Isolate byte code of class class. This is needed as Android usually gives us more
229*d57664e9SAndroid Build Coastguard Worker // than the class we need.
230*d57664e9SAndroid Build Coastguard Worker dex::Reader reader(classData, classDataLen);
231*d57664e9SAndroid Build Coastguard Worker
232*d57664e9SAndroid Build Coastguard Worker dex::u4 index = reader.FindClassIndex(classNameToDescriptor(name).c_str());
233*d57664e9SAndroid Build Coastguard Worker CHECK_NE(index, kNoIndex);
234*d57664e9SAndroid Build Coastguard Worker reader.CreateClassIr(index);
235*d57664e9SAndroid Build Coastguard Worker std::shared_ptr<ir::DexFile> ir = reader.GetIr();
236*d57664e9SAndroid Build Coastguard Worker
237*d57664e9SAndroid Build Coastguard Worker {
238*d57664e9SAndroid Build Coastguard Worker Transformer transformer(ir);
239*d57664e9SAndroid Build Coastguard Worker if (!transformer.transform()) {
240*d57664e9SAndroid Build Coastguard Worker return std::make_pair(nullptr, 0);
241*d57664e9SAndroid Build Coastguard Worker }
242*d57664e9SAndroid Build Coastguard Worker }
243*d57664e9SAndroid Build Coastguard Worker
244*d57664e9SAndroid Build Coastguard Worker size_t new_size;
245*d57664e9SAndroid Build Coastguard Worker dex::Writer writer(ir);
246*d57664e9SAndroid Build Coastguard Worker dex::u1* newClassData = writer.CreateImage(allocator, &new_size);
247*d57664e9SAndroid Build Coastguard Worker return std::make_pair(newClassData, new_size);
248*d57664e9SAndroid Build Coastguard Worker }
249*d57664e9SAndroid Build Coastguard Worker
transformHook(jvmtiEnv * jvmtiEnv,JNIEnv * env ATTRIBUTE_UNUSED,jclass classBeingRedefined ATTRIBUTE_UNUSED,jobject loader,const char * name,jobject protectionDomain ATTRIBUTE_UNUSED,jint classDataLen,const unsigned char * classData,jint * newClassDataLen,unsigned char ** newClassData)250*d57664e9SAndroid Build Coastguard Worker void transformHook(jvmtiEnv* jvmtiEnv, JNIEnv* env ATTRIBUTE_UNUSED,
251*d57664e9SAndroid Build Coastguard Worker jclass classBeingRedefined ATTRIBUTE_UNUSED, jobject loader, const char* name,
252*d57664e9SAndroid Build Coastguard Worker jobject protectionDomain ATTRIBUTE_UNUSED, jint classDataLen,
253*d57664e9SAndroid Build Coastguard Worker const unsigned char* classData, jint* newClassDataLen, unsigned char** newClassData) {
254*d57664e9SAndroid Build Coastguard Worker // Even reading the classData array is expensive as the data is only generated when the
255*d57664e9SAndroid Build Coastguard Worker // memory is touched. Hence call JvmtiAgent#shouldTransform to check if we need to transform
256*d57664e9SAndroid Build Coastguard Worker // the class.
257*d57664e9SAndroid Build Coastguard Worker
258*d57664e9SAndroid Build Coastguard Worker // Skip bootclasspath classes. TODO: Make this configurable.
259*d57664e9SAndroid Build Coastguard Worker if (loader == nullptr) {
260*d57664e9SAndroid Build Coastguard Worker return;
261*d57664e9SAndroid Build Coastguard Worker }
262*d57664e9SAndroid Build Coastguard Worker
263*d57664e9SAndroid Build Coastguard Worker // Do not look into java.* classes. Should technically be filtered by above, but when that's
264*d57664e9SAndroid Build Coastguard Worker // configurable have this.
265*d57664e9SAndroid Build Coastguard Worker if (strncmp("java", name, 4) == 0) {
266*d57664e9SAndroid Build Coastguard Worker return;
267*d57664e9SAndroid Build Coastguard Worker }
268*d57664e9SAndroid Build Coastguard Worker
269*d57664e9SAndroid Build Coastguard Worker // Do not look into our Java classes.
270*d57664e9SAndroid Build Coastguard Worker if (strncmp("com/android/lock_checker", name, 24) == 0) {
271*d57664e9SAndroid Build Coastguard Worker return;
272*d57664e9SAndroid Build Coastguard Worker }
273*d57664e9SAndroid Build Coastguard Worker
274*d57664e9SAndroid Build Coastguard Worker class JvmtiAllocator: public dex::Writer::Allocator {
275*d57664e9SAndroid Build Coastguard Worker public:
276*d57664e9SAndroid Build Coastguard Worker explicit JvmtiAllocator(::jvmtiEnv* jvmti) :
277*d57664e9SAndroid Build Coastguard Worker jvmti_(jvmti) {
278*d57664e9SAndroid Build Coastguard Worker }
279*d57664e9SAndroid Build Coastguard Worker
280*d57664e9SAndroid Build Coastguard Worker void* Allocate(size_t size) override {
281*d57664e9SAndroid Build Coastguard Worker unsigned char* res = nullptr;
282*d57664e9SAndroid Build Coastguard Worker jvmti_->Allocate(size, &res);
283*d57664e9SAndroid Build Coastguard Worker return res;
284*d57664e9SAndroid Build Coastguard Worker }
285*d57664e9SAndroid Build Coastguard Worker
286*d57664e9SAndroid Build Coastguard Worker void Free(void* ptr) override {
287*d57664e9SAndroid Build Coastguard Worker jvmti_->Deallocate(reinterpret_cast<unsigned char*>(ptr));
288*d57664e9SAndroid Build Coastguard Worker }
289*d57664e9SAndroid Build Coastguard Worker
290*d57664e9SAndroid Build Coastguard Worker private:
291*d57664e9SAndroid Build Coastguard Worker ::jvmtiEnv* jvmti_;
292*d57664e9SAndroid Build Coastguard Worker };
293*d57664e9SAndroid Build Coastguard Worker JvmtiAllocator allocator(jvmtiEnv);
294*d57664e9SAndroid Build Coastguard Worker std::pair<dex::u1*, size_t> result = maybeTransform(name, classDataLen, classData,
295*d57664e9SAndroid Build Coastguard Worker &allocator);
296*d57664e9SAndroid Build Coastguard Worker
297*d57664e9SAndroid Build Coastguard Worker if (result.second > 0) {
298*d57664e9SAndroid Build Coastguard Worker *newClassData = result.first;
299*d57664e9SAndroid Build Coastguard Worker *newClassDataLen = static_cast<jint>(result.second);
300*d57664e9SAndroid Build Coastguard Worker }
301*d57664e9SAndroid Build Coastguard Worker }
302*d57664e9SAndroid Build Coastguard Worker
dataDumpRequestHook(jvmtiEnv * jvmtiEnv ATTRIBUTE_UNUSED)303*d57664e9SAndroid Build Coastguard Worker void dataDumpRequestHook(jvmtiEnv* jvmtiEnv ATTRIBUTE_UNUSED) {
304*d57664e9SAndroid Build Coastguard Worker if (gJavaVM == nullptr) {
305*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "No JavaVM for dump";
306*d57664e9SAndroid Build Coastguard Worker return;
307*d57664e9SAndroid Build Coastguard Worker }
308*d57664e9SAndroid Build Coastguard Worker JNIEnv* env;
309*d57664e9SAndroid Build Coastguard Worker if (gJavaVM->GetEnv(reinterpret_cast<void**>(&env), JNI_VERSION_1_6) != JNI_OK) {
310*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Could not get env for dump";
311*d57664e9SAndroid Build Coastguard Worker return;
312*d57664e9SAndroid Build Coastguard Worker }
313*d57664e9SAndroid Build Coastguard Worker jclass lockHookClass = env->FindClass("com/android/lock_checker/LockHook");
314*d57664e9SAndroid Build Coastguard Worker if (lockHookClass == nullptr) {
315*d57664e9SAndroid Build Coastguard Worker env->ExceptionClear();
316*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Could not find LockHook class";
317*d57664e9SAndroid Build Coastguard Worker return;
318*d57664e9SAndroid Build Coastguard Worker }
319*d57664e9SAndroid Build Coastguard Worker jmethodID dumpId = env->GetStaticMethodID(lockHookClass, "dump", "()V");
320*d57664e9SAndroid Build Coastguard Worker if (dumpId == nullptr) {
321*d57664e9SAndroid Build Coastguard Worker env->ExceptionClear();
322*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "Could not find LockHook.dump";
323*d57664e9SAndroid Build Coastguard Worker return;
324*d57664e9SAndroid Build Coastguard Worker }
325*d57664e9SAndroid Build Coastguard Worker env->CallStaticVoidMethod(lockHookClass, dumpId);
326*d57664e9SAndroid Build Coastguard Worker env->ExceptionClear();
327*d57664e9SAndroid Build Coastguard Worker }
328*d57664e9SAndroid Build Coastguard Worker
329*d57664e9SAndroid Build Coastguard Worker // A function for dladdr to search.
lock_agent_tag_fn()330*d57664e9SAndroid Build Coastguard Worker extern "C" __attribute__ ((visibility ("default"))) void lock_agent_tag_fn() {
331*d57664e9SAndroid Build Coastguard Worker }
332*d57664e9SAndroid Build Coastguard Worker
fileExists(const std::string & path)333*d57664e9SAndroid Build Coastguard Worker bool fileExists(const std::string& path) {
334*d57664e9SAndroid Build Coastguard Worker struct stat statBuf;
335*d57664e9SAndroid Build Coastguard Worker int rc = stat(path.c_str(), &statBuf);
336*d57664e9SAndroid Build Coastguard Worker return rc == 0;
337*d57664e9SAndroid Build Coastguard Worker }
338*d57664e9SAndroid Build Coastguard Worker
findLockAgentJar()339*d57664e9SAndroid Build Coastguard Worker std::string findLockAgentJar() {
340*d57664e9SAndroid Build Coastguard Worker // Check whether the jar is located next to the agent's so.
341*d57664e9SAndroid Build Coastguard Worker #ifndef __APPLE__
342*d57664e9SAndroid Build Coastguard Worker {
343*d57664e9SAndroid Build Coastguard Worker Dl_info info;
344*d57664e9SAndroid Build Coastguard Worker if (dladdr(reinterpret_cast<const void*>(&lock_agent_tag_fn), /* out */ &info) != 0) {
345*d57664e9SAndroid Build Coastguard Worker std::string lockAgentSoPath = info.dli_fname;
346*d57664e9SAndroid Build Coastguard Worker std::string dir = android::base::Dirname(lockAgentSoPath);
347*d57664e9SAndroid Build Coastguard Worker std::string lockAgentJarPath = dir + "/" + "lockagent.jar";
348*d57664e9SAndroid Build Coastguard Worker if (fileExists(lockAgentJarPath)) {
349*d57664e9SAndroid Build Coastguard Worker return lockAgentJarPath;
350*d57664e9SAndroid Build Coastguard Worker }
351*d57664e9SAndroid Build Coastguard Worker } else {
352*d57664e9SAndroid Build Coastguard Worker LOG(ERROR) << "dladdr failed";
353*d57664e9SAndroid Build Coastguard Worker }
354*d57664e9SAndroid Build Coastguard Worker }
355*d57664e9SAndroid Build Coastguard Worker #endif
356*d57664e9SAndroid Build Coastguard Worker
357*d57664e9SAndroid Build Coastguard Worker std::string sysFrameworkPath = "/system/framework/lockagent.jar";
358*d57664e9SAndroid Build Coastguard Worker if (fileExists(sysFrameworkPath)) {
359*d57664e9SAndroid Build Coastguard Worker return sysFrameworkPath;
360*d57664e9SAndroid Build Coastguard Worker }
361*d57664e9SAndroid Build Coastguard Worker
362*d57664e9SAndroid Build Coastguard Worker std::string relPath = "lockagent.jar";
363*d57664e9SAndroid Build Coastguard Worker if (fileExists(relPath)) {
364*d57664e9SAndroid Build Coastguard Worker return relPath;
365*d57664e9SAndroid Build Coastguard Worker }
366*d57664e9SAndroid Build Coastguard Worker
367*d57664e9SAndroid Build Coastguard Worker return "";
368*d57664e9SAndroid Build Coastguard Worker }
369*d57664e9SAndroid Build Coastguard Worker
prepareHook(jvmtiEnv * env)370*d57664e9SAndroid Build Coastguard Worker void prepareHook(jvmtiEnv* env) {
371*d57664e9SAndroid Build Coastguard Worker // Inject the agent Java code.
372*d57664e9SAndroid Build Coastguard Worker {
373*d57664e9SAndroid Build Coastguard Worker std::string path = findLockAgentJar();
374*d57664e9SAndroid Build Coastguard Worker if (path.empty()) {
375*d57664e9SAndroid Build Coastguard Worker LOG(FATAL) << "Could not find lockagent.jar";
376*d57664e9SAndroid Build Coastguard Worker }
377*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "Will load Java parts from " << path;
378*d57664e9SAndroid Build Coastguard Worker jvmtiError res = env->AddToBootstrapClassLoaderSearch(path.c_str());
379*d57664e9SAndroid Build Coastguard Worker if (res != JVMTI_ERROR_NONE) {
380*d57664e9SAndroid Build Coastguard Worker LOG(FATAL) << "Could not add lockagent from " << path << " to boot classpath: " << res;
381*d57664e9SAndroid Build Coastguard Worker }
382*d57664e9SAndroid Build Coastguard Worker }
383*d57664e9SAndroid Build Coastguard Worker
384*d57664e9SAndroid Build Coastguard Worker jvmtiCapabilities caps;
385*d57664e9SAndroid Build Coastguard Worker memset(&caps, 0, sizeof(caps));
386*d57664e9SAndroid Build Coastguard Worker caps.can_retransform_classes = 1;
387*d57664e9SAndroid Build Coastguard Worker
388*d57664e9SAndroid Build Coastguard Worker if (env->AddCapabilities(&caps) != JVMTI_ERROR_NONE) {
389*d57664e9SAndroid Build Coastguard Worker LOG(FATAL) << "Could not add caps";
390*d57664e9SAndroid Build Coastguard Worker }
391*d57664e9SAndroid Build Coastguard Worker
392*d57664e9SAndroid Build Coastguard Worker jvmtiEventCallbacks cb;
393*d57664e9SAndroid Build Coastguard Worker memset(&cb, 0, sizeof(cb));
394*d57664e9SAndroid Build Coastguard Worker cb.ClassFileLoadHook = transformHook;
395*d57664e9SAndroid Build Coastguard Worker cb.DataDumpRequest = dataDumpRequestHook;
396*d57664e9SAndroid Build Coastguard Worker
397*d57664e9SAndroid Build Coastguard Worker if (env->SetEventCallbacks(&cb, sizeof(cb)) != JVMTI_ERROR_NONE) {
398*d57664e9SAndroid Build Coastguard Worker LOG(FATAL) << "Could not set cb";
399*d57664e9SAndroid Build Coastguard Worker }
400*d57664e9SAndroid Build Coastguard Worker
401*d57664e9SAndroid Build Coastguard Worker if (env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, nullptr)
402*d57664e9SAndroid Build Coastguard Worker != JVMTI_ERROR_NONE) {
403*d57664e9SAndroid Build Coastguard Worker LOG(FATAL) << "Could not enable events";
404*d57664e9SAndroid Build Coastguard Worker }
405*d57664e9SAndroid Build Coastguard Worker if (env->SetEventNotificationMode(JVMTI_ENABLE, JVMTI_EVENT_DATA_DUMP_REQUEST, nullptr)
406*d57664e9SAndroid Build Coastguard Worker != JVMTI_ERROR_NONE) {
407*d57664e9SAndroid Build Coastguard Worker LOG(FATAL) << "Could not enable events";
408*d57664e9SAndroid Build Coastguard Worker }
409*d57664e9SAndroid Build Coastguard Worker }
410*d57664e9SAndroid Build Coastguard Worker
attach(JavaVM * vm,char * options,void * reserved ATTRIBUTE_UNUSED)411*d57664e9SAndroid Build Coastguard Worker jint attach(JavaVM* vm, char* options, void* reserved ATTRIBUTE_UNUSED) {
412*d57664e9SAndroid Build Coastguard Worker gJavaVM = vm;
413*d57664e9SAndroid Build Coastguard Worker
414*d57664e9SAndroid Build Coastguard Worker jvmtiEnv* env;
415*d57664e9SAndroid Build Coastguard Worker jint jvmError = vm->GetEnv(reinterpret_cast<void**>(&env), JVMTI_VERSION_1_2);
416*d57664e9SAndroid Build Coastguard Worker if (jvmError != JNI_OK) {
417*d57664e9SAndroid Build Coastguard Worker return jvmError;
418*d57664e9SAndroid Build Coastguard Worker }
419*d57664e9SAndroid Build Coastguard Worker
420*d57664e9SAndroid Build Coastguard Worker prepareHook(env);
421*d57664e9SAndroid Build Coastguard Worker
422*d57664e9SAndroid Build Coastguard Worker std::vector<std::string> config = android::base::Split(options, ",");
423*d57664e9SAndroid Build Coastguard Worker for (const std::string& c : config) {
424*d57664e9SAndroid Build Coastguard Worker if (c == "native_crash") {
425*d57664e9SAndroid Build Coastguard Worker gForkCrash = true;
426*d57664e9SAndroid Build Coastguard Worker } else if (c == "java_crash") {
427*d57664e9SAndroid Build Coastguard Worker gJavaCrash = true;
428*d57664e9SAndroid Build Coastguard Worker }
429*d57664e9SAndroid Build Coastguard Worker }
430*d57664e9SAndroid Build Coastguard Worker
431*d57664e9SAndroid Build Coastguard Worker return JVMTI_ERROR_NONE;
432*d57664e9SAndroid Build Coastguard Worker }
433*d57664e9SAndroid Build Coastguard Worker
434*d57664e9SAndroid Build Coastguard Worker extern "C" JNIEXPORT
Java_com_android_lock_1checker_LockHook_getNativeHandlingConfig(JNIEnv *,jclass)435*d57664e9SAndroid Build Coastguard Worker jboolean JNICALL Java_com_android_lock_1checker_LockHook_getNativeHandlingConfig(JNIEnv*, jclass) {
436*d57664e9SAndroid Build Coastguard Worker return gForkCrash ? JNI_TRUE : JNI_FALSE;
437*d57664e9SAndroid Build Coastguard Worker }
438*d57664e9SAndroid Build Coastguard Worker
439*d57664e9SAndroid Build Coastguard Worker extern "C" JNIEXPORT jboolean JNICALL
Java_com_android_lock_1checker_LockHook_getSimulateCrashConfig(JNIEnv *,jclass)440*d57664e9SAndroid Build Coastguard Worker Java_com_android_lock_1checker_LockHook_getSimulateCrashConfig(JNIEnv*, jclass) {
441*d57664e9SAndroid Build Coastguard Worker return gJavaCrash ? JNI_TRUE : JNI_FALSE;
442*d57664e9SAndroid Build Coastguard Worker }
443*d57664e9SAndroid Build Coastguard Worker
Java_com_android_lock_1checker_LockHook_nWtf(JNIEnv * env,jclass,jstring msg)444*d57664e9SAndroid Build Coastguard Worker extern "C" JNIEXPORT void JNICALL Java_com_android_lock_1checker_LockHook_nWtf(JNIEnv* env, jclass,
445*d57664e9SAndroid Build Coastguard Worker jstring msg) {
446*d57664e9SAndroid Build Coastguard Worker if (!gForkCrash || msg == nullptr) {
447*d57664e9SAndroid Build Coastguard Worker return;
448*d57664e9SAndroid Build Coastguard Worker }
449*d57664e9SAndroid Build Coastguard Worker
450*d57664e9SAndroid Build Coastguard Worker // Create a native crash with the given message. Decouple from the current crash to create a
451*d57664e9SAndroid Build Coastguard Worker // tombstone but continue on.
452*d57664e9SAndroid Build Coastguard Worker //
453*d57664e9SAndroid Build Coastguard Worker // TODO: Once there are not so many reports, consider making this fatal for the calling process.
454*d57664e9SAndroid Build Coastguard Worker ScopedUtfChars utf(env, msg);
455*d57664e9SAndroid Build Coastguard Worker if (utf.c_str() == nullptr) {
456*d57664e9SAndroid Build Coastguard Worker return;
457*d57664e9SAndroid Build Coastguard Worker }
458*d57664e9SAndroid Build Coastguard Worker const char* args[] = {
459*d57664e9SAndroid Build Coastguard Worker "/system/bin/lockagent_crasher",
460*d57664e9SAndroid Build Coastguard Worker utf.c_str(),
461*d57664e9SAndroid Build Coastguard Worker nullptr
462*d57664e9SAndroid Build Coastguard Worker };
463*d57664e9SAndroid Build Coastguard Worker pid_t pid = fork();
464*d57664e9SAndroid Build Coastguard Worker if (pid < 0) {
465*d57664e9SAndroid Build Coastguard Worker return;
466*d57664e9SAndroid Build Coastguard Worker }
467*d57664e9SAndroid Build Coastguard Worker if (pid == 0) {
468*d57664e9SAndroid Build Coastguard Worker // Double fork so we return quickly. Leave init to deal with the zombie.
469*d57664e9SAndroid Build Coastguard Worker pid_t pid2 = fork();
470*d57664e9SAndroid Build Coastguard Worker if (pid2 == 0) {
471*d57664e9SAndroid Build Coastguard Worker execv(args[0], const_cast<char* const*>(args));
472*d57664e9SAndroid Build Coastguard Worker _exit(1);
473*d57664e9SAndroid Build Coastguard Worker __builtin_unreachable();
474*d57664e9SAndroid Build Coastguard Worker }
475*d57664e9SAndroid Build Coastguard Worker _exit(0);
476*d57664e9SAndroid Build Coastguard Worker __builtin_unreachable();
477*d57664e9SAndroid Build Coastguard Worker }
478*d57664e9SAndroid Build Coastguard Worker int status;
479*d57664e9SAndroid Build Coastguard Worker waitpid(pid, &status, 0); // Ignore any results.
480*d57664e9SAndroid Build Coastguard Worker }
481*d57664e9SAndroid Build Coastguard Worker
Agent_OnAttach(JavaVM * vm,char * options,void * reserved)482*d57664e9SAndroid Build Coastguard Worker extern "C" JNIEXPORT jint JNICALL Agent_OnAttach(JavaVM* vm, char* options, void* reserved) {
483*d57664e9SAndroid Build Coastguard Worker return attach(vm, options, reserved);
484*d57664e9SAndroid Build Coastguard Worker }
485*d57664e9SAndroid Build Coastguard Worker
Agent_OnLoad(JavaVM * vm,char * options,void * reserved)486*d57664e9SAndroid Build Coastguard Worker extern "C" JNIEXPORT jint JNICALL Agent_OnLoad(JavaVM* vm, char* options, void* reserved) {
487*d57664e9SAndroid Build Coastguard Worker return attach(vm, options, reserved);
488*d57664e9SAndroid Build Coastguard Worker }
489*d57664e9SAndroid Build Coastguard Worker
locktest_main(int argc,char * argv[])490*d57664e9SAndroid Build Coastguard Worker int locktest_main(int argc, char *argv[]) {
491*d57664e9SAndroid Build Coastguard Worker if (argc != 3) {
492*d57664e9SAndroid Build Coastguard Worker LOG(FATAL) << "Need two arguments: dex-file class-name";
493*d57664e9SAndroid Build Coastguard Worker }
494*d57664e9SAndroid Build Coastguard Worker struct stat statBuf;
495*d57664e9SAndroid Build Coastguard Worker int rc = stat(argv[1], &statBuf);
496*d57664e9SAndroid Build Coastguard Worker if (rc != 0) {
497*d57664e9SAndroid Build Coastguard Worker PLOG(FATAL) << "Could not get file size for " << argv[1];
498*d57664e9SAndroid Build Coastguard Worker }
499*d57664e9SAndroid Build Coastguard Worker std::unique_ptr<char[]> data(new char[statBuf.st_size]);
500*d57664e9SAndroid Build Coastguard Worker {
501*d57664e9SAndroid Build Coastguard Worker android::base::unique_fd fd(open(argv[1], O_RDONLY));
502*d57664e9SAndroid Build Coastguard Worker if (fd.get() == -1) {
503*d57664e9SAndroid Build Coastguard Worker PLOG(FATAL) << "Could not open file " << argv[1];
504*d57664e9SAndroid Build Coastguard Worker }
505*d57664e9SAndroid Build Coastguard Worker if (!android::base::ReadFully(fd.get(), data.get(), statBuf.st_size)) {
506*d57664e9SAndroid Build Coastguard Worker PLOG(FATAL) << "Could not read file " << argv[1];
507*d57664e9SAndroid Build Coastguard Worker }
508*d57664e9SAndroid Build Coastguard Worker }
509*d57664e9SAndroid Build Coastguard Worker
510*d57664e9SAndroid Build Coastguard Worker class NewDeleteAllocator: public dex::Writer::Allocator {
511*d57664e9SAndroid Build Coastguard Worker public:
512*d57664e9SAndroid Build Coastguard Worker explicit NewDeleteAllocator() {
513*d57664e9SAndroid Build Coastguard Worker }
514*d57664e9SAndroid Build Coastguard Worker
515*d57664e9SAndroid Build Coastguard Worker void* Allocate(size_t size) override {
516*d57664e9SAndroid Build Coastguard Worker return new char[size];
517*d57664e9SAndroid Build Coastguard Worker }
518*d57664e9SAndroid Build Coastguard Worker
519*d57664e9SAndroid Build Coastguard Worker void Free(void* ptr) override {
520*d57664e9SAndroid Build Coastguard Worker delete[] reinterpret_cast<char*>(ptr);
521*d57664e9SAndroid Build Coastguard Worker }
522*d57664e9SAndroid Build Coastguard Worker };
523*d57664e9SAndroid Build Coastguard Worker NewDeleteAllocator allocator;
524*d57664e9SAndroid Build Coastguard Worker
525*d57664e9SAndroid Build Coastguard Worker std::pair<dex::u1*, size_t> result = maybeTransform(argv[2], statBuf.st_size,
526*d57664e9SAndroid Build Coastguard Worker reinterpret_cast<unsigned char*>(data.get()), &allocator);
527*d57664e9SAndroid Build Coastguard Worker
528*d57664e9SAndroid Build Coastguard Worker if (result.second == 0) {
529*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "No transformation";
530*d57664e9SAndroid Build Coastguard Worker return 0;
531*d57664e9SAndroid Build Coastguard Worker }
532*d57664e9SAndroid Build Coastguard Worker
533*d57664e9SAndroid Build Coastguard Worker std::string newName(argv[1]);
534*d57664e9SAndroid Build Coastguard Worker newName.append(".new");
535*d57664e9SAndroid Build Coastguard Worker
536*d57664e9SAndroid Build Coastguard Worker {
537*d57664e9SAndroid Build Coastguard Worker android::base::unique_fd fd(
538*d57664e9SAndroid Build Coastguard Worker open(newName.c_str(), O_CREAT | O_TRUNC | O_WRONLY, S_IRUSR | S_IWUSR));
539*d57664e9SAndroid Build Coastguard Worker if (fd.get() == -1) {
540*d57664e9SAndroid Build Coastguard Worker PLOG(FATAL) << "Could not open file " << newName;
541*d57664e9SAndroid Build Coastguard Worker }
542*d57664e9SAndroid Build Coastguard Worker if (!android::base::WriteFully(fd.get(), result.first, result.second)) {
543*d57664e9SAndroid Build Coastguard Worker PLOG(FATAL) << "Could not write file " << newName;
544*d57664e9SAndroid Build Coastguard Worker }
545*d57664e9SAndroid Build Coastguard Worker }
546*d57664e9SAndroid Build Coastguard Worker LOG(INFO) << "Transformed file written to " << newName;
547*d57664e9SAndroid Build Coastguard Worker
548*d57664e9SAndroid Build Coastguard Worker return 0;
549*d57664e9SAndroid Build Coastguard Worker }
550*d57664e9SAndroid Build Coastguard Worker
551*d57664e9SAndroid Build Coastguard Worker } // namespace
552*d57664e9SAndroid Build Coastguard Worker
main(int argc,char * argv[])553*d57664e9SAndroid Build Coastguard Worker int main(int argc, char *argv[]) {
554*d57664e9SAndroid Build Coastguard Worker return locktest_main(argc, argv);
555*d57664e9SAndroid Build Coastguard Worker }
556