Skip to content

WebAssembly System Interface (WASI)

[Stable: 1 - Experimental]

Stable: 1 Stability: 1 - 実験的

node:wasi モジュールは現在、一部の WASI ランタイムが提供する包括的なファイルシステムセキュリティプロパティを提供していません。安全なファイルシステムサンドボックスの完全なサポートは、将来実装される可能性もあれば、されない可能性もあります。それまでの間、信頼できないコードを実行するためにそれを使用しないでください。

ソースコード: lib/wasi.js

WASI API は、WebAssembly System Interface 仕様の実装を提供します。WASI は、一連の POSIX のような関数を介して、WebAssembly アプリケーションに基盤となるオペレーティングシステムへのアクセスを提供します。

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);
})();

上記の例を実行するには、demo.wat という名前の新しい WebAssembly テキスト形式ファイルを作成します。

text
(module
    ;; Import the required fd_write WASI function which will write the given io vectors to stdout
    ;; The function signature for fd_write is:
    ;; (File Descriptor, *iovs, iovs_len, nwritten) -> Returns number of bytes written
    (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (param i32 i32 i32 i32) (result i32)))

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

    ;; Write 'hello world\n' to memory at an offset of 8 bytes
    ;; Note the trailing newline which is required for the text to appear
    (data (i32.const 8) "hello world\n")

    (func $main (export "_start")
        ;; Creating a new io vector within linear memory
        (i32.store (i32.const 0) (i32.const 8))  ;; iov.iov_base - This is a pointer to the start of the 'hello world\n' string
        (i32.store (i32.const 4) (i32.const 12))  ;; iov.iov_len - The length of the 'hello world\n' string

        (call $fd_write
            (i32.const 1) ;; file_descriptor - 1 for stdout
            (i32.const 0) ;; *iovs - The pointer to the iov array, which is stored at memory location 0
            (i32.const 1) ;; iovs_len - We're printing 1 string stored in an iov - so one.
            (i32.const 20) ;; nwritten - A place in memory to store the number of bytes written
        )
        drop ;; Discard the number of bytes written from the top of the stack
    )
)

wabt を使用して .wat.wasm にコンパイルします

bash
wat2wasm demo.wat

Security

[History]

バージョン変更点
v21.2.0, v20.11.0WASIのセキュリティプロパティを明確化。
v21.2.0, v20.11.0Added in: v21.2.0, v20.11.0

WASIは、アプリケーションに独自のカスタムenvpreopensstdinstdoutstderr、およびexit機能を提供する、capabilityベースのモデルを提供します。

現在のNode.jsの脅威モデルは、一部のWASIランタイムに存在するような安全なサンドボックスを提供しません。

capability機能はサポートされていますが、Node.jsではセキュリティモデルを形成しません。 たとえば、ファイルシステムサンドボックスは、さまざまな手法でエスケープできます。 プロジェクトは、これらのセキュリティ保証を将来追加できるかどうかを検討しています。

Class: WASI

Added in: v13.3.0, v12.16.0

WASI クラスは、WASI システムコール API と、WASI ベースのアプリケーションを操作するための追加の便利なメソッドを提供します。 各 WASI インスタンスは、個別の環境を表します。

new WASI([options])

[History]

バージョン変更点
v20.1.0returnOnExitのデフォルト値がtrueに変更されました。
v20.0.0versionオプションが必須になり、デフォルト値がなくなりました。
v19.8.0versionフィールドがオプションに追加されました。
v13.3.0, v12.16.0Added in: v13.3.0, v12.16.0
  • options <Object>
    • args <Array> WebAssemblyアプリケーションがコマンドライン引数として認識する文字列の配列。 最初の引数は、WASIコマンド自体の仮想パスです。 デフォルト: [].
    • env <Object> WebAssemblyアプリケーションが環境として認識する process.env に似たオブジェクト。 デフォルト: {}.
    • preopens <Object> このオブジェクトは、WebAssemblyアプリケーションのローカルディレクトリ構造を表します。 preopens の文字列キーは、ファイルシステム内のディレクトリとして扱われます。 preopens の対応する値は、ホストマシン上のそれらのディレクトリへの実際のパスです。
    • returnOnExit <boolean> デフォルトでは、WASIアプリケーションが __wasi_proc_exit() を呼び出すと、wasi.start() はプロセスを終了するのではなく、指定された終了コードで返されます。 このオプションを false に設定すると、Node.jsプロセスが代わりに指定された終了コードで終了します。 デフォルト: true.
    • stdin <integer> WebAssemblyアプリケーションで標準入力として使用されるファイル記述子。 デフォルト: 0.
    • stdout <integer> WebAssemblyアプリケーションで標準出力として使用されるファイル記述子。 デフォルト: 1.
    • stderr <integer> WebAssemblyアプリケーションで標準エラーとして使用されるファイル記述子。 デフォルト: 2.
    • version <string> 要求されたWASIのバージョン。 現在サポートされているバージョンは unstablepreview1 のみです。 このオプションは必須です。

wasi.getImportObject()

Added in: v19.8.0

WASI によって提供されるもの以外の WASM インポートが不要な場合に、WebAssembly.instantiate() に渡すことができるインポートオブジェクトを返します。

コンストラクタにバージョン unstable が渡された場合、以下を返します。

json
{ wasi_unstable: wasi.wasiImport }

コンストラクタにバージョン preview1 が渡されたか、バージョンが指定されなかった場合、以下を返します。

json
{ wasi_snapshot_preview1: wasi.wasiImport }

wasi.start(instance)

Added in: v13.3.0, v12.16.0

instance_start() エクスポートを呼び出して、WASI コマンドとしての instance の実行を開始しようとします。 instance_start() エクスポートを含まない場合、または instance_initialize() エクスポートを含む場合、例外がスローされます。

start() は、instancememory という名前の WebAssembly.Memory をエクスポートすることを要求します。 instancememory エクスポートがない場合、例外がスローされます。

start() が複数回呼び出された場合、例外がスローされます。

wasi.initialize(instance)

Added in: v14.6.0, v12.19.0

instance_initialize() エクスポートが存在する場合、それを呼び出すことによって、WASI リアクタとして instance を初期化しようとします。 instance_start() エクスポートを含む場合、例外がスローされます。

initialize() は、instancememory という名前の WebAssembly.Memory をエクスポートすることを要求します。 instancememory エクスポートがない場合、例外がスローされます。

initialize() が複数回呼び出された場合、例外がスローされます。

wasi.wasiImport

Added in: v13.3.0, v12.16.0

wasiImport は、WASI システムコール API を実装するオブジェクトです。 このオブジェクトは、WebAssembly.Instance のインスタンス化中に wasi_snapshot_preview1 インポートとして渡される必要があります。