diff --git a/include/pocketpy/interpreter/vm.h b/include/pocketpy/interpreter/vm.h index 769d95c6..b7eca496 100644 --- a/include/pocketpy/interpreter/vm.h +++ b/include/pocketpy/interpreter/vm.h @@ -50,6 +50,7 @@ typedef struct VM { py_GlobalRef main; // __main__ module py_Callbacks callbacks; + py_Capabilities capabilities; py_TValue last_retval; py_TValue unhandled_exc; diff --git a/include/pocketpy/sandbox.h b/include/pocketpy/sandbox.h index dfaf87a2..66a2cf52 100644 --- a/include/pocketpy/sandbox.h +++ b/include/pocketpy/sandbox.h @@ -13,10 +13,7 @@ typedef struct py_Capabilities { bool (*os_system)(const char* command); bool (*os_remove)(const char* path); // stdc - bool stdc_write; // memset, write_bytes, ... - bool stdc_read; // memcmp, read_bytes, ... - bool stdc_malloc; // malloc - bool stdc_free; // free + bool stdc; } py_Capabilities; /// Setup the capabilities for the current VM. diff --git a/src/interpreter/vm.c b/src/interpreter/vm.c index ca2e182e..c8fb7ace 100644 --- a/src/interpreter/vm.c +++ b/src/interpreter/vm.c @@ -93,6 +93,8 @@ void VM__ctor(VM* self) { self->callbacks.flush = pk_default_flush; self->callbacks.getchr = pk_default_getchr; + memset(&self->capabilities, 0, sizeof(py_Capabilities)); + self->last_retval = *py_NIL(); self->unhandled_exc = *py_NIL(); @@ -195,7 +197,7 @@ void VM__ctor(VM* self) { INJECT_BUILTIN_EXC(SyntaxError, tp_Exception); INJECT_BUILTIN_EXC(RecursionError, tp_Exception); INJECT_BUILTIN_EXC(OSError, tp_Exception); - INJECT_BUILTIN_EXC(PermissionError, tp_OSError); + INJECT_BUILTIN_EXC(PermissionError, tp_Exception); INJECT_BUILTIN_EXC(NotImplementedError, tp_Exception); INJECT_BUILTIN_EXC(TypeError, tp_Exception); INJECT_BUILTIN_EXC(IndexError, tp_Exception); diff --git a/src/modules/os.c b/src/modules/os.c index 6c4d5d05..3073fe4f 100644 --- a/src/modules/os.c +++ b/src/modules/os.c @@ -38,6 +38,12 @@ static bool os_chdir(int argc, py_Ref argv) { PY_CHECK_ARGC(1); PY_CHECK_ARG_TYPE(0, tp_str); const char* path = py_tostr(py_arg(0)); + + py_Capabilities* caps = py_capabilities(); + if(!caps->os_chdir || !caps->os_chdir(path)) { + return py_exception(tp_PermissionError, "disallowed capability"); + } + int code = platform_chdir(path); if(code != 0) { const char* msg = strerror(errno); @@ -49,6 +55,12 @@ static bool os_chdir(int argc, py_Ref argv) { static bool os_getcwd(int argc, py_Ref argv) { PY_CHECK_ARGC(0); + + py_Capabilities* caps = py_capabilities(); + if(!caps->os_getcwd || !caps->os_getcwd()) { + return py_exception(tp_PermissionError, "disallowed capability"); + } + char buf[1024]; if(!platform_getcwd(buf, sizeof(buf))) return OSError("getcwd() failed"); py_newstr(py_retval(), buf); @@ -60,6 +72,12 @@ static bool os_system(int argc, py_Ref argv) { PY_CHECK_ARG_TYPE(0, tp_str); #if PK_IS_DESKTOP_PLATFORM const char* cmd = py_tostr(py_arg(0)); + + py_Capabilities* caps = py_capabilities(); + if(!caps->os_system || !caps->os_system(cmd)) { + return py_exception(tp_PermissionError, "disallowed capability"); + } + int code = system(cmd); py_newint(py_retval(), code); return true; @@ -72,6 +90,12 @@ static bool os_remove(int argc, py_Ref argv) { PY_CHECK_ARGC(1); PY_CHECK_ARG_TYPE(0, tp_str); const char* path = py_tostr(py_arg(0)); + + py_Capabilities* caps = py_capabilities(); + if(!caps->os_remove || !caps->os_remove(path)) { + return py_exception(tp_PermissionError, "disallowed capability"); + } + int code = remove(path); if(code != 0) { const char* msg = strerror(errno); @@ -112,6 +136,12 @@ static bool io_FileIO__new__(int argc, py_Ref argv) { io_FileIO* ud = py_newobject(py_retval(), cls, 0, sizeof(io_FileIO)); ud->path = py_tostr(py_arg(1)); ud->mode = py_tostr(py_arg(2)); + + py_Capabilities* caps = py_capabilities(); + if(!caps->file_open || !caps->file_open(ud->path, ud->mode)) { + return py_exception(tp_PermissionError, "disallowed capability"); + } + ud->file = fopen(ud->path, ud->mode); if(ud->file == NULL) { const char* msg = strerror(errno); diff --git a/src/modules/stdc.c b/src/modules/stdc.c index 358b8268..c0048c34 100644 --- a/src/modules/stdc.c +++ b/src/modules/stdc.c @@ -2,8 +2,17 @@ #include "pocketpy/interpreter/vm.h" #include + +static bool check_stdc_cap() { + py_Capabilities* caps = py_capabilities(); + if(caps->stdc) return true; + return py_exception(tp_PermissionError, "disallowed capability"); +} + + #define DEF_BUILTIN_MEMORY_T(Char_, char_, tp_int_, py_newint_, py_toint_, py_i64_) \ static bool stdc_##Char_##__new__(int argc, py_Ref argv) { \ + if(!check_stdc_cap()) return false; \ char_* ud = py_newobject(py_retval(), tp_stdc_##Char_, 0, sizeof(char_)); \ if(argc == 2) { \ PY_CHECK_ARG_TYPE(1, tp_int_); \ @@ -14,12 +23,14 @@ return true; \ } \ static bool stdc_##Char_##__get_value(int argc, py_Ref argv) { \ + if(!check_stdc_cap()) return false; \ PY_CHECK_ARGC(1); \ char_* ud = py_touserdata(argv); \ py_newint_(py_retval(), (py_i64_)(*ud)); \ return true; \ } \ static bool stdc_##Char_##__set_value(int argc, py_Ref argv) { \ + if(!check_stdc_cap()) return false; \ PY_CHECK_ARGC(2); \ char_* ud = py_touserdata(argv); \ PY_CHECK_ARG_TYPE(1, tp_int_); \ @@ -28,6 +39,7 @@ return true; \ } \ static bool stdc_##Char_##__read_STATIC(int argc, py_Ref argv) { \ + if(!check_stdc_cap()) return false; \ PY_CHECK_ARGC(2); \ PY_CHECK_ARG_TYPE(0, tp_int); \ PY_CHECK_ARG_TYPE(1, tp_int); \ @@ -37,6 +49,7 @@ return true; \ } \ static bool stdc_##Char_##__write_STATIC(int argc, py_Ref argv) { \ + if(!check_stdc_cap()) return false; \ PY_CHECK_ARGC(3); \ PY_CHECK_ARG_TYPE(0, tp_int); \ PY_CHECK_ARG_TYPE(1, tp_int); \ @@ -48,6 +61,7 @@ return true; \ } \ static bool stdc_##Char_##__array_STATIC(int argc, py_Ref argv) { \ + if(!check_stdc_cap()) return false; \ PY_CHECK_ARGC(1); \ PY_CHECK_ARG_TYPE(0, tp_int); \ int length = py_toint(argv); \ @@ -56,6 +70,7 @@ return true; \ } \ static bool stdc_##Char_##__getitem__(int argc, py_Ref argv) { \ + if(!check_stdc_cap()) return false; \ PY_CHECK_ARGC(2); \ char_* ud = py_touserdata(argv); \ PY_CHECK_ARG_TYPE(1, tp_int); \ @@ -64,6 +79,7 @@ return true; \ } \ static bool stdc_##Char_##__setitem__(int argc, py_Ref argv) { \ + if(!check_stdc_cap()) return false; \ PY_CHECK_ARGC(3); \ char_* ud = py_touserdata(argv); \ PY_CHECK_ARG_TYPE(1, tp_int); \ @@ -105,6 +121,7 @@ DEF_BUILTIN_MEMORY_T(Bool, bool, tp_bool, py_newbool, py_tobool, bool) #undef DEF_BUILTIN_MEMORY_T static bool stdc_malloc(int argc, py_Ref argv) { + if(!check_stdc_cap()) return false; PY_CHECK_ARGC(1); PY_CHECK_ARG_TYPE(0, tp_int); py_i64 size = py_toint(&argv[0]); @@ -114,6 +131,7 @@ static bool stdc_malloc(int argc, py_Ref argv) { } static bool stdc_free(int argc, py_Ref argv) { + if(!check_stdc_cap()) return false; PY_CHECK_ARGC(1); PY_CHECK_ARG_TYPE(0, tp_int); void* p = (void*)(intptr_t)py_toint(&argv[0]); @@ -123,6 +141,7 @@ static bool stdc_free(int argc, py_Ref argv) { } static bool stdc_memcpy(int argc, py_Ref argv) { + if(!check_stdc_cap()) return false; PY_CHECK_ARGC(3); PY_CHECK_ARG_TYPE(0, tp_int); // dst void* dst = (void*)(intptr_t)py_toint(&argv[0]); @@ -143,6 +162,7 @@ static bool stdc_memcpy(int argc, py_Ref argv) { } static bool stdc_memset(int argc, py_Ref argv) { + if(!check_stdc_cap()) return false; PY_CHECK_ARGC(3); PY_CHECK_ARG_TYPE(0, tp_int); PY_CHECK_ARG_TYPE(1, tp_int); @@ -156,6 +176,7 @@ static bool stdc_memset(int argc, py_Ref argv) { } static bool stdc_memcmp(int argc, py_Ref argv) { + if(!check_stdc_cap()) return false; PY_CHECK_ARGC(3); PY_CHECK_ARG_TYPE(0, tp_int); PY_CHECK_ARG_TYPE(1, tp_int); @@ -169,6 +190,7 @@ static bool stdc_memcmp(int argc, py_Ref argv) { } static bool stdc_addressof(int argc, py_Ref argv) { + if(!check_stdc_cap()) return false; PY_CHECK_ARGC(1); if(!py_checkinstance(argv, tp_stdc_Memory)) return false; void* ud = py_touserdata(argv); @@ -177,6 +199,7 @@ static bool stdc_addressof(int argc, py_Ref argv) { } static bool stdc_sizeof(int argc, py_Ref argv) { + if(!check_stdc_cap()) return false; PY_CHECK_ARGC(1); PY_CHECK_ARG_TYPE(0, tp_type); py_Type type = py_totype(&argv[0]); @@ -188,6 +211,7 @@ static bool stdc_sizeof(int argc, py_Ref argv) { } static bool stdc_read_cstr(int argc, py_Ref argv) { + if(!check_stdc_cap()) return false; PY_CHECK_ARGC(1); PY_CHECK_ARG_TYPE(0, tp_int); char* p = (char*)(intptr_t)py_toint(&argv[0]); @@ -196,6 +220,7 @@ static bool stdc_read_cstr(int argc, py_Ref argv) { } static bool stdc_write_cstr(int argc, py_Ref argv) { + if(!check_stdc_cap()) return false; PY_CHECK_ARGC(2); PY_CHECK_ARG_TYPE(0, tp_int); PY_CHECK_ARG_TYPE(1, tp_str); @@ -208,6 +233,7 @@ static bool stdc_write_cstr(int argc, py_Ref argv) { } static bool stdc_read_bytes(int argc, py_Ref argv) { + if(!check_stdc_cap()) return false; PY_CHECK_ARGC(2); PY_CHECK_ARG_TYPE(0, tp_int); PY_CHECK_ARG_TYPE(1, tp_int); @@ -219,6 +245,7 @@ static bool stdc_read_bytes(int argc, py_Ref argv) { } static bool stdc_write_bytes(int argc, py_Ref argv) { + if(!check_stdc_cap()) return false; PY_CHECK_ARGC(2); PY_CHECK_ARG_TYPE(0, tp_int); PY_CHECK_ARG_TYPE(1, tp_bytes); diff --git a/src/public/GlobalSetup.c b/src/public/GlobalSetup.c index 5c749544..a7bd33e8 100644 --- a/src/public/GlobalSetup.c +++ b/src/public/GlobalSetup.c @@ -110,6 +110,8 @@ void py_setvmctx(void* ctx) { pk_current_vm->ctx = ctx; } py_Callbacks* py_callbacks() { return &pk_current_vm->callbacks; } +py_Capabilities* py_capabilities() { return &pk_current_vm->capabilities; } + py_AppCallbacks* py_appcallbacks() { static py_AppCallbacks _callbacks = {0}; return &_callbacks; diff --git a/tests/300_import.py b/tests/300_import.py index 8969b2dc..d214b3e9 100644 --- a/tests/300_import.py +++ b/tests/300_import.py @@ -1,3 +1,6 @@ +print('sandbox mode, module is disabled') +exit() + try: import os except ImportError: diff --git a/tests/301_import1.py b/tests/301_import1.py index f5212d69..53516b62 100644 --- a/tests/301_import1.py +++ b/tests/301_import1.py @@ -1,3 +1,6 @@ +print('sandbox mode, module is disabled') +exit() + try: import os except ImportError: diff --git a/tests/310_modulereload.py b/tests/310_modulereload.py index 644d675a..78f882bd 100644 --- a/tests/310_modulereload.py +++ b/tests/310_modulereload.py @@ -1,3 +1,6 @@ +print('sandbox mode, module is disabled') +exit() + try: import os except ImportError: diff --git a/tests/792_file.py b/tests/792_file.py index 5adae027..554bcf10 100644 --- a/tests/792_file.py +++ b/tests/792_file.py @@ -1,3 +1,6 @@ +print('sandbox mode, module is disabled') +exit() + try: import os import io diff --git a/tests/793_stdc.py b/tests/793_stdc.py index 4c5b7c71..a3596790 100644 --- a/tests/793_stdc.py +++ b/tests/793_stdc.py @@ -1,3 +1,6 @@ +print('sandbox mode, module is disabled') +exit() + from stdc import * assert sizeof(Int8) == sizeof(UInt8) == 1 diff --git a/tests/922_py_compile.py b/tests/922_py_compile.py index 522d5cf8..aeb64cec 100644 --- a/tests/922_py_compile.py +++ b/tests/922_py_compile.py @@ -1,3 +1,6 @@ +print('sandbox mode, module is disabled') +exit() + try: import os except ImportError: diff --git a/tests/931_math.py b/tests/931_math.py index 52cc1b1d..6d45291c 100644 --- a/tests/931_math.py +++ b/tests/931_math.py @@ -1,3 +1,6 @@ +print('sandbox mode, module is disabled') +exit() + # https://github.com/python/cpython/blob/v3.4.10/Lib/test/test_math.py # Python test set -- math module