The deriveaddresses
JSON-RPC endpoint accepts a descriptor and an index for the derivation.
Currently, the RPC interface caps the allowed index derivation range in the interval [0,2^31-1].
However, calling deriveaddresses
using a range that includes the index 2147483647
(2^31-1) results in a crash of bitcoind (on an AMD64 machine):
0bitcoin-cli deriveaddresses "descriptor" "[2147483647, 2147483647]"
1
2[bitcoind dumps core]
In the PR that addresses this pull request (#26275) is included a test case that causes the crash. For convenience, here’s the contents of a core dump generated with that test:
0$ sudo coredumpctl debug bitcoind
1 PID: 110184 (bitcoind)
2 UID: 1000 (muxator)
3 GID: 1000 (muxator)
4 Signal: 6 (ABRT)
5 Timestamp: Thu 2022-10-06 17:48:08 CEST (4min 56s ago)
6 Command Line: <base>/src/bitcoind -datadir=/tmp/test_runner_₿_🏃_20221006_174805/rpc_deriveaddresses_crash_0/node0 -logtimemicros -debug -debugexclude=libevent -debugexclude=leveldb -uacomment=testnode0 -logthreadnames -logsourcelocations -loglevel=trace -sandbox=log-and-abort
7 Executable: <base>/src/bitcoind
8[...]
9 Message: Process 110184 (bitcoind) of user 1000 dumped core.
10
11[...]
12 ELF object binary architecture: AMD x86-64
13
14GNU gdb (GDB) Fedora 12.1-1.fc36
15[...]
16Core was generated by `<base>/src/bitcoind -datadir=/tmp/test_runner_₿_��'.
17Program terminated with signal SIGABRT, Aborted.
18[#0](/bitcoin-bitcoin/0/) 0x00007f55a8ac6c4c in __pthread_kill_implementation () from /lib64/libc.so.6
19[Current thread is 1 (Thread 0x7f5576ffd640 (LWP 110197))]
20Missing separate debuginfos, use: dnf debuginfo-install glibc-2.35-17.fc36.x86_64 libevent-2.1.12-6.fc36.x86_64 libgcc-12.2.1-2.fc36.x86_64 libstdc++-12.2.1-2.fc36.x86_64 sqlite-libs-3.36.0-5.fc36.x86_64 zlib-1.2.11-33.fc36.x86_64
21(gdb) bt
22[#0](/bitcoin-bitcoin/0/) 0x00007f55a8ac6c4c in __pthread_kill_implementation () from /lib64/libc.so.6
23[#1](/bitcoin-bitcoin/1/) 0x00007f55a8a769c6 in raise () from /lib64/libc.so.6
24[#2](/bitcoin-bitcoin/2/) 0x00007f55a8a607f4 in abort () from /lib64/libc.so.6
25[#3](/bitcoin-bitcoin/3/) 0x00007f55a8c40c11 in __addvsi3 () from /lib64/libgcc_s.so.1
26[#4](/bitcoin-bitcoin/4/) 0x0000563935a84d73 in operator() (__closure=0x7f5576ffbd50, self=..., request=...) at rpc/output_script.cpp:276
27[#5](/bitcoin-bitcoin/5/) 0x0000563935a87ec2 in std::__invoke_impl<UniValue, deriveaddresses()::<lambda(const RPCHelpMan&, const JSONRPCRequest&)>&, const RPCHelpMan&, const JSONRPCRequest&>(std::__invoke_other, struct {...} &) (__f=...)
28 at /usr/include/c++/12/bits/invoke.h:61
29[#6](/bitcoin-bitcoin/6/) 0x0000563935a8773f in std::__invoke_r<UniValue, deriveaddresses()::<lambda(const RPCHelpMan&, const JSONRPCRequest&)>&, const RPCHelpMan&, const JSONRPCRequest&>(struct {...} &) (__fn=...) at /usr/include/c++/12/bits/invoke.h:116
30[#7](/bitcoin-bitcoin/7/) 0x0000563935a86ec3 in std::_Function_handler<UniValue(const RPCHelpMan&, const JSONRPCRequest&), deriveaddresses()::<lambda(const RPCHelpMan&, const JSONRPCRequest&)> >::_M_invoke(const std::_Any_data &, const RPCHelpMan &, const JSONRPCRequest &) (__functor=..., __args#0=..., __args#1=...) at /usr/include/c++/12/bits/std_function.h:291
31[#8](/bitcoin-bitcoin/8/) 0x00005639360b4641 in std::function<UniValue (RPCHelpMan const&, JSONRPCRequest const&)>::operator()(RPCHelpMan const&, JSONRPCRequest const&) const (this=0x7f5576ffbd50, __args#0=..., __args#1=...)
32 at /usr/include/c++/12/bits/std_function.h:591
33[#9](/bitcoin-bitcoin/9/) 0x00005639360a93b8 in RPCHelpMan::HandleRequest (this=0x7f5576ffbd30, request=...) at rpc/util.cpp:585
34[#10](/bitcoin-bitcoin/10/) 0x00005639359cc1a2 in CRPCCommand::CRPCCommand(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, RPCHelpMan (*)())::{lambda(JSONRPCRequest const&, UniValue&, bool)#1}::operator()(JSONRPCRequest const&, UniValue&, bool) const (__closure=0x5639368fbb00 <RegisterOutputScriptRPCCommands(CRPCTable&)::commands+320>, request=..., result=...) at ./rpc/server.h:109
35[#11](/bitcoin-bitcoin/11/) 0x00005639359e0be3 in std::__invoke_impl<bool, CRPCCommand::CRPCCommand(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, RPCHelpMan (*)())::{lambda(JSONRPCRequest const&, UniValue&, bool)#1}&, JSONRPCRequest const&, UniValue&, bool>(std::__invoke_other, CRPCCommand::CRPCCommand(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, RPCHelpMan (*)())::{lambda(JSONRPCRequest const&, UniValue&, bool)#1}&, JSONRPCRequest const&, UniValue&, bool&&) (__f=...) at /usr/include/c++/12/bits/invoke.h:61
36[#12](/bitcoin-bitcoin/12/) 0x00005639359da9ba in std::__invoke_r<bool, CRPCCommand::CRPCCommand(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, RPCHelpMan (*)())::{lambda(JSONRPCRequest const&, UniValue&, bool)#1}&, JSONRPCRequest const&, UniValue&, bool>(CRPCCommand::CRPCCommand(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, RPCHelpMan (*)())::{lambda(JSONRPCRequest const&, UniValue&, bool)#1}&, JSONRPCRequest const&, UniValue&, bool&&) (__fn=...) at /usr/include/c++/12/bits/invoke.h:114
37[#13](/bitcoin-bitcoin/13/) 0x00005639359d4916 in std::_Function_handler<bool (JSONRPCRequest const&, UniValue&, bool), CRPCCommand::CRPCCommand(std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >, RPCHelpMan (*)())::{lambda(JSONRPCRequest const&, UniValue&, bool)#1}>::_M_invoke(std::_Any_data const&, JSONRPCRequest const&, UniValue&, bool&&) (__functor=..., __args#0=..., __args#1=..., __args#2=@0x7f5576ffbf44: true) at /usr/include/c++/12/bits/std_function.h:290
38[#14](/bitcoin-bitcoin/14/) 0x00005639359302c6 in std::function<bool (JSONRPCRequest const&, UniValue&, bool)>::operator()(JSONRPCRequest const&, UniValue&, bool) const (this=0x5639368fbb00 <RegisterOutputScriptRPCCommands(CRPCTable&)::commands+320>,
39 __args#0=..., __args#1=..., __args#2=true) at /usr/include/c++/12/bits/std_function.h:591
40[#15](/bitcoin-bitcoin/15/) 0x0000563935b0afd5 in ExecuteCommand (command=..., request=..., result=..., last_handler=true) at rpc/server.cpp:475
41[#16](/bitcoin-bitcoin/16/) 0x0000563935b0abae in ExecuteCommands (commands=std::vector of length 1, capacity 1 = {...}, request=..., result=...) at rpc/server.cpp:440
42[#17](/bitcoin-bitcoin/17/) 0x0000563935b0ad52 in CRPCTable::execute (this=0x5639368fc4c0 <tableRPC>, request=...) at rpc/server.cpp:460
43[#18](/bitcoin-bitcoin/18/) 0x0000563935cbe3f5 in HTTPReq_JSONRPC (context=std::any containing node::NodeContext * = {...}, req=0x7f556c002da0) at httprpc.cpp:201
44[#19](/bitcoin-bitcoin/19/) 0x0000563935cc0548 in operator() (__closure=0x7f556c001980, req=0x7f556c002da0) at httprpc.cpp:300
45[#20](/bitcoin-bitcoin/20/) 0x0000563935cc1c3a in std::__invoke_impl<bool, StartHTTPRPC(const std::any&)::<lambda(HTTPRequest*, const std::string&)>&, HTTPRequest*, const std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>(std::__invoke_other, struct {...} &) (__f=...) at /usr/include/c++/12/bits/invoke.h:61
46[#21](/bitcoin-bitcoin/21/) 0x0000563935cc1a78 in std::__invoke_r<bool, StartHTTPRPC(const std::any&)::<lambda(HTTPRequest*, const std::string&)>&, HTTPRequest*, const std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&>(struct {...} &) (__fn=...) at /usr/include/c++/12/bits/invoke.h:114
47[#22](/bitcoin-bitcoin/22/) 0x0000563935cc182e in std::_Function_handler<bool(HTTPRequest*, const std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> >&), StartHTTPRPC(const std::any&)::<lambda(HTTPRequest*, const std::string&)> >::_M_invoke(const std::_Any_data &, HTTPRequest *&&, const std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > &) (__functor=..., __args#0=@0x7f5576ffcb80: 0x7f556c002da0, __args#1="")
48 at /usr/include/c++/12/bits/std_function.h:290
49[#23](/bitcoin-bitcoin/23/) 0x0000563935cd1c0c in std::function<bool (HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&)>::operator()(HTTPRequest*, std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > const&) const (this=0x7f556c003fb0, __args#0=0x7f556c002da0, __args#1="") at /usr/include/c++/12/bits/std_function.h:591
50[#24](/bitcoin-bitcoin/24/) 0x0000563935cd0fc2 in HTTPWorkItem::operator() (this=0x7f556c003f80) at httpserver.cpp:56
51[#25](/bitcoin-bitcoin/25/) 0x0000563935cd326d in WorkQueue<HTTPClosure>::Run (this=0x563938765d10) at httpserver.cpp:111
52[#26](/bitcoin-bitcoin/26/) 0x0000563935ccbf1d in HTTPWorkQueueRun (queue=0x563938765d10, worker_num=3) at httpserver.cpp:343
53[#27](/bitcoin-bitcoin/27/) 0x0000563935cdfd51 in std::__invoke_impl<void, void (*)(WorkQueue<HTTPClosure>*, int), WorkQueue<HTTPClosure>*, int> (__f=@0x56393877e7f8: 0x563935ccbeb2 <HTTPWorkQueueRun(WorkQueue<HTTPClosure>*, int)>)
54 at /usr/include/c++/12/bits/invoke.h:61
55[#28](/bitcoin-bitcoin/28/) 0x0000563935cdfaaa in std::__invoke<void (*)(WorkQueue<HTTPClosure>*, int), WorkQueue<HTTPClosure>*, int> (__fn=@0x56393877e7f8: 0x563935ccbeb2 <HTTPWorkQueueRun(WorkQueue<HTTPClosure>*, int)>)
56 at /usr/include/c++/12/bits/invoke.h:96
57[#29](/bitcoin-bitcoin/29/) 0x0000563935cdf8a6 in std::thread::_Invoker<std::tuple<void (*)(WorkQueue<HTTPClosure>*, int), WorkQueue<HTTPClosure>*, int> >::_M_invoke<0ul, 1ul, 2ul> (this=0x56393877e7e8) at /usr/include/c++/12/bits/std_thread.h:252
58[#30](/bitcoin-bitcoin/30/) 0x0000563935cdf7db in std::thread::_Invoker<std::tuple<void (*)(WorkQueue<HTTPClosure>*, int), WorkQueue<HTTPClosure>*, int> >::operator() (this=0x56393877e7e8) at /usr/include/c++/12/bits/std_thread.h:259
59[#31](/bitcoin-bitcoin/31/) 0x0000563935cdf60f in std::thread::_State_impl<std::thread::_Invoker<std::tuple<void (*)(WorkQueue<HTTPClosure>*, int), WorkQueue<HTTPClosure>*, int> > >::_M_run (this=0x56393877e7e0) at /usr/include/c++/12/bits/std_thread.h:210
60[#32](/bitcoin-bitcoin/32/) 0x00007f55a8e15b03 in execute_native_thread_routine () from /lib64/libstdc++.so.6
61[#33](/bitcoin-bitcoin/33/) 0x00007f55a8ac4e2d in start_thread () from /lib64/libc.so.6
62[#34](/bitcoin-bitcoin/34/) 0x00007f55a8b4a1b0 in clone3 () from /lib64/libc.so.6
The affected code seems to be in frame 4, and corresponds to the following code:
0(gdb) frame 4
1[#4](/bitcoin-bitcoin/4/) 0x0000563935a84d73 in operator() (__closure=0x7f5576ffbd50, self=..., request=...) at rpc/output_script.cpp:276
2276 for (int i = range_begin; i <= range_end; ++i) {
I think the reason is that, while range_begin
and range_end
are uint64_t
, i
is an int
, which on many platforms means int32_t
.
When i
is assigned 2^31-1
and is then incremented, it wraps back and causes the crash.