| /* | |
| * Copyright 2024 The Android Open Source Project | |
| * | |
| * Licensed under the Apache License, Version 2.0 (the "License"); | |
| * you may not use this file except in compliance with the License. | |
| * You may obtain a copy of the License at | |
| * | |
| * http://www.apache.org/licenses/LICENSE-2.0 | |
| * | |
| * Unless required by applicable law or agreed to in writing, software | |
| * distributed under the License is distributed on an "AS IS" BASIS, | |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| * See the License for the specific language governing permissions and | |
| * limitations under the License. | |
| */ | |
| #include <aidl/android/system/virtualizationservice/IVirtualizationService.h> | |
| #include <android-base/file.h> | |
| #include <android-base/result.h> | |
| #include <android-base/unique_fd.h> | |
| #include <fuzzbinder/libbinder_ndk_driver.h> | |
| #include <fuzzer/FuzzedDataProvider.h> | |
| #include <unistd.h> | |
| #include <binder_rpc_unstable.hpp> | |
| #include <cstdlib> | |
| #include <iostream> | |
| using aidl::android::system::virtualizationservice::IVirtualizationService; | |
| using android::fuzzService; | |
| using android::base::ErrnoError; | |
| using android::base::Error; | |
| using android::base::Pipe; | |
| using android::base::Result; | |
| using android::base::Socketpair; | |
| using android::base::unique_fd; | |
| using ndk::SpAIBinder; | |
| static constexpr const char VIRTMGR_PATH[] = "/apex/com.android.virt/bin/virtmgr"; | |
| static constexpr size_t VIRTMGR_THREADS = 2; | |
| Result<unique_fd> get_service_fd() { | |
| unique_fd server_fd, client_fd; | |
| if (!Socketpair(SOCK_STREAM, &server_fd, &client_fd)) { | |
| return ErrnoError() << "Failed to create socketpair"; | |
| } | |
| unique_fd wait_fd, ready_fd; | |
| if (!Pipe(&wait_fd, &ready_fd, 0)) { | |
| return ErrnoError() << "Failed to create pipe"; | |
| } | |
| if (int pid = fork(); pid == 0) { | |
| client_fd.reset(); | |
| wait_fd.reset(); | |
| auto server_fd_str = std::to_string(server_fd.get()); | |
| auto ready_fd_str = std::to_string(ready_fd.get()); | |
| if (execl(VIRTMGR_PATH, VIRTMGR_PATH, "--rpc-server-fd", server_fd_str.c_str(), | |
| "--ready-fd", ready_fd_str.c_str(), nullptr) == -1) { | |
| return ErrnoError() << "Failed to execute virtmgr"; | |
| } | |
| } else if (pid < 0) { | |
| return ErrnoError() << "Failed to fork"; | |
| } | |
| server_fd.reset(); | |
| ready_fd.reset(); | |
| char buf; | |
| if (read(wait_fd.get(), &buf, sizeof(buf)) < 0) { | |
| return ErrnoError() << "Failed to wait for VirtualizationService to be ready"; | |
| } | |
| return client_fd; | |
| } | |
| Result<std::shared_ptr<IVirtualizationService>> connect_service(int fd) { | |
| std::unique_ptr<ARpcSession, decltype(&ARpcSession_free)> session(ARpcSession_new(), | |
| &ARpcSession_free); | |
| ARpcSession_setFileDescriptorTransportMode(session.get(), | |
| ARpcSession_FileDescriptorTransportMode::Unix); | |
| ARpcSession_setMaxIncomingThreads(session.get(), VIRTMGR_THREADS); | |
| ARpcSession_setMaxOutgoingConnections(session.get(), VIRTMGR_THREADS); | |
| AIBinder* binder = ARpcSession_setupUnixDomainBootstrapClient(session.get(), fd); | |
| if (binder == nullptr) { | |
| return Error() << "Failed to connect to VirtualizationService"; | |
| } | |
| return IVirtualizationService::fromBinder(SpAIBinder{binder}); | |
| } | |
| Result<void> inner_fuzz(const uint8_t* data, size_t size) { | |
| unique_fd fd = OR_RETURN(get_service_fd()); | |
| std::shared_ptr<IVirtualizationService> service = OR_RETURN(connect_service(fd.get())); | |
| fuzzService(service->asBinder().get(), FuzzedDataProvider(data, size)); | |
| return {}; | |
| } | |
| extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) { | |
| if (auto ret = inner_fuzz(data, size); !ret.ok()) { | |
| std::cerr << "connecting to service failed: " << ret.error() << std::endl; | |
| abort(); | |
| } | |
| return 0; | |
| } |