configurable trans-membrance hostcall blocklist
This commit is contained in:
@@ -8,3 +8,9 @@ gen_noise64
|
||||
gen_float
|
||||
gen_int
|
||||
gen_sha1
|
||||
sha256
|
||||
sha256_hex
|
||||
hmac_sha256
|
||||
hmac_sha256_hex
|
||||
random_bytes
|
||||
crypto_equal
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
Socket Functions
|
||||
|
||||
http_request
|
||||
http_request_async
|
||||
socket_close
|
||||
socket_connect
|
||||
socket_read
|
||||
|
||||
+24
-1
@@ -4,7 +4,6 @@ basename
|
||||
dirname
|
||||
expand_path
|
||||
file_append
|
||||
file_append_contents
|
||||
file_exists
|
||||
file_get_contents
|
||||
file_mtime
|
||||
@@ -16,6 +15,11 @@ path_join
|
||||
cwd_set
|
||||
shell_escape
|
||||
shell_exec
|
||||
shell_spawn
|
||||
job_status
|
||||
job_result
|
||||
job_await
|
||||
job_cancel
|
||||
file_unlink
|
||||
zip_create
|
||||
zip_list
|
||||
@@ -25,3 +29,22 @@ gz_compress
|
||||
gz_uncompress
|
||||
server_start_http
|
||||
server_stop
|
||||
file_open
|
||||
file_read
|
||||
file_pread
|
||||
file_write
|
||||
file_pwrite
|
||||
file_seek
|
||||
file_tell
|
||||
file_close
|
||||
file_stat
|
||||
dir_list
|
||||
file_rename
|
||||
file_copy
|
||||
file_truncate
|
||||
dir_remove
|
||||
file_temp
|
||||
file_chmod
|
||||
file_symlink
|
||||
file_readlink
|
||||
file_fsync
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
:title
|
||||
Blocked functions (hostcall blocklist)
|
||||
|
||||
:content
|
||||
UCE units reach the operating system only through a fixed set of `uce_host_*`
|
||||
membrane hostcalls (see the runtime architecture). A server operator can
|
||||
**disable individual hostcalls** so a deployment exposes only the capabilities it
|
||||
wants — for example turning off `shell_exec` or `http_request` on a hardened
|
||||
host. A unit that calls a disabled function fails at request time with the
|
||||
configurable error page, stating exactly which function was blocked and why.
|
||||
|
||||
## Configuration
|
||||
|
||||
Set `UCE_HOSTCALL_BLOCKLIST` in `/etc/uce/settings.cfg` to a comma-separated list
|
||||
of hostcall names. Names may be given bare (`shell_exec`) or fully qualified
|
||||
(`uce_host_shell_exec`); whitespace is ignored. Empty (the default) blocks
|
||||
nothing.
|
||||
|
||||
```
|
||||
UCE_HOSTCALL_BLOCKLIST=shell_exec, shell_spawn, http_request, http_request_async, mysql
|
||||
```
|
||||
|
||||
Changes take effect on **restart** (`systemctl restart uce`). There is no hot
|
||||
reload — the list is parsed once per worker process into a fast lookup, so an
|
||||
empty list has zero runtime cost and a non-empty list costs only a single check
|
||||
per hostcall at workspace birth (never per call).
|
||||
|
||||
## Behaviour when a blocked function is called
|
||||
|
||||
The blocked hostcall resolves to a trap stub instead of its real implementation.
|
||||
When a unit invokes it, the request fails into the runtime error page with:
|
||||
|
||||
- error type `policy_blocked` (so a custom error page template can special-case it),
|
||||
- a title `function disabled by server policy`,
|
||||
- a message naming the exact function, e.g. *"this unit called uce_host_shell_exec,
|
||||
which is disabled on this server by configuration (UCE_HOSTCALL_BLOCKLIST)"*.
|
||||
|
||||
The worker is unharmed (it is a clean guest trap, like any other), and only the
|
||||
offending request fails. A unit cannot catch this — blocking is enforcement, not
|
||||
a soft signal.
|
||||
|
||||
## What can and cannot be blocked
|
||||
|
||||
Any `uce_host_*` capability hostcall can be listed — file I/O, `shell_exec` /
|
||||
`shell_spawn`, `http_request`, `mysql`, sockets, memcache, crypto, the job
|
||||
registry, etc. (the full set is the membrane list in the runtime architecture
|
||||
doc and `src/wasm/core_hostcalls.syms`).
|
||||
|
||||
A small core set the runtime itself needs is **exempt** and ignored even if
|
||||
listed, so a deployment cannot be bricked by an over-broad blocklist:
|
||||
`component_resolve` (used for `component()` / unit rendering).
|
||||
|
||||
## Notes
|
||||
|
||||
- No recompilation is required (neither the wasm core nor the native binary) —
|
||||
this is pure runtime configuration; blocked hostcalls still exist as imports,
|
||||
they simply resolve to a trap.
|
||||
- Pure-compute library functions that are NOT hostcalls (string ops, `DValue`
|
||||
methods, hashing helpers like `gen_noise`, etc.) are not OS capabilities and
|
||||
cannot be blocked this way — only `uce_host_*` membrane calls are gateable.
|
||||
@@ -0,0 +1,7 @@
|
||||
# crypto_equal
|
||||
|
||||
```cpp
|
||||
bool crypto_equal(String a, String b)
|
||||
```
|
||||
|
||||
Constant-time byte comparison for secrets such as MACs and tokens.
|
||||
@@ -0,0 +1,3 @@
|
||||
DValue dir_list(String path)
|
||||
|
||||
Returns a list of `{ name, type, size, mtime }` entries for a policy-gated directory. Names are sorted and exclude `.`/`..`.
|
||||
@@ -0,0 +1,3 @@
|
||||
dir_remove
|
||||
|
||||
Structural filesystem operation across the wasm host membrane. All path arguments are policy-gated through the same guest file/write roots as other file APIs and return false on denial or OS error.
|
||||
@@ -11,6 +11,7 @@ file_name : file name of file that should be written to
|
||||
:content
|
||||
Opens or creates a file and appends data to it.
|
||||
|
||||
The append transparently takes an exclusive file lock for the duration of the append operation. Concurrent writers are serialized, and `file_get_contents()` waits for in-progress writes to finish; callers do not manage locks manually.
|
||||
## Related Concepts
|
||||
|
||||
- PHP: `file_put_contents($file, $data, FILE_APPEND)`
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
:sig
|
||||
bool file_append_contents(String file_name, String content)
|
||||
|
||||
:params
|
||||
file_name : path to open or create
|
||||
content : bytes to append
|
||||
return value : `true` when the append succeeds
|
||||
|
||||
:see
|
||||
>sys
|
||||
file_append
|
||||
file_put_contents
|
||||
file_get_contents
|
||||
|
||||
:content
|
||||
Appends one string to a file.
|
||||
|
||||
`file_append()` is the variadic convenience wrapper for ordinary page code. Use `file_append_contents()` when you already have one string buffer.
|
||||
|
||||
Example:
|
||||
|
||||
```uce
|
||||
bool ok = file_append_contents("/tmp/uce-log.txt", "line\n");
|
||||
```
|
||||
|
||||
The file is created if it does not exist.
|
||||
@@ -0,0 +1,3 @@
|
||||
file_chmod
|
||||
|
||||
Filesystem nicety added to the wasm host membrane. Path arguments are policy-gated; operations return an empty value or false on denial/error. file_fsync() takes an open file handle and flushes it with fsync().
|
||||
@@ -0,0 +1,5 @@
|
||||
file_close
|
||||
|
||||
Streaming/handle-based file I/O across the wasm host membrane. Handles are opaque u64 values returned by file_open(); 0 means open failed (including path policy denial or bounded lock timeout). Locks are automatic and lifetime-scoped: read opens take a shared lock, write/append/read-write opens take an exclusive lock, and file_close() releases it. Lock wait is bounded by UCE_FILE_LOCK_TIMEOUT_MS (default 2000ms).
|
||||
|
||||
See also: file_get_contents, file_put_contents, file_append.
|
||||
@@ -1,12 +0,0 @@
|
||||
:sig
|
||||
void file_close_locked(int fd)
|
||||
|
||||
:params
|
||||
fd : handle returned by `file_open_locked()`
|
||||
|
||||
:see
|
||||
>sys
|
||||
>file_open_locked
|
||||
|
||||
:content
|
||||
Releases the flock and closes a locked file handle. Wasm handles are opaque and request-local.
|
||||
@@ -0,0 +1,3 @@
|
||||
file_copy
|
||||
|
||||
Structural filesystem operation across the wasm host membrane. All path arguments are policy-gated through the same guest file/write roots as other file APIs and return false on denial or OS error.
|
||||
@@ -0,0 +1,3 @@
|
||||
file_fsync
|
||||
|
||||
Filesystem nicety added to the wasm host membrane. Path arguments are policy-gated; operations return an empty value or false on denial/error. file_fsync() takes an open file handle and flushes it with fsync().
|
||||
@@ -11,8 +11,9 @@ return value : String containing the file's contents
|
||||
:content
|
||||
Reads the file identified by `file_name` and returns it as a `String`.
|
||||
|
||||
If the file cannot be read, this function returns an empty string.
|
||||
The read transparently takes a shared file lock for the duration of the call. If another worker is writing the same file with `file_put_contents()` or `file_append()`, this read waits for that exclusive write lock to finish, so callers do not manage locks manually.
|
||||
|
||||
If the file cannot be read, this function returns an empty string.
|
||||
## Related Concepts
|
||||
|
||||
- PHP: `file_get_contents()`
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
:sig
|
||||
String file_get_contents_locked_fd(int fd)
|
||||
|
||||
:params
|
||||
fd : handle returned by `file_open_locked()`
|
||||
return value : complete file contents, or an empty string on error/empty file
|
||||
|
||||
:see
|
||||
>sys
|
||||
>file_open_locked
|
||||
>file_put_contents_locked_fd
|
||||
|
||||
:content
|
||||
Reads the full contents of a locked file handle from the start of the file.
|
||||
@@ -0,0 +1,5 @@
|
||||
file_open
|
||||
|
||||
Streaming/handle-based file I/O across the wasm host membrane. Handles are opaque u64 values returned by file_open(); 0 means open failed (including path policy denial or bounded lock timeout). Locks are automatic and lifetime-scoped: read opens take a shared lock, write/append/read-write opens take an exclusive lock, and file_close() releases it. Lock wait is bounded by UCE_FILE_LOCK_TIMEOUT_MS (default 2000ms).
|
||||
|
||||
See also: file_get_contents, file_put_contents, file_append.
|
||||
@@ -1,18 +0,0 @@
|
||||
:sig
|
||||
int file_open_locked(String file_name, int open_flags, int lock_type = LOCK_SH, int create_mode = 0644, f64 wait_timeout_seconds = 3.0, String purpose = "")
|
||||
|
||||
:params
|
||||
file_name : path to open
|
||||
open_flags : host open(2) flags
|
||||
lock_type : `LOCK_SH` or `LOCK_EX`
|
||||
create_mode : mode used when creating
|
||||
return value : opaque locked file handle, or -1
|
||||
|
||||
:see
|
||||
>sys
|
||||
>file_close_locked
|
||||
>file_get_contents_locked_fd
|
||||
>file_put_contents_locked_fd
|
||||
|
||||
:content
|
||||
Opens and locks a file on the host. In wasm units the returned integer is an opaque worker-owned handle that is valid only for the current request.
|
||||
@@ -0,0 +1,5 @@
|
||||
file_pread
|
||||
|
||||
Streaming/handle-based file I/O across the wasm host membrane. Handles are opaque u64 values returned by file_open(); 0 means open failed (including path policy denial or bounded lock timeout). Locks are automatic and lifetime-scoped: read opens take a shared lock, write/append/read-write opens take an exclusive lock, and file_close() releases it. Lock wait is bounded by UCE_FILE_LOCK_TIMEOUT_MS (default 2000ms).
|
||||
|
||||
See also: file_get_contents, file_put_contents, file_append.
|
||||
@@ -12,6 +12,7 @@ return value : true if write was successful
|
||||
:content
|
||||
Writes `content` into the file identified by `file_name`, overwriting any pre-existing content.
|
||||
|
||||
The write transparently takes an exclusive file lock for the duration of the truncate-and-write operation. Concurrent writers are serialized, and `file_get_contents()` waits for in-progress writes to finish; callers do not manage locks manually.
|
||||
## Related Concepts
|
||||
|
||||
- PHP: `file_put_contents()`
|
||||
|
||||
@@ -1,15 +0,0 @@
|
||||
:sig
|
||||
bool file_put_contents_locked_fd(int fd, String content)
|
||||
|
||||
:params
|
||||
fd : handle returned by `file_open_locked()`
|
||||
content : bytes to write
|
||||
return value : true on complete write
|
||||
|
||||
:see
|
||||
>sys
|
||||
>file_open_locked
|
||||
>file_get_contents_locked_fd
|
||||
|
||||
:content
|
||||
Truncates and rewrites the file behind a locked file handle.
|
||||
@@ -0,0 +1,5 @@
|
||||
file_pwrite
|
||||
|
||||
Streaming/handle-based file I/O across the wasm host membrane. Handles are opaque u64 values returned by file_open(); 0 means open failed (including path policy denial or bounded lock timeout). Locks are automatic and lifetime-scoped: read opens take a shared lock, write/append/read-write opens take an exclusive lock, and file_close() releases it. Lock wait is bounded by UCE_FILE_LOCK_TIMEOUT_MS (default 2000ms).
|
||||
|
||||
See also: file_get_contents, file_put_contents, file_append.
|
||||
@@ -0,0 +1,5 @@
|
||||
file_read
|
||||
|
||||
Streaming/handle-based file I/O across the wasm host membrane. Handles are opaque u64 values returned by file_open(); 0 means open failed (including path policy denial or bounded lock timeout). Locks are automatic and lifetime-scoped: read opens take a shared lock, write/append/read-write opens take an exclusive lock, and file_close() releases it. Lock wait is bounded by UCE_FILE_LOCK_TIMEOUT_MS (default 2000ms).
|
||||
|
||||
See also: file_get_contents, file_put_contents, file_append.
|
||||
@@ -0,0 +1,3 @@
|
||||
file_readlink
|
||||
|
||||
Filesystem nicety added to the wasm host membrane. Path arguments are policy-gated; operations return an empty value or false on denial/error. file_fsync() takes an open file handle and flushes it with fsync().
|
||||
@@ -1,12 +0,0 @@
|
||||
:sig
|
||||
void file_release_process_locks(String reason = "")
|
||||
|
||||
:params
|
||||
reason : diagnostic reason for releasing locks
|
||||
|
||||
:see
|
||||
>sys
|
||||
>file_open_locked
|
||||
|
||||
:content
|
||||
Releases locked file handles owned by the current process/workspace. Wasm uses this to close all request-local locked file handles.
|
||||
@@ -0,0 +1,3 @@
|
||||
file_rename
|
||||
|
||||
Structural filesystem operation across the wasm host membrane. All path arguments are policy-gated through the same guest file/write roots as other file APIs and return false on denial or OS error.
|
||||
@@ -0,0 +1,5 @@
|
||||
file_seek
|
||||
|
||||
Streaming/handle-based file I/O across the wasm host membrane. Handles are opaque u64 values returned by file_open(); 0 means open failed (including path policy denial or bounded lock timeout). Locks are automatic and lifetime-scoped: read opens take a shared lock, write/append/read-write opens take an exclusive lock, and file_close() releases it. Lock wait is bounded by UCE_FILE_LOCK_TIMEOUT_MS (default 2000ms).
|
||||
|
||||
See also: file_get_contents, file_put_contents, file_append.
|
||||
@@ -0,0 +1,3 @@
|
||||
DValue file_stat(String path)
|
||||
|
||||
Returns `{ exists, size, mtime, ctime, mode, is_dir, is_file, is_symlink }` for a policy-gated path. Missing or denied paths return `exists=false`.
|
||||
@@ -0,0 +1,3 @@
|
||||
file_symlink
|
||||
|
||||
Filesystem nicety added to the wasm host membrane. Path arguments are policy-gated; operations return an empty value or false on denial/error. file_fsync() takes an open file handle and flushes it with fsync().
|
||||
@@ -0,0 +1,5 @@
|
||||
file_tell
|
||||
|
||||
Streaming/handle-based file I/O across the wasm host membrane. Handles are opaque u64 values returned by file_open(); 0 means open failed (including path policy denial or bounded lock timeout). Locks are automatic and lifetime-scoped: read opens take a shared lock, write/append/read-write opens take an exclusive lock, and file_close() releases it. Lock wait is bounded by UCE_FILE_LOCK_TIMEOUT_MS (default 2000ms).
|
||||
|
||||
See also: file_get_contents, file_put_contents, file_append.
|
||||
@@ -0,0 +1,3 @@
|
||||
file_temp
|
||||
|
||||
Filesystem nicety added to the wasm host membrane. Path arguments are policy-gated; operations return an empty value or false on denial/error. file_fsync() takes an open file handle and flushes it with fsync().
|
||||
@@ -0,0 +1,3 @@
|
||||
file_truncate
|
||||
|
||||
Structural filesystem operation across the wasm host membrane. All path arguments are policy-gated through the same guest file/write roots as other file APIs and return false on denial or OS error.
|
||||
@@ -0,0 +1,5 @@
|
||||
file_write
|
||||
|
||||
Streaming/handle-based file I/O across the wasm host membrane. Handles are opaque u64 values returned by file_open(); 0 means open failed (including path policy denial or bounded lock timeout). Locks are automatic and lifetime-scoped: read opens take a shared lock, write/append/read-write opens take an exclusive lock, and file_close() releases it. Lock wait is bounded by UCE_FILE_LOCK_TIMEOUT_MS (default 2000ms).
|
||||
|
||||
See also: file_get_contents, file_put_contents, file_append.
|
||||
@@ -0,0 +1,7 @@
|
||||
# hmac_sha256
|
||||
|
||||
```cpp
|
||||
String hmac_sha256(String key, String data)
|
||||
```
|
||||
|
||||
Returns the raw 32-byte HMAC-SHA-256 digest for `data` keyed by `key`.
|
||||
@@ -0,0 +1,7 @@
|
||||
# hmac_sha256_hex
|
||||
|
||||
```cpp
|
||||
String hmac_sha256_hex(String key, String data)
|
||||
```
|
||||
|
||||
Returns the lowercase hexadecimal HMAC-SHA-256 digest.
|
||||
@@ -0,0 +1,9 @@
|
||||
# http_request
|
||||
|
||||
```cpp
|
||||
DValue http_request(DValue req)
|
||||
```
|
||||
|
||||
Performs a bounded outbound HTTP(S) request using the runtime `curl` binary. Request fields: `method`, `url`, `headers`, `body`, `timeout_ms`, `follow_redirects`.
|
||||
|
||||
Returns `{ status, headers, body, error }`. `headers` is a name/value map. A missing `curl` binary returns a clear `error` string.
|
||||
@@ -0,0 +1,7 @@
|
||||
# http_request_async
|
||||
|
||||
```cpp
|
||||
u64 http_request_async(DValue req)
|
||||
```
|
||||
|
||||
Starts the same bounded curl-backed request as `http_request()` in the file-backed async job registry and returns a job id. Use `job_await()` or `job_result()` to retrieve the HTTP result.
|
||||
@@ -0,0 +1,7 @@
|
||||
# job_await
|
||||
|
||||
```cpp
|
||||
DValue job_await(u64 job_id, u64 timeout_ms)
|
||||
```
|
||||
|
||||
Waits up to `timeout_ms` for a job to finish, then returns status/result data. The wait is always bounded and returns with `state=running` if the job is still active.
|
||||
@@ -0,0 +1,7 @@
|
||||
# job_cancel
|
||||
|
||||
```cpp
|
||||
bool job_cancel(u64 job_id)
|
||||
```
|
||||
|
||||
Attempts to terminate the background job process group and marks the registry entry as `cancelled`.
|
||||
@@ -0,0 +1,7 @@
|
||||
# job_result
|
||||
|
||||
```cpp
|
||||
DValue job_result(u64 job_id)
|
||||
```
|
||||
|
||||
Checks a job result with a small bounded wait. The returned value includes the current status fields and, when complete, a structured `result` value.
|
||||
@@ -0,0 +1,7 @@
|
||||
# job_status
|
||||
|
||||
```cpp
|
||||
DValue job_status(u64 job_id)
|
||||
```
|
||||
|
||||
Returns the file-backed async job state, e.g. `{ state, done, kind, pid, job_id }`. States include `pending`, `running`, `done`, `failed`, `cancelled`, and `missing`.
|
||||
@@ -0,0 +1,7 @@
|
||||
# random_bytes
|
||||
|
||||
```cpp
|
||||
String random_bytes(u64 n)
|
||||
```
|
||||
|
||||
Returns up to `n` bytes from the host CSPRNG. Requests are capped to a bounded size.
|
||||
@@ -0,0 +1,7 @@
|
||||
# sha256
|
||||
|
||||
```cpp
|
||||
String sha256(String data)
|
||||
```
|
||||
|
||||
Returns the raw 32-byte SHA-256 digest for `data`. Use `sha256_hex()` for printable lowercase hex.
|
||||
@@ -0,0 +1,7 @@
|
||||
# sha256_hex
|
||||
|
||||
```cpp
|
||||
String sha256_hex(String data)
|
||||
```
|
||||
|
||||
Returns the lowercase hexadecimal SHA-256 digest for `data`.
|
||||
@@ -0,0 +1,9 @@
|
||||
# shell_spawn
|
||||
|
||||
```cpp
|
||||
u64 shell_spawn(DValue spec)
|
||||
```
|
||||
|
||||
Starts a bounded background shell job and returns a job id. `spec` fields: `cmd`, optional `stdin`, optional `env` map, optional `timeout_ms`.
|
||||
|
||||
Use `job_status()`, `job_await()`, `job_result()`, or `job_cancel()` with the returned id.
|
||||
Reference in New Issue
Block a user