Skip to content

Interface Système WebAssembly (WASI)

[Stable : 1 - Expérimental]

Stable : 1 Stabilité : 1 - Expérimental

Le module node:wasi ne fournit pas actuellement les propriétés complètes de sécurité du système de fichiers offertes par certains environnements d'exécution WASI. La prise en charge complète du confinement sécurisé du système de fichiers peut ou non être implémentée à l'avenir. Entre-temps, ne vous fiez pas à lui pour exécuter du code non fiable.

Code source : lib/wasi.js

L'API WASI fournit une implémentation de la spécification de l'Interface Système WebAssembly. WASI donne aux applications WebAssembly l'accès au système d'exploitation sous-jacent via une collection de fonctions de type POSIX.

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

Pour exécuter l'exemple ci-dessus, créez un nouveau fichier au format texte WebAssembly nommé demo.wat :

text
(module
    ;; Importe la fonction WASI fd_write requise qui écrira les vecteurs io donnés sur stdout
    ;; La signature de la fonction pour fd_write est :
    ;; (Descripteur de fichier, *iovs, iovs_len, nwritten) -> Renvoie le nombre d'octets écrits
    (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (param i32 i32 i32 i32) (result i32)))

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

    ;; Écrit 'hello world\n' en mémoire à un décalage de 8 octets
    ;; Notez la nouvelle ligne de fin qui est requise pour que le texte apparaisse
    (data (i32.const 8) "hello world\n")

    (func $main (export "_start")
        ;; Création d'un nouveau vecteur io dans la mémoire linéaire
        (i32.store (i32.const 0) (i32.const 8))  ;; iov.iov_base - Il s'agit d'un pointeur vers le début de la chaîne 'hello world\n'
        (i32.store (i32.const 4) (i32.const 12))  ;; iov.iov_len - La longueur de la chaîne 'hello world\n'

        (call $fd_write
            (i32.const 1) ;; file_descriptor - 1 pour stdout
            (i32.const 0) ;; *iovs - Le pointeur vers le tableau iov, qui est stocké à l'emplacement mémoire 0
            (i32.const 1) ;; iovs_len - Nous imprimons 1 chaîne stockée dans un iov - donc un.
            (i32.const 20) ;; nwritten - Un emplacement en mémoire pour stocker le nombre d'octets écrits
        )
        drop ;; Supprime le nombre d'octets écrits depuis le haut de la pile
    )
)

Utilisez wabt pour compiler .wat en .wasm

bash
wat2wasm demo.wat

Sécurité

[Historique]

VersionModifications
v21.2.0, v20.11.0Clarification des propriétés de sécurité WASI.
v21.2.0, v20.11.0Ajouté dans : v21.2.0, v20.11.0

WASI fournit un modèle basé sur les capacités grâce auquel les applications se voient attribuer leurs propres capacités personnalisées : env, preopens, stdin, stdout, stderr et exit.

Le modèle de menace actuel de Node.js ne fournit pas de sandbox sécurisé comme cela est présent dans certains runtimes WASI.

Bien que les fonctionnalités de capacité soient prises en charge, elles ne forment pas un modèle de sécurité dans Node.js. Par exemple, le sandboxage du système de fichiers peut être contourné à l'aide de diverses techniques. Le projet explore la possibilité d'ajouter ces garanties de sécurité à l'avenir.

Classe : WASI

Ajouté dans : v13.3.0, v12.16.0

La classe WASI fournit l'API d'appel système WASI et des méthodes de commodité supplémentaires pour travailler avec les applications basées sur WASI. Chaque instance WASI représente un environnement distinct.

new WASI([options])

[Historique]

VersionModifications
v20.1.0valeur par défaut de returnOnExit modifiée en true.
v20.0.0L'option version est désormais obligatoire et n'a pas de valeur par défaut.
v19.8.0champ version ajouté aux options.
v13.3.0, v12.16.0Ajouté dans : v13.3.0, v12.16.0
  • options <Objet>
    • args <Tableau> Un tableau de chaînes de caractères que l'application WebAssembly verra comme des arguments de ligne de commande. Le premier argument est le chemin virtuel vers la commande WASI elle-même. Valeur par défaut : [].
    • env <Objet> Un objet similaire à process.env que l'application WebAssembly verra comme son environnement. Valeur par défaut : {}.
    • preopens <Objet> Cet objet représente la structure de répertoire locale de l'application WebAssembly. Les clés chaînes de preopens sont traitées comme des répertoires dans le système de fichiers. Les valeurs correspondantes dans preopens sont les chemins réels vers ces répertoires sur la machine hôte.
    • returnOnExit <booléen> Par défaut, lorsque les applications WASI appellent __wasi_proc_exit(), wasi.start() renvoie le code de sortie spécifié au lieu de terminer le processus. Le fait de définir cette option sur false entraînera la fin du processus Node.js avec le code de sortie spécifié. Valeur par défaut : true.
    • stdin <entier> Le descripteur de fichier utilisé comme entrée standard dans l'application WebAssembly. Valeur par défaut : 0.
    • stdout <entier> Le descripteur de fichier utilisé comme sortie standard dans l'application WebAssembly. Valeur par défaut : 1.
    • stderr <entier> Le descripteur de fichier utilisé comme erreur standard dans l'application WebAssembly. Valeur par défaut : 2.
    • version <chaîne de caractères> La version de WASI demandée. Actuellement, les seules versions prises en charge sont unstable et preview1. Cette option est obligatoire.

wasi.getImportObject()

Ajouté dans : v19.8.0

Retourne un objet d'importation qui peut être passé à WebAssembly.instantiate() si aucune autre importation WASM n'est nécessaire au-delà de celles fournies par WASI.

Si la version unstable a été passée au constructeur, elle retournera :

json
{ wasi_unstable: wasi.wasiImport }

Si la version preview1 a été passée au constructeur ou si aucune version n'a été spécifiée, elle retournera :

json
{ wasi_snapshot_preview1: wasi.wasiImport }

wasi.start(instance)

Ajouté dans : v13.3.0, v12.16.0

Tente de commencer l'exécution de instance en tant que commande WASI en invoquant son exportation _start(). Si instance ne contient pas d'exportation _start(), ou si instance contient une exportation _initialize(), une exception est levée.

start() exige que instance exporte une WebAssembly.Memory nommée memory. Si instance n'a pas d'exportation memory, une exception est levée.

Si start() est appelé plus d'une fois, une exception est levée.

wasi.initialize(instance)

Ajouté dans : v14.6.0, v12.19.0

Tente d'initialiser instance en tant que réacteur WASI en invoquant son exportation _initialize(), si elle est présente. Si instance contient une exportation _start(), une exception est levée.

initialize() exige que instance exporte une WebAssembly.Memory nommée memory. Si instance n'a pas d'exportation memory, une exception est levée.

Si initialize() est appelé plus d'une fois, une exception est levée.

wasi.wasiImport

Ajouté dans : v13.3.0, v12.16.0

wasiImport est un objet qui implémente l'API d'appel système WASI. Cet objet doit être passé en tant qu'importation wasi_snapshot_preview1 lors de l'instantiation d'une WebAssembly.Instance.