blob: 0fc451d6983b6050b512f9ed49358816c518e55f [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";
Jiyong Parkdcf17412022-02-08 15:07:23 +090051static constexpr const char kPlatformVersion[] = "~1.0";
David Brazdil49f8a4d2021-03-04 09:57:33 +000052
Andrew Walbran97aade02022-02-02 16:42:44 +000053/** Returns true if the kernel supports unprotected VMs. */
54bool isUnprotectedVmSupported() {
Andrew Walbran9d39f302022-02-02 17:51:43 +000055 return android::sysprop::HypervisorProperties::hypervisor_vm_supported().value_or(false);
Andrew Walbran3e73a092021-06-25 11:32:23 +000056}
Jiyong Parkdd4720b2021-06-25 13:05:50 +090057
Andrew Scull6ad03d82022-02-11 19:26:07 +000058TEST_F(VirtualizationTest, TestVsock) {
59 if (!isUnprotectedVmSupported()) {
60 GTEST_SKIP() << "Skipping as unprotected VMs are not supported on this device.";
Jiyong Parkaaf32f22021-08-30 19:11:19 +090061 }
62
David Brazdil49f8a4d2021-03-04 09:57:33 +000063 binder::Status status;
64
65 unique_fd server_fd(TEMP_FAILURE_RETRY(socket(AF_VSOCK, SOCK_STREAM, 0)));
66 ASSERT_GE(server_fd, 0) << strerror(errno);
67
68 struct sockaddr_vm server_sa = (struct sockaddr_vm){
69 .svm_family = AF_VSOCK,
70 .svm_port = kGuestPort,
71 .svm_cid = VMADDR_CID_ANY,
72 };
73
74 int ret = TEMP_FAILURE_RETRY(bind(server_fd, (struct sockaddr *)&server_sa, sizeof(server_sa)));
75 ASSERT_EQ(ret, 0) << strerror(errno);
76
77 LOG(INFO) << "Listening on port " << kGuestPort << "...";
78 ret = TEMP_FAILURE_RETRY(listen(server_fd, 1));
79 ASSERT_EQ(ret, 0) << strerror(errno);
80
Jooyung Han21e9b922021-06-26 04:14:16 +090081 VirtualMachineRawConfig raw_config;
82 raw_config.kernel = ParcelFileDescriptor(unique_fd(open(kVmKernelPath, O_RDONLY | O_CLOEXEC)));
83 raw_config.initrd = ParcelFileDescriptor(unique_fd(open(kVmInitrdPath, O_RDONLY | O_CLOEXEC)));
84 raw_config.params = kVmParams;
Andrew Scull6ad03d82022-02-11 19:26:07 +000085 raw_config.protectedVm = false;
Jiyong Parkdcf17412022-02-08 15:07:23 +090086 raw_config.platformVersion = kPlatformVersion;
Andrew Walbran3a5a9212021-05-04 17:09:08 +000087
Jooyung Han21e9b922021-06-26 04:14:16 +090088 VirtualMachineConfig config(std::move(raw_config));
David Brazdil49f8a4d2021-03-04 09:57:33 +000089 sp<IVirtualMachine> vm;
Andrew Scull6ad03d82022-02-11 19:26:07 +000090 status = mVirtualizationService->createVm(config, std::nullopt, std::nullopt, &vm);
Andrew Walbranf8d94112021-09-07 11:45:36 +000091 ASSERT_TRUE(status.isOk()) << "Error creating VM: " << status;
David Brazdil49f8a4d2021-03-04 09:57:33 +000092
93 int32_t cid;
94 status = vm->getCid(&cid);
95 ASSERT_TRUE(status.isOk()) << "Error getting CID: " << status;
96 LOG(INFO) << "VM starting with CID " << cid;
97
Andrew Walbranf8d94112021-09-07 11:45:36 +000098 status = vm->start();
99 ASSERT_TRUE(status.isOk()) << "Error starting VM: " << status;
100
David Brazdil49f8a4d2021-03-04 09:57:33 +0000101 LOG(INFO) << "Accepting connection...";
102 struct sockaddr_vm client_sa;
103 socklen_t client_sa_len = sizeof(client_sa);
104 unique_fd client_fd(
105 TEMP_FAILURE_RETRY(accept(server_fd, (struct sockaddr *)&client_sa, &client_sa_len)));
106 ASSERT_GE(client_fd, 0) << strerror(errno);
107 LOG(INFO) << "Connection from CID " << client_sa.svm_cid << " on port " << client_sa.svm_port;
108
109 LOG(INFO) << "Reading message from the client...";
110 std::string msg;
111 ASSERT_TRUE(ReadFdToString(client_fd, &msg));
112
113 LOG(INFO) << "Received message: " << msg;
114 ASSERT_EQ(msg, kTestMessage);
115}
116
Jiyong Parkdcf17412022-02-08 15:07:23 +0900117TEST_F(VirtualizationTest, RejectIncompatiblePlatformVersion) {
118 VirtualMachineRawConfig raw_config;
119 raw_config.kernel = ParcelFileDescriptor(unique_fd(open(kVmKernelPath, O_RDONLY | O_CLOEXEC)));
120 raw_config.initrd = ParcelFileDescriptor(unique_fd(open(kVmInitrdPath, O_RDONLY | O_CLOEXEC)));
121 raw_config.params = kVmParams;
122 raw_config.platformVersion = "~2.0"; // The current platform version is 1.0.0.
123
124 VirtualMachineConfig config(std::move(raw_config));
125 sp<IVirtualMachine> vm;
126 auto status = mVirtualizationService->createVm(config, std::nullopt, std::nullopt, &vm);
127 ASSERT_FALSE(status.isOk());
128}
129
David Brazdil49f8a4d2021-03-04 09:57:33 +0000130} // namespace virt