Skip to content

WebAssembly System Interface (WASI)

[Stabil: 1 - Experimentell]

Stabil: 1 Stabilität: 1 - Experimentell

Das Modul node:wasi bietet derzeit nicht die umfassenden Dateisystemsicherheitseigenschaften, die von einigen WASI-Laufzeiten bereitgestellt werden. Eine vollständige Unterstützung für sichere Dateisystem-Sandboxing kann in Zukunft implementiert werden oder auch nicht. Vertrauen Sie in der Zwischenzeit nicht darauf, nicht vertrauenswürdigen Code auszuführen.

Quellcode: lib/wasi.js

Die WASI-API bietet eine Implementierung der WebAssembly System Interface-Spezifikation. WASI ermöglicht WebAssembly-Anwendungen den Zugriff auf das zugrunde liegende Betriebssystem über eine Sammlung von POSIX-ähnlichen Funktionen.

js
import { readFile } from 'node:fs/promises'
import { WASI } from 'node:wasi'
import { argv, env } from 'node:process'

const wasi = new WASI({
  version: 'preview1',
  args: argv,
  env,
  preopens: {
    '/local': '/some/real/path/that/wasm/can/access',
  },
})

const wasm = await WebAssembly.compile(await readFile(new URL('./demo.wasm', import.meta.url)))
const instance = await WebAssembly.instantiate(wasm, wasi.getImportObject())

wasi.start(instance)
js
'use strict'
const { readFile } = require('node:fs/promises')
const { WASI } = require('node:wasi')
const { argv, env } = require('node:process')
const { join } = require('node:path')

const wasi = new WASI({
  version: 'preview1',
  args: argv,
  env,
  preopens: {
    '/local': '/some/real/path/that/wasm/can/access',
  },
})

;(async () => {
  const wasm = await WebAssembly.compile(await readFile(join(__dirname, 'demo.wasm')))
  const instance = await WebAssembly.instantiate(wasm, wasi.getImportObject())

  wasi.start(instance)
})()

Um das obige Beispiel auszuführen, erstellen Sie eine neue WebAssembly-Textformatdatei namens demo.wat:

text
(module
    ;; Importieren Sie die erforderliche fd_write WASI-Funktion, die die angegebenen IO-Vektoren nach stdout schreibt
    ;; Die Funktionssignatur für fd_write lautet:
    ;; (File Descriptor, *iovs, iovs_len, nwritten) -> Gibt die Anzahl der geschriebenen Bytes zurück
    (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (param i32 i32 i32 i32) (result i32)))

    (memory 1)
    (export "memory" (memory 0))

    ;; Schreibe 'hello world\n' in den Speicher bei einem Offset von 8 Bytes
    ;; Beachten Sie die nachgestellte Newline, die erforderlich ist, damit der Text angezeigt wird
    (data (i32.const 8) "hello world\n")

    (func $main (export "_start")
        ;; Erstellen eines neuen IO-Vektors im linearen Speicher
        (i32.store (i32.const 0) (i32.const 8))  ;; iov.iov_base - Dies ist ein Zeiger auf den Start der Zeichenfolge 'hello world\n'
        (i32.store (i32.const 4) (i32.const 12))  ;; iov.iov_len - Die Länge der Zeichenfolge 'hello world\n'

        (call $fd_write
            (i32.const 1) ;; file_descriptor - 1 für stdout
            (i32.const 0) ;; *iovs - Der Zeiger auf das iov-Array, das an Speicherstelle 0 gespeichert ist
            (i32.const 1) ;; iovs_len - Wir geben 1 Zeichenfolge aus, die in einem iov gespeichert ist - also eins.
            (i32.const 20) ;; nwritten - Ein Ort im Speicher, um die Anzahl der geschriebenen Bytes zu speichern
        )
        drop ;; Verwirft die Anzahl der geschriebenen Bytes vom oberen Rand des Stacks
    )
)

Verwenden Sie wabt, um .wat in .wasm zu kompilieren.

bash
wat2wasm demo.wat

Sicherheit

[Verlauf]

VersionÄnderungen
v21.2.0, v20.11.0Klarstellung der WASI-Sicherheitseigenschaften.
v21.2.0, v20.11.0Hinzugefügt in: v21.2.0, v20.11.0

WASI bietet ein auf Fähigkeiten basierendes Modell, durch das Anwendungen ihre eigenen benutzerdefinierten env, preopens, stdin, stdout, stderr und exit-Fähigkeiten erhalten.

Das aktuelle Node.js-Bedrohungsmodell bietet keine sichere Sandboxing-Umgebung, wie sie in einigen WASI-Laufzeitumgebungen vorhanden ist.

Obwohl die Fähigkeitsfunktionen unterstützt werden, bilden sie kein Sicherheitsmodell in Node.js. Zum Beispiel kann das Dateisystem-Sandboxing mit verschiedenen Techniken umgangen werden. Das Projekt untersucht, ob diese Sicherheitsgarantien in der Zukunft hinzugefügt werden können.

Klasse: WASI

Hinzugefügt in: v13.3.0, v12.16.0

Die Klasse WASI bietet die WASI-Systemaufruf-API und zusätzliche Komfortmethoden für die Arbeit mit WASI-basierten Anwendungen. Jede WASI-Instanz repräsentiert eine eigene Umgebung.

new WASI([optionen])

[Verlauf]

VersionÄnderungen
v20.1.0Standardwert von returnOnExit auf true geändert.
v20.0.0Die Option version ist jetzt erforderlich und hat keinen Standardwert.
v19.8.0Feld version zu Optionen hinzugefügt.
v13.3.0, v12.16.0Hinzugefügt in: v13.3.0, v12.16.0
  • optionen <Object>
    • args <Array> Ein Array von Zeichenketten, die die WebAssembly-Anwendung als Befehlszeilenargumente sehen wird. Das erste Argument ist der virtuelle Pfad zum WASI-Befehl selbst. Standard: [].
    • env <Object> Ein Objekt ähnlich wie process.env, das die WebAssembly-Anwendung als ihre Umgebung sehen wird. Standard: {}.
    • preopens <Object> Dieses Objekt repräsentiert die lokale Verzeichnisstruktur der WebAssembly-Anwendung. Die String-Schlüssel von preopens werden als Verzeichnisse innerhalb des Dateisystems behandelt. Die entsprechenden Werte in preopens sind die tatsächlichen Pfade zu diesen Verzeichnissen auf dem Hostrechner.
    • returnOnExit <boolean> Standardmäßig gibt wasi.start() zurück, wenn WASI-Anwendungen __wasi_proc_exit() aufrufen, und zwar mit dem angegebenen Exit-Code, anstatt den Prozess zu beenden. Wenn diese Option auf false gesetzt wird, wird der Node.js-Prozess stattdessen mit dem angegebenen Exit-Code beendet. Standard: true.
    • stdin <integer> Der Dateideskriptor, der als Standardeingabe in der WebAssembly-Anwendung verwendet wird. Standard: 0.
    • stdout <integer> Der Dateideskriptor, der als Standardausgabe in der WebAssembly-Anwendung verwendet wird. Standard: 1.
    • stderr <integer> Der Dateideskriptor, der als Standardfehlerausgabe in der WebAssembly-Anwendung verwendet wird. Standard: 2.
    • version <string> Die angeforderte Version von WASI. Derzeit werden nur die Versionen unstable und preview1 unterstützt. Diese Option ist obligatorisch.

wasi.getImportObject()

Hinzugefügt in: v19.8.0

Gibt ein Importobjekt zurück, das an WebAssembly.instantiate() übergeben werden kann, wenn keine anderen WASM-Importe benötigt werden, die über die von WASI bereitgestellten hinausgehen.

Wenn die Version unstable an den Konstruktor übergeben wurde, wird Folgendes zurückgegeben:

json
{ wasi_unstable: wasi.wasiImport }

Wenn die Version preview1 an den Konstruktor übergeben wurde oder keine Version angegeben wurde, wird Folgendes zurückgegeben:

json
{ wasi_snapshot_preview1: wasi.wasiImport }

wasi.start(instance)

Hinzugefügt in: v13.3.0, v12.16.0

Versucht, die Ausführung von instance als WASI-Befehl zu starten, indem der Export _start() aufgerufen wird. Wenn instance keinen _start()-Export enthält oder instance einen _initialize()-Export enthält, wird eine Ausnahme ausgelöst.

start() erfordert, dass instance einen WebAssembly.Memory mit dem Namen memory exportiert. Wenn instance keinen memory-Export hat, wird eine Ausnahme ausgelöst.

Wenn start() mehr als einmal aufgerufen wird, wird eine Ausnahme ausgelöst.

wasi.initialize(instance)

Hinzugefügt in: v14.6.0, v12.19.0

Versucht, instance als WASI-Reaktor zu initialisieren, indem der Export _initialize() aufgerufen wird, falls vorhanden. Wenn instance einen _start()-Export enthält, wird eine Ausnahme ausgelöst.

initialize() erfordert, dass instance einen WebAssembly.Memory mit dem Namen memory exportiert. Wenn instance keinen memory-Export hat, wird eine Ausnahme ausgelöst.

Wenn initialize() mehr als einmal aufgerufen wird, wird eine Ausnahme ausgelöst.

wasi.wasiImport

Hinzugefügt in: v13.3.0, v12.16.0

wasiImport ist ein Objekt, das die WASI-Systemaufruf-API implementiert. Dieses Objekt sollte als wasi_snapshot_preview1-Import während der Instanziierung einer WebAssembly.Instance übergeben werden.