shim_sandbox.c 11 KB

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