1
0

plugin_enable_cap.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323
  1. /*
  2. * Copyright 2020 The ChromiumOS Authors
  3. * Use of this source code is governed by a BSD-style license that can be
  4. * found in the LICENSE file.
  5. */
  6. #include <errno.h>
  7. #include <fcntl.h>
  8. #include <linux/kvm.h>
  9. #include <linux/memfd.h>
  10. #include <stdint.h>
  11. #include <stdio.h>
  12. #include <stdlib.h>
  13. #include <string.h>
  14. #include <sys/mman.h>
  15. #include <sys/syscall.h>
  16. #include <unistd.h>
  17. #include "crosvm.h"
  18. #define KILL_ADDRESS 0x3f9
  19. #ifndef F_LINUX_SPECIFIC_BASE
  20. #define F_LINUX_SPECIFIC_BASE 1024
  21. #endif
  22. #ifndef F_ADD_SEALS
  23. #define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
  24. #endif
  25. #ifndef F_SEAL_SHRINK
  26. #define F_SEAL_SHRINK 0x0002
  27. #endif
  28. const uint8_t code[] = {
  29. // Set a non-zero value for HV_X64_MSR_GUEST_OS_ID
  30. // to enable hypercalls.
  31. // mov edx, 0xffffffff
  32. 0x66, 0xba, 0xff, 0xff, 0xff, 0xff,
  33. // mov eax, 0xffffffff
  34. 0x66, 0xb8, 0xff, 0xff, 0xff, 0xff,
  35. // mov ecx, 0x40000000 # HV_X64_MSR_GUEST_OS_ID
  36. 0x66, 0xb9, 0x00, 0x00, 0x00, 0x40,
  37. // wrmsr
  38. 0x0f, 0x30,
  39. // Establish page at 0x2000 as the hypercall page.
  40. // mov edx, 0x00000000
  41. 0x66, 0xba, 0x00, 0x00, 0x00, 0x00,
  42. // mov eax, 0x00002001 # lowest bit is enable bit
  43. 0x66, 0xb8, 0x01, 0x20, 0x00, 0x00,
  44. // mov ecx, 0x40000001 # HV_X64_MSR_HYPERCALL
  45. 0x66, 0xb9, 0x01, 0x00, 0x00, 0x40,
  46. // wrmsr
  47. 0x0f, 0x30,
  48. // We can't test generic hypercalls since they're
  49. // defined to UD for processors running in real mode.
  50. // for HV_X64_MSR_CONTROL:
  51. // edx:eax gets transferred as 'control'
  52. // mov edx, 0x05060708
  53. 0x66, 0xba, 0x08, 0x07, 0x06, 0x05,
  54. // mov eax, 0x01020304
  55. 0x66, 0xb8, 0x04, 0x03, 0x02, 0x01,
  56. // mov ecx, 0x40000080 # HV_X64_MSR_SCONTROL
  57. 0x66, 0xb9, 0x80, 0x00, 0x00, 0x40,
  58. // wrmsr
  59. 0x0f, 0x30,
  60. // Establish page at 0x3000 as the evt_page.
  61. // mov edx, 0x00000000
  62. 0x66, 0xba, 0x00, 0x00, 0x00, 0x00,
  63. // mov eax, 0x00003000
  64. 0x66, 0xb8, 0x00, 0x30, 0x00, 0x00,
  65. // mov ecx, 0x40000082 # HV_X64_MSR_SIEFP
  66. 0x66, 0xb9, 0x82, 0x00, 0x00, 0x40,
  67. // wrmsr
  68. 0x0f, 0x30,
  69. // Establish page at 0x4000 as the 'msg_page'.
  70. // mov edx, 0x00000000
  71. 0x66, 0xba, 0x00, 0x00, 0x00, 0x00,
  72. // mov eax, 0x00004000
  73. 0x66, 0xb8, 0x00, 0x40, 0x00, 0x00,
  74. // mov ecx, 0x40000083 # HV_X64_MSR_SIMP
  75. 0x66, 0xb9, 0x83, 0x00, 0x00, 0x40,
  76. // wrmsr
  77. 0x0f, 0x30,
  78. // Request a kill.
  79. // mov dx, 0x3f9
  80. 0xba, 0xf9, 0x03,
  81. // mov al, 0x1
  82. 0xb0, 0x01,
  83. // out dx, al
  84. 0xee,
  85. // hlt
  86. 0xf4
  87. };
  88. int check_synic_access(struct crosvm_vcpu* vcpu, struct crosvm_vcpu_event *evt,
  89. uint32_t msr, uint64_t control, uint64_t evt_page,
  90. uint64_t msg_page, const char *phase) {
  91. if (evt->kind != CROSVM_VCPU_EVENT_KIND_HYPERV_SYNIC) {
  92. fprintf(stderr, "Got incorrect exit type before %s: %d\n", phase,
  93. evt->kind);
  94. return 1;
  95. }
  96. if (evt->hyperv_synic.msr != msr ||
  97. evt->hyperv_synic._reserved != 0 ||
  98. evt->hyperv_synic.control != control ||
  99. evt->hyperv_synic.evt_page != evt_page ||
  100. evt->hyperv_synic.msg_page != msg_page) {
  101. fprintf(stderr, "Got unexpected synic message after %s: "
  102. "0x%x vs 0x%x, 0x%lx vs 0x%lx, 0x%lx vs 0x%lx, "
  103. "0x%lx vs 0x%lx\n",
  104. phase, msr, evt->hyperv_synic.msr,
  105. control, evt->hyperv_synic.control,
  106. evt_page, evt->hyperv_synic.evt_page,
  107. msg_page, evt->hyperv_synic.msg_page);
  108. return 1;
  109. }
  110. if (crosvm_vcpu_resume(vcpu) != 0) {
  111. fprintf(stderr, "Failed to resume after %s\n", phase);
  112. return 1;
  113. }
  114. if (crosvm_vcpu_wait(vcpu, evt) != 0) {
  115. fprintf(stderr, "Failed to wait after %s\n", phase);
  116. return 1;
  117. }
  118. return 0;
  119. }
  120. int main(int argc, char** argv) {
  121. struct crosvm* crosvm = NULL;
  122. uint64_t cap_args[4] = {0};
  123. int ret = crosvm_connect(&crosvm);
  124. if (ret) {
  125. fprintf(stderr, "failed to connect to crosvm: %d\n", ret);
  126. return 1;
  127. }
  128. ret = crosvm_reserve_range(crosvm, CROSVM_ADDRESS_SPACE_IOPORT,
  129. KILL_ADDRESS, 1);
  130. if (ret) {
  131. fprintf(stderr, "failed to reserve kill port: %d\n", ret);
  132. return 1;
  133. }
  134. // VM mem layout:
  135. // null page, code page, hypercall page, synic evt_page, synic msg_page
  136. int mem_size = 0x4000;
  137. int mem_fd = syscall(SYS_memfd_create, "guest_mem",
  138. MFD_CLOEXEC | MFD_ALLOW_SEALING);
  139. if (mem_fd < 0) {
  140. fprintf(stderr, "failed to create guest memfd: %d\n", errno);
  141. return 1;
  142. }
  143. ret = ftruncate(mem_fd, mem_size);
  144. if (ret) {
  145. fprintf(stderr, "failed to set size of guest memory: %d\n", errno);
  146. return 1;
  147. }
  148. uint8_t *mem = mmap(NULL, mem_size, PROT_READ | PROT_WRITE, MAP_SHARED,
  149. mem_fd, 0x0);
  150. if (mem == MAP_FAILED) {
  151. fprintf(stderr, "failed to mmap guest memory: %d\n", errno);
  152. return 1;
  153. }
  154. fcntl(mem_fd, F_ADD_SEALS, F_SEAL_SHRINK);
  155. memcpy(mem, code, sizeof(code));
  156. // Before MSR verify hypercall page is zero
  157. int i;
  158. for (i = 0; i < 5; ++i) {
  159. if (mem[0x1000 + i]) {
  160. fprintf(stderr, "Hypercall page isn't zero\n");
  161. return 1;
  162. }
  163. }
  164. struct crosvm_memory *mem_obj;
  165. ret = crosvm_create_memory(crosvm, mem_fd, 0x0, mem_size, 0x1000,
  166. false, false, &mem_obj);
  167. if (ret) {
  168. fprintf(stderr, "failed to create memory in crosvm: %d\n", ret);
  169. return 1;
  170. }
  171. struct crosvm_vcpu* vcpu = NULL;
  172. ret = crosvm_get_vcpu(crosvm, 0, &vcpu);
  173. if (ret) {
  174. fprintf(stderr, "failed to get vcpu #0: %d\n", ret);
  175. return 1;
  176. }
  177. ret = crosvm_start(crosvm);
  178. if (ret) {
  179. fprintf(stderr, "failed to start vm: %d\n", ret);
  180. return 1;
  181. }
  182. struct crosvm_vcpu_event evt = {0};
  183. ret = crosvm_vcpu_wait(vcpu, &evt);
  184. if (ret) {
  185. fprintf(stderr, "failed to wait for vm start: %d\n", ret);
  186. return 1;
  187. }
  188. if (evt.kind != CROSVM_VCPU_EVENT_KIND_INIT) {
  189. fprintf(stderr, "Got unexpected exit type: %d\n", evt.kind);
  190. return 1;
  191. }
  192. ret = crosvm_enable_capability(crosvm, 0, 0, cap_args);
  193. if (ret != -EINVAL) {
  194. fprintf(stderr, "Unexpected crosvm_enable_capability result: %d\n",
  195. ret);
  196. return 1;
  197. }
  198. ret = crosvm_vcpu_enable_capability(vcpu, KVM_CAP_HYPERV_SYNIC, 0,
  199. cap_args);
  200. if (ret) {
  201. fprintf(stderr, "crosvm_vcpu_enable_capability() failed: %d\n", ret);
  202. return 1;
  203. }
  204. {
  205. struct kvm_sregs sregs = {0};
  206. crosvm_vcpu_get_sregs(vcpu, &sregs);
  207. sregs.cs.base = 0;
  208. sregs.cs.selector = 0;
  209. sregs.es.base = 0;
  210. sregs.es.selector = 0;
  211. crosvm_vcpu_set_sregs(vcpu, &sregs);
  212. struct kvm_regs regs = {0};
  213. crosvm_vcpu_get_regs(vcpu, &regs);
  214. regs.rip = 0x1000;
  215. regs.rflags = 2;
  216. crosvm_vcpu_set_regs(vcpu, &regs);
  217. }
  218. if (crosvm_vcpu_resume(vcpu) != 0) {
  219. fprintf(stderr, "Failed to resume after init\n");
  220. return 1;
  221. }
  222. if (crosvm_vcpu_wait(vcpu, &evt) != 0) {
  223. fprintf(stderr, "Failed to wait after init\n");
  224. return 1;
  225. }
  226. if (check_synic_access(vcpu, &evt, 0x40000080, 0x506070801020304, 0, 0,
  227. "synic msg #1")) {
  228. return 1;
  229. }
  230. // After first MSR verify hypercall page is non-zero
  231. uint8_t value = 0;
  232. for (i = 0; i < 5; ++i) {
  233. value |= mem[0x1000+i];
  234. }
  235. if (value == 0) {
  236. fprintf(stderr, "Hypercall page is still zero\n");
  237. return 1;
  238. }
  239. if (check_synic_access(vcpu, &evt, 0x40000082, 0x506070801020304, 0x3000,
  240. 0, "synic msg #2")) {
  241. return 1;
  242. }
  243. if (check_synic_access(vcpu, &evt, 0x40000083, 0x506070801020304, 0x3000,
  244. 0x4000, "synic msg #3")) {
  245. return 1;
  246. }
  247. if (evt.kind != CROSVM_VCPU_EVENT_KIND_IO_ACCESS) {
  248. fprintf(stderr, "Got incorrect exit type after synic #3: %d\n",
  249. evt.kind);
  250. return 1;
  251. }
  252. if (evt.io_access.address_space != CROSVM_ADDRESS_SPACE_IOPORT ||
  253. evt.io_access.address != KILL_ADDRESS ||
  254. !evt.io_access.is_write ||
  255. evt.io_access.length != 1 ||
  256. evt.io_access.data[0] != 1) {
  257. fprintf(stderr, "Didn't see kill request from VM\n");
  258. return 1;
  259. }
  260. fprintf(stderr, "Saw kill request from VM, exiting\n");
  261. return 0;
  262. }