shim_sandbox.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399
  1. /* Copyright (C) 2014 Stony Brook University
  2. This file is part of Graphene Library OS.
  3. Graphene Library OS is free software: you can redistribute it and/or
  4. modify it under the terms of the GNU Lesser General Public License
  5. as published by the Free Software Foundation, either version 3 of the
  6. License, or (at your option) any later version.
  7. Graphene Library OS is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU Lesser General Public License for more details.
  11. You should have received a copy of the GNU Lesser General Public License
  12. along with this program. If not, see <http://www.gnu.org/licenses/>. */
  13. /*
  14. * shim_sandbox.c
  15. */
  16. #include <shim_internal.h>
  17. #include <shim_table.h>
  18. #include <shim_fs.h>
  19. #include <shim_checkpoint.h>
  20. #include <shim_ipc.h>
  21. #include <pal.h>
  22. #include <pal_error.h>
  23. #include <errno.h>
  24. struct shim_sandbox {
  25. unsigned int sbid;
  26. unsigned int parent_sbid;
  27. IDTYPE parent_vmid;
  28. };
  29. static struct shim_sandbox sandbox_info __attribute_migratable;
  30. static inline void append_uri (char * uri, int prefix_len, char * append,
  31. int append_len)
  32. {
  33. if (prefix_len && uri[prefix_len - 1] == ':') {
  34. if (append[0] == '/')
  35. memcpy(uri + prefix_len, append + 1, append_len);
  36. else
  37. memcpy(uri + prefix_len, append, append_len + 1);
  38. } else {
  39. if (append[0] != '/')
  40. uri[prefix_len++] = '/';
  41. memcpy(uri + prefix_len, append, append_len + 1);
  42. }
  43. }
  44. static int isolate_fs (struct config_store * cfg, const char * path)
  45. {
  46. struct shim_dentry * dent = NULL;
  47. int ret = 0;
  48. if ((ret = path_lookupat(NULL, path, LOOKUP_OPEN, &dent, NULL)) < 0)
  49. return ret;
  50. if (!(dent->state & DENTRY_ISDIRECTORY)) {
  51. put_dentry(dent);
  52. return -ENOTDIR;
  53. }
  54. size_t dpath_len = 0;
  55. char * dpath = dentry_get_path(dent, true, &dpath_len);
  56. bool root_created = false;
  57. char t[CONFIG_MAX], u[CONFIG_MAX];
  58. ssize_t prefix_len;
  59. int nkeys;
  60. ssize_t keybuf_size;
  61. keybuf_size = get_config_entries_size(cfg, "fs.mount.other");
  62. if (keybuf_size <= 0)
  63. goto root;
  64. char * keybuf = __alloca(keybuf_size);
  65. nkeys = get_config_entries(cfg, "fs.mount.other", keybuf, keybuf_size);
  66. if (nkeys <= 0)
  67. goto root;
  68. char k[CONFIG_MAX], p[CONFIG_MAX];
  69. char * tmp = strcpy_static(k, "fs.mount.other.", CONFIG_MAX);
  70. const char * key = keybuf, * next = NULL;
  71. for (int n = 0 ; n < nkeys ; key = next, n++) {
  72. for (next = key ; *next ; next++);
  73. next++;
  74. size_t key_len = next - key - 1;
  75. memcpy(tmp, key, key_len);
  76. char * kp = tmp + key_len;
  77. ssize_t ulen, plen;
  78. bool is_chroot = false;
  79. /* Skip FS that are not chroot */
  80. strcpy_static(kp, ".type", (size_t) ((k + CONFIG_MAX) - kp));
  81. if (get_config(cfg, k, t, CONFIG_MAX) <= 0)
  82. continue;
  83. if (strpartcmp_static(t, "chroot"))
  84. is_chroot = true;
  85. strcpy_static(kp, ".uri", (size_t) ((k + CONFIG_MAX) - kp));
  86. if ((ulen = get_config(cfg, k, u, CONFIG_MAX)) <= 0)
  87. continue;
  88. strcpy_static(kp, ".path", (size_t) ((k + CONFIG_MAX) - kp));
  89. if ((plen = get_config(cfg, k, p, CONFIG_MAX)) <= 0)
  90. continue;
  91. if ((size_t) plen >= dpath_len) {
  92. if (!memcmp(p, dpath, dpath_len)) {
  93. if (!p[dpath_len]) {
  94. root_created = true;
  95. debug("kept file rule: %s => %s\n", p, u);
  96. continue;
  97. }
  98. if (p[dpath_len] != '/')
  99. goto remove;
  100. /* keep this FS */
  101. continue;
  102. } else {
  103. remove:
  104. if (!is_chroot) {
  105. debug("kept file rule: %s => %s\n", p, u);
  106. continue;
  107. }
  108. set_config(cfg, k, NULL);
  109. strcpy_static(kp, ".type", (size_t) ((k + CONFIG_MAX) - kp));
  110. set_config(cfg, k, NULL);
  111. strcpy_static(kp, ".uri", (size_t) ((k + CONFIG_MAX) - kp));
  112. set_config(cfg, k, NULL);
  113. debug("deleted file rule: %s => %s\n", p, u);
  114. }
  115. } else {
  116. if (memcmp(p, dpath, plen))
  117. goto remove;
  118. assert(dpath[plen]);
  119. if (dpath[plen] != '/')
  120. goto remove;
  121. if (!is_chroot) {
  122. root_created = true;
  123. debug("kept file rule: %s => %s\n", p, u);
  124. continue;
  125. }
  126. append_uri(u, ulen, dpath + plen, dpath_len - plen);
  127. set_config(cfg, k, dpath);
  128. strcpy_static(kp, "uri", (size_t) ((k + CONFIG_MAX) - kp));
  129. set_config(cfg, k, u);
  130. root_created = true;
  131. debug("added file rule: %s => %s\n", dpath, u);
  132. }
  133. }
  134. root:
  135. if ((prefix_len = get_config(cfg, "fs.mount.root.uri", u, CONFIG_MAX)) > 0) {
  136. if (get_config(cfg, "fs.mount.root.type", t, CONFIG_MAX) > 0 &&
  137. strcmp_static(t, "chroot")) {
  138. /* remove the root FS */
  139. set_config(cfg, "fs.mount.root.uri", NULL);
  140. set_config(cfg, "fs.mount.root.type", NULL);
  141. debug("deleted file rule: root\n");
  142. /* add another FS as part of the original root FS */
  143. if (!root_created) {
  144. append_uri(u, prefix_len, dpath, dpath_len);
  145. set_config(cfg, "fs.mount.other.root.path", dpath);
  146. set_config(cfg, "fs.mount.other.root.uri", u);
  147. set_config(cfg, "fs.mount.other.root.type", "chroot");
  148. debug("added file rule: %s => %s\n", dpath, u);
  149. }
  150. }
  151. }
  152. return 0;
  153. }
  154. static int isolate_net (struct config_store * cfg, struct net_sb * sb)
  155. {
  156. int nkeys;
  157. ssize_t keybuf_size;
  158. char k[CONFIG_MAX], * keybuf;
  159. keybuf_size = get_config_entries_size(cfg, "net.rules");
  160. if (keybuf_size <= 0)
  161. goto add;
  162. keybuf = __alloca(keybuf_size);
  163. nkeys = get_config_entries(cfg, "net.rules", keybuf, keybuf_size);
  164. if (nkeys <= 0)
  165. goto add;
  166. const char * key = keybuf, * next = NULL;
  167. memcpy(k, "net.rules.", 10);
  168. for (int n = 0 ; n < nkeys ; key = next, n++) {
  169. for (next = key ; *next ; next++);
  170. next++;
  171. int key_len = next - key - 1;
  172. memcpy(k + 10, key, key_len);
  173. k[10 + key_len] = 0;
  174. set_config(cfg, k, NULL);
  175. }
  176. add:
  177. if (!sb)
  178. return 0;
  179. for (int i = 0 ; i < sb->nrules ; i++) {
  180. struct net_sb_rule * r = &sb->rules[i];
  181. char u[CONFIG_MAX];
  182. int ulen;
  183. int family = -1;
  184. undo:
  185. ulen = 0;
  186. for (int turn = 0 ; turn < 2 ; turn++) {
  187. struct sockaddr * addr = turn ? r->r_addr : r->l_addr;
  188. if (turn)
  189. u[ulen++] = ':';
  190. if (!addr) {
  191. if (family == -1 || family == AF_INET)
  192. ulen += snprintf(u + ulen, CONFIG_MAX - ulen,
  193. "0.0.0.0:0-65535");
  194. else
  195. ulen += snprintf(u + ulen, CONFIG_MAX - ulen,
  196. "[0:0:0:0:0:0:0:0]:0-65535]");
  197. } else {
  198. if (addr->sa_family == AF_INET) {
  199. if (family == AF_INET6)
  200. goto next;
  201. family = AF_INET;
  202. struct sockaddr_in * saddr = (void *) addr;
  203. unsigned char * a = (void *) &saddr->sin_addr.s_addr;
  204. ulen += snprintf(u + ulen, CONFIG_MAX - ulen,
  205. "%d.%d.%d.%d:%u",
  206. a[0], a[1], a[2], a[3],
  207. __ntohs(saddr->sin_port));
  208. continue;
  209. }
  210. if (addr->sa_family == AF_INET6) {
  211. if (family == AF_INET)
  212. goto next;
  213. if (turn && family == -1) {
  214. family = AF_INET6;
  215. goto undo;
  216. }
  217. family = AF_INET6;
  218. struct sockaddr_in6 * saddr = (void *) addr;
  219. unsigned short * a = (void *) &saddr->sin6_addr.s6_addr;
  220. ulen += snprintf(u + ulen, CONFIG_MAX - ulen,
  221. "[%d:%d:%d:%d:%d:%d:%d:%d]:%u",
  222. a[0], a[1], a[2], a[3],
  223. a[4], a[5], a[6], a[7],
  224. __ntohs(saddr->sin6_port));
  225. continue;
  226. }
  227. goto next;
  228. }
  229. }
  230. snprintf(k + 10, CONFIG_MAX - 10, "%d", i + 1);
  231. set_config(cfg, k, u);
  232. debug("added net rule: %s\n", u);
  233. next:
  234. continue;
  235. }
  236. return 0;
  237. }
  238. static void * __malloc (size_t size)
  239. {
  240. return malloc(size);
  241. }
  242. static void __free (void * mem)
  243. {
  244. free(mem);
  245. }
  246. struct cfg_arg {
  247. PAL_HANDLE handle;
  248. int offset;
  249. };
  250. static int __write (void * f, void * buf, int len)
  251. {
  252. struct cfg_arg * arg = f;
  253. int bytes = DkStreamWrite(arg->handle, arg->offset, len, buf, NULL);
  254. if (!bytes)
  255. return -PAL_ERRNO;
  256. arg->offset += bytes;
  257. return bytes;
  258. }
  259. long shim_do_sandbox_create (int flags, const char * fs_sb,
  260. struct net_sb * net_sb)
  261. {
  262. unsigned int sbid;
  263. char uri[24];
  264. PAL_HANDLE handle = NULL;
  265. int ret = create_handle("file:sandbox-", uri, 24, &handle, &sbid);
  266. if (ret < 0)
  267. return ret;
  268. debug("create manifest: %s\n", uri);
  269. struct config_store * newcfg = __alloca(sizeof(struct config_store));
  270. memset(newcfg, 0, sizeof(struct config_store));
  271. newcfg->malloc = __malloc;
  272. newcfg->free = __free;
  273. if ((ret = copy_config(root_config, newcfg)) < 0) {
  274. newcfg = NULL;
  275. goto err;
  276. }
  277. if (flags & SANDBOX_FS)
  278. if ((ret = isolate_fs(newcfg, fs_sb)) < 0)
  279. goto err;
  280. if (flags & SANDBOX_NET)
  281. if ((ret = isolate_net(newcfg, net_sb)) < 0)
  282. goto err;
  283. struct cfg_arg arg;
  284. arg.handle = handle;
  285. arg.offset = 0;
  286. if ((ret = write_config(&arg, __write, newcfg)) < 0)
  287. goto err;
  288. DkObjectClose(handle);
  289. PAL_BOL success = DkProcessSandboxCreate(uri, flags & SANDBOX_RPC ?
  290. PAL_SANDBOX_PIPE : 0);
  291. if (!success) {
  292. ret = -PAL_ERRNO;
  293. goto err;
  294. }
  295. if (sandbox_info.sbid) {
  296. if (!sandbox_info.parent_sbid ||
  297. sandbox_info.parent_vmid != cur_process.vmid) {
  298. sandbox_info.parent_sbid = sandbox_info.sbid;
  299. sandbox_info.parent_vmid = cur_process.vmid;
  300. }
  301. }
  302. if (flags & SANDBOX_RPC)
  303. del_all_ipc_ports();
  304. if ((ret = free_config(root_config)) < 0)
  305. goto err;
  306. handle = DkStreamOpen(uri, PAL_ACCESS_RDONLY, 0, 0, 0);
  307. if (!handle)
  308. return -PAL_ERRNO;
  309. root_config = newcfg;
  310. sandbox_info.sbid = sbid;
  311. return sbid;
  312. err:
  313. free_config(newcfg);
  314. DkStreamDelete(handle, 0);
  315. DkObjectClose(handle);
  316. return ret;
  317. }
  318. int shim_do_sandbox_attach (unsigned int sbid)
  319. {
  320. __UNUSED(sbid);
  321. return -ENOSYS;
  322. }
  323. long shim_do_sandbox_current (void)
  324. {
  325. return sandbox_info.sbid;
  326. }