blob: 9550651f920bb18d6db53f004cfd257c7f21ad95 [file] [log] [blame]
David Brazdil49f8a4d2021-03-04 09:57:33 +00001/*
2 * Copyright (C) 2020 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
Andrew Walbran9d39f302022-02-02 17:51:43 +000017#include <android/sysprop/HypervisorProperties.sysprop.h>
Andrew Walbran3e73a092021-06-25 11:32:23 +000018#include <linux/kvm.h>
19#include <sys/ioctl.h>
David Brazdil49f8a4d2021-03-04 09:57:33 +000020#include <sys/socket.h>
21#include <unistd.h>
22
23// Needs to be included after sys/socket.h
24#include <linux/vm_sockets.h>
25
Jiyong Parkdd4720b2021-06-25 13:05:50 +090026#include <algorithm>
27#include <array>
David Brazdil49f8a4d2021-03-04 09:57:33 +000028#include <iostream>
Andrew Walbrana89fc132021-03-17 17:08:36 +000029#include <optional>
David Brazdil49f8a4d2021-03-04 09:57:33 +000030
31#include "android-base/file.h"
32#include "android-base/logging.h"
33#include "android-base/parseint.h"
34#include "android-base/unique_fd.h"
Andrew Walbranf6bf6862021-05-21 12:41:13 +000035#include "android/system/virtualizationservice/VirtualMachineConfig.h"
Jooyung Han21e9b922021-06-26 04:14:16 +090036#include "android/system/virtualizationservice/VirtualMachineRawConfig.h"
David Brazdil49f8a4d2021-03-04 09:57:33 +000037#include "virt/VirtualizationTest.h"
38
Andrew Walbran3e73a092021-06-25 11:32:23 +000039#define KVM_CAP_ARM_PROTECTED_VM 0xffbadab1
40
David Brazdil49f8a4d2021-03-04 09:57:33 +000041using namespace android::base;
Andrew Walbran06b5f5c2021-03-31 12:34:13 +000042using namespace android::os;
David Brazdil49f8a4d2021-03-04 09:57:33 +000043
44namespace virt {
45
46static constexpr int kGuestPort = 45678;
Andrew Walbran3a5a9212021-05-04 17:09:08 +000047static constexpr const char kVmKernelPath[] = "/data/local/tmp/virt-test/kernel";
48static constexpr const char kVmInitrdPath[] = "/data/local/tmp/virt-test/initramfs";
49static constexpr const char kVmParams[] = "rdinit=/bin/init bin/vsock_client 2 45678 HelloWorld";
David Brazdil49f8a4d2021-03-04 09:57:33 +000050static constexpr const char kTestMessage[] = "HelloWorld";
51
Andrew Walbran97aade02022-02-02 16:42:44 +000052/** Returns true if the kernel supports protected VMs. */
53bool isProtectedVmSupported() {
Andrew Walbran9d39f302022-02-02 17:51:43 +000054 return android::sysprop::HypervisorProperties::hypervisor_protected_vm_supported().value_or(
55 false);
Andrew Walbran97aade02022-02-02 16:42:44 +000056}
57
58/** Returns true if the kernel supports unprotected VMs. */
59bool isUnprotectedVmSupported() {
Andrew Walbran9d39f302022-02-02 17:51:43 +000060 return android::sysprop::HypervisorProperties::hypervisor_vm_supported().value_or(false);
Andrew Walbran3e73a092021-06-25 11:32:23 +000061}
Jiyong Parkdd4720b2021-06-25 13:05:50 +090062
Andrew Walbran3e73a092021-06-25 11:32:23 +000063void runTest(sp<IVirtualizationService> virtualization_service, bool protected_vm) {
Andrew Walbran97aade02022-02-02 16:42:44 +000064 if (protected_vm) {
65 if (!isProtectedVmSupported()) {
66 GTEST_SKIP() << "Skipping as protected VMs are not supported on this device.";
67 }
68 } else {
69 if (!isUnprotectedVmSupported()) {
70 GTEST_SKIP() << "Skipping as unprotected VMs are not supported on this device.";
71 }
Jiyong Parkaaf32f22021-08-30 19:11:19 +090072 }
73
David Brazdil49f8a4d2021-03-04 09:57:33 +000074 binder::Status status;
75
76 unique_fd server_fd(TEMP_FAILURE_RETRY(socket(AF_VSOCK, SOCK_STREAM, 0)));
77 ASSERT_GE(server_fd, 0) << strerror(errno);
78
79 struct sockaddr_vm server_sa = (struct sockaddr_vm){
80 .svm_family = AF_VSOCK,
81 .svm_port = kGuestPort,
82 .svm_cid = VMADDR_CID_ANY,
83 };
84
85 int ret = TEMP_FAILURE_RETRY(bind(server_fd, (struct sockaddr *)&server_sa, sizeof(server_sa)));
86 ASSERT_EQ(ret, 0) << strerror(errno);
87
88 LOG(INFO) << "Listening on port " << kGuestPort << "...";
89 ret = TEMP_FAILURE_RETRY(listen(server_fd, 1));
90 ASSERT_EQ(ret, 0) << strerror(errno);
91
Jooyung Han21e9b922021-06-26 04:14:16 +090092 VirtualMachineRawConfig raw_config;
93 raw_config.kernel = ParcelFileDescriptor(unique_fd(open(kVmKernelPath, O_RDONLY | O_CLOEXEC)));
94 raw_config.initrd = ParcelFileDescriptor(unique_fd(open(kVmInitrdPath, O_RDONLY | O_CLOEXEC)));
95 raw_config.params = kVmParams;
Andrew Walbrancc045902021-07-27 16:06:17 +000096 raw_config.protectedVm = protected_vm;
Andrew Walbran3a5a9212021-05-04 17:09:08 +000097
Jooyung Han21e9b922021-06-26 04:14:16 +090098 VirtualMachineConfig config(std::move(raw_config));
David Brazdil49f8a4d2021-03-04 09:57:33 +000099 sp<IVirtualMachine> vm;
Jiyong Parkb8182bb2021-10-26 22:53:08 +0900100 status = virtualization_service->createVm(config, std::nullopt, std::nullopt, &vm);
Andrew Walbranf8d94112021-09-07 11:45:36 +0000101 ASSERT_TRUE(status.isOk()) << "Error creating VM: " << status;
David Brazdil49f8a4d2021-03-04 09:57:33 +0000102
103 int32_t cid;
104 status = vm->getCid(&cid);
105 ASSERT_TRUE(status.isOk()) << "Error getting CID: " << status;
106 LOG(INFO) << "VM starting with CID " << cid;
107
Andrew Walbranf8d94112021-09-07 11:45:36 +0000108 status = vm->start();
109 ASSERT_TRUE(status.isOk()) << "Error starting VM: " << status;
110
David Brazdil49f8a4d2021-03-04 09:57:33 +0000111 LOG(INFO) << "Accepting connection...";
112 struct sockaddr_vm client_sa;
113 socklen_t client_sa_len = sizeof(client_sa);
114 unique_fd client_fd(
115 TEMP_FAILURE_RETRY(accept(server_fd, (struct sockaddr *)&client_sa, &client_sa_len)));
116 ASSERT_GE(client_fd, 0) << strerror(errno);
117 LOG(INFO) << "Connection from CID " << client_sa.svm_cid << " on port " << client_sa.svm_port;
118
119 LOG(INFO) << "Reading message from the client...";
120 std::string msg;
121 ASSERT_TRUE(ReadFdToString(client_fd, &msg));
122
123 LOG(INFO) << "Received message: " << msg;
124 ASSERT_EQ(msg, kTestMessage);
125}
126
Andrew Walbran3e73a092021-06-25 11:32:23 +0000127TEST_F(VirtualizationTest, TestVsock) {
Andrew Walbran3e73a092021-06-25 11:32:23 +0000128 runTest(mVirtualizationService, false);
129}
130
131TEST_F(VirtualizationTest, TestVsockProtected) {
Andrew Walbran3e73a092021-06-25 11:32:23 +0000132 runTest(mVirtualizationService, true);
133}
134
David Brazdil49f8a4d2021-03-04 09:57:33 +0000135} // namespace virt