Repository navigation
workers, crypto: passing KeyObject as workerData crashes #35263
Copy link
Copy link
Closed
Labels
c++Issues and PRs that require attention from people who are familiar with C++.Issues and PRs that require attention from people who are familiar with C++.cryptoIssues and PRs related to the crypto subsystem.Issues and PRs related to the crypto subsystem.good first issueIssues that are suitable for first-time contributors.Issues that are suitable for first-time contributors.workerIssues and PRs related to the worker_threads module and Worker API.Issues and PRs related to the worker_threads module and Worker API.
Description
@addaleax @nodejs/workers ... The following segfaults on master and 14.x ...
I'll be investigating shortly...
'use strict';
const { createSecretKey } = require('crypto');
const { Worker, isMainThread, workerData } = require('worker_threads');
if (isMainThread) {
const key = createSecretKey(Buffer.from('hello'));
new Worker(__filename, { workerData: key });
} else {
console.log(workerData);
}lldb yields...
james@ubuntu:~/node/node$ lldb -- node ../tmp/test
(lldb) target create "node"
Current executable set to 'node' (x86_64).
(lldb) settings set -- target.run-args "../tmp/test"
(lldb) r
Process 20852 launched: '/home/james/node/node/node' (x86_64)
Process 20852 stopped
* thread #2, name = 'node', stop reason = signal SIGSEGV: invalid address (fault address: 0x0)
frame #0: 0x00005555560fb837 node`v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&) + 103
node`v8::internal::(anonymous namespace)::Invoke:
-> 0x5555560fb837 <+103>: movq (%r13), %rax
0x5555560fb83b <+107>: testb $0x1, %al
0x5555560fb83d <+109>: jne 0x5555560fba10 ; <+576>
0x5555560fb843 <+115>: movl 0x3320(%rbx), %r13d
(lldb) bt
* thread #2, name = 'node', stop reason = signal SIGSEGV: invalid address (fault address: 0x0)
* frame #0: 0x00005555560fb837 node`v8::internal::(anonymous namespace)::Invoke(v8::internal::Isolate*, v8::internal::(anonymous namespace)::InvokeParams const&) + 103
frame #1: 0x00005555560fcb7d node`v8::internal::Execution::New(v8::internal::Isolate*, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Object>, int, v8::internal::Handle<v8::internal::Object>*) + 109
frame #2: 0x0000555555f8f01f node`v8::Function::NewInstanceWithSideEffectType(v8::Local<v8::Context>, int, v8::Local<v8::Value>*, v8::SideEffectType) const + 415
frame #3: 0x0000555555ee51d8 node`node::crypto::KeyObjectHandle::Create(node::Environment*, std::shared_ptr<node::crypto::KeyObjectData>) + 40
frame #4: 0x0000555555ee6f91 node`node::crypto::NativeKeyObject::KeyObjectTransferData::Deserialize(node::Environment*, v8::Local<v8::Context>, std::unique_ptr<node::worker::TransferData, std::default_delete<node::worker::TransferData> >) + 385
frame #5: 0x0000555555d73130 node`node::worker::Message::Deserialize(node::Environment*, v8::Local<v8::Context>) + 464
frame #6: 0x0000555555d78335 node`node::worker::MessagePort::ReceiveMessage(v8::Local<v8::Context>, bool) + 1605
frame #7: 0x0000555555d788b8 node`node::worker::MessagePort::OnMessage() + 312
frame #8: 0x000055555686c8c6 node`uv__async_io(loop=0x00007ffff447ba48, w=<unavailable>, events=<unavailable>) at async.c:163
frame #9: 0x0000555556880f84 node`uv__io_poll(loop=0x00007ffff447ba48, timeout=<unavailable>) at linux-core.c:461
frame #10: 0x000055555686d1fa node`uv_run(loop=0x00007ffff447ba48, mode=UV_RUN_DEFAULT) at core.c:385
frame #11: 0x0000555555e00336 node`node::worker::Worker::Run() + 5766
frame #12: 0x0000555555e00707 node`node::worker::Worker::StartThread(v8::FunctionCallbackInfo<v8::Value> const&)::'lambda'(void*)::_FUN(void*) + 71
frame #13: 0x00007ffff707a6db libpthread.so.0`start_thread + 219
frame #14: 0x00007ffff6da3a3f libc.so.6`__GI___clone at clone.S:95
(lldb)
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
c++Issues and PRs that require attention from people who are familiar with C++.Issues and PRs that require attention from people who are familiar with C++.cryptoIssues and PRs related to the crypto subsystem.Issues and PRs related to the crypto subsystem.good first issueIssues that are suitable for first-time contributors.Issues that are suitable for first-time contributors.workerIssues and PRs related to the worker_threads module and Worker API.Issues and PRs related to the worker_threads module and Worker API.
Activity
jasnell commentedon Sep 18, 2020
Ok... yeah, it's what I suspected...
KeyObjectHandle::Create()depends onenv->crypto_key_object_handle_constructor()being set, which it is not untilinternalBinding('crypto')is called... so when the attempt is made to deserialize theKeyObjectin the Worker, we get a crash.I added a CHECK to verify in my local branch:
addaleax commentedon Sep 20, 2020
We could probably make
KeyObjectHandle::Initialize()innode_crypto.ccdo something like we do inGetMessagePortConstructorTemplate()innode_messaging.cc, where we create theFunctionTemplateonly once, and then afterwards return the cached value.addaleax commentedon Sep 20, 2020
I’ve marked this
good first issue, but if you want to pick this up, you’ll probably want to know some C++ and maybe also be a bit familiar with the V8 API (if you are not, https://github.com/nodejs/node/blob/master/src/README.md has some overview over the concepts involved here).jasnell commentedon Sep 20, 2020
I was going to work up the fix this next week as part of #35093 but if someone wants to pick it up, feel free!
ThakurKarthik commentedon Sep 20, 2020
@addaleax @jasnell I want to pick it up. As a starter how much c++ should i know be knowing to tackle this issue?
Edit: I am going through the relevant details from https://github.com/nodejs/node/blob/master/src/README.md and i will try to work on it.
Thanks
addaleax commentedon Sep 20, 2020
@ThakurKarthik I don’t think it requires a deep knowledge of the language, but some basic understanding would be helpful.
Fwiw, the relevant parts of the code base are:
node/src/node_crypto.cc
Lines 3268 to 3288 in a8971f8
node/src/node_crypto.cc
Lines 6953 to 6954 in a8971f8
And this is how we’ve solved this for the
MessagePortcase, another situation where the same problem occurred:node/src/node_messaging.cc
Lines 1076 to 1094 in a8971f8
ThakurKarthik commentedon Sep 20, 2020
Thanks @addaleax for the pointers
ThakurKarthik commentedon Sep 26, 2020
Hi @addaleax with your reference I made these changes and ran
./configure && make -j4 testit was successful .But running this code still showing error.
For some reason i am not able to generate the debug build.
Can you guide me how to proceed further ?
Thanks
addaleax commentedon Sep 26, 2020
@ThakurKarthik
It’s hard to tell without further information, but the only reason that I know of why this might not work is that debug builds take up a lot more memory and disk space. In this case, using
./configure --debug-nodeinstead of./configure --debugmight be more helpful anyway, because you only want to debug the Node.js part, not dependencies like V8 (I assume).ThakurKarthik commentedon Sep 27, 2020
Hi @addaleax I was able to generate the debug build with

--debug-nodeand used gdb, the ouput is similar to what @jasnell has posted earlier. I tried debugging step by stepI can see
env->crypto_key_object_handle_constructor()is defined and giving some value when printed but i think this iskey_ctor = env->crypto_key_object_secret_constructor();undefined. It is set inside this functionCreateNativeKeyObjectClass. So maybe i need to call this inside Deserialize method.You can see the different variables i printed in this screenshot
addaleax commentedon Sep 27, 2020
@ThakurKarthik Oh, right, that’s … unfortunate, sorry
That’s probably the best approach here – the function is called from
lib/internal/crypto/keys.js. I think you should be able to load that viaenv->native_module_require()->Call(context, Null(isolate), 1, &arg))whereargisFIXED_ONE_BYTE_STRING(isolate, "internal/crypto/keys"), maybe you could try that? (It’s basically the C++ equivalent of writingrequire('internal/crypto/keys'))crypto: set env values in KeyObject Deserialize method
crypto: set env values in KeyObject Deserialize method
crypto: set env values in KeyObject Deserialize method
crypto: set env values in KeyObject Deserialize method
crypto: set env values in KeyObject Deserialize method