Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 #include <linux/kvm.h>
0003 #include <linux/psp-sev.h>
0004 #include <stdio.h>
0005 #include <sys/ioctl.h>
0006 #include <stdlib.h>
0007 #include <errno.h>
0008 #include <pthread.h>
0009 
0010 #include "test_util.h"
0011 #include "kvm_util.h"
0012 #include "processor.h"
0013 #include "svm_util.h"
0014 #include "kselftest.h"
0015 
0016 #define SEV_POLICY_ES 0b100
0017 
0018 #define NR_MIGRATE_TEST_VCPUS 4
0019 #define NR_MIGRATE_TEST_VMS 3
0020 #define NR_LOCK_TESTING_THREADS 3
0021 #define NR_LOCK_TESTING_ITERATIONS 10000
0022 
0023 bool have_sev_es;
0024 
0025 static int __sev_ioctl(int vm_fd, int cmd_id, void *data, __u32 *fw_error)
0026 {
0027     struct kvm_sev_cmd cmd = {
0028         .id = cmd_id,
0029         .data = (uint64_t)data,
0030         .sev_fd = open_sev_dev_path_or_exit(),
0031     };
0032     int ret;
0033 
0034     ret = ioctl(vm_fd, KVM_MEMORY_ENCRYPT_OP, &cmd);
0035     *fw_error = cmd.error;
0036     return ret;
0037 }
0038 
0039 static void sev_ioctl(int vm_fd, int cmd_id, void *data)
0040 {
0041     int ret;
0042     __u32 fw_error;
0043 
0044     ret = __sev_ioctl(vm_fd, cmd_id, data, &fw_error);
0045     TEST_ASSERT(ret == 0 && fw_error == SEV_RET_SUCCESS,
0046             "%d failed: return code: %d, errno: %d, fw error: %d",
0047             cmd_id, ret, errno, fw_error);
0048 }
0049 
0050 static struct kvm_vm *sev_vm_create(bool es)
0051 {
0052     struct kvm_vm *vm;
0053     struct kvm_sev_launch_start start = { 0 };
0054     int i;
0055 
0056     vm = vm_create_barebones();
0057     sev_ioctl(vm->fd, es ? KVM_SEV_ES_INIT : KVM_SEV_INIT, NULL);
0058     for (i = 0; i < NR_MIGRATE_TEST_VCPUS; ++i)
0059         __vm_vcpu_add(vm, i);
0060     if (es)
0061         start.policy |= SEV_POLICY_ES;
0062     sev_ioctl(vm->fd, KVM_SEV_LAUNCH_START, &start);
0063     if (es)
0064         sev_ioctl(vm->fd, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL);
0065     return vm;
0066 }
0067 
0068 static struct kvm_vm *aux_vm_create(bool with_vcpus)
0069 {
0070     struct kvm_vm *vm;
0071     int i;
0072 
0073     vm = vm_create_barebones();
0074     if (!with_vcpus)
0075         return vm;
0076 
0077     for (i = 0; i < NR_MIGRATE_TEST_VCPUS; ++i)
0078         __vm_vcpu_add(vm, i);
0079 
0080     return vm;
0081 }
0082 
0083 static int __sev_migrate_from(struct kvm_vm *dst, struct kvm_vm *src)
0084 {
0085     return __vm_enable_cap(dst, KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM, src->fd);
0086 }
0087 
0088 
0089 static void sev_migrate_from(struct kvm_vm *dst, struct kvm_vm *src)
0090 {
0091     int ret;
0092 
0093     ret = __sev_migrate_from(dst, src);
0094     TEST_ASSERT(!ret, "Migration failed, ret: %d, errno: %d\n", ret, errno);
0095 }
0096 
0097 static void test_sev_migrate_from(bool es)
0098 {
0099     struct kvm_vm *src_vm;
0100     struct kvm_vm *dst_vms[NR_MIGRATE_TEST_VMS];
0101     int i, ret;
0102 
0103     src_vm = sev_vm_create(es);
0104     for (i = 0; i < NR_MIGRATE_TEST_VMS; ++i)
0105         dst_vms[i] = aux_vm_create(true);
0106 
0107     /* Initial migration from the src to the first dst. */
0108     sev_migrate_from(dst_vms[0], src_vm);
0109 
0110     for (i = 1; i < NR_MIGRATE_TEST_VMS; i++)
0111         sev_migrate_from(dst_vms[i], dst_vms[i - 1]);
0112 
0113     /* Migrate the guest back to the original VM. */
0114     ret = __sev_migrate_from(src_vm, dst_vms[NR_MIGRATE_TEST_VMS - 1]);
0115     TEST_ASSERT(ret == -1 && errno == EIO,
0116             "VM that was migrated from should be dead. ret %d, errno: %d\n", ret,
0117             errno);
0118 
0119     kvm_vm_free(src_vm);
0120     for (i = 0; i < NR_MIGRATE_TEST_VMS; ++i)
0121         kvm_vm_free(dst_vms[i]);
0122 }
0123 
0124 struct locking_thread_input {
0125     struct kvm_vm *vm;
0126     struct kvm_vm *source_vms[NR_LOCK_TESTING_THREADS];
0127 };
0128 
0129 static void *locking_test_thread(void *arg)
0130 {
0131     int i, j;
0132     struct locking_thread_input *input = (struct locking_thread_input *)arg;
0133 
0134     for (i = 0; i < NR_LOCK_TESTING_ITERATIONS; ++i) {
0135         j = i % NR_LOCK_TESTING_THREADS;
0136         __sev_migrate_from(input->vm, input->source_vms[j]);
0137     }
0138 
0139     return NULL;
0140 }
0141 
0142 static void test_sev_migrate_locking(void)
0143 {
0144     struct locking_thread_input input[NR_LOCK_TESTING_THREADS];
0145     pthread_t pt[NR_LOCK_TESTING_THREADS];
0146     int i;
0147 
0148     for (i = 0; i < NR_LOCK_TESTING_THREADS; ++i) {
0149         input[i].vm = sev_vm_create(/* es= */ false);
0150         input[0].source_vms[i] = input[i].vm;
0151     }
0152     for (i = 1; i < NR_LOCK_TESTING_THREADS; ++i)
0153         memcpy(input[i].source_vms, input[0].source_vms,
0154                sizeof(input[i].source_vms));
0155 
0156     for (i = 0; i < NR_LOCK_TESTING_THREADS; ++i)
0157         pthread_create(&pt[i], NULL, locking_test_thread, &input[i]);
0158 
0159     for (i = 0; i < NR_LOCK_TESTING_THREADS; ++i)
0160         pthread_join(pt[i], NULL);
0161     for (i = 0; i < NR_LOCK_TESTING_THREADS; ++i)
0162         kvm_vm_free(input[i].vm);
0163 }
0164 
0165 static void test_sev_migrate_parameters(void)
0166 {
0167     struct kvm_vm *sev_vm, *sev_es_vm, *vm_no_vcpu, *vm_no_sev,
0168         *sev_es_vm_no_vmsa;
0169     int ret;
0170 
0171     vm_no_vcpu = vm_create_barebones();
0172     vm_no_sev = aux_vm_create(true);
0173     ret = __sev_migrate_from(vm_no_vcpu, vm_no_sev);
0174     TEST_ASSERT(ret == -1 && errno == EINVAL,
0175             "Migrations require SEV enabled. ret %d, errno: %d\n", ret,
0176             errno);
0177 
0178     if (!have_sev_es)
0179         goto out;
0180 
0181     sev_vm = sev_vm_create(/* es= */ false);
0182     sev_es_vm = sev_vm_create(/* es= */ true);
0183     sev_es_vm_no_vmsa = vm_create_barebones();
0184     sev_ioctl(sev_es_vm_no_vmsa->fd, KVM_SEV_ES_INIT, NULL);
0185     __vm_vcpu_add(sev_es_vm_no_vmsa, 1);
0186 
0187     ret = __sev_migrate_from(sev_vm, sev_es_vm);
0188     TEST_ASSERT(
0189         ret == -1 && errno == EINVAL,
0190         "Should not be able migrate to SEV enabled VM. ret: %d, errno: %d\n",
0191         ret, errno);
0192 
0193     ret = __sev_migrate_from(sev_es_vm, sev_vm);
0194     TEST_ASSERT(
0195         ret == -1 && errno == EINVAL,
0196         "Should not be able migrate to SEV-ES enabled VM. ret: %d, errno: %d\n",
0197         ret, errno);
0198 
0199     ret = __sev_migrate_from(vm_no_vcpu, sev_es_vm);
0200     TEST_ASSERT(
0201         ret == -1 && errno == EINVAL,
0202         "SEV-ES migrations require same number of vCPUS. ret: %d, errno: %d\n",
0203         ret, errno);
0204 
0205     ret = __sev_migrate_from(vm_no_vcpu, sev_es_vm_no_vmsa);
0206     TEST_ASSERT(
0207         ret == -1 && errno == EINVAL,
0208         "SEV-ES migrations require UPDATE_VMSA. ret %d, errno: %d\n",
0209         ret, errno);
0210 
0211     kvm_vm_free(sev_vm);
0212     kvm_vm_free(sev_es_vm);
0213     kvm_vm_free(sev_es_vm_no_vmsa);
0214 out:
0215     kvm_vm_free(vm_no_vcpu);
0216     kvm_vm_free(vm_no_sev);
0217 }
0218 
0219 static int __sev_mirror_create(struct kvm_vm *dst, struct kvm_vm *src)
0220 {
0221     return __vm_enable_cap(dst, KVM_CAP_VM_COPY_ENC_CONTEXT_FROM, src->fd);
0222 }
0223 
0224 
0225 static void sev_mirror_create(struct kvm_vm *dst, struct kvm_vm *src)
0226 {
0227     int ret;
0228 
0229     ret = __sev_mirror_create(dst, src);
0230     TEST_ASSERT(!ret, "Copying context failed, ret: %d, errno: %d\n", ret, errno);
0231 }
0232 
0233 static void verify_mirror_allowed_cmds(int vm_fd)
0234 {
0235     struct kvm_sev_guest_status status;
0236 
0237     for (int cmd_id = KVM_SEV_INIT; cmd_id < KVM_SEV_NR_MAX; ++cmd_id) {
0238         int ret;
0239         __u32 fw_error;
0240 
0241         /*
0242          * These commands are allowed for mirror VMs, all others are
0243          * not.
0244          */
0245         switch (cmd_id) {
0246         case KVM_SEV_LAUNCH_UPDATE_VMSA:
0247         case KVM_SEV_GUEST_STATUS:
0248         case KVM_SEV_DBG_DECRYPT:
0249         case KVM_SEV_DBG_ENCRYPT:
0250             continue;
0251         default:
0252             break;
0253         }
0254 
0255         /*
0256          * These commands should be disallowed before the data
0257          * parameter is examined so NULL is OK here.
0258          */
0259         ret = __sev_ioctl(vm_fd, cmd_id, NULL, &fw_error);
0260         TEST_ASSERT(
0261             ret == -1 && errno == EINVAL,
0262             "Should not be able call command: %d. ret: %d, errno: %d\n",
0263             cmd_id, ret, errno);
0264     }
0265 
0266     sev_ioctl(vm_fd, KVM_SEV_GUEST_STATUS, &status);
0267 }
0268 
0269 static void test_sev_mirror(bool es)
0270 {
0271     struct kvm_vm *src_vm, *dst_vm;
0272     int i;
0273 
0274     src_vm = sev_vm_create(es);
0275     dst_vm = aux_vm_create(false);
0276 
0277     sev_mirror_create(dst_vm, src_vm);
0278 
0279     /* Check that we can complete creation of the mirror VM.  */
0280     for (i = 0; i < NR_MIGRATE_TEST_VCPUS; ++i)
0281         __vm_vcpu_add(dst_vm, i);
0282 
0283     if (es)
0284         sev_ioctl(dst_vm->fd, KVM_SEV_LAUNCH_UPDATE_VMSA, NULL);
0285 
0286     verify_mirror_allowed_cmds(dst_vm->fd);
0287 
0288     kvm_vm_free(src_vm);
0289     kvm_vm_free(dst_vm);
0290 }
0291 
0292 static void test_sev_mirror_parameters(void)
0293 {
0294     struct kvm_vm *sev_vm, *sev_es_vm, *vm_no_vcpu, *vm_with_vcpu;
0295     int ret;
0296 
0297     sev_vm = sev_vm_create(/* es= */ false);
0298     vm_with_vcpu = aux_vm_create(true);
0299     vm_no_vcpu = aux_vm_create(false);
0300 
0301     ret = __sev_mirror_create(sev_vm, sev_vm);
0302     TEST_ASSERT(
0303         ret == -1 && errno == EINVAL,
0304         "Should not be able copy context to self. ret: %d, errno: %d\n",
0305         ret, errno);
0306 
0307     ret = __sev_mirror_create(vm_no_vcpu, vm_with_vcpu);
0308     TEST_ASSERT(ret == -1 && errno == EINVAL,
0309             "Copy context requires SEV enabled. ret %d, errno: %d\n", ret,
0310             errno);
0311 
0312     ret = __sev_mirror_create(vm_with_vcpu, sev_vm);
0313     TEST_ASSERT(
0314         ret == -1 && errno == EINVAL,
0315         "SEV copy context requires no vCPUS on the destination. ret: %d, errno: %d\n",
0316         ret, errno);
0317 
0318     if (!have_sev_es)
0319         goto out;
0320 
0321     sev_es_vm = sev_vm_create(/* es= */ true);
0322     ret = __sev_mirror_create(sev_vm, sev_es_vm);
0323     TEST_ASSERT(
0324         ret == -1 && errno == EINVAL,
0325         "Should not be able copy context to SEV enabled VM. ret: %d, errno: %d\n",
0326         ret, errno);
0327 
0328     ret = __sev_mirror_create(sev_es_vm, sev_vm);
0329     TEST_ASSERT(
0330         ret == -1 && errno == EINVAL,
0331         "Should not be able copy context to SEV-ES enabled VM. ret: %d, errno: %d\n",
0332         ret, errno);
0333 
0334     kvm_vm_free(sev_es_vm);
0335 
0336 out:
0337     kvm_vm_free(sev_vm);
0338     kvm_vm_free(vm_with_vcpu);
0339     kvm_vm_free(vm_no_vcpu);
0340 }
0341 
0342 static void test_sev_move_copy(void)
0343 {
0344     struct kvm_vm *dst_vm, *dst2_vm, *dst3_vm, *sev_vm, *mirror_vm,
0345               *dst_mirror_vm, *dst2_mirror_vm, *dst3_mirror_vm;
0346 
0347     sev_vm = sev_vm_create(/* es= */ false);
0348     dst_vm = aux_vm_create(true);
0349     dst2_vm = aux_vm_create(true);
0350     dst3_vm = aux_vm_create(true);
0351     mirror_vm = aux_vm_create(false);
0352     dst_mirror_vm = aux_vm_create(false);
0353     dst2_mirror_vm = aux_vm_create(false);
0354     dst3_mirror_vm = aux_vm_create(false);
0355 
0356     sev_mirror_create(mirror_vm, sev_vm);
0357 
0358     sev_migrate_from(dst_mirror_vm, mirror_vm);
0359     sev_migrate_from(dst_vm, sev_vm);
0360 
0361     sev_migrate_from(dst2_vm, dst_vm);
0362     sev_migrate_from(dst2_mirror_vm, dst_mirror_vm);
0363 
0364     sev_migrate_from(dst3_mirror_vm, dst2_mirror_vm);
0365     sev_migrate_from(dst3_vm, dst2_vm);
0366 
0367     kvm_vm_free(dst_vm);
0368     kvm_vm_free(sev_vm);
0369     kvm_vm_free(dst2_vm);
0370     kvm_vm_free(dst3_vm);
0371     kvm_vm_free(mirror_vm);
0372     kvm_vm_free(dst_mirror_vm);
0373     kvm_vm_free(dst2_mirror_vm);
0374     kvm_vm_free(dst3_mirror_vm);
0375 
0376     /*
0377      * Run similar test be destroy mirrors before mirrored VMs to ensure
0378      * destruction is done safely.
0379      */
0380     sev_vm = sev_vm_create(/* es= */ false);
0381     dst_vm = aux_vm_create(true);
0382     mirror_vm = aux_vm_create(false);
0383     dst_mirror_vm = aux_vm_create(false);
0384 
0385     sev_mirror_create(mirror_vm, sev_vm);
0386 
0387     sev_migrate_from(dst_mirror_vm, mirror_vm);
0388     sev_migrate_from(dst_vm, sev_vm);
0389 
0390     kvm_vm_free(mirror_vm);
0391     kvm_vm_free(dst_mirror_vm);
0392     kvm_vm_free(dst_vm);
0393     kvm_vm_free(sev_vm);
0394 }
0395 
0396 int main(int argc, char *argv[])
0397 {
0398     TEST_REQUIRE(kvm_has_cap(KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM));
0399     TEST_REQUIRE(kvm_has_cap(KVM_CAP_VM_COPY_ENC_CONTEXT_FROM));
0400 
0401     TEST_REQUIRE(kvm_cpu_has(X86_FEATURE_SEV));
0402 
0403     have_sev_es = kvm_cpu_has(X86_FEATURE_SEV_ES);
0404 
0405     if (kvm_has_cap(KVM_CAP_VM_MOVE_ENC_CONTEXT_FROM)) {
0406         test_sev_migrate_from(/* es= */ false);
0407         if (have_sev_es)
0408             test_sev_migrate_from(/* es= */ true);
0409         test_sev_migrate_locking();
0410         test_sev_migrate_parameters();
0411         if (kvm_has_cap(KVM_CAP_VM_COPY_ENC_CONTEXT_FROM))
0412             test_sev_move_copy();
0413     }
0414     if (kvm_has_cap(KVM_CAP_VM_COPY_ENC_CONTEXT_FROM)) {
0415         test_sev_mirror(/* es= */ false);
0416         if (have_sev_es)
0417             test_sev_mirror(/* es= */ true);
0418         test_sev_mirror_parameters();
0419     }
0420     return 0;
0421 }