From bb4403328220d42e750a25ba01be8c546481d5c7 Mon Sep 17 00:00:00 2001 From: Guy Bedford Date: Thu, 31 Aug 2023 20:42:43 -0700 Subject: [PATCH] fix: add test for and verify full encapsulation (#15) --- Cargo.lock | 1 + Cargo.toml | 1 + README.md | 8 ++++ lib/virtual_adapter.wasm | Bin 182364 -> 181132 bytes lib/wasi_snapshot_preview1.reactor.wasm | Bin 101607 -> 101639 bytes src/virt_deny.rs | 8 +++- src/virt_io.rs | 61 ++++++++++++++++-------- tests/cases/encapsulate-none.toml | 15 ++++++ tests/virt.rs | 58 ++++++++++++++++++++-- update-wasi.sh | 1 + 10 files changed, 129 insertions(+), 24 deletions(-) create mode 100644 tests/cases/encapsulate-none.toml diff --git a/Cargo.lock b/Cargo.lock index 5850974..e63a0bd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1992,6 +1992,7 @@ dependencies = [ "wasm-compose", "wasm-metadata", "wasm-opt", + "wasmparser 0.112.0", "wasmtime", "wasmtime-wasi", "wit-component", diff --git a/Cargo.toml b/Cargo.toml index 2826223..6593319 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,6 +48,7 @@ heck = { version = "0.4" } tokio = { version = "1.30.0", features = ["macros"] } wasmtime = { git = "https://github.com/bytecodealliance/wasmtime", features = ["component-model"] } wasmtime-wasi = { git = "https://github.com/bytecodealliance/wasmtime" } +wasmparser = "0.112.0" [workspace.dependencies] anyhow = "1" diff --git a/README.md b/README.md index e2db62d..4fc75e5 100644 --- a/README.md +++ b/README.md @@ -20,6 +20,7 @@ Supports all of the current WASI subsystems: - [Environment](#env): Set environment variables, configure host environment variable permissions - [Exit](#exit): Allow / Deny - [Filesystem](#filesystem): Mount a read-only filesystem, configure host filesystem preopen remappings or pass-through. +- [HTTP](#http): Allow / Deny - [Random](#random): Allow / Deny - [Sockets](#sockets): Allow / Deny - [Stdio](#stdio): Allow / Deny / Ignore @@ -106,6 +107,13 @@ wasi-virt component.wasm --preopen /=/restricted/path -o virt.wasm wasi-virt component.wasm --mount /virt-dir=./local --preopen /host-dir=/host/path -o virt.wasm ``` +### HTTP + +```sh +# Allow HTTP +wasi-virt component.wasm --allow-http -o virt.wasm +``` + ### Random ```sh diff --git a/lib/virtual_adapter.wasm b/lib/virtual_adapter.wasm index 68a73a64d8e7f8b59779341e5fba27111e17548b..072c1faa257a72f1262e92caad4219a732b7d032 100755 GIT binary patch delta 39045 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%0D;+nx z6~DY+DIY(G(*5nU%;M1Mr6Ffz)f#A~X@C{>&WrpS$oZP+-Yj1;9S#M8jZkHoX0}kP zQ80nHq-?x_u3Mp|MTi6?vly@uc8$zr6EU`tvQ(MCJIPS0xG0$`i%)2erE;=pfT3(F zX$cm#u*nkVCR{>UQIsevE15q89hQ|X62}R4niPe(u{MotCHymu46~0EMy1}C;bPKO zR%yV+t5r#PAv7cw;FQ*)c}#N%;3U~(+P$4Y$`RpE+D)Yx%wJCjRV%t=-t9mhPa|VO z`X!>4W^|x3;X>)pay-sqX?NA$X}85@sl9up-L!lFSE6(52cdEVEwSTlB1E^wJar?& zE2$MNDD;>Kz~*Y!GR!9aap7UzWt#}v$y&F1yQx~VlLKOnI3FIIiThQk_j z!>W}3#>Nddab!o!)}fXb>xZlZOx*cjZQ_6!nK-Pe?86$|^L0#IahQqwve8P)j{rw~ zU@sE~Xss1^EPzrqmb7GVlQ$fxnvqBqEny#Nlwg$!E&%jzZQhQ3*t~yZ@`jI2RmU$e zsU@_@=1H_i+B{hols0d+Y4hA<^N0$N3Nm?hLnaSfqH0H)yejpF1UMHP534P*5ta^( zr3y)-DlHxE)FV7HEghB*wc3TM#Cy1<`-*NO4Bhz*$(}>=$gLT2=S#6<>bzu;8ev?B ziPFZ+GV70r0S5K3hcs= z>QgUyeC3!GXGN40dXeNE=RNCCu3Q3_9&Z_~0Muc=^-^%mT-l9=jt(CG# z3xz#;R2V#;EELQRStx0mYEhz;Kw!mIhW~NzE-*eYdkw zX7@fOZ}@1-7#8H76I;JK4k7Z~GdjdSzuQ~CTiOCzg_F(jJaWc3_EQPe&j0FUe~>_F z-}PBQx&Mzqb?g%;6NscHCZFMF&tUS&*2Hg|(Q}{|Si(n{M6nNoDF0(p6u)xTl2_Yb zR{kLKi1v;EA(^HeiDZ$ywuY;ve!dV{E^pJ60re_!?U5j9pb_0T@2rJ*@8sjNd`%Y;98~Z2Ify=(00MiF7+3r+>?OaYI3ElodFhi3{PO8h zv-uxQ-yy^*pa183i;=}qwM1J}j@nn3{iePVO%fGXuf(cUO0In>23YlhBZi>Fo}5T~ z3GK{WgRxbqT5P%SVD=mF$%Pl;_xl%( z^#-&G%8#&)NlJ;T_<+A!JbIB1JpOS}@Q5CyL+YypFP~!mN1D;&uS6#rnyz~N)jl`o zaB9`qqX;0eM>@$)qoGj1M5WdRTB$FI(=PV)BR8SyD}q*1qpIZRxTFo^h*X>|MDxyt zJ~yom`E~P+trv#;rXmxQ8Hjb}a1AAE9eCZFM`4cWXI`mQX z(B9BJsHd_XQ>d7R+E5E29g$8!iF6rNb>BIieX<- z3*~2aLWCtXf)GkZfgY!+%-w<}n$~7P!mT(QA=J zHxUK77HZYB>626LNIULj)`|V0K1Hh{B30oLQdnBq0PJ)J+tLVy8kxsp(>T?)OPsGH zR7l+@#l%eI>=NQ?CfJmoO#wHnfg}tFbcc2rFvv1=0_SnuM>c_9&_S*c4XAe##Z5M# zP>om)D#oWk6L@bCg$KK2FwvQoa)I+bU<~cIq#a|x5oM5RI7ehT8wVr-voJ5PhVzm1 zaT9H6odGlQVYDTQ>*Z6h_94kyp>CC&hi9?Kij`+d`G?V!YRV)D7G22)g03~V_eHwW z#&MKIst*bQ3r#H2RB#Ii7!0k#;uLvhIwwxW!GG9b$+1fH zE;)o9baO(vJdhL@6d(M8DS{x&eT-5SB+JUm>f=L{)%m>)kG7gD!GA8P@oW95F4tKkpYqh1@wWqLLi`aCLf3aa-$*@ z$w^nKW+9jOvD<8a2o~fNawfs)@zuHQMM*0NFoeh44koAAON&i0fC(on1`A~AI`{xd zc99>H!pCUa;=W|wv~W*CE%qX|s|KYVY}B>hg%FF3Q7z@fL$kRKEeCH1ORqD!Rr06^ z_tu%rPHLB}`=)qtU89)2ZZh6LyJFoG@l9O)eqC#q!H4<=%3Jj{`C0~3-w@qb<=8s0 z=Bm*Z$@YPMMG>2?>d{bt0SO6DDrbOFErgG(O5&0Fj`-76Q`m3C#H;t`tC?7M^|V%# zXm~k-yd2?4D==<3;7_lZ&x1`71#D8KaiwS zNF?bwj)24re^Ac$k{H=wu1#-6n>c6?m?1&|Q>jmih1a%K%EZy-x<*`lZQHRQSwmu& zX__+C9^(gTXbY1?Iv1sRecdo1IQHhnOWkzxKe| zBzB&d9KibXk45UbGmrWS%_e=lERQL)q^1712|_P#hlXNOY@Fq=r*t}-0tZE^G*@3J zwVMTv#={eZdVN>NiDcrSj3+{{i^yr^=(K;xKB#^mrd=Olv&8D_zrkjUhp%sT0cw0U zfO=08uU|ir9kjLnhGSU|95SZ)1i(lLVJpmW6tcq>l;VQ*tquvV*tEX&1T&z(Kz%UE zIP}6S*-c9(7Yj8gs}-E!X%Air!$E_!xAp@N4y4X_JqpDDx#=4|NayD=@%sAaUMd*) z@Q7lC;h>qsqr$JG)j{H<4Zm)jjUiwiXQ81=t>LuPkHwKUwz7}K{2NcQtz>rbxLk?D?~gO?P9IE446ql;4DC@F)SVO*(B>W~zgccrLXcggm_ zt`HnP$>@jd%vCCEY76~}DVu6Z>>&2%OR>icZYUEBwp1|%3Y4^ei{#sHqhQsR-1Oq6 z7Zoz3HkdU8D#dAds|mZc)kjD!2ym&f2xnSA4oHL-m}31ODB|5G5@6hh8E6*=+}zpG zVoDbD!><0cBv@Vo9dam6zd6+14#Bd-faXN)$3mPW6mO5gEs1AuezTrt10TIOD9|?$ z{>Qg`d(Kx-u1up!i$*sx&W9H8_dz9$dI3?%Bu&5K72o|~N5I;6K=Px&?nOZ=K2`g^ z#?OsO62R60C^8lnT#x^7YE;7Ia#brP3zEvvDH}TFu1c$cs|P1y@~u61Upg&+zkh2_ zNU~48kYIAvS}oO!_z*uG^+#s7LN@vX7#kI1v}z z*4$_Iw!ta_Ag=zt)L)Ka>&GgQG`ZNvss2_xdz;2y7w_NJ&b-3Csci!GLZSufi24WW zn8bgRly&FqT7^!UW0K;9U|7Z&eE-&_L6=3}2?WCno4z@|1br{&AA+7w(Exuh!B73+ zQ2Kzv)E|)>yY)v$n~1o(OQd8P7xi0PMCA5%mo*@bCcb@pg8gdi6}Qi3wdQSE@1Q6D zyd#M$>Kk|N$9^U9cg{kpdjFk)CNr0njVJ)1L=L&^Wp{T5(uP4+-+ zhSuWK%`NP0(X=HIq`}b#Ohro=CIaD)L+v3?K6H)p7Kr&&cCPxiShc0O%fw1ff$@+6 z!<4AMHoMXI+qXmy#mKl#n_V#gfC1Gd0rs9k`N9-54&LN|(*VqkB7FDavWWH*lkd2@ zpMSJk%zdU=G;eK`6x8g*IU=1Yi!--2O?uGI>?J!$TXfh6Lx|01Bj`%f(L&Ne#%ROV z#v)=t$X+RkKAMDGb4Pf4lm4kA5Ndezc1s1#v!j8N}VKb%r{$gqJLAjt?7 zVJ2^n!2&ZxxfYycMrAzID;~b*pdh+ftrd!d5tmLuJcBr$(7yLmJS{Sg<_1M z!Q+~d2atxjRxbq+fe9=VqBA%innzr;J;YuTySBHmH^s}_$FS=z+tJTD#DpE=I(msd z*rHW=8a2iUn2>tXaDC#`9izwgfI&!UH5{Cily)5W{z?ZOlIm%blrEgfnLief?l=iG zOy9khIe`QyzdiKy}rPJx=u0+QW22R%`O>~MI=XT>f>VL zgQHVO@`;_M6d;g8EKKp-Y%4CsBexmRnVkvjpGh^N(id$HM1|r5QU8#yIN8J)JM2h1 zBj#1WM3n+7+KYxkDE&YXNCd#FzA6fEP==wmrfpNCKtmi*Iwv8;+xCc@$V$+<1-uvK z%%o`Q1ri2GCR#}`99!gg*N;yjz59T)4I7VlDa%O4xzv6#ywWNnmW7e7o~o_6RlWIa zl4gnVl;q`7NhOdbj^(j@cq7h)LIUVWu3~az3nDpI(Fd)E)2+VM=cbM~OCV|x-_g}Z zy7JWm*&3ODX;{pa`!d{%5Z4w<*lP~JTZd>LQe&e?4*ohhNbl(oi?C-zqKk5hrhi;wb zmf++F;0HGR%H1hcQg9amw9V8bY07D<7V56+2`0RZ>jZ5P3DBlq&3*_j9Rwu`hH^ur zBsOYOR6GHzs6<7D#8QdLB{9OXIbkPpEIk43WMu|!hF%K>Otn%POc0c@m_KG)1@tJ> z+DK_X(mvwa&2*2pGuNRI1t68=T2RHLjZ{v!i#w!1!B!IqA-WELX};18s@%gMm5R)k zVR37zj#!?QUJ_mkxdfus=2jQ%K$71zF(+`0AU-yqNaDNc2;$e5i&>_S(8gFIzD;5Z z9RQi+3*00pyhL(*Rs^bEqB&?d9dlDxO0*YhHVKNPxwX-jXzrB^#PYnXYe~wNDJyC2 z!4oXOb1Gd7EBRTqSV=S@I^M7=V!Sc|i0W%g6-DemAXw_mcd=>doM164iVS5Av$QyD zcqNIrn^yDzx@wgbSn3^`xXh}pO^NZ z`S2}6v$QDHmpF{w@+F()u(*NIWoc1?>!&mVz?DmjXxww0A4Z_0lDMJKJJNDMv_)wV zvVeCOr8dbIopE6@$1E+@5<3V3vw%(|a}DCViizT*twk7T&>Yxe)9Y&Z7zlmF2G~`K;Nw~mw)|lDI7qc@ zU?*Qyc2u(5L^+SOo(EW3KqRwXf*>2|U%8-TRRQpRU%8-zmSlLzrNiixHHHHvYYa}! zFx{QsB!=nlq-KGFkOpp|2)I=7;p5$?Y&QO6{3um@TndzmH&8$STv_IqqIZzLLLC2- zo}Y}(9S@lKw1k-a5O6~rt39RKPwm@>^?YhtC69~uxtaOe?FJiEsm7%*v@ z{D8z9^-+Yh;(_N{z6l#-aSDsIw3>sIj0jJ&S`34I0>el<8Fee)md&u|OtkLy*IDFJ z*At~&ON?|qqtZfpcb}N^a#am<%u;@x|5>cx-HK;Bcefu}>UNXtrj~fGs5i?SckrQQ z6bJ}2kto$-F(f#73$+x!=e7Sn#-(l#UwnDK`+qbUM3UGeAT%4TW0y(*h>Hk5Kq!jdM4 zOJ5kx{vzK0c@qdx@e3>i^~hD53BR})74QdtG5ss1-}oPyzPHS>+a#&WEPL$*D2=q! zg1tzEy;(1Q#>!6@{P(b@;o>lk-64m$i*YuhGVB=6Gm~hfEcA5-KXl;^e+5;5D^LN( zO;QScqyhE~3rHaeVgLTLdKChH*nBbzGCMLe6>|4@=}dMt zxlJ9wW^|zT^t80(q;c0U6z-HL47+icywNx$mYeB@{04*US1Xkgd5vsWCejTr4JXp5 z=5l}86Bd8#$o4%i4{z@o2EaDi@KJH$%cHC!CqxXzlg%%WYUm?6QhBOhksljm$%uIQ z<*_UxY`^-(M7i}HCY(fk^2kzq05?INK0LwV3$2?%Aea0q@iqI%!kg^#%dg!BaicZQ zfxrH`^GGWs=ehOQM~$-7aTslONZM=@wXZbSNd1)3MP;GTE8`g#b6y$Uh1D>)UO%v< zy@NPlCm|$D)y$8 zcYWbbKpgYhLX%A}MFfcYc31aK0#kig${yMOIv47C!_YvTUa&pwraBS|R^Prolg0Ai z{AeHd-`;EH&ew1I!kxa$-Z*owo9DkV7OTf=-|Q8yeCe~j2RixH-U@^x47jX)(=V=k zYsp^tjb`r({q3F+cd073>TPU+6C2(h$(rAZ$KRfKph;N7L@%68gf4xE6wXSnkHDyd zXR>5ymWUz5%HgU{vCq#ixFIGrt zeRsFSj?<8cK+WCH6!zyPq)U|KH)FckV#{;oX{u~sT5 zJAbVkZ1nIEfgwUMdwHMKwsZYuW&=qV5IvAOwL<>nU z89MVJ;z=ry$+(Al%g_#)04<$5)!$Knzmv?PynzNd$8rd⁢TB35{mr2o_hUFG{#* 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 LCNH%=;5+{Vwc#nRtJdv&@YQG=@ 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 delta 9961 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 Result<()> { + stub_clocks_virt(module)?; add_stub_exported_func( module, "wasi:clocks/monotonic-clock#now", @@ -72,6 +76,7 @@ pub(crate) fn deny_clocks_virt(module: &mut Module) -> Result<()> { } pub(crate) fn deny_http_virt(module: &mut Module) -> Result<()> { + stub_http_virt(module)?; add_stub_exported_func( module, "wasi:http/incoming-handler#handle", @@ -373,6 +378,7 @@ pub(crate) fn deny_exit_virt(module: &mut Module) -> Result<()> { } pub(crate) fn deny_sockets_virt(module: &mut Module) -> Result<()> { + stub_sockets_virt(module)?; add_stub_exported_func( module, "wasi:sockets/instance-network#instance-network", diff --git a/src/virt_io.rs b/src/virt_io.rs index 9db8e26..8e8611d 100644 --- a/src/virt_io.rs +++ b/src/virt_io.rs @@ -325,23 +325,38 @@ pub(crate) fn create_io_virt<'a>( flags |= FLAGS_HOST_PREOPENS; } } + let mut disable_stdio = true; if let Some(stdio) = stdio { match stdio.stdin { - StdioCfg::Allow => flags |= FLAGS_ENABLE_STDIN, + StdioCfg::Allow => { + flags |= FLAGS_ENABLE_STDIN; + disable_stdio = false; + } StdioCfg::Ignore => flags |= FLAGS_IGNORE_STDIN, // deny is the default StdioCfg::Deny => {} } match stdio.stdout { - StdioCfg::Allow => flags |= FLAGS_ENABLE_STDOUT, + StdioCfg::Allow => { + flags |= FLAGS_ENABLE_STDOUT; + disable_stdio = false; + } StdioCfg::Ignore => flags |= FLAGS_IGNORE_STDOUT, StdioCfg::Deny => {} } match stdio.stderr { - StdioCfg::Allow => flags |= FLAGS_ENABLE_STDERR, + StdioCfg::Allow => { + flags |= FLAGS_ENABLE_STDERR; + disable_stdio = false; + } StdioCfg::Ignore => flags |= FLAGS_IGNORE_STDERR, StdioCfg::Deny => {} } + } else { + strip_stdio_virt(module)?; + } + if disable_stdio { + stub_stdio_virt(module)?; } // First we iterate the options and fill in all HostDir and HostFile entries @@ -498,6 +513,7 @@ pub(crate) fn create_io_virt<'a>( // replacing it with a stub panic if !fs_passthrough { stub_io_virt(module)?; + stub_fs_virt(module, true)?; } else { flags |= FLAGS_HOST_PASSTHROUGH; } @@ -548,18 +564,23 @@ pub(crate) fn create_io_virt<'a>( // when stubbing functions that are not part of the virtual adapter exports, we therefore // have to create this functions fresh. // Ideally, we should generate these stubs automatically from WASI definitions. -pub(crate) fn stub_fs_virt(module: &mut Module) -> Result<()> { - stub_imported_func(module, "wasi:filesystem/preopens", "get-directories", true)?; - stub_imported_func(module, "wasi:filesystem/types", "read-via-stream", true)?; +pub(crate) fn stub_fs_virt(module: &mut Module, uses_fs: bool) -> Result<()> { + stub_imported_func( + module, + "wasi:filesystem/preopens", + "get-directories", + uses_fs, + )?; + stub_imported_func(module, "wasi:filesystem/types", "read-via-stream", uses_fs)?; stub_imported_func(module, "wasi:filesystem/types", "write-via-stream", false)?; stub_imported_func(module, "wasi:filesystem/types", "append-via-stream", false)?; stub_imported_func(module, "wasi:filesystem/types", "advise", false)?; stub_imported_func(module, "wasi:filesystem/types", "sync-data", false)?; stub_imported_func(module, "wasi:filesystem/types", "get-flags", false)?; - stub_imported_func(module, "wasi:filesystem/types", "get-type", true)?; + stub_imported_func(module, "wasi:filesystem/types", "get-type", uses_fs)?; stub_imported_func(module, "wasi:filesystem/types", "set-size", false)?; stub_imported_func(module, "wasi:filesystem/types", "set-times", false)?; - stub_imported_func(module, "wasi:filesystem/types", "read", true)?; + stub_imported_func(module, "wasi:filesystem/types", "read", uses_fs)?; stub_imported_func(module, "wasi:filesystem/types", "write", false)?; stub_imported_func(module, "wasi:filesystem/types", "read-directory", false)?; stub_imported_func(module, "wasi:filesystem/types", "sync", false)?; @@ -569,11 +590,11 @@ pub(crate) fn stub_fs_virt(module: &mut Module) -> Result<()> { "create-directory-at", false, )?; - stub_imported_func(module, "wasi:filesystem/types", "stat", true)?; - stub_imported_func(module, "wasi:filesystem/types", "stat-at", true)?; + stub_imported_func(module, "wasi:filesystem/types", "stat", uses_fs)?; + stub_imported_func(module, "wasi:filesystem/types", "stat-at", uses_fs)?; stub_imported_func(module, "wasi:filesystem/types", "set-times-at", false)?; stub_imported_func(module, "wasi:filesystem/types", "link-at", false)?; - stub_imported_func(module, "wasi:filesystem/types", "open-at", true)?; + stub_imported_func(module, "wasi:filesystem/types", "open-at", uses_fs)?; stub_imported_func(module, "wasi:filesystem/types", "readlink-at", false)?; stub_imported_func( module, @@ -602,26 +623,26 @@ pub(crate) fn stub_fs_virt(module: &mut Module) -> Result<()> { stub_imported_func(module, "wasi:filesystem/types", "try-lock-shared", false)?; stub_imported_func(module, "wasi:filesystem/types", "try-lock-exclusive", false)?; stub_imported_func(module, "wasi:filesystem/types", "unlock", false)?; - stub_imported_func(module, "wasi:filesystem/types", "drop-descriptor", true)?; + stub_imported_func(module, "wasi:filesystem/types", "drop-descriptor", uses_fs)?; stub_imported_func( module, "wasi:filesystem/types", "read-directory-entry", - true, + uses_fs, )?; stub_imported_func( module, "wasi:filesystem/types", "drop-directory-entry-stream", - true, + uses_fs, )?; - stub_imported_func(module, "wasi:filesystem/types", "is-same-object", true)?; + stub_imported_func(module, "wasi:filesystem/types", "is-same-object", uses_fs)?; stub_imported_func(module, "wasi:filesystem/types", "metadata-hash", false)?; stub_imported_func(module, "wasi:filesystem/types", "metadata-hash-at", false)?; Ok(()) } -pub(crate) fn stub_io_virt(module: &mut Module) -> Result<()> { +fn stub_io_virt(module: &mut Module) -> Result<()> { stub_imported_func(module, "wasi:poll/poll", "drop-pollable", true)?; stub_imported_func(module, "wasi:poll/poll", "poll-oneoff", true)?; stub_imported_func(module, "wasi:io/streams", "read", false)?; @@ -655,9 +676,9 @@ pub(crate) fn stub_clocks_virt(module: &mut Module) -> Result<()> { } pub(crate) fn stub_stdio_virt(module: &mut Module) -> Result<()> { - stub_imported_func(module, "wasi:cli/stdin", "get-stdin", true)?; - stub_imported_func(module, "wasi:cli/stdout", "get-stdout", true)?; - stub_imported_func(module, "wasi:cli/stderr", "get-stderr", true)?; + stub_imported_func(module, "wasi:cli/stdin", "get-stdin", false)?; + stub_imported_func(module, "wasi:cli/stdout", "get-stdout", false)?; + stub_imported_func(module, "wasi:cli/stderr", "get-stderr", false)?; stub_imported_func( module, "wasi:cli/terminal-stdin", @@ -764,7 +785,7 @@ pub(crate) fn stub_sockets_virt(module: &mut Module) -> Result<()> { // strip functions only have to dce the virtual adapter pub(crate) fn strip_fs_virt(module: &mut Module) -> Result<()> { - stub_fs_virt(module)?; + stub_fs_virt(module, false)?; remove_exported_func(module, "wasi:filesystem/preopens#get-directories")?; remove_exported_func(module, "wasi:filesystem/types#read-via-stream")?; diff --git a/tests/cases/encapsulate-none.toml b/tests/cases/encapsulate-none.toml new file mode 100644 index 0000000..dc33b23 --- /dev/null +++ b/tests/cases/encapsulate-none.toml @@ -0,0 +1,15 @@ +component = "do-everything" + +[virt-opts] +exit = false +fs.host-preopens = false +stdio.stdin = "ignore" +stdio.stdout = "ignore" +stdio.stderr = "ignore" +clocks = false +http = false +random = false +sockets = false + +[expect] +encapsulation = true diff --git a/tests/virt.rs b/tests/virt.rs index 4991e16..c1a14e1 100644 --- a/tests/virt.rs +++ b/tests/virt.rs @@ -7,6 +7,7 @@ use std::process::Command; use std::{fs, path::PathBuf}; use wasi_virt::WasiVirt; use wasm_compose::composer::ComponentComposer; +use wasmparser::{Chunk, Parser, Payload}; use wasmtime::{ component::{Component, Linker}, Config, Engine, Store, WasmBacktraceDetails, @@ -48,6 +49,7 @@ fn cmd(arg: &str) -> Result<()> { struct TestExpectation { env: Option>, file_read: Option, + encapsulation: Option, } #[derive(Deserialize, Debug)] @@ -60,7 +62,7 @@ struct TestCase { expect: TestExpectation, } -const DEBUG: bool = true; +const DEBUG: bool = false; #[tokio::test] async fn virt_test() -> Result<()> { @@ -73,7 +75,7 @@ async fn virt_test() -> Result<()> { let test_case_name = test_case_file_name.strip_suffix(".toml").unwrap(); // Filtering... - // if test_case_name != "encapsulate" { + // if test_case_name != "encapsulate-none" { // continue; // } @@ -136,7 +138,17 @@ async fn virt_test() -> Result<()> { .finish() .with_context(|| format!("Error creating virtual adapter for {:?}", test_case_path))?; - fs::write(&virt_component_path, virt_component.adapter)?; + fs::write(&virt_component_path, &virt_component.adapter)?; + + // verify the encapsulation + if test.expect.encapsulation.unwrap_or(false) { + if let Some(impt) = has_component_import(virt_component.adapter.as_slice())? { + panic!( + "Unexpected import \"{impt}\" in virtualization {:?}", + virt_component_path + ); + } + } // compose the test component with the defined test virtualization if DEBUG { @@ -262,3 +274,43 @@ async fn virt_test() -> Result<()> { } Ok(()) } + +fn has_component_import(bytes: &[u8]) -> Result> { + let mut parser = Parser::new(0); + let mut offset = 0; + loop { + let payload = match parser.parse(&bytes[offset..], true)? { + Chunk::NeedMoreData(_) => unreachable!(), + Chunk::Parsed { payload, consumed } => { + offset += consumed; + payload + } + }; + match payload { + Payload::ModuleSection { mut parser, range } => { + let mut ioffset = range.start; + loop { + let payload = match parser.parse(&bytes[ioffset..], true)? { + Chunk::NeedMoreData(_) => unreachable!(), + Chunk::Parsed { payload, consumed } => { + ioffset += consumed; + payload + } + }; + match payload { + Payload::ImportSection(impt_section_reader) => { + for impt in impt_section_reader { + let impt = impt?; + return Ok(Some(format!("{}#{}", impt.module, impt.name))); + } + } + Payload::End(_) => return Ok(None), + _ => {} + } + } + } + Payload::End(_) => return Ok(None), + _ => {} + } + } +} diff --git a/update-wasi.sh b/update-wasi.sh index e05454d..9d349d7 100755 --- a/update-wasi.sh +++ b/update-wasi.sh @@ -1,5 +1,6 @@ git clone https://github.com/bytecodealliance/wasmtime --depth 1 cd wasmtime +git checkout 134dddc git submodule init git submodule update cargo build -p wasi-preview1-component-adapter --target wasm32-unknown-unknown --release