1 /*
2  * Copyright (C) 2021 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 #include <android-base/file.h>
17 #include <android-base/logging.h>
18 #include <android-base/unique_fd.h>
19 #include <binder/Binder.h>
20 #include <binder/Parcel.h>
21 #include <binder/RpcServer.h>
22 #include <binder/RpcSession.h>
23 
24 #include <sys/resource.h>
25 #include <sys/un.h>
26 
27 namespace android {
28 
29 static const std::string kSock = std::string(getenv("TMPDIR") ?: "/tmp") +
30         "/binderRpcFuzzerSocket_" + std::to_string(getpid());
31 
getHardMemoryLimit()32 size_t getHardMemoryLimit() {
33     struct rlimit limit;
34     CHECK(0 == getrlimit(RLIMIT_AS, &limit)) << errno;
35     return limit.rlim_max;
36 }
37 
setMemoryLimit(size_t cur,size_t max)38 void setMemoryLimit(size_t cur, size_t max) {
39     const struct rlimit kLimit = {
40             .rlim_cur = cur,
41             .rlim_max = max,
42     };
43     CHECK(0 == setrlimit(RLIMIT_AS, &kLimit)) << errno;
44 }
45 
46 class SomeBinder : public BBinder {
onTransact(uint32_t code,const Parcel & data,Parcel * reply,uint32_t flags=0)47     status_t onTransact(uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags = 0) {
48         (void)flags;
49 
50         if ((code & 1) == 0) {
51             sp<IBinder> binder;
52             (void)data.readStrongBinder(&binder);
53             if (binder != nullptr) {
54                 (void)binder->pingBinder();
55             }
56         }
57         if ((code & 2) == 0) {
58             (void)data.readInt32();
59         }
60         if ((code & 4) == 0) {
61             (void)reply->writeStrongBinder(sp<BBinder>::make());
62         }
63 
64         return OK;
65     }
66 };
67 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)68 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
69     if (size > 50000) return 0;
70 
71     unlink(kSock.c_str());
72 
73     sp<RpcServer> server = RpcServer::make();
74     server->setRootObject(sp<SomeBinder>::make());
75     server->iUnderstandThisCodeIsExperimentalAndIWillNotUseItInProduction();
76     CHECK(server->setupUnixDomainServer(kSock.c_str()));
77 
78     static constexpr size_t kMemLimit = 1llu * 1024 * 1024 * 1024;
79     size_t hardLimit = getHardMemoryLimit();
80     setMemoryLimit(std::min(kMemLimit, hardLimit), hardLimit);
81 
82     std::thread serverThread([=] { (void)server->acceptOne(); });
83 
84     sockaddr_un addr{
85             .sun_family = AF_UNIX,
86     };
87     CHECK_LT(kSock.size(), sizeof(addr.sun_path));
88     memcpy(&addr.sun_path, kSock.c_str(), kSock.size());
89 
90     base::unique_fd clientFd(TEMP_FAILURE_RETRY(socket(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0)));
91     CHECK_NE(clientFd.get(), -1);
92     CHECK_EQ(0,
93              TEMP_FAILURE_RETRY(
94                      connect(clientFd.get(), reinterpret_cast<sockaddr*>(&addr), sizeof(addr))))
95             << strerror(errno);
96 
97     serverThread.join();
98 
99     // TODO(b/182938024): fuzz multiple sessions, instead of just one
100 
101 #if 0
102     // make fuzzer more productive locally by forcing it to create a new session
103     int32_t id = -1;
104     CHECK(base::WriteFully(clientFd, &id, sizeof(id)));
105 #endif
106 
107     CHECK(base::WriteFully(clientFd, data, size));
108 
109     clientFd.reset();
110 
111     // TODO(b/185167543): better way to force a server to shutdown
112     while (!server->listSessions().empty() && server->numUninitializedSessions()) {
113         usleep(1);
114     }
115 
116     setMemoryLimit(hardLimit, hardLimit);
117 
118     return 0;
119 }
120 
121 } // namespace android
122