Skip to content

WebAssembly 시스템 인터페이스 (WASI)

[안정성: 1 - 실험적]

안정성: 1 안정성: 1 - 실험적

node:wasi 모듈은 현재 일부 WASI 런타임에서 제공하는 포괄적인 파일 시스템 보안 속성을 제공하지 않습니다. 보안 파일 시스템 샌드박싱에 대한 완전한 지원이 향후 구현될 수도 있고 그렇지 않을 수도 있습니다. 그동안 신뢰할 수 없는 코드를 실행하는 데 의존하지 마십시오.

소스 코드: lib/wasi.js

WASI API는 WebAssembly 시스템 인터페이스 사양의 구현을 제공합니다. WASI는 WebAssembly 애플리케이션에 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)
})()

위의 예제를 실행하려면 demo.wat이라는 새 WebAssembly 텍스트 형식 파일을 만듭니다.

text
(module
    ;; stdout에 주어진 io 벡터를 쓰는 데 필요한 fd_write WASI 함수를 가져옵니다.
    ;; 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))

    ;; 8바이트 오프셋에서 메모리에 'hello world\n'을 씁니다.
    ;; 텍스트가 표시되려면 후행 줄바꿈이 필요합니다.
    (data (i32.const 8) "hello world\n")

    (func $main (export "_start")
        ;; 선형 메모리 내에서 새 io 벡터를 만듭니다.
        (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 - stdout의 경우 1입니다.
            (i32.const 0) ;; *iovs - 메모리 위치 0에 저장된 iov 배열의 포인터입니다.
            (i32.const 1) ;; iovs_len - iov에 저장된 1개의 문자열을 인쇄하고 있으므로 1입니다.
            (i32.const 20) ;; nwritten - 메모리에 쓰여진 바이트 수를 저장할 위치입니다.
        )
        drop ;; 스택 맨 위에서 쓰여진 바이트 수를 삭제합니다.
    )
)

wabt를 사용하여 .wat.wasm으로 컴파일합니다.

bash
wat2wasm demo.wat

보안

[역사]

버전변경 사항
v21.2.0, v20.11.0WASI 보안 속성을 명확히 했습니다.
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 클래스는 WASI 시스템 호출 API와 WASI 기반 애플리케이션 작업을 위한 추가 편의 메서드를 제공합니다. 각 WASI 인스턴스는 고유한 환경을 나타냅니다.

new WASI([options])

[역사]

버전변경 사항
v20.1.0returnOnExit의 기본값이 true로 변경되었습니다.
v20.0.0version 옵션이 필수가 되었으며 기본값이 없습니다.
v19.8.0옵션에 version 필드가 추가되었습니다.
v13.3.0, v12.16.0다음 버전에서 추가됨: v13.3.0, v12.16.0
  • options <Object>
    • args <Array> WebAssembly 애플리케이션이 명령줄 인수로 인식할 문자열 배열입니다. 첫 번째 인수는 WASI 명령 자체의 가상 경로입니다. 기본값: [].
    • env <Object> WebAssembly 애플리케이션이 환경으로 인식할 process.env와 유사한 객체입니다. 기본값: {}.
    • 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 버전입니다. 현재 지원되는 유일한 버전은 unstablepreview1입니다. 이 옵션은 필수입니다.

wasi.getImportObject()

추가된 버전: v19.8.0

WASI에서 제공하는 것 외에 다른 WASM import가 필요하지 않은 경우, WebAssembly.instantiate()에 전달할 수 있는 import 객체를 반환합니다.

생성자에 unstable 버전이 전달된 경우, 다음을 반환합니다.

json
{ wasi_unstable: wasi.wasiImport }

생성자에 preview1 버전이 전달되었거나 버전이 지정되지 않은 경우, 다음을 반환합니다.

json
{ wasi_snapshot_preview1: wasi.wasiImport }

wasi.start(instance)

추가된 버전: v13.3.0, v12.16.0

instance_start() export를 호출하여 WASI 명령으로 instance 실행을 시작하려고 시도합니다. instance_start() export가 없거나 instance_initialize() export가 포함된 경우 예외가 발생합니다.

start()instancememory라는 이름의 WebAssembly.Memory를 export하도록 요구합니다. instancememory export가 없는 경우 예외가 발생합니다.

start()가 두 번 이상 호출되면 예외가 발생합니다.

wasi.initialize(instance)

추가된 버전: v14.6.0, v12.19.0

instance_initialize() export가 있는 경우, 해당 export를 호출하여 WASI reactor로 instance를 초기화하려고 시도합니다. instance_start() export가 포함된 경우 예외가 발생합니다.

initialize()instancememory라는 이름의 WebAssembly.Memory를 export하도록 요구합니다. instancememory export가 없는 경우 예외가 발생합니다.

initialize()가 두 번 이상 호출되면 예외가 발생합니다.

wasi.wasiImport

추가된 버전: v13.3.0, v12.16.0

wasiImport는 WASI 시스템 호출 API를 구현하는 객체입니다. 이 객체는 WebAssembly.Instance를 인스턴스화하는 동안 wasi_snapshot_preview1 import로 전달되어야 합니다.