Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Chrome Extension Manifest v3 refuses to evaulate unsafe-eval / wasm-unsafe-eval #3098

Closed
cryptoquick opened this issue Oct 3, 2022 · 10 comments
Labels

Comments

@cryptoquick
Copy link

cryptoquick commented Oct 3, 2022

Describe the Bug

In a Chrome Extension using the new Manifest v3 format, using more recent versions of Chrome (97+?), wasm-unsafe-eval is supposed to be used as the content security policy for calling wasm methods. It seems to work in some cases, but it still catches some wasm-bidgen generated calls as violating ordinary unsafe-eval rules. For example:

Error

Uncaught (in promise) EvalError: Refused to evaluate a string as JavaScript because 'unsafe-eval' is not an allowed source of script in the following Content Security Policy directive: "script-src 'self' 'wasm-unsafe-eval'".

Stack Trace

function __wbg_new_d87f272aec784ec0(arg0, arg1) {
  const ret = new Function(getStringFromWasm0(arg0, arg1));  // <-- highlighted line
  return addHeapObject(ret);
}

Steps to Reproduce

  1. Use wasm-pack to generate a pkg of a wasm-bindgen project
  2. Bundle it into a project using webpack (might be unnecessary, but it's part of my build process, so it might bear mentioning)
  3. Load the extension unpacked into the Chrome extensions page set to developer mode
  4. Open the extension popup
  5. View the Errors page for the extension

Expected Behavior

The Chrome extension should be able to execute the wasm bundle without triggering an unsafe-eval exception.

Actual Behavior

Screenshot from 2022-10-03 07-38-22

Additional Context

If I had to guess, Chrome is doing some form of static analysis, and there might be a way it expects to see WASM methods called that wasm-bindgen exceeds the bounds of in some ways (but not all). This might include creating a function from strings provided by the wasm binary, as highlighted in the stack trace.

@cryptoquick cryptoquick added the bug label Oct 3, 2022
@Liamolucko
Copy link
Collaborator

That looks to me like the generated bindings for Function::new_no_args; so, I think this is happening because there's some Rust code calling new Function(), rightfully triggering the CSP error.

Do you have the full stack trace of the error? That should show what crate is calling new Function() and causing the problem.

@cryptoquick
Copy link
Author

@Liamolucko Thanks for the quick reply! It didn't provide the entire stack trace, but I was able to get about 2000 lines:

wasm-stack-trace-error-line-23562.zip

(I just realized after uploading the error is actually on line 501 in that file)

I'll look into what's needed to get a more complete stack trace...

@cryptoquick
Copy link
Author

Okay, figured it out. This should provide a more complete set of information:
wasm-full-stack-trace-error-line-1181.zip

module.zip

Screenshot from 2022-10-04 07-43-52

Let me know if there's anything else I can provide that might help!

@Liamolucko
Copy link
Collaborator

Could you compile your code with debug symbols enabled? That should make the stack trace show Rust function names instead of the byte addresses it's currently showing. (So, instead of module.wasm:0x20976d in that screenshot, it should show something like crate_name::module_name::function_name (module.wasm:0x20976d)).

You mentioned you're using wasm-pack, which strips debug symbols in --release mode (the default); building in --dev mode instead should include them.

@cryptoquick
Copy link
Author

Ah! Right, good point. I'm actually using wasm-pack's npm publish capability. I'll set it to import from a local path.

Here you go, I just zipped the pkg directory, all that code is open source anyway:
pkg.zip

Also, here's the contents of the new line exception in the JS file (I've realized the line numbers in the browser and the JS files don't always match):

export function __wbg_new_d87f272aec784ec0(arg0, arg1) {
    const ret = new Function(getStringFromWasm0(arg0, arg1));
    return addHeapObject(ret);
};

@alexcrichton
Copy link
Contributor

You're probably running into this which means that in your context you won't be able to use js_sys::global() or you'll need to hardcode a paritcular implementation of that.

@Liamolucko
Copy link
Collaborator

I managed to get the debug symbols working (thank you for providing the link to the repo!) and it turns out that it's coming from this line in a very old version of the now-deprecated rand_os:

https://github.com/rust-random/rand/blob/bce70e348242a3a4f91b85b0bf90de2d03527f08/rand_os/src/wasm32_bindgen.rs#L32

That's being depended on by rand v0.6.5, which is depended on by both bitmask-core and secp256k1. So, updating rand in both those places should fix this issue.

@cryptoquick
Copy link
Author

Holy cow, that's awesome, thanks a ton, @Liamolucko ! You gotta tell me how you got proper debug symbols working!? 🙏

@Liamolucko
Copy link
Collaborator

You gotta tell me how you got proper debug symbols working!? 🙏

The debug symbols get stripped when wasm-pack runs wasm-opt on the binary. To avoid that, you can run wasm-pack build --dev instead of wasm-pack build, which skips wasm-opt, but also compiles the Rust code in dev mode, making it much slower. If you want to preserve debug symbols in release mode, you can add this to Cargo.toml to tell wasm-opt not to strip debug symbols:

[package.metadata.wasm-pack.profile.release]
# default is ["-O"]; -g means to preserve debug symbols.
wasm-opt = ["-O", "-g"]

@cryptoquick
Copy link
Author

Aha! Thank you very much! Also, thanks for chiming in, @alexcrichton. Your stewardship of all your work is appreciated. Closing this now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants