sgx_capable.cpp 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376
  1. /*
  2. * Copyright (C) 2011-2018 Intel Corporation. All rights reserved.
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * * Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * * Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in
  12. * the documentation and/or other materials provided with the
  13. * distribution.
  14. * * Neither the name of Intel Corporation nor the names of its
  15. * contributors may be used to endorse or promote products derived
  16. * from this software without specific prior written permission.
  17. *
  18. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  19. * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  20. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  21. * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  22. * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  23. * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  24. * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  25. * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  26. * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  27. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  28. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  29. *
  30. */
  31. #include <sys/stat.h>
  32. #include <sys/types.h>
  33. #include <stdio.h>
  34. #include <memory.h>
  35. #include <unistd.h>
  36. #include <errno.h>
  37. #include <sgx_uae_service.h>
  38. #include <sgx_capable.h>
  39. #include "se_cdefs.h"
  40. SGX_ACCESS_VERSION(capable, 1);
  41. /* __cpuid(unsinged int info[4], unsigned int leaf, unsigned int subleaf); */
  42. /* Because gcc's __get_cpuid() intrinsic is difficult to work with */
  43. #define __cpuid(x,y,z) asm volatile("cpuid":"=a"(x[0]),"=b"(x[1]),"=c"(x[2]),"=d"(x[3]):"a"(y),"c"(z))
  44. #define Genu 0x756e6547
  45. #define ineI 0x49656e69
  46. #define ntel 0x6c65746e
  47. #define EFIFS_PATH "/sys/firmware/efi/"
  48. #define EFIVARS_PATH EFIFS_PATH"efivars/"
  49. #define EFIVAR_EPCBIOS EFIVARS_PATH"EPCBIOS-c60aa7f6-e8d6-4956-8ba1-fe26298f5e87"
  50. #define EFIVAR_EPCSW EFIVARS_PATH"EPCSW-d69a279b-58eb-45d1-a148-771bb9eb5251"
  51. static int _is_sgx_available();
  52. static int _is_cpu_supported();
  53. sgx_status_t sgx_is_capable (int *sgx_capable)
  54. {
  55. struct stat sb;
  56. memset(&sb, 0, sizeof(struct stat));
  57. if ( sgx_capable == NULL ) return SGX_ERROR_INVALID_PARAMETER;
  58. if ( ! _is_cpu_supported() ) {
  59. *sgx_capable= 0;
  60. return SGX_SUCCESS;
  61. }
  62. if ( _is_sgx_available() ) {
  63. *sgx_capable= 1;
  64. return SGX_SUCCESS;
  65. }
  66. /* Check to see if the Software Control Interface is available */
  67. if ( stat(EFIVAR_EPCBIOS, &sb) == -1 ) {
  68. if ( errno == EACCES ) return SGX_ERROR_NO_PRIVILEGE;
  69. *sgx_capable = 0;
  70. return SGX_SUCCESS;
  71. }
  72. *sgx_capable= 1;
  73. return SGX_SUCCESS;
  74. }
  75. sgx_status_t sgx_cap_get_status (sgx_device_status_t *sgx_device_status)
  76. {
  77. struct stat sb;
  78. int has_efifs= 0;
  79. memset(&sb, 0, sizeof(struct stat));
  80. if ( sgx_device_status == NULL ) return SGX_ERROR_INVALID_PARAMETER;
  81. if ( ! _is_cpu_supported() ) {
  82. *sgx_device_status= SGX_DISABLED_UNSUPPORTED_CPU;
  83. return SGX_SUCCESS;
  84. }
  85. if ( _is_sgx_available() ) {
  86. *sgx_device_status= SGX_ENABLED;
  87. return SGX_SUCCESS;
  88. }
  89. /*
  90. * Intel SGX is supported, but not enabled. Figure out what
  91. * it will take to enable it.
  92. */
  93. /* Were we booted in UEFI mode? */
  94. if ( stat(EFIFS_PATH, &sb) == 0 ) {
  95. has_efifs= 1;
  96. if ( stat(EFIVARS_PATH, &sb) == -1 )
  97. {
  98. /* We have /sys/firmware/efi but not efivars */
  99. switch (errno) {
  100. case EACCES:
  101. return SGX_ERROR_NO_PRIVILEGE;
  102. case ENOENT:
  103. case ENOTDIR:
  104. break;
  105. default:
  106. return SGX_ERROR_UNEXPECTED;
  107. }
  108. }
  109. } else {
  110. switch (errno) {
  111. case EACCES:
  112. return SGX_ERROR_NO_PRIVILEGE;
  113. case ENOENT:
  114. case ENOTDIR:
  115. break;
  116. default:
  117. return SGX_ERROR_UNEXPECTED;
  118. }
  119. }
  120. if ( ! has_efifs ) {
  121. /*
  122. * We don't have /sys/firmware/efi mounted. It could have been
  123. * unmounted by the user, or we might not have UEFI support in
  124. * the OS. If /boot/efi exists, then we are probably capable of
  125. * UEFI and should report SGX_DISABLED. Otherwise report
  126. * SGX_DISABLED_LEGACY_OS.
  127. */
  128. if ( stat("/boot/efi", &sb) == 0 ) *sgx_device_status= SGX_DISABLED;
  129. else {
  130. switch(errno) {
  131. case ENOENT:
  132. case ENOTDIR:
  133. *sgx_device_status= SGX_DISABLED_LEGACY_OS;
  134. break;
  135. default:
  136. /*
  137. * We don't have enough information to figure this out
  138. * so report SGX_DISABLED.
  139. */
  140. *sgx_device_status= SGX_DISABLED;
  141. }
  142. }
  143. return SGX_SUCCESS;
  144. }
  145. /*
  146. * We have access to efivars. Now examine the EFI variable for the
  147. * Software Control Interface.
  148. */
  149. if ( stat(EFIVAR_EPCBIOS, &sb) == -1 ) {
  150. if ( errno == EACCES ) return SGX_ERROR_NO_PRIVILEGE;
  151. /* No SCI is present so we can't do a s/w enabled */
  152. *sgx_device_status= SGX_DISABLED_MANUAL_ENABLE;
  153. return SGX_SUCCESS;
  154. }
  155. /*
  156. * Check to see if the software enable has already been
  157. * performed. If so, then we will be enabled on the next
  158. * reboot.
  159. */
  160. if ( stat(EFIVAR_EPCSW, &sb) == -1 ) {
  161. if ( errno == EACCES ) return SGX_ERROR_NO_PRIVILEGE;
  162. /* The software enable hasn't been attempted yet. */
  163. *sgx_device_status= SGX_DISABLED_SCI_AVAILABLE;
  164. return SGX_SUCCESS;
  165. }
  166. /* Software enable has occurred. Need a reboot. */
  167. *sgx_device_status= SGX_DISABLED_REBOOT_REQUIRED;
  168. return SGX_SUCCESS;
  169. }
  170. /* Determine if the CPU supports Intel SGX */
  171. static int _is_cpu_supported()
  172. {
  173. unsigned int info[4] = {0, 0, 0, 0};
  174. unsigned int *ebx, *ecx, *edx;
  175. ebx= &info[1];
  176. ecx= &info[2];
  177. edx= &info[3];
  178. /* Is this an Intel CPU? */
  179. __cpuid (info, 0x00, 0);
  180. if ( *ebx != Genu || *ecx != ntel || *edx != ineI )
  181. return 0;
  182. /* Does the CPU support Intel SGX? */
  183. __cpuid (info, 0x07, 0);
  184. return ( *ebx & (0x1<<2) );
  185. }
  186. /* Are SGX instructions available for use? */
  187. static int _is_sgx_available ()
  188. {
  189. unsigned int info[4] = {0, 0, 0, 0};
  190. unsigned int *eax, *ebx, *ecx, *edx;
  191. unsigned int subleaf= 2;
  192. unsigned int flag;
  193. eax= &info[0];
  194. ebx= &info[1];
  195. ecx= &info[2];
  196. edx= &info[3];
  197. /* Are Intel SGX instructions available for use? */
  198. __cpuid(info, 0x12, 0);
  199. flag= *eax&0x3;
  200. if ( flag == 0 ) return 0;
  201. /* Do we have non-zero, max enclave sizes? */
  202. if ( (*edx & 0xFFFF) == 0 ) return 0;
  203. /*
  204. * Enumerate the subleafs for the EPC. At least one must be a valid
  205. * subleaf that describes a page.
  206. */
  207. while (1) {
  208. __cpuid(info, 0x12, subleaf);
  209. /*
  210. * Is this an invalid subleaf? If we've hit an invalid subleaf
  211. * before finding a valid subleaf with a non-zero page size,
  212. * then we have no EPC memory allocated, and thus no Intel SGX
  213. * capability.
  214. */
  215. if ( ! (*eax & 0x1) ) return 0;
  216. /*
  217. * Is there a non-zero size for this EPC subleaf? If so, we
  218. * have memory allocated to the EPC for Intel SGX, and are
  219. * enabled.
  220. */
  221. if (
  222. (*eax&0xFFFFF000 || *ebx&0xFFFFF) &&
  223. (*ecx&0xFFFFF000 || *edx&0xFFFFF)
  224. ) return 1;
  225. ++subleaf;
  226. }
  227. /* We'll never get here, but we need to keep the compiler happy */
  228. return 0;
  229. }
  230. sgx_status_t sgx_cap_enable_device (sgx_device_status_t *sgx_device_status)
  231. {
  232. sgx_status_t status;
  233. struct epcbios_stuct {
  234. uint32_t attrs;
  235. uint32_t sprmbins;
  236. uint32_t maxepcsz;
  237. /* There's more, but this is all we need */
  238. } epcbios;
  239. struct epcsw_struct {
  240. uint32_t attrs;
  241. uint32_t maxepcsz;
  242. } epcsw;
  243. FILE *fefivar;
  244. if ( sgx_device_status == NULL ) return SGX_ERROR_INVALID_PARAMETER;
  245. status= sgx_cap_get_status(sgx_device_status);
  246. if ( status != SGX_SUCCESS ) return status;
  247. /*
  248. * If we get back anything other than SGX_DISABLED_SCI_AVAILABLE
  249. * then return, because there is nothing to do.
  250. */
  251. if ( *sgx_device_status != SGX_DISABLED_SCI_AVAILABLE )
  252. return SGX_SUCCESS;
  253. /* Attempt the software enable */
  254. /* First, read the EPCBIOS EFI variable to get the max EPC size */
  255. fefivar= fopen(EFIVAR_EPCBIOS, "r");
  256. if ( fefivar == NULL ) {
  257. if ( errno == EACCES ) return SGX_ERROR_NO_PRIVILEGE;
  258. return SGX_ERROR_UNEXPECTED;
  259. }
  260. /*
  261. * The first 4 bytes are the EFI variable attributes. Data starts
  262. * at offset 0x4, and the value we want is a UINT32 at offset 0x8.
  263. */
  264. if ( fread(&epcbios, sizeof(epcbios), 1, fefivar) != 1 ) {
  265. fclose(fefivar);
  266. return SGX_ERROR_UNEXPECTED;
  267. }
  268. if ( fclose(fefivar)) {
  269. return SGX_ERROR_UNEXPECTED;
  270. }
  271. /*
  272. * Now create the EPCSW EFI variable. The variable data is a
  273. * single UINT32 specifying the requested EPC size.
  274. */
  275. epcsw.attrs= epcbios.attrs;
  276. epcsw.maxepcsz= epcbios.maxepcsz;
  277. fefivar= fopen(EFIVAR_EPCSW, "w");
  278. if ( fefivar == NULL ) {
  279. if ( errno == EACCES ) return SGX_ERROR_NO_PRIVILEGE;
  280. return SGX_ERROR_UNEXPECTED;
  281. }
  282. /* Write out the EPCSW structure */
  283. if ( fwrite(&epcsw, sizeof(epcsw), 1, fefivar) != 1 ) {
  284. unlink(EFIVAR_EPCSW);
  285. fclose(fefivar);
  286. return SGX_ERROR_UNEXPECTED;
  287. }
  288. if ( fclose(fefivar)) {
  289. return SGX_ERROR_UNEXPECTED;
  290. }
  291. *sgx_device_status= SGX_DISABLED_REBOOT_REQUIRED;
  292. return SGX_SUCCESS;
  293. }