1 /*
2  * Copyright (C) 2020 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 <android-base/logging.h>
18 #include <binder/Parcel.h>
19 #include <binder/IServiceManager.h>
20 #include <gtest/gtest.h>
21 #include <utils/CallStack.h>
22 
23 #include <malloc.h>
24 #include <functional>
25 #include <vector>
26 
27 struct DestructionAction {
DestructionActionDestructionAction28     DestructionAction(std::function<void()> f) : mF(std::move(f)) {}
~DestructionActionDestructionAction29     ~DestructionAction() { mF(); };
30 private:
31     std::function<void()> mF;
32 };
33 
34 // Group of hooks
35 struct MallocHooks {
36     decltype(__malloc_hook) malloc_hook;
37     decltype(__realloc_hook) realloc_hook;
38 
saveMallocHooks39     static MallocHooks save() {
40         return {
41             .malloc_hook = __malloc_hook,
42             .realloc_hook = __realloc_hook,
43         };
44     }
45 
overwriteMallocHooks46     void overwrite() const {
47         __malloc_hook = malloc_hook;
48         __realloc_hook = realloc_hook;
49     }
50 };
51 
52 static const MallocHooks orig_malloc_hooks = MallocHooks::save();
53 
54 // When malloc is hit, executes lambda.
55 namespace LambdaHooks {
56     using AllocationHook = std::function<void(size_t)>;
57     static std::vector<AllocationHook> lambdas = {};
58 
59     static void* lambda_realloc_hook(void* ptr, size_t bytes, const void* arg);
60     static void* lambda_malloc_hook(size_t bytes, const void* arg);
61 
62     static const MallocHooks lambda_malloc_hooks = {
63         .malloc_hook = lambda_malloc_hook,
64         .realloc_hook = lambda_realloc_hook,
65     };
66 
lambda_malloc_hook(size_t bytes,const void * arg)67     static void* lambda_malloc_hook(size_t bytes, const void* arg) {
68         {
69             orig_malloc_hooks.overwrite();
70             lambdas.at(lambdas.size() - 1)(bytes);
71             lambda_malloc_hooks.overwrite();
72         }
73         return orig_malloc_hooks.malloc_hook(bytes, arg);
74     }
75 
lambda_realloc_hook(void * ptr,size_t bytes,const void * arg)76     static void* lambda_realloc_hook(void* ptr, size_t bytes, const void* arg) {
77         {
78             orig_malloc_hooks.overwrite();
79             lambdas.at(lambdas.size() - 1)(bytes);
80             lambda_malloc_hooks.overwrite();
81         }
82         return orig_malloc_hooks.realloc_hook(ptr, bytes, arg);
83     }
84 
85 }
86 
87 // Action to execute when malloc is hit. Supports nesting. Malloc is not
88 // restricted when the allocation hook is being processed.
89 __attribute__((warn_unused_result))
OnMalloc(LambdaHooks::AllocationHook f)90 DestructionAction OnMalloc(LambdaHooks::AllocationHook f) {
91     MallocHooks before = MallocHooks::save();
92     LambdaHooks::lambdas.emplace_back(std::move(f));
93     LambdaHooks::lambda_malloc_hooks.overwrite();
94     return DestructionAction([before]() {
95         before.overwrite();
96         LambdaHooks::lambdas.pop_back();
97     });
98 }
99 
100 // exported symbol, to force compiler not to optimize away pointers we set here
101 const void* imaginary_use;
102 
TEST(TestTheTest,OnMalloc)103 TEST(TestTheTest, OnMalloc) {
104     size_t mallocs = 0;
105     {
106         const auto on_malloc = OnMalloc([&](size_t bytes) {
107             mallocs++;
108             EXPECT_EQ(bytes, 40);
109         });
110 
111         imaginary_use = new int[10];
112     }
113     EXPECT_EQ(mallocs, 1);
114 }
115 
116 
117 __attribute__((warn_unused_result))
ScopeDisallowMalloc()118 DestructionAction ScopeDisallowMalloc() {
119     return OnMalloc([&](size_t bytes) {
120         ADD_FAILURE() << "Unexpected allocation: " << bytes;
121         using android::CallStack;
122         std::cout << CallStack::stackToString("UNEXPECTED ALLOCATION", CallStack::getCurrent(4 /*ignoreDepth*/).get())
123                   << std::endl;
124     });
125 }
126 
127 using android::IBinder;
128 using android::Parcel;
129 using android::String16;
130 using android::defaultServiceManager;
131 using android::sp;
132 using android::IServiceManager;
133 
GetRemoteBinder()134 static sp<IBinder> GetRemoteBinder() {
135     // This gets binder representing the service manager
136     // the current IServiceManager API doesn't expose the binder, and
137     // I want to avoid adding usages of the AIDL generated interface it
138     // is using underneath, so to avoid people copying it.
139     sp<IBinder> binder = defaultServiceManager()->checkService(String16("manager"));
140     EXPECT_NE(nullptr, binder);
141     return binder;
142 }
143 
TEST(BinderAllocation,ParcelOnStack)144 TEST(BinderAllocation, ParcelOnStack) {
145     const auto m = ScopeDisallowMalloc();
146     Parcel p;
147     imaginary_use = p.data();
148 }
149 
TEST(BinderAllocation,GetServiceManager)150 TEST(BinderAllocation, GetServiceManager) {
151     defaultServiceManager(); // first call may alloc
152     const auto m = ScopeDisallowMalloc();
153     defaultServiceManager();
154 }
155 
156 // note, ping does not include interface descriptor
TEST(BinderAllocation,PingTransaction)157 TEST(BinderAllocation, PingTransaction) {
158     sp<IBinder> a_binder = GetRemoteBinder();
159     const auto m = ScopeDisallowMalloc();
160     a_binder->pingBinder();
161 }
162 
TEST(BinderAllocation,SmallTransaction)163 TEST(BinderAllocation, SmallTransaction) {
164     String16 empty_descriptor = String16("");
165     sp<IServiceManager> manager = defaultServiceManager();
166 
167     size_t mallocs = 0;
168     const auto on_malloc = OnMalloc([&](size_t bytes) {
169         mallocs++;
170         // Parcel should allocate a small amount by default
171         EXPECT_EQ(bytes, 128);
172     });
173     manager->checkService(empty_descriptor);
174 
175     EXPECT_EQ(mallocs, 1);
176 }
177 
main(int argc,char ** argv)178 int main(int argc, char** argv) {
179     if (getenv("LIBC_HOOKS_ENABLE") == nullptr) {
180         CHECK(0 == setenv("LIBC_HOOKS_ENABLE", "1", true /*overwrite*/));
181         execv(argv[0], argv);
182         return 1;
183     }
184     ::testing::InitGoogleTest(&argc, argv);
185     return RUN_ALL_TESTS();
186 }
187