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