123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252 |
- /*
- * Sandboxing example
- *
- * Uses custom memory allocation functions which keep track of total amount
- * of memory allocated, imposing a maximum total allocation size.
- */
- #include <stdio.h>
- #include <stdlib.h>
- #include "duktape.h"
- /*
- * Memory allocator which backs to standard library memory functions but
- * keeps a small header to track current allocation size.
- *
- * Many other sandbox allocation models are useful, e.g. preallocated pools.
- */
- typedef struct {
- /* The double value in the union is there to ensure alignment is
- * good for IEEE doubles too. In many 32-bit environments 4 bytes
- * would be sufficiently aligned and the double value is unnecessary.
- */
- union {
- size_t sz;
- double d;
- } u;
- } alloc_hdr;
- static size_t total_allocated = 0;
- static size_t max_allocated = 256 * 1024; /* 256kB sandbox */
- static void sandbox_dump_memstate(void) {
- #if 0
- fprintf(stderr, "Total allocated: %ld\n", (long) total_allocated);
- fflush(stderr);
- #endif
- }
- static void *sandbox_alloc(void *udata, duk_size_t size) {
- alloc_hdr *hdr;
- (void) udata; /* Suppress warning. */
- if (size == 0) {
- return NULL;
- }
- if (total_allocated + size > max_allocated) {
- fprintf(stderr, "Sandbox maximum allocation size reached, %ld requested in sandbox_alloc\n",
- (long) size);
- fflush(stderr);
- return NULL;
- }
- hdr = (alloc_hdr *) malloc(size + sizeof(alloc_hdr));
- if (!hdr) {
- return NULL;
- }
- hdr->u.sz = size;
- total_allocated += size;
- sandbox_dump_memstate();
- return (void *) (hdr + 1);
- }
- static void *sandbox_realloc(void *udata, void *ptr, duk_size_t size) {
- alloc_hdr *hdr;
- size_t old_size;
- void *t;
- (void) udata; /* Suppress warning. */
- /* Handle the ptr-NULL vs. size-zero cases explicitly to minimize
- * platform assumptions. You can get away with much less in specific
- * well-behaving environments.
- */
- if (ptr) {
- hdr = (alloc_hdr *) (((char *) ptr) - sizeof(alloc_hdr));
- old_size = hdr->u.sz;
- if (size == 0) {
- total_allocated -= old_size;
- free((void *) hdr);
- sandbox_dump_memstate();
- return NULL;
- } else {
- if (total_allocated - old_size + size > max_allocated) {
- fprintf(stderr, "Sandbox maximum allocation size reached, %ld requested in sandbox_realloc\n",
- (long) size);
- fflush(stderr);
- return NULL;
- }
- t = realloc((void *) hdr, size + sizeof(alloc_hdr));
- if (!t) {
- return NULL;
- }
- hdr = (alloc_hdr *) t;
- total_allocated -= old_size;
- total_allocated += size;
- hdr->u.sz = size;
- sandbox_dump_memstate();
- return (void *) (hdr + 1);
- }
- } else {
- if (size == 0) {
- return NULL;
- } else {
- if (total_allocated + size > max_allocated) {
- fprintf(stderr, "Sandbox maximum allocation size reached, %ld requested in sandbox_realloc\n",
- (long) size);
- fflush(stderr);
- return NULL;
- }
- hdr = (alloc_hdr *) malloc(size + sizeof(alloc_hdr));
- if (!hdr) {
- return NULL;
- }
- hdr->u.sz = size;
- total_allocated += size;
- sandbox_dump_memstate();
- return (void *) (hdr + 1);
- }
- }
- }
- static void sandbox_free(void *udata, void *ptr) {
- alloc_hdr *hdr;
- (void) udata; /* Suppress warning. */
- if (!ptr) {
- return;
- }
- hdr = (alloc_hdr *) (((char *) ptr) - sizeof(alloc_hdr));
- total_allocated -= hdr->u.sz;
- free((void *) hdr);
- sandbox_dump_memstate();
- }
- /*
- * Sandbox setup and test
- */
- static duk_ret_t do_sandbox_test(duk_context *ctx) {
- FILE *f;
- char buf[4096];
- size_t ret;
- const char *globobj;
- /*
- * Setup sandbox
- */
- globobj =
- "({\n"
- " print: print,\n"
- " Math: {\n"
- " max: Math.max\n"
- " }\n"
- "})\n";
- #if 1
- fprintf(stderr, "Sandbox global object:\n----------------\n%s----------------\n", globobj);
- fflush(stderr);
- #endif
- duk_eval_string(ctx, globobj);
- duk_set_global_object(ctx);
- /*
- * Execute code from specified file
- */
- f = fopen(duk_require_string(ctx, -1), "rb");
- if (!f) {
- duk_error(ctx, DUK_ERR_ERROR, "failed to open file");
- }
- for (;;) {
- if (ferror(f)) {
- fclose(f);
- duk_error(ctx, DUK_ERR_ERROR, "ferror when reading file");
- }
- if (feof(f)) {
- break;
- }
- ret = fread(buf, 1, sizeof(buf), f);
- if (ret == 0) {
- break;
- }
- duk_push_lstring(ctx, (const char *) buf, ret);
- }
- duk_concat(ctx, duk_get_top(ctx) - 1); /* -1 for filename */
- /* -> [ ... filename source ] */
- duk_insert(ctx, -2);
- /* -> [ ... source filename ] */
- duk_compile(ctx, 0 /*flags*/); /* Compile as program */
- duk_call(ctx, 0 /*nargs*/);
- return 0;
- }
- /*
- * Main
- */
- static void sandbox_fatal(duk_context *ctx, duk_errcode_t code, const char *msg) {
- (void) ctx; /* Suppress warning. */
- fprintf(stderr, "FATAL %ld: %s\n", (long) code, (msg ? msg : "no message"));
- fflush(stderr);
- exit(1); /* must not return */
- }
- int main(int argc, char *argv[]) {
- duk_context *ctx;
- duk_int_t rc;
- if (argc < 2) {
- fprintf(stderr, "Usage: sandbox <test.js>\n");
- fflush(stderr);
- exit(1);
- }
- ctx = duk_create_heap(sandbox_alloc,
- sandbox_realloc,
- sandbox_free,
- NULL,
- sandbox_fatal);
- duk_push_string(ctx, argv[1]);
- rc = duk_safe_call(ctx, do_sandbox_test, 1 /*nargs*/, 1 /*nrets*/);
- if (rc) {
- fprintf(stderr, "ERROR: %s\n", duk_safe_to_string(ctx, -1));
- fflush(stderr);
- }
- duk_destroy_heap(ctx);
- /* Should be zero. */
- fprintf(stderr, "Final allocation: %ld\n", (long) total_allocated);
- fflush(stderr);
- return 1;
- }
|