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.
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)
'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
:
(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
wat2wasm demo.wat
Segurança
[Histórico]
Versão | Alterações |
---|---|
v21.2.0, v20.11.0 | Esclarece as propriedades de segurança do WASI. |
v21.2.0, v20.11.0 | Adicionado 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ão | Alterações |
---|---|
v20.1.0 | Valor padrão de returnOnExit alterado para true. |
v20.0.0 | A opção de versão agora é obrigatória e não tem valor padrão. |
v19.8.0 | Campo de versão adicionado às opções. |
v13.3.0, v12.16.0 | Adicionado 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 aprocess.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 depreopens
são tratadas como diretórios dentro do sistema de arquivos. Os valores correspondentes empreopens
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 comofalse
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ãounstable
epreview1
. 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á:
{ wasi_unstable: wasi.wasiImport }
Se a versão preview1
foi passada para o construtor ou nenhuma versão foi especificada, ele retornará:
{ wasi_snapshot_preview1: wasi.wasiImport }
wasi.start(instance)
Adicionado em: v13.3.0, v12.16.0
instance
<WebAssembly.Instance>
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
instance
<WebAssembly.Instance>
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
.