Skip to content

Interfaz del sistema WebAssembly (WASI)

[Estable: 1 - Experimental]

Estable: 1 Estabilidad: 1 - Experimental

El módulo node:wasi actualmente no proporciona las propiedades de seguridad integrales del sistema de archivos proporcionadas por algunos tiempos de ejecución de WASI. El soporte completo para el sandbox seguro del sistema de archivos puede o no implementarse en futuro. Mientras tanto, no confíe en él para ejecutar código que no sea de confianza.

Código fuente: lib/wasi.js

La API de WASI proporciona una implementación de la especificación Interfaz del sistema WebAssembly. WASI brinda a las aplicaciones de WebAssembly acceso al sistema operativo subyacente a través de una colección de funciones tipo 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)
})()

Para ejecutar el ejemplo anterior, cree un nuevo archivo de formato de texto WebAssembly llamado demo.wat:

text
(module
    ;; Importar la función WASI fd_write requerida que escribirá los vectores io dados en stdout
    ;; La firma de la función para fd_write es:
    ;; (Descriptor de archivo, *iovs, iovs_len, nwritten) -> Devuelve el número de bytes escritos
    (import "wasi_snapshot_preview1" "fd_write" (func $fd_write (param i32 i32 i32 i32) (result i32)))

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

    ;; Escribir 'hola mundo\n' en la memoria con un desplazamiento de 8 bytes
    ;; Tenga en cuenta la nueva línea final que se requiere para que aparezca el texto
    (data (i32.const 8) "hola mundo\n")

    (func $main (export "_start")
        ;; Creando un nuevo vector io dentro de la memoria lineal
        (i32.store (i32.const 0) (i32.const 8))  ;; iov.iov_base - Este es un puntero al inicio de la cadena 'hola mundo\n'
        (i32.store (i32.const 4) (i32.const 12))  ;; iov.iov_len - La longitud de la cadena 'hola mundo\n'

        (call $fd_write
            (i32.const 1) ;; file_descriptor - 1 para stdout
            (i32.const 0) ;; *iovs - El puntero a la matriz iov, que se almacena en la ubicación de memoria 0
            (i32.const 1) ;; iovs_len - Estamos imprimiendo 1 cadena almacenada en un iov, así que uno.
            (i32.const 20) ;; nwritten - Un lugar en la memoria para almacenar el número de bytes escritos
        )
        drop ;; Descartar el número de bytes escritos de la parte superior de la pila
    )
)

Use wabt para compilar .wat a .wasm

bash
wat2wasm demo.wat

Seguridad

[Historial]

VersiónCambios
v21.2.0, v20.11.0Se aclaran las propiedades de seguridad de WASI.
v21.2.0, v20.11.0Añadido en: v21.2.0, v20.11.0

WASI proporciona un modelo basado en capacidades a través del cual las aplicaciones reciben sus propias capacidades personalizadas env, preopens, stdin, stdout, stderr y exit.

El modelo de amenazas actual de Node.js no proporciona un espacio aislado seguro como el que está presente en algunos tiempos de ejecución de WASI.

Aunque las características de capacidad son compatibles, no forman un modelo de seguridad en Node.js. Por ejemplo, el espacio aislado del sistema de archivos puede evitarse con varias técnicas. El proyecto está explorando si estas garantías de seguridad podrían añadirse en el futuro.

Clase: WASI

Añadido en: v13.3.0, v12.16.0

La clase WASI proporciona la API de llamadas al sistema WASI y métodos de conveniencia adicionales para trabajar con aplicaciones basadas en WASI. Cada instancia WASI representa un entorno distinto.

new WASI([options])

[Historial]

VersiónCambios
v20.1.0el valor predeterminado de returnOnExit cambió a true.
v20.0.0La opción de versión ahora es obligatoria y no tiene valor predeterminado.
v19.8.0se añadió el campo versión a las opciones.
v13.3.0, v12.16.0Añadido en: v13.3.0, v12.16.0
  • options <Objeto>
    • args <Array> Un array de cadenas que la aplicación WebAssembly verá como argumentos de línea de comandos. El primer argumento es la ruta virtual al comando WASI en sí. Predeterminado: [].
    • env <Objeto> Un objeto similar a process.env que la aplicación WebAssembly verá como su entorno. Predeterminado: {}.
    • preopens <Objeto> Este objeto representa la estructura de directorios local de la aplicación WebAssembly. Las claves de cadena de preopens se tratan como directorios dentro del sistema de archivos. Los valores correspondientes en preopens son las rutas reales a esos directorios en la máquina host.
    • returnOnExit <booleano> De forma predeterminada, cuando las aplicaciones WASI llaman a __wasi_proc_exit() wasi.start() devolverá el código de salida especificado en lugar de terminar el proceso. Si se establece esta opción en false, el proceso de Node.js saldrá con el código de salida especificado en su lugar. Predeterminado: true.
    • stdin <entero> El descriptor de archivo utilizado como entrada estándar en la aplicación WebAssembly. Predeterminado: 0.
    • stdout <entero> El descriptor de archivo utilizado como salida estándar en la aplicación WebAssembly. Predeterminado: 1.
    • stderr <entero> El descriptor de archivo utilizado como error estándar en la aplicación WebAssembly. Predeterminado: 2.
    • version <cadena> La versión de WASI solicitada. Actualmente, las únicas versiones admitidas son unstable y preview1. Esta opción es obligatoria.

wasi.getImportObject()

Añadido en: v19.8.0

Devuelve un objeto de importación que se puede pasar a WebAssembly.instantiate() si no se necesitan otras importaciones WASM más allá de las proporcionadas por WASI.

Si se pasó la versión unstable al constructor, devolverá:

json
{ wasi_unstable: wasi.wasiImport }

Si se pasó la versión preview1 al constructor o no se especificó ninguna versión, devolverá:

json
{ wasi_snapshot_preview1: wasi.wasiImport }

wasi.start(instance)

Añadido en: v13.3.0, v12.16.0

Intenta comenzar la ejecución de instance como un comando WASI invocando su exportación _start(). Si instance no contiene una exportación _start(), o si instance contiene una exportación _initialize(), entonces se lanza una excepción.

start() requiere que instance exporte un WebAssembly.Memory llamado memory. Si instance no tiene una exportación memory, se lanza una excepción.

Si se llama a start() más de una vez, se lanza una excepción.

wasi.initialize(instance)

Añadido en: v14.6.0, v12.19.0

Intenta inicializar instance como un reactor WASI invocando su exportación _initialize(), si está presente. Si instance contiene una exportación _start(), se lanza una excepción.

initialize() requiere que instance exporte una WebAssembly.Memory llamada memory. Si instance no tiene una exportación memory, se lanza una excepción.

Si se llama a initialize() más de una vez, se lanza una excepción.

wasi.wasiImport

Añadido en: v13.3.0, v12.16.0

wasiImport es un objeto que implementa la API de llamadas al sistema WASI. Este objeto debe pasarse como importación wasi_snapshot_preview1 durante la instanciación de una WebAssembly.Instance.