db_process.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483
  1. /* -*- mode:c; c-file-style:"k&r"; c-basic-offset: 4; tab-width:4; indent-tabs-mode:nil; mode:auto-fill; fill-column:78; -*- */
  2. /* vim: set ts=4 sw=4 et tw=78 fo=cqt wm=0: */
  3. /* Copyright (C) 2014 Stony Brook University
  4. This file is part of Graphene Library OS.
  5. Graphene Library OS is free software: you can redistribute it and/or
  6. modify it under the terms of the GNU Lesser General Public License
  7. as published by the Free Software Foundation, either version 3 of the
  8. License, or (at your option) any later version.
  9. Graphene Library OS is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. GNU Lesser General Public License for more details.
  13. You should have received a copy of the GNU Lesser General Public License
  14. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  15. /*
  16. * db_process.c
  17. *
  18. * This source file contains functions to create a child process and terminate
  19. * the running process. Child does not inherit any objects or memory from its
  20. * parent pricess. A Parent process may not modify the execution of its
  21. * children. It can wait for a child to exit using its handle. Also, parent and
  22. * child may communicate through I/O streams provided by the parent to the child
  23. * at creation.
  24. */
  25. #include "pal_defs.h"
  26. #include "pal_linux_defs.h"
  27. #include "pal.h"
  28. #include "pal_internal.h"
  29. #include "pal_linux.h"
  30. #include "pal_linux_error.h"
  31. #include "pal_debug.h"
  32. #include "pal_error.h"
  33. #include "pal_security.h"
  34. #include "pal_crypto.h"
  35. #include "api.h"
  36. #include <linux/sched.h>
  37. #include <linux/types.h>
  38. #include <linux/fs.h>
  39. typedef __kernel_pid_t pid_t;
  40. #include <asm/fcntl.h>
  41. DEFINE_LIST(trusted_child);
  42. struct trusted_child {
  43. LIST_TYPE(trusted_child) list;
  44. sgx_arch_hash_t mrenclave;
  45. char uri[];
  46. };
  47. DEFINE_LISTP(trusted_child);
  48. static LISTP_TYPE(trusted_child) trusted_children = LISTP_INIT;
  49. static struct spinlock trusted_children_lock = LOCK_INIT;
  50. int register_trusted_child(const char * uri, const char * mrenclave_str)
  51. {
  52. struct trusted_child * tc = NULL, * new;
  53. int uri_len = strlen(uri);
  54. _DkSpinLock(&trusted_children_lock);
  55. LISTP_FOR_EACH_ENTRY(tc, &trusted_children, list) {
  56. if (!memcmp(tc->uri, uri, uri_len + 1)) {
  57. _DkSpinUnlock(&trusted_children_lock);
  58. return 0;
  59. }
  60. }
  61. _DkSpinUnlock(&trusted_children_lock);
  62. new = malloc(sizeof(struct trusted_child) + uri_len);
  63. if (!new)
  64. return -PAL_ERROR_NOMEM;
  65. INIT_LIST_HEAD(new, list);
  66. memcpy(new->uri, uri, uri_len + 1);
  67. char mrenclave_text[sizeof(sgx_arch_hash_t) * 2 + 1] = "\0";
  68. size_t nbytes = 0;
  69. for (; nbytes < sizeof(sgx_arch_hash_t) ; nbytes++) {
  70. char byte1 = mrenclave_str[nbytes * 2];
  71. char byte2 = mrenclave_str[nbytes * 2 + 1];
  72. unsigned char val = 0;
  73. if (byte1 == 0 || byte2 == 0) {
  74. break;
  75. }
  76. if (!(byte1 >= '0' && byte1 <= '9') &&
  77. !(byte1 >= 'a' && byte1 <= 'f')) {
  78. break;
  79. }
  80. if (!(byte2 >= '0' && byte2 <= '9') &&
  81. !(byte2 >= 'a' && byte2 <= 'f')) {
  82. break;
  83. }
  84. if (byte1 >= '0' && byte1 <= '9')
  85. val = byte1 - '0';
  86. if (byte1 >= 'a' && byte1 <= 'f')
  87. val = byte1 - 'a' + 10;
  88. val *= 16;
  89. if (byte2 >= '0' && byte2 <= '9')
  90. val += byte2 - '0';
  91. if (byte2 >= 'a' && byte2 <= 'f')
  92. val += byte2 - 'a' + 10;
  93. new->mrenclave[nbytes] = val;
  94. snprintf(mrenclave_text + nbytes * 2, 3, "%02x", val);
  95. }
  96. if (nbytes < sizeof(sgx_arch_hash_t)) {
  97. free(new);
  98. return -PAL_ERROR_INVAL;
  99. }
  100. SGX_DBG(DBG_S, "trusted: %s %s\n", mrenclave_text, new->uri);
  101. _DkSpinLock(&trusted_children_lock);
  102. LISTP_FOR_EACH_ENTRY(tc, &trusted_children, list) {
  103. if (!memcmp(tc->uri, uri, uri_len + 1)) {
  104. _DkSpinUnlock(&trusted_children_lock);
  105. free(new);
  106. return 0;
  107. }
  108. }
  109. LISTP_ADD_TAIL(new, &trusted_children, list);
  110. _DkSpinUnlock(&trusted_children_lock);
  111. return 0;
  112. }
  113. struct proc_attestation_data {
  114. sgx_arch_mac_t keyhash_mac;
  115. uint8_t reserved[PAL_ATTESTATION_DATA_SIZE - sizeof(sgx_arch_mac_t)];
  116. } __attribute__((packed));
  117. struct check_child_param {
  118. PAL_MAC_KEY mac_key;
  119. const char * uri;
  120. };
  121. static int check_child_mrenclave (sgx_arch_hash_t * mrenclave,
  122. void * signed_data, void * check_param)
  123. {
  124. struct pal_enclave_state * remote_state = signed_data;
  125. struct proc_attestation_data * data = (void *) &remote_state->data;
  126. /* the process must be a clean process */
  127. if (remote_state->enclave_flags & PAL_ENCLAVE_INITIALIZED)
  128. return 1;
  129. struct check_child_param * param = check_param;
  130. /* must make sure the signer of the report is also the owner of the key,
  131. in order to prevent man-in-the-middle attack */
  132. struct proc_attestation_data check_data;
  133. memset(&check_data, 0, sizeof(struct proc_attestation_data));
  134. lib_AESCMAC((void *) &param->mac_key, AES_CMAC_KEY_LEN,
  135. remote_state->enclave_identifier,
  136. sizeof(remote_state->enclave_identifier),
  137. check_data.keyhash_mac, sizeof(check_data.keyhash_mac));
  138. if (memcmp(data, &check_data, sizeof(struct proc_attestation_data)))
  139. return 1;
  140. /* always accept our own as child */
  141. if (!memcmp(mrenclave, pal_sec.mrenclave, sizeof(sgx_arch_hash_t))) {
  142. SGX_DBG(DBG_S, "trusted child: <forked>\n");
  143. return 0;
  144. }
  145. struct trusted_child * tc;
  146. _DkSpinLock(&trusted_children_lock);
  147. LISTP_FOR_EACH_ENTRY(tc, &trusted_children, list) {
  148. if (!memcmp(mrenclave, tc->mrenclave, sizeof(sgx_arch_hash_t))) {
  149. _DkSpinUnlock(&trusted_children_lock);
  150. SGX_DBG(DBG_S, "trusted child: %s\n", tc->uri);
  151. return 0;
  152. }
  153. }
  154. _DkSpinUnlock(&trusted_children_lock);
  155. return 1;
  156. }
  157. int _DkProcessCreate (PAL_HANDLE * handle, const char * uri, const char ** args)
  158. {
  159. /* only access creating process with regular file */
  160. if (!strpartcmp_static(uri, "file:"))
  161. return -PAL_ERROR_INVAL;
  162. unsigned int child_pid;
  163. int proc_fds[3];
  164. int nargs = 0, ret;
  165. if (args)
  166. for (const char ** a = args ; *a ; a++)
  167. nargs++;
  168. ret = ocall_create_process(uri, nargs, args,
  169. proc_fds,
  170. &child_pid);
  171. if (IS_ERR(ret))
  172. return unix_to_pal_error(ERRNO(ret));
  173. PAL_HANDLE proc = malloc(HANDLE_SIZE(process));
  174. SET_HANDLE_TYPE(proc, process);
  175. HANDLE_HDR(proc)->flags |= RFD(0)|WFD(1)|RFD(2)|WFD(2)|WRITABLE(1)|WRITABLE(2);
  176. proc->process.stream_in = proc_fds[0];
  177. proc->process.stream_out = proc_fds[1];
  178. proc->process.cargo = proc_fds[2];
  179. proc->process.pid = child_pid;
  180. proc->process.nonblocking = PAL_FALSE;
  181. PAL_SESSION_KEY session_key;
  182. ret = _DkStreamKeyExchange(proc, &session_key);
  183. if (ret < 0)
  184. return ret;
  185. struct check_child_param param;
  186. session_key_to_mac_key(&session_key, &param.mac_key);
  187. param.uri = uri;
  188. struct proc_attestation_data data;
  189. memset(&data, 0, sizeof(struct proc_attestation_data));
  190. lib_AESCMAC((void *) &param.mac_key, AES_CMAC_KEY_LEN,
  191. pal_enclave_state.enclave_identifier,
  192. sizeof(pal_enclave_state.enclave_identifier),
  193. data.keyhash_mac, sizeof(data.keyhash_mac));
  194. SGX_DBG(DBG_P|DBG_S, "Attestation data: %s\n",
  195. ALLOCA_BYTES2HEXSTR(data.keyhash_mac));
  196. ret = _DkStreamAttestationRequest(proc, &data,
  197. &check_child_mrenclave, &param);
  198. if (ret < 0)
  199. return ret;
  200. *handle = proc;
  201. return 0;
  202. }
  203. struct check_parent_param {
  204. PAL_MAC_KEY mac_key;
  205. };
  206. static int check_parent_mrenclave (sgx_arch_hash_t * mrenclave,
  207. void * signed_data, void * check_param)
  208. {
  209. __UNUSED(mrenclave);
  210. struct pal_enclave_state * remote_state = signed_data;
  211. struct proc_attestation_param * data = (void *) &remote_state->data;
  212. struct check_parent_param * param = check_param;
  213. /* must make sure the signer of the report is also the owner of the key,
  214. in order to prevent man-in-the-middle attack */
  215. struct proc_attestation_data check_data;
  216. memset(&check_data, 0, sizeof(struct proc_attestation_data));
  217. lib_AESCMAC((void *) &param->mac_key, AES_CMAC_KEY_LEN,
  218. remote_state->enclave_identifier,
  219. sizeof(remote_state->enclave_identifier),
  220. check_data.keyhash_mac, sizeof(check_data.keyhash_mac));
  221. if (memcmp(data, &check_data, sizeof(struct proc_attestation_data)))
  222. return 1;
  223. /* for now, we will accept any enclave as a parent, but eventually
  224. we should check parent, maybe using crypto challenge */
  225. return 0;
  226. }
  227. int init_child_process (PAL_HANDLE * parent_handle)
  228. {
  229. PAL_HANDLE parent = malloc(HANDLE_SIZE(process));
  230. SET_HANDLE_TYPE(parent, process);
  231. HANDLE_HDR(parent)->flags |= RFD(0)|WFD(1)|RFD(2)|WFD(2)|WRITABLE(1)|WRITABLE(2);
  232. parent->process.stream_in = pal_sec.proc_fds[0];
  233. parent->process.stream_out = pal_sec.proc_fds[1];
  234. parent->process.cargo = pal_sec.proc_fds[2];
  235. parent->process.pid = pal_sec.ppid;
  236. parent->process.nonblocking = PAL_FALSE;
  237. PAL_SESSION_KEY session_key;
  238. int ret = _DkStreamKeyExchange(parent, &session_key);
  239. if (ret < 0)
  240. return ret;
  241. struct check_parent_param param;
  242. session_key_to_mac_key(&session_key, &param.mac_key);
  243. struct proc_attestation_data data;
  244. memset(&data, 0, sizeof(struct proc_attestation_data));
  245. lib_AESCMAC((void *) &param.mac_key, AES_CMAC_KEY_LEN,
  246. pal_enclave_state.enclave_identifier,
  247. sizeof(pal_enclave_state.enclave_identifier),
  248. data.keyhash_mac, sizeof(data.keyhash_mac));
  249. SGX_DBG(DBG_P|DBG_S, "Attestation data: %s\n",
  250. ALLOCA_BYTES2HEXSTR(data.keyhash_mac));
  251. ret = _DkStreamAttestationRespond(parent, &data,
  252. &check_parent_mrenclave,
  253. &param);
  254. if (ret < 0)
  255. return ret;
  256. *parent_handle = parent;
  257. return 0;
  258. }
  259. void print_alloced_pages (void);
  260. noreturn void _DkProcessExit (int exitcode)
  261. {
  262. #if PRINT_ENCLAVE_STAT
  263. print_alloced_pages();
  264. #endif
  265. if (exitcode)
  266. SGX_DBG(DBG_I, "DkProcessExit: Returning exit code %d\n", exitcode);
  267. ocall_exit(exitcode);
  268. while (true) {
  269. /* nothing */;
  270. }
  271. }
  272. int _DkProcessSandboxCreate (const char * manifest, int flags)
  273. {
  274. __UNUSED(manifest);
  275. __UNUSED(flags);
  276. return -PAL_ERROR_NOTIMPLEMENTED;
  277. }
  278. static int64_t proc_read (PAL_HANDLE handle, uint64_t offset, uint64_t count,
  279. void * buffer)
  280. {
  281. if (offset)
  282. return -PAL_ERROR_INVAL;
  283. if (count >= (1ULL << (sizeof(unsigned int) * 8)))
  284. return -PAL_ERROR_INVAL;
  285. int bytes = ocall_read(handle->process.stream_in, buffer, count);
  286. return IS_ERR(bytes) ? unix_to_pal_error(ERRNO(bytes)) : bytes;
  287. }
  288. static int64_t proc_write (PAL_HANDLE handle, uint64_t offset, uint64_t count,
  289. const void * buffer)
  290. {
  291. if (offset)
  292. return -PAL_ERROR_INVAL;
  293. if (count >= (1ULL << (sizeof(unsigned int) * 8)))
  294. return -PAL_ERROR_INVAL;
  295. int bytes = ocall_write(handle->process.stream_out, buffer, count);
  296. if (IS_ERR(bytes)) {
  297. bytes = unix_to_pal_error(ERRNO(bytes));
  298. if (bytes == -PAL_ERROR_TRYAGAIN)
  299. HANDLE_HDR(handle)->flags &= ~WRITABLE(1);
  300. return bytes;
  301. }
  302. if ((uint64_t)bytes == count)
  303. HANDLE_HDR(handle)->flags |= WRITABLE(1);
  304. else
  305. HANDLE_HDR(handle)->flags &= ~WRITABLE(1);
  306. return bytes;
  307. }
  308. static int proc_close (PAL_HANDLE handle)
  309. {
  310. if (handle->process.stream_in != PAL_IDX_POISON) {
  311. ocall_close(handle->process.stream_in);
  312. handle->process.stream_in = PAL_IDX_POISON;
  313. }
  314. if (handle->process.stream_out != PAL_IDX_POISON) {
  315. ocall_close(handle->process.stream_out);
  316. handle->process.stream_out = PAL_IDX_POISON;
  317. }
  318. if (handle->process.cargo != PAL_IDX_POISON) {
  319. ocall_close(handle->process.cargo);
  320. handle->process.cargo = PAL_IDX_POISON;
  321. }
  322. return 0;
  323. }
  324. static int proc_delete (PAL_HANDLE handle, int access)
  325. {
  326. int shutdown;
  327. switch (access) {
  328. case 0:
  329. shutdown = SHUT_RDWR;
  330. break;
  331. case PAL_DELETE_RD:
  332. shutdown = SHUT_RD;
  333. break;
  334. case PAL_DELETE_WR:
  335. shutdown = SHUT_WR;
  336. break;
  337. default:
  338. return -PAL_ERROR_INVAL;
  339. }
  340. if (access != PAL_DELETE_WR &&
  341. handle->process.stream_in != PAL_IDX_POISON) {
  342. ocall_close(handle->process.stream_in);
  343. handle->process.stream_in = PAL_IDX_POISON;
  344. }
  345. if (access != PAL_DELETE_RD &&
  346. handle->process.stream_out != PAL_IDX_POISON) {
  347. ocall_close(handle->process.stream_out);
  348. handle->process.stream_out = PAL_IDX_POISON;
  349. }
  350. if (handle->process.cargo != PAL_IDX_POISON)
  351. ocall_sock_shutdown(handle->process.cargo, shutdown);
  352. return 0;
  353. }
  354. static int proc_attrquerybyhdl (PAL_HANDLE handle, PAL_STREAM_ATTR * attr)
  355. {
  356. if (handle->process.stream_in == PAL_IDX_POISON)
  357. return -PAL_ERROR_BADHANDLE;
  358. int ret = ocall_fionread(handle->process.stream_in);
  359. if (IS_ERR(ret))
  360. return unix_to_pal_error(ERRNO(ret));
  361. memset(attr, 0, sizeof(PAL_STREAM_ATTR));
  362. attr->pending_size = ret;
  363. attr->disconnected = HANDLE_HDR(handle)->flags & (ERROR(0)|ERROR(1));
  364. attr->readable = (attr->pending_size > 0);
  365. attr->writable = HANDLE_HDR(handle)->flags & WRITABLE(1);
  366. attr->nonblocking = handle->process.nonblocking;
  367. return 0;
  368. }
  369. static int proc_attrsetbyhdl (PAL_HANDLE handle, PAL_STREAM_ATTR * attr)
  370. {
  371. if (handle->process.stream_in == PAL_IDX_POISON)
  372. return -PAL_ERROR_BADHANDLE;
  373. if (attr->nonblocking != handle->process.nonblocking) {
  374. int ret = ocall_fsetnonblock(handle->process.stream_in,
  375. handle->process.nonblocking);
  376. if (IS_ERR(ret))
  377. return unix_to_pal_error(ERRNO(ret));
  378. handle->process.nonblocking = attr->nonblocking;
  379. }
  380. return 0;
  381. }
  382. struct handle_ops proc_ops = {
  383. .read = &proc_read,
  384. .write = &proc_write,
  385. .close = &proc_close,
  386. .delete = &proc_delete,
  387. .attrquerybyhdl = &proc_attrquerybyhdl,
  388. .attrsetbyhdl = &proc_attrsetbyhdl,
  389. };