Add virtualizationmanager fuzzer
Bug: 294158658
Test: run fuzzer
Change-Id: Ie5360c7e21b816079f0de16b19dc756cb4952cae
diff --git a/virtualizationmanager/Android.bp b/virtualizationmanager/Android.bp
index d8f8209..d1ef4de 100644
--- a/virtualizationmanager/Android.bp
+++ b/virtualizationmanager/Android.bp
@@ -100,3 +100,21 @@
],
test_suites: ["general-tests"],
}
+
+cc_fuzz {
+ name: "virtualizationmanager_fuzzer",
+ defaults: ["service_fuzzer_defaults"],
+ srcs: ["fuzzer.cpp"],
+ static_libs: [
+ "android.system.virtualizationservice-ndk",
+ "libbase",
+ ],
+ shared_libs: [
+ "libbinder_ndk",
+ "libbinder_rpc_unstable",
+ "liblog",
+ ],
+ fuzz_config: {
+ cc: ["android-kvm@google.com"],
+ },
+}
diff --git a/virtualizationmanager/fuzzer.cpp b/virtualizationmanager/fuzzer.cpp
new file mode 100644
index 0000000..6afea46
--- /dev/null
+++ b/virtualizationmanager/fuzzer.cpp
@@ -0,0 +1,106 @@
+/*
+ * 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;
+}