mirror of
https://github.com/janet-lang/janet
synced 2025-02-04 03:09:10 +00:00
Add sandboxing API.
The sandboxing API is meant to make janet a bit more attractive for certain application embedding use cases. The sandboxing API puts limits on what system resources the interpreter can access.
This commit is contained in:
parent
9476016741
commit
b032d94877
@ -667,6 +667,59 @@ JANET_CORE_FN(janet_core_memcmp,
|
||||
return janet_wrap_integer(memcmp(a.bytes + offset_a, b.bytes + offset_b, (size_t) len));
|
||||
}
|
||||
|
||||
typedef struct SandboxOption {
|
||||
const char *name;
|
||||
uint32_t flag;
|
||||
} SandboxOption;
|
||||
|
||||
static const SandboxOption sandbox_options[] = {
|
||||
{"all", JANET_SANDBOX_ALL},
|
||||
{"env", JANET_SANDBOX_ENV},
|
||||
{"ffi", JANET_SANDBOX_FFI},
|
||||
{"fs", JANET_SANDBOX_FS},
|
||||
{"fs-read", JANET_SANDBOX_FS_READ},
|
||||
{"fs-write", JANET_SANDBOX_FS_WRITE},
|
||||
{"hrtime", JANET_SANDBOX_HRTIME},
|
||||
{"net", JANET_SANDBOX_NET},
|
||||
{"net-connect", JANET_SANDBOX_NET_CONNECT},
|
||||
{"net-listen", JANET_SANDBOX_NET_LISTEN},
|
||||
{"sandbox", JANET_SANDBOX_SANDBOX},
|
||||
{"subprocess", JANET_SANDBOX_SUBPROCESS},
|
||||
{NULL, 0}
|
||||
};
|
||||
|
||||
JANET_CORE_FN(janet_core_sandbox,
|
||||
"(sandbox & forbidden-capabilities)",
|
||||
"Disable feature sets to prevent the interpreter from using certain system resources. "
|
||||
"Once a feature is disabled, there is no way to re-enable it. Cabapiblities can be:\n\n"
|
||||
"* :sandbox - disallow calling this function\n"
|
||||
"* :fs - disallow access to the file system\n"
|
||||
"* :fs-read - disallow read access to the file system\n"
|
||||
"* :fs-write - disallow write access to the file system\n"
|
||||
"* :env - disallow reading and write env variables\n"
|
||||
"* :subprocess - disallow running subprocesses\n"
|
||||
"* :hrtime - disallow high-resolution timers\n"
|
||||
"* :ffi - disallow FFI (recommended if disabling anythin else)\n"
|
||||
"* :net-connect - disallow making outbound network connctions\n"
|
||||
"* :net-listen - disallow accepting inbound network connctions\n"
|
||||
"* :net - disallow network access\n"
|
||||
"* :all - disallow all (except IO to stdout, stderr, and stdin)") {
|
||||
uint32_t flags = 0;
|
||||
for (int32_t i = 0; i < argc; i++) {
|
||||
JanetKeyword kw = janet_getkeyword(argv, i);
|
||||
const SandboxOption *opt = sandbox_options;
|
||||
while (opt->name != NULL) {
|
||||
if (janet_cstrcmp(kw, opt->name) == 0) {
|
||||
flags |= opt->flag;
|
||||
break;
|
||||
}
|
||||
opt++;
|
||||
}
|
||||
}
|
||||
janet_sandbox(flags);
|
||||
return janet_wrap_nil();
|
||||
}
|
||||
|
||||
#ifdef JANET_BOOTSTRAP
|
||||
|
||||
/* Utility for inline assembly */
|
||||
@ -970,6 +1023,7 @@ static void janet_load_libs(JanetTable *env) {
|
||||
JANET_CORE_REG("signal", janet_core_signal),
|
||||
JANET_CORE_REG("memcmp", janet_core_memcmp),
|
||||
JANET_CORE_REG("getproto", janet_core_getproto),
|
||||
JANET_CORE_REG("sandbox", janet_core_sandbox),
|
||||
JANET_REG_END
|
||||
};
|
||||
janet_core_cfuns_ext(env, NULL, corelib_cfuns);
|
||||
|
@ -2778,6 +2778,7 @@ static JanetEVGenericMessage janet_go_thread_subr(JanetEVGenericMessage args) {
|
||||
uint32_t flags = args.tag;
|
||||
args.tag = 0;
|
||||
janet_init();
|
||||
janet_vm.sandbox_flags = (uint32_t) args.argi;
|
||||
JanetTryState tstate;
|
||||
JanetSignal signal = janet_try(&tstate);
|
||||
if (!signal) {
|
||||
@ -2930,13 +2931,13 @@ JANET_CORE_FN(cfun_ev_thread,
|
||||
JanetEVGenericMessage arguments;
|
||||
memset(&arguments, 0, sizeof(arguments));
|
||||
arguments.tag = (uint32_t) flags;
|
||||
arguments.argi = argc;
|
||||
arguments.argi = (uint32_t) janet_vm.sandbox_flags;
|
||||
arguments.argp = buffer;
|
||||
arguments.fiber = NULL;
|
||||
janet_ev_threaded_call(janet_go_thread_subr, arguments, janet_ev_default_threaded_callback);
|
||||
return janet_wrap_nil();
|
||||
} else {
|
||||
janet_ev_threaded_await(janet_go_thread_subr, (uint32_t) flags, argc, buffer);
|
||||
janet_ev_threaded_await(janet_go_thread_subr, (uint32_t) flags, (uint32_t) janet_vm.sandbox_flags, buffer);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1301,6 +1301,7 @@ JANET_CORE_FN(cfun_ffi_jitfn,
|
||||
"(ffi/jitfn bytes)",
|
||||
"Create an abstract type that can be used as the pointer argument to `ffi/call`. The content "
|
||||
"of `bytes` is architecture specific machine code that will be copied into executable memory.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_FFI);
|
||||
janet_fixarity(argc, 1);
|
||||
JanetByteView bytes = janet_getbytes(argv, 0);
|
||||
|
||||
@ -1349,6 +1350,7 @@ JANET_CORE_FN(cfun_ffi_call,
|
||||
"(ffi/call pointer signature & args)",
|
||||
"Call a raw pointer as a function pointer. The function signature specifies "
|
||||
"how Janet values in `args` are converted to native machine types.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_FFI);
|
||||
janet_arity(argc, 2, -1);
|
||||
void *function_pointer = janet_ffi_get_callable_pointer(argv, 0);
|
||||
JanetFFISignature *signature = janet_getabstract(argv, 1, &janet_signature_type);
|
||||
@ -1373,6 +1375,7 @@ JANET_CORE_FN(cfun_ffi_buffer_write,
|
||||
"Append a native tyep to a buffer such as it would appear in memory. This can be used "
|
||||
"to pass pointers to structs in the ffi, or send C/C++/native structs over the network "
|
||||
"or to files. Returns a modifed buffer or a new buffer if one is not supplied.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_FFI);
|
||||
janet_arity(argc, 2, 3);
|
||||
JanetFFIType type = decode_ffi_type(argv[0]);
|
||||
uint32_t el_size = (uint32_t) type_size(type);
|
||||
@ -1389,6 +1392,7 @@ JANET_CORE_FN(cfun_ffi_buffer_read,
|
||||
"Parse a native struct out of a buffer and convert it to normal Janet data structures. "
|
||||
"This function is the inverse of `ffi/write`. `bytes` can also be a raw pointer, although "
|
||||
"this is unsafe.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_FFI);
|
||||
janet_arity(argc, 2, 3);
|
||||
JanetFFIType type = decode_ffi_type(argv[0]);
|
||||
size_t offset = (size_t) janet_optnat(argv, argc, 2, 0);
|
||||
@ -1435,6 +1439,7 @@ JANET_CORE_FN(janet_core_raw_native,
|
||||
" or run any code from it. This is different than `native`, which will "
|
||||
"run initialization code to get a module table. If `path` is nil, opens the current running binary. "
|
||||
"Returns a `core/native`.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_FFI);
|
||||
janet_arity(argc, 0, 1);
|
||||
const char *path = janet_optcstring(argv, argc, 0, NULL);
|
||||
Clib lib = load_clib(path);
|
||||
@ -1450,6 +1455,7 @@ JANET_CORE_FN(janet_core_native_lookup,
|
||||
"(ffi/lookup native symbol-name)",
|
||||
"Lookup a symbol from a native object. All symbol lookups will return a raw pointer "
|
||||
"if the symbol is found, else nil.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_FFI);
|
||||
janet_fixarity(argc, 2);
|
||||
JanetAbstractNative *anative = janet_getabstract(argv, 0, &janet_native_type);
|
||||
const char *sym = janet_getcstring(argv, 1);
|
||||
@ -1463,6 +1469,7 @@ JANET_CORE_FN(janet_core_native_close,
|
||||
"(ffi/close native)",
|
||||
"Free a native object. Dereferencing pointers to symbols in the object will have undefined "
|
||||
"behavior after freeing.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_FFI);
|
||||
janet_fixarity(argc, 1);
|
||||
JanetAbstractNative *anative = janet_getabstract(argv, 0, &janet_native_type);
|
||||
if (anative->closed) janet_panic("native object already closed");
|
||||
@ -1475,6 +1482,7 @@ JANET_CORE_FN(janet_core_native_close,
|
||||
JANET_CORE_FN(cfun_ffi_malloc,
|
||||
"(ffi/malloc size)",
|
||||
"Allocates memory directly using the system memory allocator. Memory allocated in this way must be freed manually! Returns a raw pointer, or nil if size = 0.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_FFI);
|
||||
janet_fixarity(argc, 1);
|
||||
size_t size = janet_getsize(argv, 0);
|
||||
if (size == 0) return janet_wrap_nil();
|
||||
@ -1484,6 +1492,7 @@ JANET_CORE_FN(cfun_ffi_malloc,
|
||||
JANET_CORE_FN(cfun_ffi_free,
|
||||
"(ffi/free pointer)",
|
||||
"Free memory allocated with `ffi/malloc`.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_FFI);
|
||||
janet_fixarity(argc, 1);
|
||||
if (janet_checktype(argv[0], JANET_NIL)) return janet_wrap_nil();
|
||||
void *pointer = janet_getpointer(argv, 0);
|
||||
|
@ -69,12 +69,15 @@ static int32_t checkflags(const uint8_t *str) {
|
||||
break;
|
||||
case 'w':
|
||||
flags |= JANET_FILE_WRITE;
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_WRITE);
|
||||
break;
|
||||
case 'a':
|
||||
flags |= JANET_FILE_APPEND;
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS);
|
||||
break;
|
||||
case 'r':
|
||||
flags |= JANET_FILE_READ;
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_READ);
|
||||
break;
|
||||
}
|
||||
for (i = 1; i < len; i++) {
|
||||
@ -84,6 +87,7 @@ static int32_t checkflags(const uint8_t *str) {
|
||||
break;
|
||||
case '+':
|
||||
if (flags & JANET_FILE_UPDATE) return -1;
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_WRITE);
|
||||
flags |= JANET_FILE_UPDATE;
|
||||
break;
|
||||
case 'b':
|
||||
@ -116,6 +120,7 @@ JANET_CORE_FN(cfun_io_temp,
|
||||
"(file/temp)",
|
||||
"Open an anonymous temporary file that is removed on close. "
|
||||
"Raises an error on failure.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_WRITE);
|
||||
(void)argv;
|
||||
janet_fixarity(argc, 0);
|
||||
// XXX use mkostemp when we can to avoid CLOEXEC race.
|
||||
@ -148,6 +153,7 @@ JANET_CORE_FN(cfun_io_fopen,
|
||||
flags = checkflags(fmode);
|
||||
} else {
|
||||
fmode = (const uint8_t *)"r";
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_READ);
|
||||
flags = JANET_FILE_READ;
|
||||
}
|
||||
FILE *f = fopen((const char *)fname, (const char *)fmode);
|
||||
|
@ -379,6 +379,7 @@ JANET_CORE_FN(cfun_net_connect,
|
||||
"to specify a connection type, either :stream or :datagram. The default is :stream. "
|
||||
"Bindhost is an optional string to select from what address to make the outgoing "
|
||||
"connection, with the default being the same as using the OS's preferred address. ") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_NET_CONNECT);
|
||||
janet_arity(argc, 2, 5);
|
||||
|
||||
/* Check arguments */
|
||||
@ -573,6 +574,7 @@ JANET_CORE_FN(cfun_net_listen,
|
||||
"The type parameter specifies the type of network connection, either "
|
||||
"a :stream (usually tcp), or :datagram (usually udp). If not specified, the default is "
|
||||
":stream. The host and port arguments are the same as in net/address.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_NET_LISTEN);
|
||||
janet_arity(argc, 2, 3);
|
||||
|
||||
/* Get host, port, and handler*/
|
||||
|
@ -878,6 +878,7 @@ static JanetFile *get_stdio_for_handle(JanetHandle handle, void *orig, int iswri
|
||||
#endif
|
||||
|
||||
static Janet os_execute_impl(int32_t argc, Janet *argv, int is_spawn) {
|
||||
janet_sandbox_assert(JANET_SANDBOX_SUBPROCESS);
|
||||
janet_arity(argc, 1, 3);
|
||||
|
||||
/* Get flags */
|
||||
@ -1171,6 +1172,7 @@ static JanetEVGenericMessage os_shell_subr(JanetEVGenericMessage args) {
|
||||
JANET_CORE_FN(os_shell,
|
||||
"(os/shell str)",
|
||||
"Pass a command string str directly to the system shell.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_SUBPROCESS);
|
||||
janet_arity(argc, 0, 1);
|
||||
const char *cmd = argc
|
||||
? janet_getcstring(argv, 0)
|
||||
@ -1190,6 +1192,7 @@ JANET_CORE_FN(os_shell,
|
||||
JANET_CORE_FN(os_environ,
|
||||
"(os/environ)",
|
||||
"Get a copy of the OS environment table.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_ENV);
|
||||
(void) argv;
|
||||
janet_fixarity(argc, 0);
|
||||
int32_t nenv = 0;
|
||||
@ -1221,6 +1224,7 @@ JANET_CORE_FN(os_environ,
|
||||
JANET_CORE_FN(os_getenv,
|
||||
"(os/getenv variable &opt dflt)",
|
||||
"Get the string value of an environment variable.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_ENV);
|
||||
janet_arity(argc, 1, 2);
|
||||
const char *cstr = janet_getcstring(argv, 0);
|
||||
const char *res = getenv(cstr);
|
||||
@ -1244,6 +1248,7 @@ JANET_CORE_FN(os_setenv,
|
||||
#define SETENV(K,V) setenv(K, V, 1)
|
||||
#define UNSETENV(K) unsetenv(K)
|
||||
#endif
|
||||
janet_sandbox_assert(JANET_SANDBOX_ENV);
|
||||
janet_arity(argc, 1, 2);
|
||||
const char *ks = janet_getcstring(argv, 0);
|
||||
const char *vs = janet_optcstring(argv, argc, 1, NULL);
|
||||
@ -1271,6 +1276,7 @@ JANET_CORE_FN(os_clock,
|
||||
"(os/clock)",
|
||||
"Return the number of whole + fractional seconds since some fixed point in time. The clock "
|
||||
"is guaranteed to be non-decreasing in real time.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_HRTIME);
|
||||
janet_fixarity(argc, 0);
|
||||
(void) argv;
|
||||
struct timespec tv;
|
||||
@ -1512,6 +1518,7 @@ JANET_CORE_FN(os_link,
|
||||
"Iff symlink is truthy, creates a symlink. "
|
||||
"Iff symlink is falsey or not provided, "
|
||||
"creates a hard link. Does not work on Windows.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_WRITE);
|
||||
janet_arity(argc, 2, 3);
|
||||
#ifdef JANET_WINDOWS
|
||||
(void) argc;
|
||||
@ -1530,6 +1537,7 @@ JANET_CORE_FN(os_link,
|
||||
JANET_CORE_FN(os_symlink,
|
||||
"(os/symlink oldpath newpath)",
|
||||
"Create a symlink from oldpath to newpath, returning nil. Same as `(os/link oldpath newpath true)`.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_WRITE);
|
||||
janet_fixarity(argc, 2);
|
||||
#ifdef JANET_WINDOWS
|
||||
(void) argc;
|
||||
@ -1552,6 +1560,7 @@ JANET_CORE_FN(os_mkdir,
|
||||
"Create a new directory. The path will be relative to the current directory if relative, otherwise "
|
||||
"it will be an absolute path. Returns true if the directory was created, false if the directory already exists, and "
|
||||
"errors otherwise.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_WRITE);
|
||||
janet_fixarity(argc, 1);
|
||||
const char *path = janet_getcstring(argv, 0);
|
||||
#ifdef JANET_WINDOWS
|
||||
@ -1567,6 +1576,7 @@ JANET_CORE_FN(os_mkdir,
|
||||
JANET_CORE_FN(os_rmdir,
|
||||
"(os/rmdir path)",
|
||||
"Delete a directory. The directory must be empty to succeed.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_WRITE);
|
||||
janet_fixarity(argc, 1);
|
||||
const char *path = janet_getcstring(argv, 0);
|
||||
#ifdef JANET_WINDOWS
|
||||
@ -1581,6 +1591,7 @@ JANET_CORE_FN(os_rmdir,
|
||||
JANET_CORE_FN(os_cd,
|
||||
"(os/cd path)",
|
||||
"Change current directory to path. Returns nil on success, errors on failure.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_READ);
|
||||
janet_fixarity(argc, 1);
|
||||
const char *path = janet_getcstring(argv, 0);
|
||||
#ifdef JANET_WINDOWS
|
||||
@ -1596,6 +1607,7 @@ JANET_CORE_FN(os_touch,
|
||||
"(os/touch path &opt actime modtime)",
|
||||
"Update the access time and modification times for a file. By default, sets "
|
||||
"times to the current time.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_WRITE);
|
||||
janet_arity(argc, 1, 3);
|
||||
const char *path = janet_getcstring(argv, 0);
|
||||
struct utimbuf timebuf, *bufp;
|
||||
@ -1845,6 +1857,7 @@ static const struct OsStatGetter os_stat_getters[] = {
|
||||
};
|
||||
|
||||
static Janet os_stat_or_lstat(int do_lstat, int32_t argc, Janet *argv) {
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_READ);
|
||||
janet_arity(argc, 1, 2);
|
||||
const char *path = janet_getcstring(argv, 0);
|
||||
JanetTable *tab = NULL;
|
||||
@ -1926,6 +1939,7 @@ JANET_CORE_FN(os_chmod,
|
||||
"`os/perm-string`, or an integer as returned by `os/perm-int`. "
|
||||
"When `mode` is an integer, it is interpreted as a Unix permission value, best specified in octal, like "
|
||||
"8r666 or 8r400. Windows will not differentiate between user, group, and other permissions, and thus will combine all of these permissions. Returns nil.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_WRITE);
|
||||
janet_fixarity(argc, 2);
|
||||
const char *path = janet_getcstring(argv, 0);
|
||||
#ifdef JANET_WINDOWS
|
||||
@ -1941,6 +1955,7 @@ JANET_CORE_FN(os_chmod,
|
||||
JANET_CORE_FN(os_umask,
|
||||
"(os/umask mask)",
|
||||
"Set a new umask, returns the old umask.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_WRITE);
|
||||
janet_fixarity(argc, 1);
|
||||
int mask = (int) os_getmode(argv, 0);
|
||||
#ifdef JANET_WINDOWS
|
||||
@ -1956,6 +1971,7 @@ JANET_CORE_FN(os_dir,
|
||||
"(os/dir dir &opt array)",
|
||||
"Iterate over files and subdirectories in a directory. Returns an array of paths parts, "
|
||||
"with only the file name or directory name and no prefix.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_READ);
|
||||
janet_arity(argc, 1, 2);
|
||||
const char *dir = janet_getcstring(argv, 0);
|
||||
JanetArray *paths = (argc == 2) ? janet_getarray(argv, 1) : janet_array(0);
|
||||
@ -1993,6 +2009,7 @@ JANET_CORE_FN(os_dir,
|
||||
JANET_CORE_FN(os_rename,
|
||||
"(os/rename oldname newname)",
|
||||
"Rename a file on disk to a new path. Returns nil.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_WRITE);
|
||||
janet_fixarity(argc, 2);
|
||||
const char *src = janet_getcstring(argv, 0);
|
||||
const char *dest = janet_getcstring(argv, 1);
|
||||
@ -2007,6 +2024,7 @@ JANET_CORE_FN(os_realpath,
|
||||
"(os/realpath path)",
|
||||
"Get the absolute path for a given path, following ../, ./, and symlinks. "
|
||||
"Returns an absolute path as a string.") {
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_READ);
|
||||
janet_fixarity(argc, 1);
|
||||
const char *src = janet_getcstring(argv, 0);
|
||||
#ifdef JANET_NO_REALPATH
|
||||
@ -2101,19 +2119,23 @@ JANET_CORE_FN(os_open,
|
||||
case 'r':
|
||||
desiredAccess |= GENERIC_READ;
|
||||
stream_flags |= JANET_STREAM_READABLE;
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_READ);
|
||||
break;
|
||||
case 'w':
|
||||
desiredAccess |= GENERIC_WRITE;
|
||||
stream_flags |= JANET_STREAM_WRITABLE;
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_WRITE);
|
||||
break;
|
||||
case 'c':
|
||||
creatUnix |= OCREAT;
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_WRITE);
|
||||
break;
|
||||
case 'e':
|
||||
creatUnix |= OEXCL;
|
||||
break;
|
||||
case 't':
|
||||
creatUnix |= OTRUNC;
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_WRITE);
|
||||
break;
|
||||
/* Windows only flags */
|
||||
case 'D':
|
||||
@ -2183,19 +2205,23 @@ JANET_CORE_FN(os_open,
|
||||
case 'r':
|
||||
read_flag = 1;
|
||||
stream_flags |= JANET_STREAM_READABLE;
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_READ);
|
||||
break;
|
||||
case 'w':
|
||||
write_flag = 1;
|
||||
stream_flags |= JANET_STREAM_WRITABLE;
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_WRITE);
|
||||
break;
|
||||
case 'c':
|
||||
open_flags |= O_CREAT;
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_WRITE);
|
||||
break;
|
||||
case 'e':
|
||||
open_flags |= O_EXCL;
|
||||
break;
|
||||
case 't':
|
||||
open_flags |= O_TRUNC;
|
||||
janet_sandbox_assert(JANET_SANDBOX_FS_WRITE);
|
||||
break;
|
||||
/* posix only */
|
||||
case 'x':
|
||||
@ -2270,48 +2296,65 @@ void janet_lib_os(JanetTable *env) {
|
||||
JANET_CORE_REG("os/arch", os_arch),
|
||||
JANET_CORE_REG("os/compiler", os_compiler),
|
||||
#ifndef JANET_REDUCED_OS
|
||||
|
||||
/* misc (un-sandboxed) */
|
||||
JANET_CORE_REG("os/cpu-count", os_cpu_count),
|
||||
JANET_CORE_REG("os/cwd", os_cwd),
|
||||
JANET_CORE_REG("os/cryptorand", os_cryptorand),
|
||||
JANET_CORE_REG("os/perm-string", os_permission_string),
|
||||
JANET_CORE_REG("os/perm-int", os_permission_int),
|
||||
JANET_CORE_REG("os/mktime", os_mktime),
|
||||
JANET_CORE_REG("os/time", os_time), /* not high resolution */
|
||||
JANET_CORE_REG("os/date", os_date), /* not high resolution */
|
||||
JANET_CORE_REG("os/sleep", os_sleep),
|
||||
|
||||
/* env functions */
|
||||
JANET_CORE_REG("os/environ", os_environ),
|
||||
JANET_CORE_REG("os/getenv", os_getenv),
|
||||
JANET_CORE_REG("os/setenv", os_setenv),
|
||||
|
||||
/* fs read */
|
||||
JANET_CORE_REG("os/dir", os_dir),
|
||||
JANET_CORE_REG("os/stat", os_stat),
|
||||
JANET_CORE_REG("os/lstat", os_lstat),
|
||||
JANET_CORE_REG("os/chmod", os_chmod),
|
||||
JANET_CORE_REG("os/touch", os_touch),
|
||||
JANET_CORE_REG("os/realpath", os_realpath),
|
||||
JANET_CORE_REG("os/cd", os_cd),
|
||||
JANET_CORE_REG("os/cpu-count", os_cpu_count),
|
||||
#ifndef JANET_NO_UMASK
|
||||
JANET_CORE_REG("os/umask", os_umask),
|
||||
#endif
|
||||
#ifndef JANET_NO_SYMLINKS
|
||||
JANET_CORE_REG("os/readlink", os_readlink),
|
||||
#endif
|
||||
|
||||
/* fs write */
|
||||
JANET_CORE_REG("os/mkdir", os_mkdir),
|
||||
JANET_CORE_REG("os/rmdir", os_rmdir),
|
||||
JANET_CORE_REG("os/rm", os_remove),
|
||||
JANET_CORE_REG("os/link", os_link),
|
||||
JANET_CORE_REG("os/rename", os_rename),
|
||||
#ifndef JANET_NO_SYMLINKS
|
||||
JANET_CORE_REG("os/symlink", os_symlink),
|
||||
JANET_CORE_REG("os/readlink", os_readlink),
|
||||
#endif
|
||||
|
||||
/* processes */
|
||||
#ifndef JANET_NO_PROCESSES
|
||||
JANET_CORE_REG("os/execute", os_execute),
|
||||
JANET_CORE_REG("os/spawn", os_spawn),
|
||||
JANET_CORE_REG("os/shell", os_shell),
|
||||
/* no need to sandbox process management if you can't create processes
|
||||
* (allows for limited functionality if use exposes C-functions to create specific processes) */
|
||||
JANET_CORE_REG("os/proc-wait", os_proc_wait),
|
||||
JANET_CORE_REG("os/proc-kill", os_proc_kill),
|
||||
JANET_CORE_REG("os/proc-close", os_proc_close),
|
||||
#endif
|
||||
JANET_CORE_REG("os/setenv", os_setenv),
|
||||
JANET_CORE_REG("os/time", os_time),
|
||||
JANET_CORE_REG("os/mktime", os_mktime),
|
||||
|
||||
/* high resolution timers */
|
||||
JANET_CORE_REG("os/clock", os_clock),
|
||||
JANET_CORE_REG("os/sleep", os_sleep),
|
||||
JANET_CORE_REG("os/cwd", os_cwd),
|
||||
JANET_CORE_REG("os/cryptorand", os_cryptorand),
|
||||
JANET_CORE_REG("os/date", os_date),
|
||||
JANET_CORE_REG("os/rename", os_rename),
|
||||
JANET_CORE_REG("os/realpath", os_realpath),
|
||||
JANET_CORE_REG("os/perm-string", os_permission_string),
|
||||
JANET_CORE_REG("os/perm-int", os_permission_int),
|
||||
|
||||
#ifdef JANET_EV
|
||||
JANET_CORE_REG("os/open", os_open),
|
||||
JANET_CORE_REG("os/open", os_open), /* fs read and write */
|
||||
JANET_CORE_REG("os/pipe", os_pipe),
|
||||
#endif
|
||||
#endif
|
||||
|
@ -135,6 +135,9 @@ struct JanetVM {
|
||||
size_t scratch_cap;
|
||||
size_t scratch_len;
|
||||
|
||||
/* Sandbox flags */
|
||||
uint32_t sandbox_flags;
|
||||
|
||||
/* Random number generator */
|
||||
JanetRNG rng;
|
||||
|
||||
|
@ -1559,6 +1559,9 @@ int janet_init(void) {
|
||||
janet_vm.scratch_len = 0;
|
||||
janet_vm.scratch_cap = 0;
|
||||
|
||||
/* Sandbox flags */
|
||||
janet_vm.sandbox_flags = 0;
|
||||
|
||||
/* Initialize registry */
|
||||
janet_vm.registry = NULL;
|
||||
janet_vm.registry_cap = 0;
|
||||
@ -1600,6 +1603,18 @@ int janet_init(void) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Disable some features at runtime with no way to re-enable them */
|
||||
void janet_sandbox(uint32_t flags) {
|
||||
janet_sandbox_assert(JANET_SANDBOX_SANDBOX);
|
||||
janet_vm.sandbox_flags |= flags;
|
||||
}
|
||||
|
||||
void janet_sandbox_assert(uint32_t forbidden_flags) {
|
||||
if (forbidden_flags & janet_vm.sandbox_flags) {
|
||||
janet_panic("operation forbidden by sandbox");
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear all memory associated with the VM */
|
||||
void janet_deinit(void) {
|
||||
janet_clear_memory();
|
||||
|
@ -1798,6 +1798,22 @@ JANET_API Janet janet_mcall(const char *name, int32_t argc, Janet *argv);
|
||||
JANET_API void janet_stacktrace(JanetFiber *fiber, Janet err);
|
||||
JANET_API void janet_stacktrace_ext(JanetFiber *fiber, Janet err, const char *prefix);
|
||||
|
||||
/* Sandboxing API */
|
||||
#define JANET_SANDBOX_SANDBOX 1
|
||||
#define JANET_SANDBOX_SUBPROCESS 2
|
||||
#define JANET_SANDBOX_NET_CONNECT 4
|
||||
#define JANET_SANDBOX_NET_LISTEN 8
|
||||
#define JANET_SANDBOX_NET (JANET_SANDBOX_NET_CONNECT | JANET_SANDBOX_NET_LISTEN)
|
||||
#define JANET_SANDBOX_FFI 16
|
||||
#define JANET_SANDBOX_FS_WRITE 32
|
||||
#define JANET_SANDBOX_FS_READ 64
|
||||
#define JANET_SANDBOX_FS (JANET_SANDBOX_FS_WRITE | JANET_SANDBOX_FS_READ)
|
||||
#define JANET_SANDBOX_HRTIME 128
|
||||
#define JANET_SANDBOX_ENV 256
|
||||
#define JANET_SANDBOX_ALL (UINT32_MAX)
|
||||
JANET_API void janet_sandbox(uint32_t flags);
|
||||
JANET_API void janet_sandbox_assert(uint32_t forbidden_flags);
|
||||
|
||||
/* Scratch Memory API */
|
||||
typedef void (*JanetScratchFinalizer)(void *);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user