sandbox.c 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /*
  2. * Sandboxing example
  3. *
  4. * Uses custom memory allocation functions which keep track of total amount
  5. * of memory allocated, imposing a maximum total allocation size.
  6. */
  7. #include <stdio.h>
  8. #include <stdlib.h>
  9. #include "duktape.h"
  10. /*
  11. * Memory allocator which backs to standard library memory functions but
  12. * keeps a small header to track current allocation size.
  13. *
  14. * Many other sandbox allocation models are useful, e.g. preallocated pools.
  15. */
  16. typedef struct {
  17. /* The double value in the union is there to ensure alignment is
  18. * good for IEEE doubles too. In many 32-bit environments 4 bytes
  19. * would be sufficiently aligned and the double value is unnecessary.
  20. */
  21. union {
  22. size_t sz;
  23. double d;
  24. } u;
  25. } alloc_hdr;
  26. static size_t total_allocated = 0;
  27. static size_t max_allocated = 256 * 1024; /* 256kB sandbox */
  28. static void sandbox_dump_memstate(void) {
  29. #if 0
  30. fprintf(stderr, "Total allocated: %ld\n", (long) total_allocated);
  31. fflush(stderr);
  32. #endif
  33. }
  34. static void *sandbox_alloc(void *udata, duk_size_t size) {
  35. alloc_hdr *hdr;
  36. (void) udata; /* Suppress warning. */
  37. if (size == 0) {
  38. return NULL;
  39. }
  40. if (total_allocated + size > max_allocated) {
  41. fprintf(stderr, "Sandbox maximum allocation size reached, %ld requested in sandbox_alloc\n",
  42. (long) size);
  43. fflush(stderr);
  44. return NULL;
  45. }
  46. hdr = (alloc_hdr *) malloc(size + sizeof(alloc_hdr));
  47. if (!hdr) {
  48. return NULL;
  49. }
  50. hdr->u.sz = size;
  51. total_allocated += size;
  52. sandbox_dump_memstate();
  53. return (void *) (hdr + 1);
  54. }
  55. static void *sandbox_realloc(void *udata, void *ptr, duk_size_t size) {
  56. alloc_hdr *hdr;
  57. size_t old_size;
  58. void *t;
  59. (void) udata; /* Suppress warning. */
  60. /* Handle the ptr-NULL vs. size-zero cases explicitly to minimize
  61. * platform assumptions. You can get away with much less in specific
  62. * well-behaving environments.
  63. */
  64. if (ptr) {
  65. hdr = (alloc_hdr *) (((char *) ptr) - sizeof(alloc_hdr));
  66. old_size = hdr->u.sz;
  67. if (size == 0) {
  68. total_allocated -= old_size;
  69. free((void *) hdr);
  70. sandbox_dump_memstate();
  71. return NULL;
  72. } else {
  73. if (total_allocated - old_size + size > max_allocated) {
  74. fprintf(stderr, "Sandbox maximum allocation size reached, %ld requested in sandbox_realloc\n",
  75. (long) size);
  76. fflush(stderr);
  77. return NULL;
  78. }
  79. t = realloc((void *) hdr, size + sizeof(alloc_hdr));
  80. if (!t) {
  81. return NULL;
  82. }
  83. hdr = (alloc_hdr *) t;
  84. total_allocated -= old_size;
  85. total_allocated += size;
  86. hdr->u.sz = size;
  87. sandbox_dump_memstate();
  88. return (void *) (hdr + 1);
  89. }
  90. } else {
  91. if (size == 0) {
  92. return NULL;
  93. } else {
  94. if (total_allocated + size > max_allocated) {
  95. fprintf(stderr, "Sandbox maximum allocation size reached, %ld requested in sandbox_realloc\n",
  96. (long) size);
  97. fflush(stderr);
  98. return NULL;
  99. }
  100. hdr = (alloc_hdr *) malloc(size + sizeof(alloc_hdr));
  101. if (!hdr) {
  102. return NULL;
  103. }
  104. hdr->u.sz = size;
  105. total_allocated += size;
  106. sandbox_dump_memstate();
  107. return (void *) (hdr + 1);
  108. }
  109. }
  110. }
  111. static void sandbox_free(void *udata, void *ptr) {
  112. alloc_hdr *hdr;
  113. (void) udata; /* Suppress warning. */
  114. if (!ptr) {
  115. return;
  116. }
  117. hdr = (alloc_hdr *) (((char *) ptr) - sizeof(alloc_hdr));
  118. total_allocated -= hdr->u.sz;
  119. free((void *) hdr);
  120. sandbox_dump_memstate();
  121. }
  122. /*
  123. * Sandbox setup and test
  124. */
  125. static duk_ret_t do_sandbox_test(duk_context *ctx) {
  126. FILE *f;
  127. char buf[4096];
  128. size_t ret;
  129. const char *globobj;
  130. /*
  131. * Setup sandbox
  132. */
  133. globobj =
  134. "({\n"
  135. " print: print,\n"
  136. " Math: {\n"
  137. " max: Math.max\n"
  138. " }\n"
  139. "})\n";
  140. #if 1
  141. fprintf(stderr, "Sandbox global object:\n----------------\n%s----------------\n", globobj);
  142. fflush(stderr);
  143. #endif
  144. duk_eval_string(ctx, globobj);
  145. duk_set_global_object(ctx);
  146. /*
  147. * Execute code from specified file
  148. */
  149. f = fopen(duk_require_string(ctx, -1), "rb");
  150. if (!f) {
  151. duk_error(ctx, DUK_ERR_ERROR, "failed to open file");
  152. }
  153. for (;;) {
  154. if (ferror(f)) {
  155. fclose(f);
  156. duk_error(ctx, DUK_ERR_ERROR, "ferror when reading file");
  157. }
  158. if (feof(f)) {
  159. break;
  160. }
  161. ret = fread(buf, 1, sizeof(buf), f);
  162. if (ret == 0) {
  163. break;
  164. }
  165. duk_push_lstring(ctx, (const char *) buf, ret);
  166. }
  167. duk_concat(ctx, duk_get_top(ctx) - 1); /* -1 for filename */
  168. /* -> [ ... filename source ] */
  169. duk_insert(ctx, -2);
  170. /* -> [ ... source filename ] */
  171. duk_compile(ctx, 0 /*flags*/); /* Compile as program */
  172. duk_call(ctx, 0 /*nargs*/);
  173. return 0;
  174. }
  175. /*
  176. * Main
  177. */
  178. static void sandbox_fatal(duk_context *ctx, duk_errcode_t code, const char *msg) {
  179. (void) ctx; /* Suppress warning. */
  180. fprintf(stderr, "FATAL %ld: %s\n", (long) code, (msg ? msg : "no message"));
  181. fflush(stderr);
  182. exit(1); /* must not return */
  183. }
  184. int main(int argc, char *argv[]) {
  185. duk_context *ctx;
  186. duk_int_t rc;
  187. if (argc < 2) {
  188. fprintf(stderr, "Usage: sandbox <test.js>\n");
  189. fflush(stderr);
  190. exit(1);
  191. }
  192. ctx = duk_create_heap(sandbox_alloc,
  193. sandbox_realloc,
  194. sandbox_free,
  195. NULL,
  196. sandbox_fatal);
  197. duk_push_string(ctx, argv[1]);
  198. rc = duk_safe_call(ctx, do_sandbox_test, 1 /*nargs*/, 1 /*nrets*/);
  199. if (rc) {
  200. fprintf(stderr, "ERROR: %s\n", duk_safe_to_string(ctx, -1));
  201. fflush(stderr);
  202. }
  203. duk_destroy_heap(ctx);
  204. /* Should be zero. */
  205. fprintf(stderr, "Final allocation: %ld\n", (long) total_allocated);
  206. fflush(stderr);
  207. return 1;
  208. }