1 /*
2  * Copyright 2024 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 <aidl/android/system/virtualizationservice/IVirtualizationService.h>
17 #include <android-base/file.h>
18 #include <android-base/result.h>
19 #include <android-base/unique_fd.h>
20 #include <fuzzbinder/libbinder_ndk_driver.h>
21 #include <fuzzer/FuzzedDataProvider.h>
22 #include <unistd.h>
23 
24 #include <binder_rpc_unstable.hpp>
25 #include <cstdlib>
26 #include <iostream>
27 
28 using aidl::android::system::virtualizationservice::IVirtualizationService;
29 using android::fuzzService;
30 using android::base::ErrnoError;
31 using android::base::Error;
32 using android::base::Pipe;
33 using android::base::Result;
34 using android::base::Socketpair;
35 using android::base::unique_fd;
36 using ndk::SpAIBinder;
37 
38 static constexpr const char VIRTMGR_PATH[] = "/apex/com.android.virt/bin/virtmgr";
39 static constexpr size_t VIRTMGR_THREADS = 2;
40 
get_service_fd()41 Result<unique_fd> get_service_fd() {
42     unique_fd server_fd, client_fd;
43     if (!Socketpair(SOCK_STREAM, &server_fd, &client_fd)) {
44         return ErrnoError() << "Failed to create socketpair";
45     }
46 
47     unique_fd wait_fd, ready_fd;
48     if (!Pipe(&wait_fd, &ready_fd, 0)) {
49         return ErrnoError() << "Failed to create pipe";
50     }
51 
52     if (int pid = fork(); pid == 0) {
53         client_fd.reset();
54         wait_fd.reset();
55 
56         auto server_fd_str = std::to_string(server_fd.get());
57         auto ready_fd_str = std::to_string(ready_fd.get());
58 
59         if (execl(VIRTMGR_PATH, VIRTMGR_PATH, "--rpc-server-fd", server_fd_str.c_str(),
60                   "--ready-fd", ready_fd_str.c_str(), nullptr) == -1) {
61             return ErrnoError() << "Failed to execute virtmgr";
62         }
63     } else if (pid < 0) {
64         return ErrnoError() << "Failed to fork";
65     }
66 
67     server_fd.reset();
68     ready_fd.reset();
69 
70     char buf;
71     if (read(wait_fd.get(), &buf, sizeof(buf)) < 0) {
72         return ErrnoError() << "Failed to wait for VirtualizationService to be ready";
73     }
74 
75     return client_fd;
76 }
77 
connect_service(int fd)78 Result<std::shared_ptr<IVirtualizationService>> connect_service(int fd) {
79     std::unique_ptr<ARpcSession, decltype(&ARpcSession_free)> session(ARpcSession_new(),
80                                                                       &ARpcSession_free);
81     ARpcSession_setFileDescriptorTransportMode(session.get(),
82                                                ARpcSession_FileDescriptorTransportMode::Unix);
83     ARpcSession_setMaxIncomingThreads(session.get(), VIRTMGR_THREADS);
84     ARpcSession_setMaxOutgoingConnections(session.get(), VIRTMGR_THREADS);
85     AIBinder* binder = ARpcSession_setupUnixDomainBootstrapClient(session.get(), fd);
86     if (binder == nullptr) {
87         return Error() << "Failed to connect to VirtualizationService";
88     }
89     return IVirtualizationService::fromBinder(SpAIBinder{binder});
90 }
91 
inner_fuzz(const uint8_t * data,size_t size)92 Result<void> inner_fuzz(const uint8_t* data, size_t size) {
93     unique_fd fd = OR_RETURN(get_service_fd());
94     std::shared_ptr<IVirtualizationService> service = OR_RETURN(connect_service(fd.get()));
95     fuzzService(service->asBinder().get(), FuzzedDataProvider(data, size));
96 
97     return {};
98 }
99 
LLVMFuzzerTestOneInput(const uint8_t * data,size_t size)100 extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
101     if (auto ret = inner_fuzz(data, size); !ret.ok()) {
102         std::cerr << "connecting to service failed: " << ret.error() << std::endl;
103         abort();
104     }
105     return 0;
106 }
107