blob: 14606607f1fdf2e301e003f2ad90db755fabda0f [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";
David Brazdil3cbface2022-07-19 22:18:28 +010051static constexpr const char kAckMessage[] = "ACK";
Jiyong Parkdcf17412022-02-08 15:07:23 +090052static constexpr const char kPlatformVersion[] = "~1.0";
David Brazdil49f8a4d2021-03-04 09:57:33 +000053
Andrew Walbran97aade02022-02-02 16:42:44 +000054/** Returns true if the kernel supports unprotected VMs. */
55bool isUnprotectedVmSupported() {
Andrew Walbran9d39f302022-02-02 17:51:43 +000056 return android::sysprop::HypervisorProperties::hypervisor_vm_supported().value_or(false);
Andrew Walbran3e73a092021-06-25 11:32:23 +000057}
Jiyong Parkdd4720b2021-06-25 13:05:50 +090058
Andrew Scull6ad03d82022-02-11 19:26:07 +000059TEST_F(VirtualizationTest, TestVsock) {
60 if (!isUnprotectedVmSupported()) {
61 GTEST_SKIP() << "Skipping as unprotected VMs are not supported on this device.";
Jiyong Parkaaf32f22021-08-30 19:11:19 +090062 }
63
David Brazdil49f8a4d2021-03-04 09:57:33 +000064 binder::Status status;
65
66 unique_fd server_fd(TEMP_FAILURE_RETRY(socket(AF_VSOCK, SOCK_STREAM, 0)));
67 ASSERT_GE(server_fd, 0) << strerror(errno);
68
69 struct sockaddr_vm server_sa = (struct sockaddr_vm){
70 .svm_family = AF_VSOCK,
71 .svm_port = kGuestPort,
72 .svm_cid = VMADDR_CID_ANY,
73 };
74
75 int ret = TEMP_FAILURE_RETRY(bind(server_fd, (struct sockaddr *)&server_sa, sizeof(server_sa)));
76 ASSERT_EQ(ret, 0) << strerror(errno);
77
78 LOG(INFO) << "Listening on port " << kGuestPort << "...";
79 ret = TEMP_FAILURE_RETRY(listen(server_fd, 1));
80 ASSERT_EQ(ret, 0) << strerror(errno);
81
Jooyung Han21e9b922021-06-26 04:14:16 +090082 VirtualMachineRawConfig raw_config;
83 raw_config.kernel = ParcelFileDescriptor(unique_fd(open(kVmKernelPath, O_RDONLY | O_CLOEXEC)));
84 raw_config.initrd = ParcelFileDescriptor(unique_fd(open(kVmInitrdPath, O_RDONLY | O_CLOEXEC)));
85 raw_config.params = kVmParams;
Andrew Scull6ad03d82022-02-11 19:26:07 +000086 raw_config.protectedVm = false;
Jiyong Parkdcf17412022-02-08 15:07:23 +090087 raw_config.platformVersion = kPlatformVersion;
Andrew Walbran3a5a9212021-05-04 17:09:08 +000088
Jooyung Han21e9b922021-06-26 04:14:16 +090089 VirtualMachineConfig config(std::move(raw_config));
David Brazdil49f8a4d2021-03-04 09:57:33 +000090 sp<IVirtualMachine> vm;
Andrew Scull6ad03d82022-02-11 19:26:07 +000091 status = mVirtualizationService->createVm(config, std::nullopt, std::nullopt, &vm);
Andrew Walbranf8d94112021-09-07 11:45:36 +000092 ASSERT_TRUE(status.isOk()) << "Error creating VM: " << status;
David Brazdil49f8a4d2021-03-04 09:57:33 +000093
94 int32_t cid;
95 status = vm->getCid(&cid);
96 ASSERT_TRUE(status.isOk()) << "Error getting CID: " << status;
97 LOG(INFO) << "VM starting with CID " << cid;
98
Andrew Walbranf8d94112021-09-07 11:45:36 +000099 status = vm->start();
100 ASSERT_TRUE(status.isOk()) << "Error starting VM: " << status;
101
David Brazdil49f8a4d2021-03-04 09:57:33 +0000102 LOG(INFO) << "Accepting connection...";
103 struct sockaddr_vm client_sa;
104 socklen_t client_sa_len = sizeof(client_sa);
105 unique_fd client_fd(
106 TEMP_FAILURE_RETRY(accept(server_fd, (struct sockaddr *)&client_sa, &client_sa_len)));
107 ASSERT_GE(client_fd, 0) << strerror(errno);
108 LOG(INFO) << "Connection from CID " << client_sa.svm_cid << " on port " << client_sa.svm_port;
109
110 LOG(INFO) << "Reading message from the client...";
111 std::string msg;
David Brazdil3cbface2022-07-19 22:18:28 +0100112 ASSERT_TRUE(ReadFdToString(client_fd, &msg)) << strerror(errno);
David Brazdil49f8a4d2021-03-04 09:57:33 +0000113 LOG(INFO) << "Received message: " << msg;
David Brazdil3cbface2022-07-19 22:18:28 +0100114
115 // The client is waiting for a response to signal it can shut down.
116 LOG(INFO) << "Replying with '" << kAckMessage << "'...";
117 ASSERT_TRUE(WriteStringToFd(kAckMessage, client_fd));
118
David Brazdil49f8a4d2021-03-04 09:57:33 +0000119 ASSERT_EQ(msg, kTestMessage);
120}
121
Jiyong Parkdcf17412022-02-08 15:07:23 +0900122TEST_F(VirtualizationTest, RejectIncompatiblePlatformVersion) {
123 VirtualMachineRawConfig raw_config;
124 raw_config.kernel = ParcelFileDescriptor(unique_fd(open(kVmKernelPath, O_RDONLY | O_CLOEXEC)));
125 raw_config.initrd = ParcelFileDescriptor(unique_fd(open(kVmInitrdPath, O_RDONLY | O_CLOEXEC)));
126 raw_config.params = kVmParams;
127 raw_config.platformVersion = "~2.0"; // The current platform version is 1.0.0.
128
129 VirtualMachineConfig config(std::move(raw_config));
130 sp<IVirtualMachine> vm;
131 auto status = mVirtualizationService->createVm(config, std::nullopt, std::nullopt, &vm);
132 ASSERT_FALSE(status.isOk());
133}
134
David Brazdil49f8a4d2021-03-04 09:57:33 +0000135} // namespace virt