按规划继续工作

结论:补充 INI 派生机器文件名的 OPFS 路径拒绝回归测试,确认非法遍历和嵌套路径不会进入主机存储,并通过 host/WASM/browser 聚合验证。
This commit is contained in:
2026-06-08 09:04:48 +08:00
parent e21f11d69f
commit 5bea38275f
4 changed files with 75 additions and 10 deletions

View File

@@ -103,7 +103,9 @@ round-trip store plus pure-text machine file and G-code stores without
defining CNC machine-state or file-format semantics. It now also validates the defining CNC machine-state or file-format semantics. It now also validates the
OPFS-to-WASM parameter-file bridge with a mock interpreter SDK to ensure the OPFS-to-WASM parameter-file bridge with a mock interpreter SDK to ensure the
host boundary copies text into and out of the WASM filesystem without defining host boundary copies text into and out of the WASM filesystem without defining
parameter semantics. parameter semantics, and that INI-derived machine file names are still
rejected by the OPFS path model when they contain traversal or nested path
segments.
The browser INI/OPFS smoke script serves `wasm-port/` over localhost and runs The browser INI/OPFS smoke script serves `wasm-port/` over localhost and runs
Chromium headless against a test page that imports the JS SDK, loads the INI Chromium headless against a test page that imports the JS SDK, loads the INI
@@ -257,9 +259,10 @@ SDK into vendored LinuxCNC file APIs, the Node machine-session bridge that
groups INI, parameter, and tool-table loading, the random-toolchanger flag groups INI, parameter, and tool-table loading, the random-toolchanger flag
derived from vendored LinuxCNC INI boolean parsing, INI-derived derived from vendored LinuxCNC INI boolean parsing, INI-derived
`[RS274NGC]PARAMETER_FILE` and `[EMCIO]TOOL_TABLE` file names mapped to OPFS `[RS274NGC]PARAMETER_FILE` and `[EMCIO]TOOL_TABLE` file names mapped to OPFS
machine files, and a browser interpreter smoke that uses the same session machine files, OPFS path-model rejection of invalid INI-derived file names,
bridge before saving OPFS-backed parameter and tool-table text through and a browser interpreter smoke that uses the same session bridge before
vendored LinuxCNC file APIs. saving OPFS-backed parameter and tool-table text through vendored LinuxCNC
file APIs.
Full browser coverage, full SDK coverage, and richer machine-state validation Full browser coverage, full SDK coverage, and richer machine-state validation
remain future work. remain future work.

View File

@@ -44,7 +44,7 @@ semantic rewrites:
| Kinematics component lifecycle | Kinematics modules are initialized through LinuxCNC module entry points where native runtime probes exist, while HAL component init/ready/exit, HAL pin allocation, and RTAPI module metadata are handled by standalone shims. | | Kinematics component lifecycle | Kinematics modules are initialized through LinuxCNC module entry points where native runtime probes exist, while HAL component init/ready/exit, HAL pin allocation, and RTAPI module metadata are handled by standalone shims. |
| Go math C/C++ linkage | `genserkins` runtime probing compiles vendored `gomath.c` through a narrow C++ wrapper so LinuxCNC `genserfuncs.c` can link to the upstream Go math symbols without editing vendored source. | | Go math C/C++ linkage | `genserkins` runtime probing compiles vendored `gomath.c` through a narrow C++ wrapper so LinuxCNC `genserfuncs.c` can link to the upstream Go math symbols without editing vendored source. |
| Switchkins iterative forward | `genhexkins` runtime probing follows LinuxCNC switchkins iterative-forward behavior, including the first-call warmup path before asserting roundtrip convergence. | | Switchkins iterative forward | `genhexkins` runtime probing follows LinuxCNC switchkins iterative-forward behavior, including the first-call warmup path before asserting roundtrip convergence. |
| Browser storage | OPFS remains outside the native core; `runtime/opfs/file-service.js` owns browser text-file persistence, `runtime/opfs/path-model.js` owns host-side storage paths for INI, tool table, parameter, G-code, preview-cache, and session-snapshot content, `runtime/opfs/snapshot-store.js` owns generic JSON session snapshot persistence, `runtime/opfs/machine-file-store.js` owns pure-text machine-file and G-code persistence, `runtime/opfs/linuxcnc-parameter-bridge.js` only copies parameter files between OPFS text storage and the LinuxCNC-backed WASM parameter-file ABI, `runtime/opfs/linuxcnc-tool-table-bridge.js` only copies tool tables between OPFS text storage and the LinuxCNC-backed WASM tool-table ABI, and `runtime/opfs/linuxcnc-machine-session-bridge.js` groups INI, parameter, and tool-table loading while using the LinuxCNC-backed INI SDK for `[EMCIO]RANDOM_TOOLCHANGER`, `[RS274NGC]PARAMETER_FILE`, and `[EMCIO]TOOL_TABLE` when available. | | Browser storage | OPFS remains outside the native core; `runtime/opfs/file-service.js` owns browser text-file persistence, `runtime/opfs/path-model.js` owns host-side storage paths for INI, tool table, parameter, G-code, preview-cache, and session-snapshot content, `runtime/opfs/snapshot-store.js` owns generic JSON session snapshot persistence, `runtime/opfs/machine-file-store.js` owns pure-text machine-file and G-code persistence, `runtime/opfs/linuxcnc-parameter-bridge.js` only copies parameter files between OPFS text storage and the LinuxCNC-backed WASM parameter-file ABI, `runtime/opfs/linuxcnc-tool-table-bridge.js` only copies tool tables between OPFS text storage and the LinuxCNC-backed WASM tool-table ABI, and `runtime/opfs/linuxcnc-machine-session-bridge.js` groups INI, parameter, and tool-table loading while using the LinuxCNC-backed INI SDK for `[EMCIO]RANDOM_TOOLCHANGER`, `[RS274NGC]PARAMETER_FILE`, and `[EMCIO]TOOL_TABLE` when available; path validation remains owned by the OPFS path model, including rejection of traversal or nested path segments from INI-derived file names. |
## Enforced Non-Drift Rules ## Enforced Non-Drift Rules
@@ -69,8 +69,9 @@ semantic rewrites:
- OPFS validation covers a Node mock of the file-service adapter, the - OPFS validation covers a Node mock of the file-service adapter, the
host-side path model, generic session snapshot storage, pure-text machine host-side path model, generic session snapshot storage, pure-text machine
file and G-code storage, parameter/tool-table bridge copying into the file and G-code storage, parameter/tool-table bridge copying into the
interpreter SDK filesystem, grouped machine-session loading, and a Chromium interpreter SDK filesystem, grouped machine-session loading, invalid
localhost round trip for those persistence paths. INI-derived machine file names, and a Chromium localhost round trip for those
persistence paths.
- Host-side smoke validation is aggregated by - Host-side smoke validation is aggregated by
`tests/host/verify_host_smokes.sh` so Node, WASM, OPFS, and browser checks `tests/host/verify_host_smokes.sh` so Node, WASM, OPFS, and browser checks
run from one command. run from one command.

View File

@@ -54,7 +54,7 @@ Current validation is intentionally mechanical:
| Dependency | LinuxCNC files that expose it | Standalone treatment | | Dependency | LinuxCNC files that expose it | Standalone treatment |
| --- | --- | --- | | --- | --- | --- |
| Native file IO | `inifile.cc`, `rs274ngc_pre.cc`, `tooldata_common.cc`, parameter file paths, tool table paths | Allowed in native probes; the interpreter WASM C ABI validates parameter-file restore/save by calling vendored `Interp::restore_parameters()` and `Interp::save_parameters()` and tool-table load/save by calling vendored `tooldata_load()` and `tooldata_save()` against Emscripten filesystem paths; browser OPFS remains a host-side adapter under `runtime/opfs/`, with path ownership in `runtime/opfs/path-model.js`, generic snapshot persistence in `runtime/opfs/snapshot-store.js`, pure-text machine-file persistence in `runtime/opfs/machine-file-store.js`, OPFS-to-WASM parameter-file copying in `runtime/opfs/linuxcnc-parameter-bridge.js`, OPFS-to-WASM tool-table copying in `runtime/opfs/linuxcnc-tool-table-bridge.js`, and grouped INI/parameter/tool-table session loading in `runtime/opfs/linuxcnc-machine-session-bridge.js`, including INI-derived `[RS274NGC]PARAMETER_FILE` and `[EMCIO]TOOL_TABLE` OPFS filename selection through the LinuxCNC-backed INI SDK | | Native file IO | `inifile.cc`, `rs274ngc_pre.cc`, `tooldata_common.cc`, parameter file paths, tool table paths | Allowed in native probes; the interpreter WASM C ABI validates parameter-file restore/save by calling vendored `Interp::restore_parameters()` and `Interp::save_parameters()` and tool-table load/save by calling vendored `tooldata_load()` and `tooldata_save()` against Emscripten filesystem paths; browser OPFS remains a host-side adapter under `runtime/opfs/`, with path ownership in `runtime/opfs/path-model.js`, generic snapshot persistence in `runtime/opfs/snapshot-store.js`, pure-text machine-file persistence in `runtime/opfs/machine-file-store.js`, OPFS-to-WASM parameter-file copying in `runtime/opfs/linuxcnc-parameter-bridge.js`, OPFS-to-WASM tool-table copying in `runtime/opfs/linuxcnc-tool-table-bridge.js`, and grouped INI/parameter/tool-table session loading in `runtime/opfs/linuxcnc-machine-session-bridge.js`, including INI-derived `[RS274NGC]PARAMETER_FILE` and `[EMCIO]TOOL_TABLE` OPFS filename selection through the LinuxCNC-backed INI SDK; OPFS path validation rejects traversal and nested segments before host storage access |
| RTAPI | `rtapi_*.h`, TP, posemath, motion headers | Minimal standalone shim in `runtime/core/shims/rtapi.h` | | RTAPI | `rtapi_*.h`, TP, posemath, motion headers | Minimal standalone shim in `runtime/core/shims/rtapi.h` |
| NML transport | `emc.hh`, motion/NML type headers | Transport is not ported; only the status/type edges needed by vendored compute code are exposed through standalone shims and probes | | NML transport | `emc.hh`, motion/NML type headers | Transport is not ported; only the status/type edges needed by vendored compute code are exposed through standalone shims and probes |
| HAL runtime | named parameter lookup, kinematics component lifecycle, and runtime status edges | Standalone HAL adapter under `runtime/core/linuxcnc_wrap/` | | HAL runtime | named parameter lookup, kinematics component lifecycle, and runtime status edges | Standalone HAL adapter under `runtime/core/linuxcnc_wrap/` |
@@ -95,6 +95,7 @@ Current validation is intentionally mechanical:
tool-table loading into one host-side session load boundary and can derive tool-table loading into one host-side session load boundary and can derive
the random-toolchanger tooldata mode from `[EMCIO]RANDOM_TOOLCHANGER` plus the random-toolchanger tooldata mode from `[EMCIO]RANDOM_TOOLCHANGER` plus
parameter/tool-table OPFS file names from `[RS274NGC]PARAMETER_FILE` and parameter/tool-table OPFS file names from `[RS274NGC]PARAMETER_FILE` and
`[EMCIO]TOOL_TABLE` through the LinuxCNC-backed INI SDK. Full machine-state `[EMCIO]TOOL_TABLE` through the LinuxCNC-backed INI SDK, with invalid
restoration remains future work. traversal or nested file names rejected by `runtime/opfs/path-model.js`.
Full machine-state restoration remains future work.
- Native LinuxCNC GUI code remains out of scope for implementation. - Native LinuxCNC GUI code remains out of scope for implementation.

View File

@@ -209,6 +209,13 @@ const bridgeIniSdk = {
) { ) {
return "custom.var"; return "custom.var";
} }
if (
path === "/work/invalid-ini-file-session.ini" &&
section === "RS274NGC" &&
tag === "PARAMETER_FILE"
) {
return "../escape.var";
}
if ( if (
path === "/work/ini-file-session.ini" && path === "/work/ini-file-session.ini" &&
section === "EMCIO" && section === "EMCIO" &&
@@ -216,6 +223,13 @@ const bridgeIniSdk = {
) { ) {
return "custom-tool.tbl"; return "custom-tool.tbl";
} }
if (
path === "/work/invalid-tool-file-session.ini" &&
section === "EMCIO" &&
tag === "TOOL_TABLE"
) {
return "nested/tool.tbl";
}
return null; return null;
}, },
getBool(path, section, tag) { getBool(path, section, tag) {
@@ -416,6 +430,52 @@ assert.equal(
"tooldata_load=0\nload_tool_path=/work/ini-file-session-tool.tbl\nrandom_toolchanger=0\n", "tooldata_load=0\nload_tool_path=/work/ini-file-session-tool.tbl\nrandom_toolchanger=0\n",
); );
await saveMachineTextFiles("invalid-ini-file-session", {
ini: [
"[EMC]",
"MACHINE = invalid-ini-file-session",
"",
"[RS274NGC]",
"PARAMETER_FILE = ../escape.var",
"",
].join("\n"),
}, { storage });
await assert.rejects(
() => loadMachineSessionFromOpfs(
bridgeInterp,
"invalid-ini-file-session",
{
storage,
iniSdk: bridgeIniSdk,
iniWasmPath: "/work/invalid-ini-file-session.ini",
},
),
/Invalid parameter filename/,
);
await saveMachineTextFiles("invalid-tool-file-session", {
ini: [
"[EMC]",
"MACHINE = invalid-tool-file-session",
"",
"[EMCIO]",
"TOOL_TABLE = nested/tool.tbl",
"",
].join("\n"),
}, { storage });
await assert.rejects(
() => loadMachineSessionFromOpfs(
bridgeInterp,
"invalid-tool-file-session",
{
storage,
iniSdk: bridgeIniSdk,
iniWasmPath: "/work/invalid-tool-file-session.ini",
},
),
/Invalid tool table filename/,
);
await assert.rejects( await assert.rejects(
() => loadTextFile("linuxcnc/machines/missing.ini", storage), () => loadTextFile("linuxcnc/machines/missing.ini", storage),
/missing file/, /missing file/,