Repository: bytecodealliance/wasmtime
Pull request #7926 (2024-02-13 15:50:01)

Return correct fs errors on the proxy adapter
This commit fixes an issue with the proxy adapter where if the proxy program attempted to look at prestat items, which wasi-libc always does on startup, it would invoke `fd_prestat_get` and receive `ERRNO_NOTSUP` in response (the standard response when using the
`cfg_filesystem_available!` macro). This error code is unexpected by wasi-libc and causes wasi-libc to abort. The PR here is to instead return `ERRNO_BADF` which is indeed expected by wasi-libc and is recognized as meaning "that prestat isn't available".

<!--
Please make sure you include the following information:

- If this work has been discussed elsewhere, please include a link to that
  conversation. If it was discussed in an issue, just mention "issue #...".

- Explain why this change is needed. If the details are in an issue already,
  this can be brief.

Our development process is documented in the Wasmtime book:
https://docs.wasmtime.dev/contributing-development-process.html

Please ensure all communication follows the code of conduct:
https://github.com/bytecodealliance/wasmtime/blob/main/CODE_OF_CONDUCT.md
-->



Patch:
diff --git a/crates/wasi-preview1-component-adapter/src/lib.rs b/crates/wasi-preview1-component-adapter/src/lib.rs
index 0df1b5e1f..3c86683f3 100644
--- a/crates/wasi-preview1-component-adapter/src/lib.rs
+++ b/crates/wasi-preview1-component-adapter/src/lib.rs
@@ -908,6 +908,13 @@ pub unsafe extern "C" fn fd_prestat_get(fd: Fd, buf: *mut Prestat) -> Errno {
         return ERRNO_BADF;
     }
 
+    // For the proxy adapter don't return `ERRNO_NOTSUP` through below, instead
+    // always return `ERRNO_BADF` which is the indicator that prestats aren't
+    // available.
+    if cfg!(feature = "proxy") {
+        return ERRNO_BADF;
+    }
+
     cfg_filesystem_available! {
         State::with(|state| {
             let ds = state.descriptors();


Test patch:
diff --git a/crates/test-programs/src/bin/api_proxy.rs b/crates/test-programs/src/bin/api_proxy.rs
index c5f3185af..77e6bba83 100644
--- a/crates/test-programs/src/bin/api_proxy.rs
+++ b/crates/test-programs/src/bin/api_proxy.rs
@@ -20,6 +20,8 @@ impl bindings::exports::wasi::http::incoming_handler::Guest for T {
         assert!(request.authority().is_some());
         assert!(request.path_with_query().is_some());
 
+        test_filesystem();
+
         let header = String::from("custom-forbidden-header");
         let req_hdrs = request.headers();
 
@@ -60,3 +62,7 @@ impl bindings::exports::wasi::http::incoming_handler::Guest for T {
 // Technically this should not be here for a proxy, but given the current
 // framework for tests it's required since this file is built as a `bin`
 fn main() {}
+
+fn test_filesystem() {
+    assert!(std::fs::File::open(".").is_err());
+}
diff --git a/crates/wasi-http/tests/all/main.rs b/crates/wasi-http/tests/all/main.rs
index 221e97bd3..268c67c50 100644
--- a/crates/wasi-http/tests/all/main.rs
+++ b/crates/wasi-http/tests/all/main.rs
@@ -174,20 +174,20 @@ async fn run_wasi_http(
             use http_body_util::BodyExt;
             let (parts, body) = resp.into_parts();
             let collected = BodyExt::collect(body).await?;
-            Ok(hyper::Response::from_parts(parts, collected))
+            Some(Ok(hyper::Response::from_parts(parts, collected)))
         }
+        Ok(Err(e)) => Some(Err(e)),
 
-        Ok(Err(e)) => Err(e),
-
-        // This happens if the wasm never calls `set-response-outparam`
-        Err(e) => panic!("Failed to receive a response: {e:?}"),
+        // Fall through below to the `resp.expect(...)` which will hopefully
+        // return a more specific error from `handle.await`.
+        Err(_) => None,
     };
 
-    // Now that the response has been processed, we can wait on the wasm to finish without
-    // deadlocking.
+    // Now that the response has been processed, we can wait on the wasm to
+    // finish without deadlocking.
     handle.await.context("Component execution")?;
 
-    Ok(resp)
+    Ok(resp.expect("wasm never called set-response-outparam"))
 }
 
 #[test_log::test(tokio::test)]