deno
3ebf6502 - fix(ext/node): vm dynamic import without callback throws ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING (#34427)

Commit
109 days ago
fix(ext/node): vm dynamic import without callback throws ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING (#34427) ## Summary `vm.runInThisContext` (and friends) currently allow dynamic `import()` to fall through to the main module loader even when no `importModuleDynamically` callback was provided. This lets sandboxed code reach modules like `node:fs`. Node throws `ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING` in this situation. Fix: tag the host-defined options of every script/function/module compiled by `node:vm` with a `VM_DYNAMIC_IMPORT_MISSING` kind, and check that kind inside the runtime's dynamic-import host callback. If the marker is present, reject the import promise with a Node-compatible `TypeError` carrying `code = "ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING"` and message `"A dynamic import callback was not specified."`. Covered entry points: - `vm.Script(...).runInThisContext()` - `vm.runInContext` / `vm.createContext` + `runInContext` - `vm.runInNewContext` - `vm.compileFunction` - `vm.SourceTextModule` Before: ``` $ deno run -A repro.mjs fsModule type inside VM: object ``` After: ``` $ deno run -A repro.mjs VM error code: ERR_VM_DYNAMIC_IMPORT_CALLBACK_MISSING VM error name: TypeError VM error message: A dynamic import callback was not specified. ``` Implementation notes: - New `libs/core/runtime/host_defined_options.rs` defines a small kind-tag layout for the `PrimitiveArray` Deno already attaches as `host_defined_options`. The existing npm marker (`[Boolean(true)]`) is left alone — it doesn't collide with the new `[Uint32]` kind. - `host_import_module_with_phase_dynamically_callback` reads the tag up front and short-circuits with the Node error when the script was compiled by `node:vm` without a callback. All other host_defined_options shapes (including the npm marker and the V8 default empty array) flow through unchanged. Future work: actually wiring the `importModuleDynamically` callback through to the user-provided function. That's a larger feature; this PR closes the immediate sandbox-escape gap to match Node. Fixes #33385. Closes denoland/orchid#245 ## Test plan - [x] `tests/specs/node/vm_dynamic_import_no_callback/` covers all six vm entry points; passes via `cargo test --test specs node::vm_dynamic_import_no_callback`. - [x] Updated `tests/unit_node/vm_test.ts` "vm runInNewContext module loader" (#22441) to assert the new (Node-matching) behavior. - [x] `cargo clippy -p deno_core -p deno_node --all-targets` clean. - [x] Verified normal Deno module imports (including npm packages) still work unchanged. --------- Co-authored-by: divybot <divybot@users.noreply.github.com> Co-authored-by: Divy Srivastava <me@littledivy.com>
Author
Parents
Loading