Skip to content

Commit c673f3f

Browse files
committed
fix: resolve Linux FFI signature mismatch for main_l_get_tab_owner
1 parent aec150e commit c673f3f

32 files changed

Lines changed: 209 additions & 160 deletions

File tree

.github/ISSUE_TEMPLATE/bug_report.yml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ body:
3939
id: plugin
4040
attributes:
4141
label: "Relevant Plugin (If Applicable)"
42-
description: "If this issue is related to a specific WebAssembly plugin (such as pTerm), specify its name and version."
43-
placeholder: "e.g., pTerm vx.x.x"
42+
description: "If this issue is related to a specific WebAssembly plugin, specify its name and version."
43+
placeholder: "e.g., plugin vx.x.x"
4444
validations:
45-
required: false
45+
required: false

CHANGELOG.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
* Shared WASM compilation module `tests/build_utils.py` to enforce `--allow-undefined` linker flags globally across all plugin builds.
1010
* Automated target binary copying and caching for Linux production builds.
1111
* Custom structured issue templates (Bug Report, Feature Request, Plugin Submission) and a Pull Request template in `.github/`.
12+
* Platform-agnostic OS detection FFI `host_get_platform` returning compile-time host platform evaluation (0 for Windows, 1 for Linux) to eliminate brittle environment variable parsing.
13+
* Linux shell executor backend (`sh.rs`) executing `/bin/sh -c` queries for the `pTerm` plugin.
14+
* Shell blacklisting security reinforcement: added `dash` shell to the banned executable list in the sandbox to block unauthorized access by untrusted plugins.
1215

1316
### Fixed
1417
* Linux CI cross-compilation failure (`x86_64-pc-windows-gnu` target) — removed orphaned `.cargo/config.toml` that forced incorrect target resolution on Linux runners.
@@ -21,6 +24,10 @@
2124
* Linux production linker `undefined reference to 'g_headless_mode'` — guarded `extern "C"` declaration in `main_l.cpp` under `#ifdef PLUG_ENABLE_HEADLESS_MODE`; production builds now use `static constexpr bool g_headless_mode = false` with zero runtime cost.
2225
* GCC `-Wextern-initializer` warning in `main.cpp` — changed `extern "C" bool g_headless_mode = false` to block-form `extern "C" { bool g_headless_mode = false; }`.
2326
* Process hang on `/e` exit in headless mode — `g_cmd_thread` was blocking indefinitely on `g_cmd_cv.wait()`; `main_l_cleanup()` now sets `g_cmd_thread_running = false`, notifies the CV, and joins the thread before returning so the process exits cleanly within the test timeout window.
27+
* Headless CI broken pipe (`test_cli_lifecycle`) — moved `g_cmd_thread` and `g_headless_stdin_thread` startup from `on_tick()` frame-clock callback to `on_activate()` so stdin reader is live before any test data arrives; frame-clock callbacks are not guaranteed to fire before GApplication idle-hold expires under `xvfb-run`.
28+
* Linux `test_sandbox_rules` 120s timeout — plugin directory was hardcoded to `C:\.plug\plugins` (Windows-only); corrected to `$HOME/.plug/plugins` matching `proc.rs` `c_init()` runtime logic.
29+
* FFI Windows-centric symbol leakage — renamed `main_w_add_tab` to platform-neutral `host_add_tab` across `plugin_mgr.rs`, pTerm manifests, source plugin files, and test mocks (`ok_plugin.rs`, `rogue_plugin.rs`, `rogue_plugin_runtime.rs`) to prevent load-time link failures.
30+
* `pTerm` Linux shell execution compatibility — resolved execution errors on Linux hosts by adding `/sh` routing to the command parser, introducing the Linux shell backend, defaulting shell mode dynamically on Unix targets, and mapping E2E test assertions to platform-specific outputs.
2431

2532
---
2633

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ cd plug.cross/linux && ./make.sh
5454
| `/?` | None | Displays help details. |
5555
| `/a` | None | Displays system environment and memory statistics. |
5656
| `/tab` | None | Spawns a new workspace tab. |
57+
| `/cmd` | `[query]` | Spawns a Windows Command Prompt tab or executes a CMD query. |
58+
| `/ps` | `[query]` | Spawns a Windows PowerShell tab or executes a PowerShell query. |
59+
| `/sh` | `[query]` | Spawns a Linux shell tab or executes a shell query. |
5760
| `/plug*` | None | Lists available online registry plugins and hashes. |
5861
| `/plug` | `[hash]` | Downloads and initializes a plugin. |
5962
| `/plug-` | `[hash]` | Unloads the specified plugin. |

docs/ARCHITECTURE.md

Lines changed: 2 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,9 @@ The framework splits operations into two layers connected via C FFI:
1818

1919
### C++ Functions (Called by Rust / Plugins)
2020
- `main_*_print_info(str)` / `main_*_print_error(str)`: Output logs to active text buffers.
21-
- `main_*_add_tab(name)`: Spawns a new tab context.
21+
- `main_*_add_tab(name)`: Spawns a new tab context. Note that the WASM FFI layer exposes a platform-neutral import named `host_add_tab` which the host runtime routes to these platform-specific functions.
2222
- `main_*_set_prompt_visibility(visible)`: Controls standard input prompt fields.
23-
- `main_*_get_tab_owner(idx)` / `main_*_set_tab_owner(idx, name)`: Syncs tab ownership state.
23+
- `main_*_get_tab_owner(idx, buf, max_len)` / `main_*_set_tab_owner(idx, name)`: Syncs tab ownership state. The `get` function writes the owner string into `buf` up to `max_len` to ensure buffer safety and avoid ABI crashes.
2424

2525
---
2626

@@ -29,35 +29,3 @@ The framework splits operations into two layers connected via C FFI:
2929
Inputs starting with `/` invoke built-in commands (e.g., `/tab` or `/plug`). Other inputs are dispatched to the WASM plugin owning the active tab.
3030

3131
If a plugin requests access to sensitive FFI imports (such as `host_exec` to run local shell subprocesses), the runtime validates its manifest permissions list (`plugin.toml`) before delegating the call to the host OS.
32-
33-
---
34-
35-
## Security Model & Sandbox Limits
36-
37-
### 1. The FFI Gate Architecture
38-
The WebAssembly sandbox isolates memory space and prevents direct OS API execution. System capabilities are exposed exclusively through imported FFI functions. The core runtime acts as a **binary gate**:
39-
- When a plugin attempts an operation (e.g., `host_exec`), the host runtime checks if the permission is listed in the plugin's manifest.
40-
- **Escape Vector by Design**: If a plugin is granted `host_exec` permission, the WASM boundary is crossed. A plugin with `host_exec` can potentially launch processes and interact with the host OS, making it a critical capability.
41-
42-
### 2. Execution Containment for Untrusted Plugins
43-
For third-party or untrusted plugins that require `host_exec` to run specific external tasks, the host runtime applies strict validation checks:
44-
- **Interpreter / LOLBin Ban**: Common shell binaries (`cmd.exe`, `powershell.exe`, `bash`, `python`) and code-execution LOLBins (`rundll32.exe`, `regsvr32.exe`) are explicitly banned.
45-
- **Canonical-Path Allowlist**: The target binary's canonical path must be explicitly mapped in the plugin manifest's `allowed_commands`.
46-
- **Regex Argument Filtering**: The command line arguments are evaluated against a linear-time regex pattern declared in the manifest.
47-
48-
### 3. Trust Tiers & Shell Emulator Bypass
49-
Core system utilities (like the shell terminal emulator `pTerm`) require execution of host shells to operate:
50-
- **Compile-Time Hash Pinning**: During compilation, the builder script computes the SHA-256 hash of the compiled `pTerm.wasm` binary and embeds it directly into the host Rust library (`plugin_mgr.rs` via `pterm_hash.txt`).
51-
- **Trust Bypass**: If a plugin's SHA-256 matches this hardcoded trust list (`TRUSTED_PLUGIN_HASHES`), it is marked as `is_trusted`. Trusted plugins bypass the interpreter bans and allowlist validations inside `host_exec`.
52-
- **Tamper Protection**: If a trusted plugin is modified, its hash changes. It falls back to the standard flow, requiring an `.integrity` file, and is blocked if tampered.
53-
54-
### 4. Cryptographic Integrity Validation
55-
- **Single-Read Verification**: To mitigate TOCTOU (Time-of-Check to Time-of-Use) filesystem attacks, plugin binaries are read into memory in a single syscall. The runtime computes the SHA-256 hash of this memory buffer and verifies it against the sidecar before Wasmer compiles it.
56-
- **Atomic Sidecar Writes**: Plugin installations write both the WASM binary and `.integrity` file to temporary files, followed by an atomic rename to prevent corrupted states.
57-
- **Registry Hash Pinning**: Remote plugin downloads are validated against SHA-256 hashes pinned in the official registry (`pluglists.json`) to prevent MITM attacks.
58-
- **Global Migration**: Pre-existing plugins are backfilled with `.integrity` files on startup, and a global marker is written. Post-migration, any loaded plugin lacking a valid `.integrity` sidecar is blocked.
59-
60-
### 5. Upstream Dependency Security Notes
61-
- **Wasmer & memmap2 Soundness (`RUSTSEC-2026-0186`)**:
62-
- The unsoundness vulnerability in `memmap2` (`RUSTSEC-2026-0186` for versions `< 0.9.11`) is currently ignored in [.cargo/audit.toml](file:///O:/prj/p01/.wip/plug/plug.app/rt/.cargo/audit.toml) because our current Wasmer version does not invoke the unsound functions (`advise_range` or `flush_range`).
63-
- **Upgrade Checklist**: Every time `wasmer` is upgraded, the developers must audit if the new Wasmer version invokes these `memmap2` range advising/flushing routines. If it does, `memmap2` must be upgraded to a safe patched version (e.g. `>= 0.9.11`) or Wasmer must be configured to bypass those calls to maintain full system safety.

docs/PLUGIN_DEVELOPMENT.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ author = "Dev"
4040
api_version = "xxx"
4141
permissions = [
4242
"host_exec", # Spawning local commands (CMD / PowerShell)
43-
"main_w_add_tab", # Spawning new tabs
43+
"host_add_tab", # Spawning new tabs
4444
"host_set_tab_owner" # Taking tab ownership
4545
]
4646
```

docs/TESTING_SYSTEM.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ Manifest configurations (`plugin.toml`) define the permission scope of the WASM
6565
```toml
6666
[[plugin]]
6767
name = "ok_plugin"
68-
permissions = ["main_w_add_tab", "host_exec"]
68+
permissions = ["host_add_tab", "host_exec"]
6969
```
7070
- **`rogue_plugin` Manifest (Load-time)**:
7171
```toml
@@ -94,8 +94,8 @@ WASM files check:
9494
- `rogue_plugin_runtime sandbox trap check` (runtime execution containment).
9595
- `ok_plugin integrity mismatch check` (tampered WASM with stale `.integrity` sidecar is blocked).
9696
- `Global migration and post-migration bypass checks` (**Plan Cases A & B**: one-time global migration backfill validation and post-migration missing sidecar blocking).
97-
- `Trusted plugin bypass integrity file check` (**Plan Case C**: verifies `pTerm` with valid compiled hash loads successfully without sidecar and executes a real `dir` command via `host_exec`).
98-
- `Tampered trusted plugin block check` (**Plan Case D**: verifies tampered `pTerm` is blocked and fails-closed).
97+
- `Trusted plugin bypass integrity file check`
98+
- `Tampered trusted plugin block check`
9999

100100
### 3.5 End-to-End Tests (`tests/e2e/`)
101101
- **`test_cli_lifecycle.py`**: Spawns the production compiled `plug` executable under test scenarios using `subprocess.Popen` with `HIDE_CONSOLE=ON` (the standard production build configuration to ensure we test the identical binary shipped).

docs/plugins/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,4 +8,4 @@ Currently, the following official plugins are deployed and verified:
88

99
| Plugin Name | Version | Description | Documentation Link |
1010
|---|---|---|---|
11-
| **pTerm** | `1.0.0` | Default core terminal runner plugin bridging WASM container to host shells. | [Details](catalog/pTerm.md) |
11+
| **pTerm** | `1.0.1` | Default core terminal runner plugin bridging WASM container to host shells. | [Details](CATALOG/pTerm.md) |

docs/plugins/catalog/pTerm.md

Lines changed: 14 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@
66

77
## 1. Specifications
88

9-
- **Role**: Spawns and manages CMD and PowerShell sessions inside dedicated UI tabs.
10-
- **Required Permissions**: `host_exec`, `main_w_add_tab`, `host_set_tab_owner`, `host_get_tab_label`.
9+
- **Role**: Spawns and manages CMD, PowerShell (Windows), and sh (Linux) sessions inside dedicated UI tabs.
10+
- **Required Permissions**: `host_exec`, `host_add_tab`, `host_set_tab_owner`, `host_get_tab_label`.
1111
- **Trust Tier**: Recognized as a trusted core utility by matching the compile-time hardcoded SHA-256 hash list. Bypasses the sandbox interpreter bans (shells block) and canonical-path allowlist checks.
1212

1313
---
@@ -27,9 +27,9 @@ The diagram below illustrates the exact control flow when a user runs a shell co
2727
|
2828
v
2929
[WASM Sandbox (pTerm.wasm)]
30-
1. Calls `get_args` to retrieve input ("dir")
31-
2. Resolves active tab mode (PowerShell vs CMD)
32-
3. Prepend shell execution wrapper (e.g. `cmd /c dir` or `powershell -Command "dir"`)
30+
1. Calls `get_args` to retrieve input (e.g. "dir" or "ls")
31+
2. Resolves active tab mode (PowerShell, CMD, or SH)
32+
3. Prepend shell execution wrapper (e.g. `cmd /c dir`, `powershell -Command "dir"`, or `sh -c "ls"`)
3333
|
3434
v
3535
[Rust Host Runtime] -> 1. Verifies memory buffer SHA-256 matches compile-time TRUSTED_PLUGIN_HASHES
@@ -43,16 +43,18 @@ The diagram below illustrates the exact control flow when a user runs a shell co
4343

4444
## 3. Operations Routing
4545

46-
### Spawning a new Sub-Shell (`/cmd` or `/ps`)
47-
1. User types `/cmd` or `/ps`.
46+
### Spawning a new Sub-Shell (`/cmd`, `/ps`, or `/sh`)
47+
1. User types `/cmd`, `/ps`, or `/sh`.
4848
2. Rust router catches the command and invokes the `pTerm` module with initialization arguments.
49-
3. `pTerm` calls `main_w_add_tab("pTerm")` to request a new UI tab from the host.
50-
4. `pTerm` labels the tab owner name as `"CMD"` or `"PS"` using the `host_set_tab_owner` hook.
49+
3. `pTerm` calls `host_add_tab("pTerm")` to request a new UI tab from the host.
50+
4. `pTerm` labels the tab owner name as `"CMD"`, `"PS"`, or `"SH"` using the `host_set_tab_owner` hook.
5151
5. The tab context is initialized, and the user can now type terminal commands directly.
5252

5353
### Running Subprocess Commands
54-
1. User types `git status` in a tab labeled `"PS"`.
54+
1. User types `git status` in a tab labeled `"PS"` (or `ls -la` in a tab labeled `"SH"`).
5555
2. The input does not start with `/`, so Rust router resolves the active tab owner (`"pTerm"`) and delegates the call.
56-
3. `pTerm` checks the tab label, matches it to `"PS"`, and reformats the command:
57-
`powershell -NoProfile -Command "git status"`
56+
3. `pTerm` checks the tab label:
57+
- Matches `"PS"` -> reformats to: `powershell -NoProfile -Command "git status"`
58+
- Matches `"CMD"` -> reformats to: `cmd /c "git status"`
59+
- Matches `"SH"` -> reformats to: `sh -c "ls -la"`
5860
4. `pTerm` calls `host_exec` to execute the string on the host OS, streaming the outputs directly to the UI rendering buffers.

plug.app/cmn/inc/sys/api/linux/main_l.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,14 @@ void main_l_cleanup(void);
9494
void main_l_print_banner(void);
9595
void main_l_print_info(const char* msg);
9696
void main_l_print_error(const char* msg);
97+
void main_l_set_prompt_visibility(int visible);
98+
void main_l_add_tab(const char* owner);
99+
void main_l_request_close(void);
100+
void main_l_replace_last_line(const char* msg);
101+
void main_l_set_tab_owner(int tab_idx, const char* owner);
102+
int main_l_get_tab_owner(int tab_idx, char* buf, int max_len);
103+
void main_l_set_tab_cwd(int tab_idx, const char* cwd);
104+
int main_l_get_current_print_tab(void);
97105

98106
#ifdef __cplusplus
99107
}

plug.app/cmn/inc/sys/api/windows/main_w.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,10 @@ int main_w_print_tab(void);
7373
void main_w_request_close(void);
7474
void main_w_set_prompt_visibility(int visible);
7575
void main_w_add_tab(const char* owner);
76+
void main_w_set_tab_owner(int tab_idx, const char* owner);
77+
int main_w_get_tab_owner(int tab_idx, char* buf, int max_len);
78+
void main_w_set_tab_cwd(int tab_idx, const char* cwd);
79+
int main_w_get_current_print_tab(void);
7680

7781
void main_w_run_message_loop(void);
7882

0 commit comments

Comments
 (0)