Stream: git-wasmtime

Topic: wasmtime / issue #8033 Wasm guest fails WasiHttpView::sen...


view this post on Zulip Wasmtime GitHub notifications bot (Feb 29 2024 at 22:10):

arlyon opened issue #8033:

Thanks for filing a feature request! Please fill out the TODOs below.

Feature

I am using a WasiHttpView to selectively allow / reject destination authorities for the outgoing-handler. If the sandbox rejects a request, I would expect it to return an error to outgoing_handler::handle on the guest such that they may handle it, however that is not the case.

    fn send_request(
        &mut self,
        request: wasmtime_wasi_http::types::OutgoingRequest,
    ) -> wasmtime::Result<
        wasmtime::component::Resource<wasmtime_wasi_http::types::HostFutureIncomingResponse>,
    >
    where
        Self: Sized,
    {
        // try to remove the port if it exists
        let authority = request
            .authority
            .rsplit_once(':')
            .map(|(authority, _)| authority)
            .unwrap_or(&request.authority);

        if !self.allowed_authorities.contains(authority) {
            tracing::error!(
                "plugin tried to access {} which is not in the list of allowed authorities",
                authority
            );
            return Err(wasmtime::Error::msg("not allowed to access authority"));
        }

        default_send_request(self, request)
    }

    // inside guest
    let Ok(result) = outgoing_handler::handle(req, None) else {
        tracing::error!("unable to send request");
        continue;
    };

In reality, throwing an error here does not return control to the guest, but throws an error which is trapped by the runtime. Note the first line is my error handling:

Error:
   0: plugin london failed to update: error while executing at wasm backtrace:
          0: 0x4cf4f - wit-component:shim!indirect-wasi:http/outgoing-handler@0.2.0-handle
          1: 0x33c42 - <unknown>!<wasm function 881>

      Caused by:
          not allowed to access authority

      Stack backtrace:
         0: anyhow::error::<impl anyhow::Error>::msg
                   at /home/arlyon/.cargo/registry/src/index.crates.io-6f17d22bba15001f/anyhow-1.0.77/src/error.rs:83:36
         1: <litehouse::runtime::PluginRunner<T> as wasmtime_wasi_http::types::WasiHttpView>::send_request
                   at ./crates/litehouse/src/runtime.rs:94:24
         2: wasmtime_wasi_http::http_impl::<impl wasmtime_wasi_http::bindings::wasi::http::outgoing_handler::Host for T>::handle
                   at /home/arlyon/.cargo/git/checkouts/wasmtime-41807828cb3a7a7e/4d54a99/crates/wasi-http/src/http_impl.rs:97:15
         3: wasmtime_wasi_http::bindings::wasi::http::outgoing_handler::add_to_linker::{{closure}}
                   at /home/arlyon/.cargo/git/checkouts/wasmtime-41807828cb3a7a7e/4d54a99/crates/wasi-http/src/lib.rs:11:5
         4: wasmtime::runtime::component::func::host::HostFunc::entrypoint::{{closure}}::{{closure}}
                   at /home/arlyon/.cargo/git/checkouts/wasmtime-41807828cb3a7a7e/4d54a99/crates/wasmtime/src/runtime/component/func/host.rs:68:35
         5: wasmtime::runtime::component::func::host::call_host
                   at /home/arlyon/.cargo/git/checkouts/wasmtime-41807828cb3a7a7e/4d54a99/crates/wasmtime/src/runtime/component/func/host.rs:227:15
         6: wasmtime::runtime::component::func::host::HostFunc::entrypoint::{{closure}}
                   at /home/arlyon/.cargo/git/checkouts/wasmtime-41807828cb3a7a7e/4d54a99/crates/wasmtime/src/runtime/component/func/host.rs:60:17
         7: <core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once
                   at /rustc/30dfb9e046aeb878db04332c74de76e52fb7db10/library/core/src/panic/unwind_safe.rs:272:9

Benefit

Plugins should be allowed to recover in this case.

Implementation

No dice, I am not super familiar with how adding this capability would fit into the wider system.

Alternatives

For now, crashing the plugin is OK but not desirable. I would like the plugin author to be able to control how it is handled.

view this post on Zulip Wasmtime GitHub notifications bot (Feb 29 2024 at 22:10):

arlyon edited issue #8033:

Thanks for filing a feature request! Please fill out the TODOs below.

Feature

I am using a WasiHttpView to selectively allow / reject destination authorities for the outgoing-handler. If the sandbox rejects a request, I would expect it to return an error to outgoing_handler::handle on the guest such that they may handle it, however that is not the case.

    fn send_request(
        &mut self,
        request: wasmtime_wasi_http::types::OutgoingRequest,
    ) -> wasmtime::Result<
        wasmtime::component::Resource<wasmtime_wasi_http::types::HostFutureIncomingResponse>,
    >
    where
        Self: Sized,
    {
        // try to remove the port if it exists
        let authority = request
            .authority
            .rsplit_once(':')
            .map(|(authority, _)| authority)
            .unwrap_or(&request.authority);

        if !self.allowed_authorities.contains(authority) {
            tracing::error!(
                "plugin tried to access {} which is not in the list of allowed authorities",
                authority
            );
            return Err(wasmtime::Error::msg("not allowed to access authority"));
        }

        default_send_request(self, request)
    }

    // inside guest
    let Ok(result) = outgoing_handler::handle(req, None) else {
        tracing::error!("unable to send request");
        continue;
    };

In reality, throwing an error here does not return control to the guest, but throws an error which is trapped by the runtime. Note the first line is my error handling:

Error:
   0: plugin london failed to update: error while executing at wasm backtrace:
          0: 0x4cf4f - wit-component:shim!indirect-wasi:http/outgoing-handler@0.2.0-handle
          1: 0x33c42 - <unknown>!<wasm function 881>

      Caused by:
          not allowed to access authority

      Stack backtrace:
         0: anyhow::error::<impl anyhow::Error>::msg
                   at /home/arlyon/.cargo/registry/src/index.crates.io-6f17d22bba15001f/anyhow-1.0.77/src/error.rs:83:36
         1: <litehouse::runtime::PluginRunner<T> as wasmtime_wasi_http::types::WasiHttpView>::send_request
                   at ./crates/litehouse/src/runtime.rs:94:24
         2: wasmtime_wasi_http::http_impl::<impl wasmtime_wasi_http::bindings::wasi::http::outgoing_handler::Host for T>::handle
                   at /home/arlyon/.cargo/git/checkouts/wasmtime-41807828cb3a7a7e/4d54a99/crates/wasi-http/src/http_impl.rs:97:15
         3: wasmtime_wasi_http::bindings::wasi::http::outgoing_handler::add_to_linker::{{closure}}
                   at /home/arlyon/.cargo/git/checkouts/wasmtime-41807828cb3a7a7e/4d54a99/crates/wasi-http/src/lib.rs:11:5
         4: wasmtime::runtime::component::func::host::HostFunc::entrypoint::{{closure}}::{{closure}}
                   at /home/arlyon/.cargo/git/checkouts/wasmtime-41807828cb3a7a7e/4d54a99/crates/wasmtime/src/runtime/component/func/host.rs:68:35
         5: wasmtime::runtime::component::func::host::call_host
                   at /home/arlyon/.cargo/git/checkouts/wasmtime-41807828cb3a7a7e/4d54a99/crates/wasmtime/src/runtime/component/func/host.rs:227:15
         6: wasmtime::runtime::component::func::host::HostFunc::entrypoint::{{closure}}
                   at /home/arlyon/.cargo/git/checkouts/wasmtime-41807828cb3a7a7e/4d54a99/crates/wasmtime/src/runtime/component/func/host.rs:60:17
         7: <core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once
                   at /rustc/30dfb9e046aeb878db04332c74de76e52fb7db10/library/core/src/panic/unwind_safe.rs:272:9

...

Benefit

Plugins should be allowed to recover in this case.

Implementation

No dice, I am not super familiar with how adding this capability would fit into the wider system.

Alternatives

For now, crashing the plugin is OK but not desirable. I would like the plugin author to be able to control how it is handled.

view this post on Zulip Wasmtime GitHub notifications bot (Feb 29 2024 at 23:59):

alexcrichton commented on issue #8033:

Thanks for the report!

In the WIT itself there's the ability to return an error-code, and would that be sufficient for your use case here? If so I think that the WasiHttpView isn't quite set up to plumb an error through to the place where it's called, for example here the error is propagated with ? which is where the trap comes from. If that location is updated to try to downcast the error to an ErrorCode, however, that I think would then enable you to return an ErrorCode in your custom implementation?

Would you be interested in making a PR for this change?

view this post on Zulip Wasmtime GitHub notifications bot (Mar 01 2024 at 10:28):

arlyon commented on issue #8033:

Yes! Thanks for the pointers, the change was fairly straightforward. Figuring out the test setup was a little more complex but all good now. PR linked above.

view this post on Zulip Wasmtime GitHub notifications bot (Mar 01 2024 at 18:59):

alexcrichton closed issue #8033:

Thanks for filing a feature request! Please fill out the TODOs below.

Feature

I am using a WasiHttpView to selectively allow / reject destination authorities for the outgoing-handler. If the sandbox rejects a request, I would expect it to return an error to outgoing_handler::handle on the guest such that they may handle it, however that is not the case.

    fn send_request(
        &mut self,
        request: wasmtime_wasi_http::types::OutgoingRequest,
    ) -> wasmtime::Result<
        wasmtime::component::Resource<wasmtime_wasi_http::types::HostFutureIncomingResponse>,
    >
    where
        Self: Sized,
    {
        // try to remove the port if it exists
        let authority = request
            .authority
            .rsplit_once(':')
            .map(|(authority, _)| authority)
            .unwrap_or(&request.authority);

        if !self.allowed_authorities.contains(authority) {
            tracing::error!(
                "plugin tried to access {} which is not in the list of allowed authorities",
                authority
            );
            return Err(wasmtime::Error::msg("not allowed to access authority"));
        }

        default_send_request(self, request)
    }

    // inside guest
    let Ok(result) = outgoing_handler::handle(req, None) else {
        tracing::error!("unable to send request");
        continue;
    };

In reality, throwing an error here does not return control to the guest, but throws an error which is trapped by the runtime. Note the first line is my error handling:

Error:
   0: plugin london failed to update: error while executing at wasm backtrace:
          0: 0x4cf4f - wit-component:shim!indirect-wasi:http/outgoing-handler@0.2.0-handle
          1: 0x33c42 - <unknown>!<wasm function 881>

      Caused by:
          not allowed to access authority

      Stack backtrace:
         0: anyhow::error::<impl anyhow::Error>::msg
                   at /home/arlyon/.cargo/registry/src/index.crates.io-6f17d22bba15001f/anyhow-1.0.77/src/error.rs:83:36
         1: <litehouse::runtime::PluginRunner<T> as wasmtime_wasi_http::types::WasiHttpView>::send_request
                   at ./crates/litehouse/src/runtime.rs:94:24
         2: wasmtime_wasi_http::http_impl::<impl wasmtime_wasi_http::bindings::wasi::http::outgoing_handler::Host for T>::handle
                   at /home/arlyon/.cargo/git/checkouts/wasmtime-41807828cb3a7a7e/4d54a99/crates/wasi-http/src/http_impl.rs:97:15
         3: wasmtime_wasi_http::bindings::wasi::http::outgoing_handler::add_to_linker::{{closure}}
                   at /home/arlyon/.cargo/git/checkouts/wasmtime-41807828cb3a7a7e/4d54a99/crates/wasi-http/src/lib.rs:11:5
         4: wasmtime::runtime::component::func::host::HostFunc::entrypoint::{{closure}}::{{closure}}
                   at /home/arlyon/.cargo/git/checkouts/wasmtime-41807828cb3a7a7e/4d54a99/crates/wasmtime/src/runtime/component/func/host.rs:68:35
         5: wasmtime::runtime::component::func::host::call_host
                   at /home/arlyon/.cargo/git/checkouts/wasmtime-41807828cb3a7a7e/4d54a99/crates/wasmtime/src/runtime/component/func/host.rs:227:15
         6: wasmtime::runtime::component::func::host::HostFunc::entrypoint::{{closure}}
                   at /home/arlyon/.cargo/git/checkouts/wasmtime-41807828cb3a7a7e/4d54a99/crates/wasmtime/src/runtime/component/func/host.rs:60:17
         7: <core::panic::unwind_safe::AssertUnwindSafe<F> as core::ops::function::FnOnce<()>>::call_once
                   at /rustc/30dfb9e046aeb878db04332c74de76e52fb7db10/library/core/src/panic/unwind_safe.rs:272:9

...

Benefit

Plugins should be allowed to recover in this case.

Implementation

No dice, I am not super familiar with how adding this capability would fit into the wider system.

Alternatives

For now, crashing the plugin is OK but not desirable. I would like the plugin author to be able to control how it is handled.

view this post on Zulip Wasmtime GitHub notifications bot (Mar 01 2024 at 18:59):

alexcrichton commented on issue #8033:

Fixed in https://github.com/bytecodealliance/wasmtime/pull/8035, so closing (thanks!)


Last updated: Dec 23 2024 at 12:05 UTC