Skip to content

Interface do Sistema WebAssembly (WASI)

[Estável: 1 - Experimental]

Estável: 1 Estabilidade: 1 - Experimental

O módulo node:wasi atualmente não fornece as propriedades abrangentes de segurança do sistema de arquivos fornecidas por alguns tempos de execução WASI. O suporte total para sandbox de sistema de arquivos seguro pode ou não ser implementado no futuro. Enquanto isso, não confie nele para executar código não confiável.

Código-fonte: lib/wasi.js

A API WASI fornece uma implementação da especificação WebAssembly System Interface. WASI fornece a aplicativos WebAssembly acesso ao sistema operacional subjacente por meio de uma coleção de funções semelhantes ao 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 executar o exemplo acima, crie um novo arquivo de formato de texto WebAssembly chamado demo.wat:

text
(module
    ;; Importa a função WASI fd_write necessária que escreverá os vetores de io fornecidos para stdout
    ;; A assinatura da função para fd_write é:
    ;; (Descriptor de Arquivo, *iovs, iovs_len, nwritten) -> Retorna o 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))

    ;; Escreve 'hello world\n' na memória em um offset de 8 bytes
    ;; Observe a nova linha final que é necessária para o texto aparecer
    (data (i32.const 8) "hello world\n")

    (func $main (export "_start")
        ;; Criando um novo vetor de io dentro da memória linear
        (i32.store (i32.const 0) (i32.const 8))  ;; iov.iov_base - Este é um ponteiro para o início da string 'hello world\n'
        (i32.store (i32.const 4) (i32.const 12))  ;; iov.iov_len - O comprimento da string 'hello world\n'

        (call $fd_write
            (i32.const 1) ;; file_descriptor - 1 para stdout
            (i32.const 0) ;; *iovs - O ponteiro para o array iov, que é armazenado no local de memória 0
            (i32.const 1) ;; iovs_len - Estamos imprimindo 1 string armazenada em um iov - então um.
            (i32.const 20) ;; nwritten - Um local na memória para armazenar o número de bytes escritos
        )
        drop ;; Descarta o número de bytes escritos do topo da pilha
    )
)

Use wabt para compilar .wat para .wasm

bash
wat2wasm demo.wat

Segurança

[Histórico]

VersãoAlterações
v21.2.0, v20.11.0Esclarece as propriedades de segurança do WASI.
v21.2.0, v20.11.0Adicionado em: v21.2.0, v20.11.0

O WASI fornece um modelo baseado em capacidades por meio do qual os aplicativos recebem suas próprias capacidades personalizadas env, preopens, stdin, stdout, stderr e exit.

O modelo de ameaças atual do Node.js não fornece sandbox seguro como presente em alguns runtimes WASI.

Embora os recursos de capacidade sejam suportados, eles não formam um modelo de segurança no Node.js. Por exemplo, o sandbox do sistema de arquivos pode ser escapado com várias técnicas. O projeto está explorando se essas garantias de segurança poderiam ser adicionadas no futuro.

Classe: WASI

Adicionado em: v13.3.0, v12.16.0

A classe WASI fornece a API de chamada do sistema WASI e métodos adicionais de conveniência para trabalhar com aplicativos baseados em WASI. Cada instância WASI representa um ambiente distinto.

new WASI([options])

[Histórico]

VersãoAlterações
v20.1.0Valor padrão de returnOnExit alterado para true.
v20.0.0A opção de versão agora é obrigatória e não tem valor padrão.
v19.8.0Campo de versão adicionado às opções.
v13.3.0, v12.16.0Adicionado em: v13.3.0, v12.16.0
  • options <Object>
    • args <Array> Uma matriz de strings que o aplicativo WebAssembly verá como argumentos de linha de comando. O primeiro argumento é o caminho virtual para o próprio comando WASI. Padrão: [].
    • env <Object> Um objeto semelhante a process.env que o aplicativo WebAssembly verá como seu ambiente. Padrão: {}.
    • preopens <Object> Este objeto representa a estrutura de diretórios local do aplicativo WebAssembly. As chaves de string de preopens são tratadas como diretórios dentro do sistema de arquivos. Os valores correspondentes em preopens são os caminhos reais para esses diretórios na máquina host.
    • returnOnExit <boolean> Por padrão, quando os aplicativos WASI chamam __wasi_proc_exit(), wasi.start() retornará com o código de saída especificado em vez de encerrar o processo. Definir esta opção como false fará com que o processo Node.js seja encerrado com o código de saída especificado. Padrão: true.
    • stdin <integer> O descritor de arquivo usado como entrada padrão no aplicativo WebAssembly. Padrão: 0.
    • stdout <integer> O descritor de arquivo usado como saída padrão no aplicativo WebAssembly. Padrão: 1.
    • stderr <integer> O descritor de arquivo usado como erro padrão no aplicativo WebAssembly. Padrão: 2.
    • version <string> A versão do WASI solicitada. Atualmente, as únicas versões suportadas são unstable e preview1. Esta opção é obrigatória.

wasi.getImportObject()

Adicionado em: v19.8.0

Retorna um objeto de importação que pode ser passado para WebAssembly.instantiate() se nenhuma outra importação WASM for necessária além daquelas fornecidas pelo WASI.

Se a versão unstable foi passada para o construtor, ele retornará:

json
{ wasi_unstable: wasi.wasiImport }

Se a versão preview1 foi passada para o construtor ou nenhuma versão foi especificada, ele retornará:

json
{ wasi_snapshot_preview1: wasi.wasiImport }

wasi.start(instance)

Adicionado em: v13.3.0, v12.16.0

Tenta iniciar a execução de instance como um comando WASI invocando sua exportação _start(). Se instance não contiver uma exportação _start(), ou se instance contiver uma exportação _initialize(), uma exceção será lançada.

start() requer que instance exporte uma WebAssembly.Memory chamada memory. Se instance não tiver uma exportação memory, uma exceção será lançada.

Se start() for chamado mais de uma vez, uma exceção será lançada.

wasi.initialize(instance)

Adicionado em: v14.6.0, v12.19.0

Tenta inicializar instance como um reator WASI invocando sua exportação _initialize(), se presente. Se instance contiver uma exportação _start(), uma exceção será lançada.

initialize() requer que instance exporte uma WebAssembly.Memory chamada memory. Se instance não tiver uma exportação memory, uma exceção será lançada.

Se initialize() for chamado mais de uma vez, uma exceção será lançada.

wasi.wasiImport

Adicionado em: v13.3.0, v12.16.0

wasiImport é um objeto que implementa a API de chamada de sistema WASI. Este objeto deve ser passado como a importação wasi_snapshot_preview1 durante a instanciação de uma WebAssembly.Instance.