WebAssembly System Interface (WASI)
[Стабильно: 1 - Экспериментально]
Стабильно: 1 Стабильность: 1 - Экспериментально
Модуль node:wasi
в настоящее время не обеспечивает всеобъемлющих свойств безопасности файловой системы, предоставляемых некоторыми средами выполнения WASI. Полная поддержка безопасного песочницы файловой системы может быть реализована в будущем, а может и нет. Тем временем не полагайтесь на него для запуска ненадежного кода.
Исходный код: lib/wasi.js
API WASI предоставляет реализацию спецификации WebAssembly System Interface. WASI предоставляет приложениям WebAssembly доступ к базовой операционной системе через набор функций, подобных 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)
})()
Для запуска приведенного выше примера создайте новый файл в формате текста WebAssembly с именем demo.wat
:
(module
;; Импорт необходимой функции WASI fd_write, которая будет записывать заданные векторы ввода-вывода в stdout
;; Сигнатура функции для fd_write:
;; (Дескриптор файла, *iovs, iovs_len, nwritten) -> Возвращает количество записанных байтов
(import "wasi_snapshot_preview1" "fd_write" (func $fd_write (param i32 i32 i32 i32) (result i32)))
(memory 1)
(export "memory" (memory 0))
;; Запись 'hello world\n' в память с смещением 8 байт
;; Обратите внимание на завершающий символ новой строки, который необходим для отображения текста
(data (i32.const 8) "hello world\n")
(func $main (export "_start")
;; Создание нового вектора ввода-вывода в линейной памяти
(i32.store (i32.const 0) (i32.const 8)) ;; iov.iov_base - Это указатель на начало строки 'hello world\n'
(i32.store (i32.const 4) (i32.const 12)) ;; iov.iov_len - Длина строки 'hello world\n'
(call $fd_write
(i32.const 1) ;; file_descriptor - 1 для stdout
(i32.const 0) ;; *iovs - Указатель на массив iov, который хранится в памяти по адресу 0
(i32.const 1) ;; iovs_len - Мы печатаем 1 строку, хранящуюся в iov - поэтому один.
(i32.const 20) ;; nwritten - Место в памяти для хранения количества записанных байтов
)
drop ;; Отбрасываем количество записанных байтов с вершины стека
)
)
Используйте wabt для компиляции .wat
в .wasm
wat2wasm demo.wat
Безопасность
[История]
Версия | Изменения |
---|---|
v21.2.0, v20.11.0 | Уточнены свойства безопасности WASI. |
v21.2.0, v20.11.0 | Добавлено в: v21.2.0, v20.11.0 |
WASI предоставляет модель на основе возможностей, с помощью которой приложениям предоставляются собственные возможности env
, preopens
, stdin
, stdout
, stderr
и exit
.
Текущая модель угроз Node.js не обеспечивает безопасную изоляцию, как в некоторых средах выполнения WASI.
Хотя функции возможностей поддерживаются, они не образуют модель безопасности в Node.js. Например, песочница файловой системы может быть обойдена с помощью различных методов. Проект изучает возможность добавления этих гарантий безопасности в будущем.
Класс: WASI
Добавлено в: v13.3.0, v12.16.0
Класс WASI
предоставляет API системных вызовов WASI и дополнительные удобные методы для работы с приложениями на основе WASI. Каждый экземпляр WASI
представляет собой отдельную среду.
new WASI([options])
[История]
Версия | Изменения |
---|---|
v20.1.0 | Значение по умолчанию для returnOnExit изменено на true. |
v20.0.0 | Опция version теперь обязательна и не имеет значения по умолчанию. |
v19.8.0 | Добавлен параметр version в options. |
v13.3.0, v12.16.0 | Добавлено в: v13.3.0, v12.16.0 |
options
<Object>args
<Array> Массив строк, которые WebAssembly-приложение будет видеть как аргументы командной строки. Первый аргумент — виртуальный путь к самой команде WASI. По умолчанию:[]
.env
<Object> Объект, похожий наprocess.env
, который WebAssembly-приложение будет видеть как свою среду. По умолчанию:{}
.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. В настоящее время поддерживаются только версииunstable
иpreview1
. Этот параметр обязателен.
wasi.getImportObject()
Добавлено в: v19.8.0
Возвращает объект импорта, который может быть передан в WebAssembly.instantiate()
, если не требуются другие импорты WASM, помимо тех, которые предоставляются WASI.
Если в конструктор был передан параметр unstable
, будет возвращено:
{ wasi_unstable: wasi.wasiImport }
Если в конструктор был передан параметр preview1
или версия не указана, будет возвращено:
{ wasi_snapshot_preview1: wasi.wasiImport }
wasi.start(instance)
Добавлено в: v13.3.0, v12.16.0
instance
<WebAssembly.Instance>
Пытается начать выполнение instance
как команды WASI, вызывая её экспорт _start()
. Если instance
не содержит экспорта _start()
или содержит экспорт _initialize()
, то выбрасывается исключение.
start()
требует, чтобы instance
экспортировал WebAssembly.Memory
с именем memory
. Если instance
не имеет экспорта memory
, выбрасывается исключение.
Если start()
вызывается более одного раза, выбрасывается исключение.
wasi.initialize(instance)
Добавлено в: v14.6.0, v12.19.0
instance
<WebAssembly.Instance>
Пытается инициализировать instance
как реактор WASI, вызывая его экспорт _initialize()
, если он присутствует. Если instance
содержит экспорт _start()
, то выбрасывается исключение.
initialize()
требует, чтобы instance
экспортировал WebAssembly.Memory
с именем memory
. Если instance
не имеет экспорта memory
, выбрасывается исключение.
Если initialize()
вызывается более одного раза, выбрасывается исключение.
wasi.wasiImport
Добавлено в: v13.3.0, v12.16.0
wasiImport
— это объект, реализующий API системных вызовов WASI. Этот объект должен передаваться как импорт wasi_snapshot_preview1
во время создания экземпляра WebAssembly.Instance
.