run.sh (16820B)
1 #!/bin/sh 2 # Driver-level checks for `kit run` Wasm sandbox CLI behavior. 3 4 set -u 5 6 script_dir=$(cd "$(dirname "$0")" && pwd) 7 repo_root=$(cd "$script_dir/../.." && pwd) 8 9 KIT="${KIT:-$repo_root/build/kit}" 10 11 if [ ! -x "$KIT" ]; then 12 echo "driver-wasm: kit binary not found at $KIT" >&2 13 exit 2 14 fi 15 16 work=$(mktemp -d "${TMPDIR:-/tmp}/kit-driver-wasm-test.XXXXXX") 17 trap 'rm -rf "$work"' EXIT 18 19 KIT_KIT_DIR="$repo_root/test/lib" 20 . "$repo_root/test/lib/kit_sh_kit.sh" 21 kit_report_init 22 23 cat > "$work/return0.wat" <<'WAT' 24 (module 25 (func (export "test_main") (result i32) 26 i32.const 0)) 27 WAT 28 29 cat > "$work/host_add.wat" <<'WAT' 30 (module 31 (import "env" "host_add" (func $host_add (param i32 i32) (result i32))) 32 (func (export "test_main") (result i32) 33 i32.const 21 34 i32.const 21 35 call $host_add 36 i32.const 42 37 i32.sub)) 38 WAT 39 40 cat > "$work/memory_2page_max.wat" <<'WAT' 41 (module 42 (memory 1 2) 43 (func (export "test_main") (result i32) 44 i32.const 0)) 45 WAT 46 47 cat > "$work/memory_one.wat" <<'WAT' 48 (module 49 (memory 1) 50 (func (export "test_main") (result i32) 51 i32.const 0)) 52 WAT 53 54 cat > "$work/wasi_exit.wat" <<'WAT' 55 (module 56 (import "wasi_snapshot_preview1" "proc_exit" (func $proc_exit (param i32))) 57 (func (export "test_main") (result i32) 58 i32.const 7 59 call $proc_exit 60 i32.const 0)) 61 WAT 62 63 cat > "$work/wasi_stdout.wat" <<'WAT' 64 (module 65 (import "wasi_snapshot_preview1" "fd_write" 66 (func $fd_write (param i32 i32 i32 i32) (result i32))) 67 (memory 1) 68 (data (i32.const 0) "\08\00\00\00\0b\00\00\00") 69 (data (i32.const 8) "hello wasi\0a") 70 (func (export "test_main") (result i32) 71 i32.const 1 72 i32.const 0 73 i32.const 1 74 i32.const 20 75 call $fd_write 76 i32.const 0 77 i32.ne)) 78 WAT 79 80 cat > "$work/wasi_env.wat" <<'WAT' 81 (module 82 (import "wasi_snapshot_preview1" "environ_sizes_get" 83 (func $sizes (param i32 i32) (result i32))) 84 (import "wasi_snapshot_preview1" "environ_get" 85 (func $get (param i32 i32) (result i32))) 86 (memory 1) 87 (func (export "test_main") (result i32) 88 (local $err i32) 89 (local $p i32) 90 i32.const 0 91 i32.const 4 92 call $sizes 93 local.set $err 94 (if (i32.ne (local.get $err) (i32.const 0)) 95 (then (return (local.get $err)))) 96 (if (i32.ne (i32.load (i32.const 0)) (i32.const 1)) 97 (then (return (i32.const 10)))) 98 i32.const 8 99 i32.const 64 100 call $get 101 local.set $err 102 (if (i32.ne (local.get $err) (i32.const 0)) 103 (then (return (local.get $err)))) 104 i32.const 8 105 i32.load 106 local.set $p 107 (if (i32.ne (i32.load8_u (local.get $p)) (i32.const 75)) 108 (then (return (i32.const 11)))) 109 (if (i32.ne (i32.load8_u offset=13 (local.get $p)) (i32.const 61)) 110 (then (return (i32.const 12)))) 111 (if (i32.ne (i32.load8_u offset=14 (local.get $p)) (i32.const 111)) 112 (then (return (i32.const 13)))) 113 i32.const 0)) 114 WAT 115 116 cat > "$work/wasi_args.wat" <<'WAT' 117 (module 118 (import "wasi_snapshot_preview1" "args_sizes_get" 119 (func $sizes (param i32 i32) (result i32))) 120 (import "wasi_snapshot_preview1" "args_get" 121 (func $get (param i32 i32) (result i32))) 122 (memory 1) 123 (func (export "test_main") (result i32) 124 (local $err i32) 125 (local $p i32) 126 i32.const 0 127 i32.const 4 128 call $sizes 129 local.set $err 130 (if (i32.ne (local.get $err) (i32.const 0)) 131 (then (return (local.get $err)))) 132 (if (i32.ne (i32.load (i32.const 0)) (i32.const 2)) 133 (then (return (i32.const 20)))) 134 i32.const 8 135 i32.const 64 136 call $get 137 local.set $err 138 (if (i32.ne (local.get $err) (i32.const 0)) 139 (then (return (local.get $err)))) 140 i32.const 12 141 i32.load 142 local.set $p 143 (if (i32.ne (i32.load8_u (local.get $p)) (i32.const 97)) 144 (then (return (i32.const 21)))) 145 (if (i32.ne (i32.load8_u offset=4 (local.get $p)) (i32.const 97)) 146 (then (return (i32.const 22)))) 147 i32.const 0)) 148 WAT 149 150 cat > "$work/wasi_fs_read.wat" <<'WAT' 151 (module 152 (import "wasi_snapshot_preview1" "path_open" 153 (func $path_open 154 (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32))) 155 (import "wasi_snapshot_preview1" "fd_read" 156 (func $fd_read (param i32 i32 i32 i32) (result i32))) 157 (import "wasi_snapshot_preview1" "fd_close" 158 (func $fd_close (param i32) (result i32))) 159 (memory 1) 160 (data (i32.const 0) "\80\00\00\00\05\00\00\00") 161 (data (i32.const 64) "hello.txt") 162 (func (export "test_main") (result i32) 163 (local $fd i32) 164 (local $err i32) 165 i32.const 3 166 i32.const 0 167 i32.const 64 168 i32.const 9 169 i32.const 0 170 i64.const 0 171 i64.const 0 172 i32.const 0 173 i32.const 16 174 call $path_open 175 local.set $err 176 (if (i32.ne (local.get $err) (i32.const 0)) 177 (then (return (local.get $err)))) 178 i32.const 16 179 i32.load 180 local.set $fd 181 local.get $fd 182 i32.const 0 183 i32.const 1 184 i32.const 20 185 call $fd_read 186 local.set $err 187 (if (i32.ne (local.get $err) (i32.const 0)) 188 (then (return (local.get $err)))) 189 (if (i32.ne (i32.load (i32.const 20)) (i32.const 5)) 190 (then (return (i32.const 30)))) 191 (if (i32.ne (i32.load8_u (i32.const 128)) (i32.const 104)) 192 (then (return (i32.const 31)))) 193 (if (i32.ne (i32.load8_u offset=4 (i32.const 128)) (i32.const 111)) 194 (then (return (i32.const 32)))) 195 local.get $fd 196 call $fd_close 197 drop 198 i32.const 0)) 199 WAT 200 201 cat > "$work/wasi_seek.wat" <<'WAT' 202 (module 203 (import "wasi_snapshot_preview1" "path_open" 204 (func $path_open (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32))) 205 (import "wasi_snapshot_preview1" "fd_read" 206 (func $fd_read (param i32 i32 i32 i32) (result i32))) 207 (import "wasi_snapshot_preview1" "fd_seek" 208 (func $fd_seek (param i32 i64 i32 i32) (result i32))) 209 (import "wasi_snapshot_preview1" "fd_tell" 210 (func $fd_tell (param i32 i32) (result i32))) 211 (import "wasi_snapshot_preview1" "fd_close" 212 (func $fd_close (param i32) (result i32))) 213 (memory 1) 214 (data (i32.const 64) "hello.txt") 215 (func (export "test_main") (result i32) 216 (local $fd i32) (local $err i32) 217 ;; path_open(dirfd=3, ..., "hello.txt", oflags=0, ..., &fd=16) 218 i32.const 3 i32.const 0 i32.const 64 i32.const 9 219 i32.const 0 i64.const 0 i64.const 0 i32.const 0 i32.const 16 220 call $path_open local.set $err 221 (if (i32.ne (local.get $err) (i32.const 0)) (then (return (i32.const 1)))) 222 (i32.load (i32.const 16)) local.set $fd 223 ;; read 2 bytes into buf=128; iov at [0]=128 [4]=2; nread at 8 224 (i32.store (i32.const 0) (i32.const 128)) 225 (i32.store (i32.const 4) (i32.const 2)) 226 local.get $fd i32.const 0 i32.const 1 i32.const 8 227 call $fd_read local.set $err 228 (if (i32.ne (local.get $err) (i32.const 0)) (then (return (i32.const 2)))) 229 (if (i32.ne (i32.load (i32.const 8)) (i32.const 2)) (then (return (i32.const 3)))) 230 (if (i32.ne (i32.load8_u (i32.const 128)) (i32.const 104)) ;; 'h' 231 (then (return (i32.const 4)))) 232 ;; fd_seek(fd, offset=3, whence=0/SET, &newpos=24) 233 local.get $fd i64.const 3 i32.const 0 i32.const 24 234 call $fd_seek local.set $err 235 (if (i32.ne (local.get $err) (i32.const 0)) (then (return (i32.const 5)))) 236 (if (i64.ne (i64.load (i32.const 24)) (i64.const 3)) (then (return (i32.const 6)))) 237 ;; fd_tell(fd, &pos=32) 238 local.get $fd i32.const 32 239 call $fd_tell local.set $err 240 (if (i32.ne (local.get $err) (i32.const 0)) (then (return (i32.const 7)))) 241 (if (i64.ne (i64.load (i32.const 32)) (i64.const 3)) (then (return (i32.const 8)))) 242 ;; read 1 byte from pos 3: expect 'l'=108 243 (i32.store (i32.const 4) (i32.const 1)) 244 local.get $fd i32.const 0 i32.const 1 i32.const 8 245 call $fd_read local.set $err 246 (if (i32.ne (local.get $err) (i32.const 0)) (then (return (i32.const 9)))) 247 (if (i32.ne (i32.load8_u (i32.const 128)) (i32.const 108)) ;; 'l' 248 (then (return (i32.const 10)))) 249 local.get $fd call $fd_close drop 250 i32.const 0)) 251 WAT 252 253 cat > "$work/wasi_filestat.wat" <<'WAT' 254 (module 255 (import "wasi_snapshot_preview1" "path_open" 256 (func $path_open (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32))) 257 (import "wasi_snapshot_preview1" "fd_filestat_get" 258 (func $fd_filestat_get (param i32 i32) (result i32))) 259 (import "wasi_snapshot_preview1" "fd_close" 260 (func $fd_close (param i32) (result i32))) 261 (memory 1) 262 (data (i32.const 256) "hello.txt") 263 (func (export "test_main") (result i32) 264 (local $fd i32) (local $err i32) 265 i32.const 3 i32.const 0 i32.const 256 i32.const 9 266 i32.const 0 i64.const 0 i64.const 0 i32.const 0 i32.const 16 267 call $path_open local.set $err 268 (if (i32.ne (local.get $err) (i32.const 0)) (then (return (i32.const 1)))) 269 (i32.load (i32.const 16)) local.set $fd 270 ;; fd_filestat_get(fd, filestat=64): 64-byte struct 271 local.get $fd i32.const 64 272 call $fd_filestat_get local.set $err 273 (if (i32.ne (local.get $err) (i32.const 0)) (then (return (i32.const 2)))) 274 ;; filetype @ 64+16=80: expect 4 (regular file) 275 (if (i32.ne (i32.load8_u (i32.const 80)) (i32.const 4)) 276 (then (return (i32.const 3)))) 277 ;; size @ 64+32=96 (u64 LE): expect 5 278 (if (i64.ne (i64.load (i32.const 96)) (i64.const 5)) 279 (then (return (i32.const 4)))) 280 local.get $fd call $fd_close drop 281 i32.const 0)) 282 WAT 283 284 cat > "$work/wasi_path_filestat.wat" <<'WAT' 285 (module 286 (import "wasi_snapshot_preview1" "path_filestat_get" 287 (func $path_filestat_get (param i32 i32 i32 i32 i32) (result i32))) 288 (memory 1) 289 (data (i32.const 256) "hello.txt") 290 (func (export "test_main") (result i32) 291 (local $err i32) 292 ;; path_filestat_get(dirfd=3, flags=0, path=256, pathlen=9, filestat=64) 293 i32.const 3 i32.const 0 i32.const 256 i32.const 9 i32.const 64 294 call $path_filestat_get local.set $err 295 (if (i32.ne (local.get $err) (i32.const 0)) (then (return (local.get $err)))) 296 ;; filetype @ 64+16=80: expect 4 (regular file) 297 (if (i32.ne (i32.load8_u (i32.const 80)) (i32.const 4)) 298 (then (return (i32.const 10)))) 299 ;; size @ 64+32=96 (u64 LE): expect 5 300 (if (i64.ne (i64.load (i32.const 96)) (i64.const 5)) 301 (then (return (i32.const 11)))) 302 i32.const 0)) 303 WAT 304 305 cat > "$work/wasi_opendir_readdir.wat" <<'WAT' 306 (module 307 (import "wasi_snapshot_preview1" "path_open" 308 (func $path_open (param i32 i32 i32 i32 i32 i64 i64 i32 i32) (result i32))) 309 (import "wasi_snapshot_preview1" "fd_readdir" 310 (func $fd_readdir (param i32 i32 i32 i64 i32) (result i32))) 311 (import "wasi_snapshot_preview1" "fd_close" 312 (func $fd_close (param i32) (result i32))) 313 (memory 1) 314 (data (i32.const 64) "subdir") 315 (func (export "test_main") (result i32) 316 (local $dir_fd i32) (local $err i32) 317 ;; path_open(3, 0, "subdir", oflags=4/OFLAGS_DIRECTORY, ..., &fd=16) 318 i32.const 3 i32.const 0 i32.const 64 i32.const 6 319 i32.const 4 i64.const 0 i64.const 0 i32.const 0 i32.const 16 320 call $path_open local.set $err 321 (if (i32.ne (local.get $err) (i32.const 0)) (then (return (i32.const 1)))) 322 (i32.load (i32.const 16)) local.set $dir_fd 323 ;; fd_readdir(dir_fd, buf=128, buflen=256, cookie=0, &bufused=32) 324 local.get $dir_fd i32.const 128 i32.const 256 i64.const 0 i32.const 32 325 call $fd_readdir local.set $err 326 (if (i32.ne (local.get $err) (i32.const 0)) (then (return (i32.const 2)))) 327 ;; expect exactly one entry: "world.txt" (9 bytes) → bufused=24+9=33 328 (if (i32.ne (i32.load (i32.const 32)) (i32.const 33)) 329 (then (return (i32.const 3)))) 330 ;; dirent namlen @ buf+16=144: expect 9 331 (if (i32.ne (i32.load (i32.const 144)) (i32.const 9)) 332 (then (return (i32.const 4)))) 333 ;; dirent filetype @ buf+20=148: expect 4 (regular) 334 (if (i32.ne (i32.load8_u (i32.const 148)) (i32.const 4)) 335 (then (return (i32.const 5)))) 336 local.get $dir_fd call $fd_close drop 337 i32.const 0)) 338 WAT 339 340 cat > "$work/wasi_unknown.wat" <<'WAT' 341 (module 342 (import "wasi_snapshot_preview1" "path_unlink_file" 343 (func $unlink (param i32 i32 i32) (result i32))) 344 (memory 1) 345 (func (export "test_main") (result i32) 346 i32.const 0 347 i32.const 0 348 i32.const 0 349 call $unlink)) 350 WAT 351 352 cat > "$work/main.c" <<'SRC' 353 int main(void) { return 0; } 354 SRC 355 356 printf 'hello' > "$work/hello.txt" 357 mkdir -p "$work/subdir" 358 printf 'world' > "$work/subdir/world.txt" 359 360 run_ok "wasm-default-runs-no-imports" \ 361 "$KIT" run -e test_main "$work/return0.wat" 362 363 KIT_TEST_HOST_IMPORTS=1 "$KIT" run -e test_main "$work/host_add.wat" \ 364 > "$work/default-deny.out" 2> "$work/default-deny.err" 365 if [ "$?" -ne 0 ]; then 366 ok "wasm-default-denies-test-env-fallback" 367 else 368 not_ok "wasm-default-denies-test-env-fallback" "$work/default-deny.out" 369 fi 370 contains "wasm-default-deny-diag" "$work/default-deny.err" \ 371 "wasm host import unresolved" 372 373 run_ok "wasm-explicit-test-import" \ 374 "$KIT" run --wasm-imports=test -e test_main "$work/host_add.wat" 375 376 run_fail "wasm-memory-cap-fails" \ 377 "$KIT" run --wasm-memory-max=64K -e test_main "$work/memory_2page_max.wat" 378 contains "wasm-memory-cap-diag" "$work/wasm-memory-cap-fails.err" \ 379 "wasm linear memory reservation exceeds 65536 bytes" 380 381 run_ok "wasm-memory-cap-allows" \ 382 "$KIT" run --wasm-memory-max=128K -e test_main "$work/memory_2page_max.wat" 383 384 run_fail "wasm-memories-cap-fails" \ 385 "$KIT" run --wasm-memories-max=0 -e test_main "$work/memory_one.wat" 386 contains "wasm-memories-cap-diag" "$work/wasm-memories-cap-fails.err" \ 387 "wasm memory count exceeds 0" 388 389 run_ok "wasm-policy-flags-parse" \ 390 "$KIT" run --wasm-env=inherit --wasm-env-pass=PATH \ 391 --wasm-env-set=KIT_TEST=1 --wasm-map-dir="$work=/work:ro" \ 392 --wasm-map-file="$work/return0.wat=/return0.wat:ro" --wasm-cwd=/work \ 393 --wasm-stdio=inherit --wasm-clock=monotonic --wasm-random=seed:abcd \ 394 -e test_main "$work/return0.wat" 395 396 "$KIT" run --wasm-wasi -e test_main "$work/wasi_exit.wat" \ 397 > "$work/wasm-wasi-proc-exit.out" 2> "$work/wasm-wasi-proc-exit.err" 398 if [ "$?" -eq 7 ]; then 399 ok "wasm-wasi-proc-exit" 400 else 401 not_ok "wasm-wasi-proc-exit" "$work/wasm-wasi-proc-exit.err" 402 fi 403 404 "$KIT" run --wasm-wasi --wasm-stdio=inherit -e test_main \ 405 "$work/wasi_stdout.wat" > "$work/wasm-wasi-stdout.out" \ 406 2> "$work/wasm-wasi-stdout.err" 407 if [ "$?" -eq 0 ]; then ok "wasm-wasi-stdout"; else 408 not_ok "wasm-wasi-stdout" "$work/wasm-wasi-stdout.err" 409 fi 410 contains "wasm-wasi-stdout-text" "$work/wasm-wasi-stdout.out" "hello wasi" 411 412 "$KIT" run --wasm-wasi --wasm-stdio=null -e test_main \ 413 "$work/wasi_stdout.wat" > "$work/wasm-wasi-stdout-null.out" \ 414 2> "$work/wasm-wasi-stdout-null.err" 415 if [ "$?" -eq 0 ] && [ ! -s "$work/wasm-wasi-stdout-null.out" ]; then 416 ok "wasm-wasi-stdout-null" 417 else 418 not_ok "wasm-wasi-stdout-null" "$work/wasm-wasi-stdout-null.err" 419 fi 420 421 run_ok "wasm-wasi-env-set" \ 422 "$KIT" run --wasm-wasi --wasm-env-set=KIT_WASM_TEST=ok \ 423 -e test_main "$work/wasi_env.wat" 424 425 run_ok "wasm-wasi-args" \ 426 "$KIT" run --wasm-wasi -e test_main "$work/wasi_args.wat" -- alpha 427 428 run_ok "wasm-wasi-fs-read" \ 429 "$KIT" run --wasm-wasi --wasm-map-dir="$work=/sandbox:ro" \ 430 -e test_main "$work/wasi_fs_read.wat" 431 432 run_ok "wasm-wasi-fs-map-file-read" \ 433 "$KIT" run --wasm-wasi \ 434 --wasm-map-file="$work/hello.txt=/sandbox/hello.txt:ro" \ 435 -e test_main "$work/wasi_fs_read.wat" 436 437 run_ok "wasm-wasi-seek-tell" \ 438 "$KIT" run --wasm-wasi --wasm-map-dir="$work=/sandbox:ro" \ 439 -e test_main "$work/wasi_seek.wat" 440 441 run_ok "wasm-wasi-fd-filestat-get" \ 442 "$KIT" run --wasm-wasi --wasm-map-dir="$work=/sandbox:ro" \ 443 -e test_main "$work/wasi_filestat.wat" 444 445 run_ok "wasm-wasi-path-filestat-get" \ 446 "$KIT" run --wasm-wasi --wasm-map-dir="$work=/sandbox:ro" \ 447 -e test_main "$work/wasi_path_filestat.wat" 448 449 run_ok "wasm-wasi-opendir-readdir" \ 450 "$KIT" run --wasm-wasi --wasm-map-dir="$work=/sandbox:ro" \ 451 -e test_main "$work/wasi_opendir_readdir.wat" 452 453 run_fail "wasm-wasi-unknown-import-fails" \ 454 "$KIT" run --wasm-wasi -e test_main "$work/wasi_unknown.wat" 455 contains "wasm-wasi-unknown-import-diag" \ 456 "$work/wasm-wasi-unknown-import-fails.err" \ 457 "wasm host import unresolved" 458 459 run_fail "wasm-flags-reject-native" \ 460 "$KIT" run --wasm-memory-max=1M "$work/main.c" 461 contains "wasm-flags-reject-native-diag" "$work/wasm-flags-reject-native.err" \ 462 "wasm sandbox flags require a wasm input" 463 464 run_fail "wasm-rejects-mixed-native-inputs" \ 465 "$KIT" run -e test_main "$work/return0.wat" "$work/main.c" 466 contains "wasm-rejects-mixed-native-inputs-diag" \ 467 "$work/wasm-rejects-mixed-native-inputs.err" \ 468 "sandboxed wasm run does not support mixed native inputs" 469 470 run_fail "wasm-import-mode-invalid" \ 471 "$KIT" run --wasm-imports=env -e test_main "$work/return0.wat" 472 contains "wasm-import-mode-invalid-diag" \ 473 "$work/wasm-import-mode-invalid.err" \ 474 "unknown --wasm-imports value" 475 476 run_fail "wasm-fs-invalid" \ 477 "$KIT" run --wasm-fs=host -e test_main "$work/return0.wat" 478 contains "wasm-fs-invalid-diag" "$work/wasm-fs-invalid.err" \ 479 "unknown --wasm-fs value" 480 481 kit_summary test-driver-wasm 482 kit_exit