[njs] Introduced sandboxing mode.

Dmitry Volyntsev xeioex at nginx.com
Thu Sep 13 14:54:26 UTC 2018


details:   http://hg.nginx.org/njs/rev/a92ae4986bc0
branches:  
changeset: 603:a92ae4986bc0
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Thu Sep 13 15:52:17 2018 +0300
description:
Introduced sandboxing mode.

Thanks to David CARLIER.

diffstat:

 njs/njs.c                    |  15 ++++++---------
 njs/njs.h                    |   1 +
 njs/njs_builtin.c            |   4 ++++
 njs/njs_generator.c          |   2 +-
 njs/njs_module.c             |  16 ++++++++++++++++
 njs/njs_module.h             |   1 +
 njs/njs_parser.c             |   4 ++--
 njs/njs_shell.c              |   7 +++++++
 njs/njs_time.c               |   2 +-
 njs/njs_variable.c           |   4 ++--
 njs/njs_vm.h                 |   4 +---
 njs/test/njs_expect_test.exp |  37 +++++++++++++++++++++++++++++++++++--
 12 files changed, 77 insertions(+), 20 deletions(-)

diffs (307 lines):

diff -r c2cddf3b97b7 -r a92ae4986bc0 njs/njs.c
--- a/njs/njs.c	Tue Sep 11 15:35:27 2018 +0300
+++ b/njs/njs.c	Thu Sep 13 15:52:17 2018 +0300
@@ -110,6 +110,8 @@ njs_vm_create(njs_vm_opt_t *options)
             return NULL;
         }
 
+        vm->options = *options;
+
         if (options->shared != NULL) {
             vm->shared = options->shared;
 
@@ -160,15 +162,11 @@ njs_vm_create(njs_vm_opt_t *options)
         nxt_lvlhsh_init(&vm->externals_hash);
         nxt_lvlhsh_init(&vm->external_prototypes_hash);
 
-        vm->ops = options->ops;
-
         vm->trace.level = NXT_LEVEL_TRACE;
         vm->trace.size = 2048;
         vm->trace.handler = njs_parser_trace_handler;
         vm->trace.data = vm;
 
-        vm->trailer = options->trailer;
-
         if (options->backtrace) {
             debug = nxt_array_create(4, sizeof(njs_function_debug_t),
                                      &njs_array_mem_proto,
@@ -180,8 +178,7 @@ njs_vm_create(njs_vm_opt_t *options)
             vm->debug = debug;
         }
 
-        vm->accumulative = options->accumulative;
-        if (vm->accumulative) {
+        if (options->accumulative) {
             ret = njs_vm_init(vm);
             if (nxt_slow_path(ret != NXT_OK)) {
                 return NULL;
@@ -232,7 +229,7 @@ njs_vm_compile(njs_vm_t *vm, u_char **st
         return NJS_ERROR;
     }
 
-    if (vm->parser != NULL && !vm->accumulative) {
+    if (vm->parser != NULL && !vm->options.accumulative) {
         return NJS_ERROR;
     }
 
@@ -307,7 +304,7 @@ njs_vm_clone(njs_vm_t *vm, njs_external_
 
     nxt_thread_log_debug("CLONE:");
 
-    if (vm->accumulative) {
+    if (vm->options.accumulative) {
         return NULL;
     }
 
@@ -347,7 +344,7 @@ njs_vm_clone(njs_vm_t *vm, njs_external_
 
         nvm->external_objects = externals;
 
-        nvm->ops = vm->ops;
+        nvm->options = vm->options;
 
         nvm->current = vm->current;
 
diff -r c2cddf3b97b7 -r a92ae4986bc0 njs/njs.h
--- a/njs/njs.h	Tue Sep 11 15:35:27 2018 +0300
+++ b/njs/njs.h	Thu Sep 13 15:52:17 2018 +0300
@@ -145,6 +145,7 @@ typedef struct {
     uint8_t                         trailer;         /* 1 bit */
     uint8_t                         accumulative;    /* 1 bit */
     uint8_t                         backtrace;       /* 1 bit */
+    uint8_t                         sandbox;         /* 1 bit */
 } njs_vm_opt_t;
 
 
diff -r c2cddf3b97b7 -r a92ae4986bc0 njs/njs_builtin.c
--- a/njs/njs_builtin.c	Tue Sep 11 15:35:27 2018 +0300
+++ b/njs/njs_builtin.c	Thu Sep 13 15:52:17 2018 +0300
@@ -256,6 +256,10 @@ njs_builtin_objects_create(njs_vm_t *vm)
     lhq.pool = vm->mem_cache_pool;
 
     for (i = NJS_MODULE_FS; i < NJS_MODULE_MAX; i++) {
+        if (vm->options.sandbox && !njs_sandbox_module(i)) {
+            continue;
+        }
+
         module = nxt_mem_cache_zalloc(vm->mem_cache_pool, sizeof(njs_module_t));
         if (nxt_slow_path(module == NULL)) {
             return NJS_ERROR;
diff -r c2cddf3b97b7 -r a92ae4986bc0 njs/njs_generator.c
--- a/njs/njs_generator.c	Tue Sep 11 15:35:27 2018 +0300
+++ b/njs/njs_generator.c	Thu Sep 13 15:52:17 2018 +0300
@@ -2558,7 +2558,7 @@ njs_generator_temp_index_get(njs_vm_t *v
          scope = scope->parent;
     }
 
-    if (vm->accumulative && scope->type == NJS_SCOPE_GLOBAL) {
+    if (vm->options.accumulative && scope->type == NJS_SCOPE_GLOBAL) {
         /*
          * When non-clonable VM runs in accumulative mode
          * all global variables are allocated in absolute scope
diff -r c2cddf3b97b7 -r a92ae4986bc0 njs/njs_module.c
--- a/njs/njs_module.c	Tue Sep 11 15:35:27 2018 +0300
+++ b/njs/njs_module.c	Thu Sep 13 15:52:17 2018 +0300
@@ -74,3 +74,19 @@ const njs_object_init_t  njs_require_fun
     NULL,
     0,
 };
+
+
+nxt_bool_t
+njs_sandbox_module(enum njs_module_e module)
+{
+    switch (module) {
+    case NJS_MODULE_CRYPTO:
+        return 1;
+
+    case NJS_MODULE_FS:
+    default:
+        break;
+    }
+
+    return 0;
+}
diff -r c2cddf3b97b7 -r a92ae4986bc0 njs/njs_module.h
--- a/njs/njs_module.h	Tue Sep 11 15:35:27 2018 +0300
+++ b/njs/njs_module.h	Thu Sep 13 15:52:17 2018 +0300
@@ -15,6 +15,7 @@ typedef struct {
 
 njs_ret_t njs_module_require(njs_vm_t *vm, njs_value_t *args,
     nxt_uint_t nargs, njs_index_t unused);
+nxt_bool_t njs_sandbox_module(enum njs_module_e module);
 
 extern const nxt_lvlhsh_proto_t  njs_modules_hash_proto;
 
diff -r c2cddf3b97b7 -r a92ae4986bc0 njs/njs_parser.c
--- a/njs/njs_parser.c	Tue Sep 11 15:35:27 2018 +0300
+++ b/njs/njs_parser.c	Thu Sep 13 15:52:17 2018 +0300
@@ -134,7 +134,7 @@ njs_parser(njs_vm_t *vm, njs_parser_t *p
             return NULL;
         }
 
-        if (token == NJS_TOKEN_CLOSE_BRACE && vm->trailer) {
+        if (token == NJS_TOKEN_CLOSE_BRACE && vm->options.trailer) {
             parser->lexer->start--;
             break;
         }
@@ -351,7 +351,7 @@ njs_parser_statement(njs_vm_t *vm, njs_p
         return njs_parser_block_statement(vm, parser);
 
     case NJS_TOKEN_CLOSE_BRACE:
-        if (vm->trailer) {
+        if (vm->options.trailer) {
             parser->node = NULL;
             nxt_thread_log_debug("BLOCK END");
             return token;
diff -r c2cddf3b97b7 -r a92ae4986bc0 njs/njs_shell.c
--- a/njs/njs_shell.c	Tue Sep 11 15:35:27 2018 +0300
+++ b/njs/njs_shell.c	Thu Sep 13 15:52:17 2018 +0300
@@ -31,6 +31,7 @@ typedef struct {
     nxt_int_t               version;
     nxt_int_t               disassemble;
     nxt_int_t               interactive;
+    nxt_int_t               sandbox;
 } njs_opts_t;
 
 
@@ -146,6 +147,7 @@ main(int argc, char **argv)
 
     vm_options.accumulative = 1;
     vm_options.backtrace = 1;
+    vm_options.sandbox = opts.sandbox;
 
     if (opts.interactive) {
         ret = njs_interactive_shell(&opts, &vm_options);
@@ -170,6 +172,7 @@ njs_get_options(njs_opts_t *opts, int ar
         "Options:\n"
         "  -v              print njs version and exit.\n"
         "  -d              print disassembled code.\n"
+        "  -s              sandbox mode.\n"
         "  <filename> | -  run code from a file or stdin.\n";
 
     ret = NXT_DONE;
@@ -201,6 +204,10 @@ njs_get_options(njs_opts_t *opts, int ar
             opts->version = 1;
             break;
 
+        case 's':
+            opts->sandbox = 1;
+            break;
+
         default:
             fprintf(stderr, "Unknown argument: \"%s\" "
                     "try \"%s -h\" for available options\n", argv[i], argv[0]);
diff -r c2cddf3b97b7 -r a92ae4986bc0 njs/njs_time.c
--- a/njs/njs_time.c	Tue Sep 11 15:35:27 2018 +0300
+++ b/njs/njs_time.c	Thu Sep 13 15:52:17 2018 +0300
@@ -28,7 +28,7 @@ njs_set_timeout(njs_vm_t *vm, njs_value_
         return NJS_ERROR;
     }
 
-    ops = vm->ops;
+    ops = vm->options.ops;
     if (nxt_slow_path(ops == NULL)) {
         njs_internal_error(vm, "not supported by host environment");
         return NJS_ERROR;
diff -r c2cddf3b97b7 -r a92ae4986bc0 njs/njs_variable.c
--- a/njs/njs_variable.c	Tue Sep 11 15:35:27 2018 +0300
+++ b/njs/njs_variable.c	Thu Sep 13 15:52:17 2018 +0300
@@ -123,7 +123,7 @@ njs_variable_add(njs_vm_t *vm, njs_parse
         return var;
     }
 
-    lhq.replace = vm->accumulative;
+    lhq.replace = vm->options.accumulative;
     lhq.value = var;
     lhq.pool = vm->mem_cache_pool;
 
@@ -389,7 +389,7 @@ njs_variable_get(njs_vm_t *vm, njs_parse
         goto not_found;
     }
 
-    if (vm->accumulative && vs.scope->type == NJS_SCOPE_GLOBAL) {
+    if (vm->options.accumulative && vs.scope->type == NJS_SCOPE_GLOBAL) {
         /*
          * When non-clonable VM runs in accumulative mode all
          * global variables should be allocated in absolute scope
diff -r c2cddf3b97b7 -r a92ae4986bc0 njs/njs_vm.h
--- a/njs/njs_vm.h	Tue Sep 11 15:35:27 2018 +0300
+++ b/njs/njs_vm.h	Thu Sep 13 15:52:17 2018 +0300
@@ -1036,7 +1036,7 @@ struct njs_vm_s {
     nxt_lvlhsh_t             events_hash;
     nxt_queue_t              posted_events;
 
-    njs_vm_ops_t             *ops;
+    njs_vm_opt_t             options;
 
     /*
      * The prototypes and constructors arrays must be together because
@@ -1073,8 +1073,6 @@ struct njs_vm_s {
     nxt_array_t              *backtrace;
 
     njs_trap_t               trap:8;
-    uint8_t                  trailer;  /* 1 bit */
-    uint8_t                  accumulative; /* 1 bit */
 };
 
 
diff -r c2cddf3b97b7 -r a92ae4986bc0 njs/test/njs_expect_test.exp
--- a/njs/test/njs_expect_test.exp	Tue Sep 11 15:35:27 2018 +0300
+++ b/njs/test/njs_expect_test.exp	Thu Sep 13 15:52:17 2018 +0300
@@ -3,8 +3,15 @@
 # Copyright (C) NGINX, Inc.
 #
 
-proc njs_test {body} {
-    spawn  -nottycopy njs
+proc njs_test {body {opts ""}} {
+
+    if {$opts eq ""} {
+        spawn  -nottycopy njs
+
+    } else {
+        spawn  -nottycopy njs $opts
+    }
+
     expect -re "interactive njs \\d+\.\\d+\.\\d+\r\n\r"
     expect "v.<Tab> -> the properties and prototype methods of v.\r
 type console.help() for more information\r
@@ -23,6 +30,12 @@ type console.help() for more information
     expect eof
 }
 
+proc njs_run {opts output} {
+    spawn  -nottycopy njs $opts
+    expect -re $output
+    expect eof
+}
+
 njs_test {
     {"njs.version\r\n"
      "njs.version\r\n\*\.\*\.\*"}
@@ -490,3 +503,23 @@ njs_test {
     {"fs.readFileSync('njs_test_file2')\r\n"
      "'ABCABC'\r\n>> "}
 }
+
+# CLI OPTIONS
+
+# version
+
+njs_run "-v" "\\d+\.\\d+\.\\d+"
+
+# disassemble
+
+njs_test {
+    {"1+1\r\n"
+     "00000 ADD*\r\n00040 STOP*\r\n\r\n2"}
+} "-d"
+
+# sandboxing
+
+njs_test {
+    {"var fs = require('fs')\r\n"
+     "Error: Cannot find module 'fs'\r\n"}
+} "-s"


More information about the nginx-devel mailing list