mirror of
				https://github.com/janet-lang/janet
				synced 2025-10-31 15:43:01 +00:00 
			
		
		
		
	Add more sandbox capabilities.
Add more granularity to ffi sandbox capabilities - distinguish between using FFI functions, creating FFI functions, and creating executable memory.
This commit is contained in:
		
							
								
								
									
										31
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										31
									
								
								README.md
									
									
									
									
									
								
							| @@ -6,7 +6,7 @@ | ||||
|  | ||||
| <img src="https://raw.githubusercontent.com/janet-lang/janet/master/assets/janet-w200.png" alt="Janet logo" width=200 align="left"> | ||||
|  | ||||
| **Janet** is a dynamic language and bytecode interpreter for system scripting, expressive automation, and | ||||
| **Janet** is a programming language for system scripting, expressive automation, and | ||||
| extending programs written in C or C++ with user scripting capabilities. | ||||
|  | ||||
| There is a REPL for trying out the language, as well as the ability | ||||
| @@ -105,34 +105,31 @@ See the examples directory for all provided example programs. | ||||
| ## Use Cases | ||||
|  | ||||
| Janet makes a good system scripting language, or a language to embed in other programs. | ||||
| It's like Lua and Guile in that regard. It has more built-in functionality and a richer core language than | ||||
| It's like Lua and GNU Guile in that regard. It has more built-in functionality and a richer core language than | ||||
| Lua, but smaller than GNU Guile or Python. However, it is much easier to embed and port than Python or Guile. | ||||
|  | ||||
| ## Features | ||||
| Some people use janet for sysadmin scripting, web development, or small video games. | ||||
|  | ||||
| ## Language Features | ||||
|  | ||||
| * 600+ functions and macros in the core library | ||||
| * Built-in socket networking, threading, subprocesses, and file system functions. | ||||
| * Parsing Expression Grammars (PEG) engine as a more robust Regex alternative | ||||
| * Macros | ||||
| * Macros and compile-time computation | ||||
| * Per-thread event loop for efficient IO (epoll/IOCP/kqueue) | ||||
| * Built-in C FFI lets you load existing binaries and run them. | ||||
| * First-class green threads (continuations) as well as OS threads | ||||
| * Erlang-style supervision trees that integrate with the event loop | ||||
| * Configurable at build time - turn features on or off for a smaller or more featureful build | ||||
| * First-class closures | ||||
| * Garbage collection | ||||
| * First-class green threads (continuations) | ||||
| * Distributed as janet.c and janet.h for embedding into a larger program. | ||||
| * Python-style generators (implemented as a plain macro) | ||||
| * Mutable and immutable arrays (array/tuple) | ||||
| * Mutable and immutable hashtables (table/struct) | ||||
| * Mutable and immutable strings (buffer/string) | ||||
| * Multithreading | ||||
| * Bytecode interpreter with an assembly interface, as well as bytecode verification | ||||
| * Tail-call optimization | ||||
| * Interface with C via abstract types and C functions | ||||
| * Dynamically load C libraries | ||||
| * REPL | ||||
| * Embedding Janet in other programs | ||||
| * Interactive environment with detailed stack traces | ||||
| * Tail recursion | ||||
| * Interface with C functions and dynamically load plugins ("natives"). | ||||
| * Built-in C FFI for when the native bindings are too much work | ||||
| * REPL development with debugger and inspectable runtime | ||||
|  | ||||
| ## Documentation | ||||
|  | ||||
| @@ -329,9 +326,7 @@ Gitter provides Matrix and IRC bridges as well. | ||||
|  | ||||
| ### How fast is it? | ||||
|  | ||||
| Medium speed. | ||||
|  | ||||
| In all seriousness, it is about the same speed as most interpreted languages without a JIT compiler. Tight, critical | ||||
| It is about the same speed as most interpreted languages without a JIT compiler. Tight, critical | ||||
| loops should probably be written in C or C++ . Programs tend to be a bit faster than | ||||
| they would be in a language like Python due to the discouragement of slow Object-Oriented abstraction | ||||
| with lots of hash-table lookups, and making late-binding explicit. All values are boxed in an 8-byte | ||||
|   | ||||
| @@ -677,6 +677,9 @@ static const SandboxOption sandbox_options[] = { | ||||
|     {"all", JANET_SANDBOX_ALL}, | ||||
|     {"env", JANET_SANDBOX_ENV}, | ||||
|     {"ffi", JANET_SANDBOX_FFI}, | ||||
|     {"ffi-define", JANET_SANDBOX_FFI_DEFINE}, | ||||
|     {"ffi-jit", JANET_SANDBOX_FFI_JIT}, | ||||
|     {"ffi-use", JANET_SANDBOX_FFI_USE}, | ||||
|     {"fs", JANET_SANDBOX_FS}, | ||||
|     {"fs-read", JANET_SANDBOX_FS_READ}, | ||||
|     {"fs-temp", JANET_SANDBOX_FS_TEMP}, | ||||
| @@ -698,6 +701,9 @@ JANET_CORE_FN(janet_core_sandbox, | ||||
|               "* :all - disallow all (except IO to stdout, stderr, and stdin)\n" | ||||
|               "* :env - disallow reading and write env variables\n" | ||||
|               "* :ffi - disallow FFI (recommended if disabling anything else)\n" | ||||
|               "* :ffi-define - disallow loading new FFI modules and binding new functions\n" | ||||
|               "* :ffi-jit - disallow calling `ffi/jitfn`\n" | ||||
|               "* :ffi-use - disallow using any previously bound FFI functions and memory-unsafe functions.\n" | ||||
|               "* :fs - disallow access to the file system\n" | ||||
|               "* :fs-read - disallow read access to the file system\n" | ||||
|               "* :fs-temp - disallow creating temporary files\n" | ||||
|   | ||||
| @@ -1303,7 +1303,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_sandbox_assert(JANET_SANDBOX_FFI_JIT); | ||||
|     janet_fixarity(argc, 1); | ||||
|     JanetByteView bytes = janet_getbytes(argv, 0); | ||||
|  | ||||
| @@ -1356,7 +1356,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_sandbox_assert(JANET_SANDBOX_FFI_USE); | ||||
|     janet_arity(argc, 2, -1); | ||||
|     void *function_pointer = janet_ffi_get_callable_pointer(argv, 0); | ||||
|     JanetFFISignature *signature = janet_getabstract(argv, 1, &janet_signature_type); | ||||
| @@ -1381,7 +1381,7 @@ JANET_CORE_FN(cfun_ffi_buffer_write, | ||||
|               "Append a native type 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_sandbox_assert(JANET_SANDBOX_FFI_USE); | ||||
|     janet_arity(argc, 2, 4); | ||||
|     JanetFFIType type = decode_ffi_type(argv[0]); | ||||
|     uint32_t el_size = (uint32_t) type_size(type); | ||||
| @@ -1404,7 +1404,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_sandbox_assert(JANET_SANDBOX_FFI_USE); | ||||
|     janet_arity(argc, 2, 3); | ||||
|     JanetFFIType type = decode_ffi_type(argv[0]); | ||||
|     size_t offset = (size_t) janet_optnat(argv, argc, 2, 0); | ||||
| @@ -1451,7 +1451,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_sandbox_assert(JANET_SANDBOX_FFI_DEFINE); | ||||
|     janet_arity(argc, 0, 1); | ||||
|     const char *path = janet_optcstring(argv, argc, 0, NULL); | ||||
|     Clib lib = load_clib(path); | ||||
| @@ -1467,7 +1467,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_sandbox_assert(JANET_SANDBOX_FFI_DEFINE); | ||||
|     janet_fixarity(argc, 2); | ||||
|     JanetAbstractNative *anative = janet_getabstract(argv, 0, &janet_native_type); | ||||
|     const char *sym = janet_getcstring(argv, 1); | ||||
| @@ -1481,7 +1481,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_sandbox_assert(JANET_SANDBOX_FFI_DEFINE); | ||||
|     janet_fixarity(argc, 1); | ||||
|     JanetAbstractNative *anative = janet_getabstract(argv, 0, &janet_native_type); | ||||
|     if (anative->closed) janet_panic("native object already closed"); | ||||
| @@ -1494,7 +1494,7 @@ JANET_CORE_FN(janet_core_native_close, | ||||
| JANET_CORE_FN(cfun_ffi_malloc, | ||||
|               "(ffi/malloc size)", | ||||
|               "Allocates memory directly using the janet 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_sandbox_assert(JANET_SANDBOX_FFI_USE); | ||||
|     janet_fixarity(argc, 1); | ||||
|     size_t size = janet_getsize(argv, 0); | ||||
|     if (size == 0) return janet_wrap_nil(); | ||||
| @@ -1504,7 +1504,7 @@ JANET_CORE_FN(cfun_ffi_malloc, | ||||
| JANET_CORE_FN(cfun_ffi_free, | ||||
|               "(ffi/free pointer)", | ||||
|               "Free memory allocated with `ffi/malloc`. Returns nil.") { | ||||
|     janet_sandbox_assert(JANET_SANDBOX_FFI); | ||||
|     janet_sandbox_assert(JANET_SANDBOX_FFI_USE); | ||||
|     janet_fixarity(argc, 1); | ||||
|     if (janet_checktype(argv[0], JANET_NIL)) return janet_wrap_nil(); | ||||
|     void *pointer = janet_getpointer(argv, 0); | ||||
| @@ -1519,7 +1519,7 @@ JANET_CORE_FN(cfun_ffi_pointer_buffer, | ||||
|               "to be manipulated with buffer functions. Attempts to resize or extend the buffer " | ||||
|               "beyond its initial capacity will raise an error. As with many FFI functions, this is memory " | ||||
|               "unsafe and can potentially allow out of bounds memory access. Returns a new buffer.") { | ||||
|     janet_sandbox_assert(JANET_SANDBOX_FFI); | ||||
|     janet_sandbox_assert(JANET_SANDBOX_FFI_USE); | ||||
|     janet_arity(argc, 2, 4); | ||||
|     void *pointer = janet_getpointer(argv, 0); | ||||
|     int32_t capacity = janet_getnat(argv, 1); | ||||
|   | ||||
| @@ -1809,13 +1809,16 @@ JANET_API void janet_stacktrace_ext(JanetFiber *fiber, Janet err, const char *pr | ||||
| #define JANET_SANDBOX_SUBPROCESS 2 | ||||
| #define JANET_SANDBOX_NET_CONNECT 4 | ||||
| #define JANET_SANDBOX_NET_LISTEN 8 | ||||
| #define JANET_SANDBOX_FFI 16 | ||||
| #define JANET_SANDBOX_FFI_DEFINE 16 | ||||
| #define JANET_SANDBOX_FS_WRITE 32 | ||||
| #define JANET_SANDBOX_FS_READ 64 | ||||
| #define JANET_SANDBOX_HRTIME 128 | ||||
| #define JANET_SANDBOX_ENV 256 | ||||
| #define JANET_SANDBOX_DYNAMIC_MODULES 512 | ||||
| #define JANET_SANDBOX_FS_TEMP 1024 | ||||
| #define JANET_SANDBOX_FFI_USE 2048 | ||||
| #define JANET_SANDBOX_FFI_JIT 4096 | ||||
| #define JANET_SANDBOX_FFI (JANET_SANDBOX_FFI_DEFINE | JANET_SANDBOX_FFI_USE | JANET_SANDBOX_FFI_JIT) | ||||
| #define JANET_SANDBOX_FS (JANET_SANDBOX_FS_WRITE | JANET_SANDBOX_FS_READ | JANET_SANDBOX_FS_TEMP) | ||||
| #define JANET_SANDBOX_NET (JANET_SANDBOX_NET_CONNECT | JANET_SANDBOX_NET_LISTEN) | ||||
| #define JANET_SANDBOX_ALL (UINT32_MAX) | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Calvin Rose
					Calvin Rose