ring icon indicating copy to clipboard operation
ring copied to clipboard

Can't use ring on ```wasm32-unknown-unknown``` due to a missing import (for Envoy Proxy)

Open libbkmz opened this issue 2 years ago • 2 comments

Hello, I'm trying to use the ring's SHA and HMAC for wasm32-unknown-unknown target. I'm building the WASM plugin for the envoy proxy. The build procedure works, but I can't load the WASM file into envoy's. Here is the reproducible source: Cargo.toml:

[package]
name = "rust_wasm_test"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
log = "0.4.14"
proxy-wasm = "0.1.4"
ring = "0.16.20"

src/lib.rs:

use proxy_wasm as wasm;
use ring;


#[no_mangle]
pub fn _start() {
    proxy_wasm::set_log_level(wasm::types::LogLevel::Trace);
    proxy_wasm::set_http_context(
        |_context_id, _root_context_id| -> Box<dyn wasm::traits::HttpContext> {
            Box::new(HelloWorld {  })
        },
    )
}

struct HelloWorld {}
impl wasm::traits::Context for HelloWorld {}
impl wasm::traits::HttpContext for HelloWorld {}

Example configuration for envoy:

static_resources:
  listeners:
    - name: main
      address:
        socket_address:
          address: 0.0.0.0
          port_value: 18000
      filter_chains:
        - filters:
            - name: envoy.http_connection_manager
              typed_config:
                "@type": type.googleapis.com/envoy.extensions.filters.network.http_connection_manager.v3.HttpConnectionManager
                stat_prefix: ingress_http
                codec_type: auto
                route_config:
                  name: local_route
                  virtual_hosts:
                    - name: local_service
                      domains:
                        - "*"
                      routes:
                        - match:
                            prefix: "/"
                          direct_response:
                            status: 200
                            body:
                              inline_string: "example body\n"
                http_filters:
                  - name: envoy.filters.http.wasm
                    typed_config:
                      "@type": type.googleapis.com/udpa.type.v1.TypedStruct
                      type_url: type.googleapis.com/envoy.extensions.filters.http.wasm.v3.Wasm
                      value:
                        config:
                          vm_config:
                            runtime: "envoy.wasm.runtime.v8"
                            code:
                              local:
                                filename: ".//target/wasm32-unknown-unknown/debug/rust_wasm_test.wasm"
                  - name: envoy.filters.http.router

admin:
  access_log_path: "/dev/null"
  address:
    socket_address:
      address: 0.0.0.0
      port_value: 8001

After building via cargo build --target=wasm32-unknown-unknown and running envoy via envoy --config-path envoy.yaml --concurrency 0 -l info I'm getting this error from the envoy side:

[2022-02-02 12:24:28.468][3533850][error][wasm] [source/extensions/common/wasm/wasm_vm.cc:38] Failed to load Wasm module due to a missing import: __wbindgen_externref_xform__.__wbindgen_externref_table_grow
[2022-02-02 12:24:28.468][3533850][error][wasm] [source/extensions/common/wasm/wasm_vm.cc:38] Failed to load Wasm module due to a missing import: __wbindgen_placeholder__.__wbindgen_describe
[2022-02-02 12:24:28.468][3533850][error][wasm] [source/extensions/common/wasm/wasm_vm.cc:38] Failed to load Wasm module due to a missing import: __wbindgen_externref_xform__.__wbindgen_externref_table_set_null
[2022-02-02 12:24:28.468][3533850][error][wasm] [source/extensions/common/wasm/wasm_vm.cc:38] Failed to load Wasm module due to a missing import: __wbindgen_placeholder__.__wbindgen_throw
[2022-02-02 12:24:28.468][3533850][error][wasm] [source/extensions/common/wasm/wasm.cc:109] Wasm VM failed Failed to initialize Wasm code
[2022-02-02 12:24:28.472][3533850][critical][wasm] [source/extensions/common/wasm/wasm.cc:471] Plugin configured to fail closed failed to load
[2022-02-02 12:24:28.481][3533850][critical][main] [source/server/server.cc:117] error initializing configuration 'envoy.yaml': Unable to create Wasm HTTP filter

There are a lot of libraries that depend on the ring, however, I can't use them because of the broken dependency...

libbkmz avatar Feb 02 '22 11:02 libbkmz

What wasm runtime does Envoy use? Knowing this would help me make progress in diagnosing this.

Could you try to reproduce this without Envoy, using just that wasm runtime, but without the Envoy-specific stuff?

briansmith avatar Mar 28 '22 22:03 briansmith

Envoy uses wee8/envoy.wasm.runtime.v8 (https://www.envoyproxy.io/docs/envoy/latest/configuration/other_features/wasm) turned on by default (at least for Linux x86_64).

Testing the above code with latest envoy from envoyproxy/envoy-dev:79205cdde2dd07cd92f175b0d699b443b516fc5d the errors are reduced:

[2022-07-22 11:47:22.235][2145515][error][wasm] [source/extensions/common/wasm/wasm_vm.cc:38] Failed to load Wasm module due to a missing import: __wbindgen_placeholder__.__wbindgen_describe
[2022-07-22 11:47:22.235][2145515][error][wasm] [source/extensions/common/wasm/wasm.cc:109] Wasm VM failed Failed to initialize Wasm code

The exact SHA used for wee8, https://github.com/envoyproxy/envoy/blob/79205cdde2dd07cd92f175b0d699b443b516fc5d/bazel/repository_locations.bzl#L889-L902

dio avatar Jul 22 '22 11:07 dio

I'm also targeting wasm32-unknown-unknown and trying to use a dependency that relies on ring.

The error I'm seeing is: Module imports function 'LIMBS_are_zero' from 'env' that is not exported by the runtime.

Does anyone have any advice on a possible way forward? Thanks.

paulyoung avatar Oct 28 '22 23:10 paulyoung

It seems like maybe https://github.com/briansmith/ring/pull/1176 is relevant and perhaps would have addressed the error I'm seeing.

There was a concern at the time around signing but I'm only interested in verifying when targeting wasm32-unknown-unknown. https://github.com/briansmith/ring/pull/1440 is linked there but it sounds like there are still some issues with it when targeting Wasm.

Does anyone know anything more?

paulyoung avatar Oct 28 '22 23:10 paulyoung

I'm trying out the tip of main.

paulyoung avatar Oct 29 '22 00:10 paulyoung

Now running into "could not find sysrand_chunk in super" as described in https://github.com/briansmith/ring/issues/1043

paulyoung avatar Oct 29 '22 00:10 paulyoung

Trying this: https://github.com/briansmith/ring/issues/918#issuecomment-1109527347

paulyoung avatar Oct 29 '22 01:10 paulyoung

This appears to have worked: https://github.com/codebase-labs/ring/commit/11aafb0eb10287a9de5bcce6f190df0ecb18b718

paulyoung avatar Oct 29 '22 01:10 paulyoung

I spoke too soon. Everything built but I'm back to the LIMBS_are_zero issue.

Module imports function 'ring_core_0_17_0_not_released_yet_LIMBS_are_zero' from 'env' that is not exported by the runtime.

paulyoung avatar Oct 29 '22 22:10 paulyoung

Actually I think it did work and I just ran into a stale lockfile issue.

paulyoung avatar Oct 29 '22 22:10 paulyoung

Nope, I think the stale lockfile was giving me the impression that things were working when they weren't.

paulyoung avatar Oct 29 '22 23:10 paulyoung

Trying this approach (env vars) next: https://github.com/briansmith/ring/issues/1483#issuecomment-1145159978

I've had no need for wasm-pack as of yet but maybe I need to use that or figure out what it's doing under the hood.

paulyoung avatar Oct 30 '22 02:10 paulyoung

I think the issue may be with extern "C" being interpreted as "expect this from the environment" for Wasm modules but I'm not sure.

I tried to summarize things here: https://users.rust-lang.org/t/extern-c-and-wasm/83579

paulyoung avatar Nov 01 '22 22:11 paulyoung

The main branch of ring (pending 0.17 release) does not use wasm-bindgen at all, as we've switched to using getrandom, so the wasm-bindgen symbols shouldn't be required any longer on this branch.

briansmith avatar Nov 09 '22 20:11 briansmith

The main branch of ring (pending 0.17 release) does not use wasm-bindgen at all, as we've switched to using getrandom, so the wasm-bindgen symbols shouldn't be required any longer on this branch.

I just tested this, and actually, getrandom does not compile on wasm32-unknown-unknown, unless you activate the js feature, which brings back wasm-bindgen. As I'm exploring I see that you already knew it, so I'm just leaving this here for others to see

I am not sure I'm going to be able to use the other working wasm targets; probably by registering my custom randomness source (that will always fail for my case)

gagbo avatar Dec 06 '22 16:12 gagbo

People will need to make their own assessment on the security implications of this but I figured I should at least share what I did in https://github.com/betrusted-io/ring-xous/pull/2 to get a fork of ring working for wasm32-unknown-unknown.

paulyoung avatar Dec 06 '22 19:12 paulyoung

I believe that ring 0.17 implements everything needed for this, except for a random number generator.

@gagbo wrote:

I just tested this, and actually, getrandom does not compile on wasm32-unknown-unknown, unless you activate the js feature, which brings back wasm-bindgen. As I'm exploring I see that you already knew it

The main question is, how are WeebAssembly plugins for Envoy supposed to get random bytes?

When researching the answer to that question, I found https://github.com/proxy-wasm/proxy-wasm-rust-sdk/issues/97 which indicates that you should use thw wasm32-wasi target instead of wasm32-unknown-unknown. That specifically will solve the random bytes issue and things will "just work." There is a PR #1568 that adds wasm32-wasi testing to ring's CI.

I'm going to close this as "not planned" because I assume everybody wlll switch to the wasm32-wasi target. LMK if that's not possible for some reason.

briansmith avatar Oct 14 '23 15:10 briansmith

The main question is, how are WeebAssembly plugins for Envoy supposed to get random bytes?

I'm not using "Envoy", so I wouldn't know, but our in-house (@Fiberplane) plugin system gets its random bytes from the host runtime. We ship a wasmer runtime with custom bindings that allow access to a source of random bytes. And we didn't migrate to something that could target wasi as far as I know, so this wouldn't help.

On the other hand, our issue with ring was a transitive issue from trying to use the AWS SDK crate to do a plugin around those services, and I bit the bullet and just removed my SDK dependency and rewritten every API call using manual API types and request signing. So this is not an issue for me anymore.

EDIT: and sorry for the delay in the response

gagbo avatar Nov 01 '23 20:11 gagbo

PR #1754 will allow you to use the getrandom crate's custom feature to support wasm32-unknown-unknown.

However, in general I recommend people use a target that's not wasm32-unknown-unknown whenever practical so that such workarounds aren't necessary. (We should create wasm32-browser and similar so that people don't need to use -unknown-unknown any more.)

briansmith avatar Nov 02 '23 20:11 briansmith