wallet: Check size after unserializing a pubkey #19237

pull elichai wants to merge 2 commits into bitcoin:master from elichai:2020-06-pubkey changing 2 files +47 −0
  1. elichai commented at 2:39 PM on June 10, 2020: contributor

    Found by practicalswift, closes #19235 Currently all the public API(except the pointer-like API) in CPubKey that sets/constructs a pubkey goes through CPubKey::Set which checks if that the length and size match and if not invalidates the key.

    This adds the same check to CPubKey::Unserialize, sadly I don't see an easy way to just push this to the existing checks in CPubKey::Set but it's only a simple condition.

    The problem with not invalidating is that if you write a pubkey like: {0x02,0x00} it will think the actual length is 33(because of size()) and will access uninitialized memory if you call any of the functions on CPubKey.

  2. Check size after Unserializing CPubKey 9b8907fade
  3. practicalswift commented at 3:37 PM on June 10, 2020: contributor

    Thanks for addressing this @elichai! :)

    Concept ACK

    Regarding the implementation: if ReadCompactSize(s) returns zero won't vch[0] be read uninitialized in size() (unsigned int size() const { return GetLen(vch[0]); }) before the call to Invalidate() takes place?

    Also, what about adding a test case for the fixed issue that would fail under MemorySanitizer or Valgrind? Something exercising these code paths (plus assertions):

    const std::vector<uint8_t> serialized_pub_key{4, 4, 0, 0, 0};
    CDataStream data_stream{serialized_pub_key, SER_NETWORK, INIT_PROTO_VERSION};
    CPubKey pub_key;
    data_stream >> pub_key;
    (void)pub_key.IsFullyValid();
    

    And perhaps also a test case where ReadCompactSize(s) returns zero to cover that case too :)

  4. elichai commented at 3:40 PM on June 10, 2020: contributor

    Regarding the implementation: if ReadCompactSize(s) returns zero won't vch[0] be read uninitialized in size()

    I thought so at first, but no the constructor invalidates it (which writes 0xFF into vch[0]) https://github.com/bitcoin/bitcoin/blob/6762a627ecb89ba8d4ed81a049a5d802e6dd75c2/src/pubkey.h#L79-L82

    const std::vector<uint8_t> serialized_pub_key{4, 4, 0, 0, 0};
    CDataStream data_stream{serialized_pub_key, SER_NETWORK, INIT_PROTO_VERSION};
    CPubKey pub_key;
    data_stream >> pub_key;
    (void)pub_key.IsFullyValid();
    

    I'll add a few tests.

  5. practicalswift commented at 7:12 PM on June 10, 2020: contributor

    @elichai Great! Another very nice thing with your fix is that it addresses another CPubKey oddity which I reported back in issue #17238: serialization-deserialization roundtrip of CPubKey did not necessarily result in an equal object. CPubKey was the only deserializable class that had that unexpected behaviour which made it a potential future gotcha. Glad to see it fixed too :)

    More specifically …

    CPubKey pk1;
    CDataStream s1{std::vector<uint8_t>{'\x01', '\x72'}, SER_NETWORK, INIT_PROTO_VERSION};
    s1 >> pk1;
    
    CDataStream s2{SER_NETWORK, INIT_PROTO_VERSION};
    s2 << pk1;
    
    CPubKey pk2;
    s2 >> pk2;
    
    assert(pk1 == pk2);
    

    … used to result in …

    Assertion `pk1 == pk2' failed.
    

    … but now passes (as expected). Note that the assertion failure was not due to UUM: no UUM takes place in this specific example.

    Might be worth adding a test case also for that too, and perhaps also enable this commented out code from the CPubKey deserialization fuzzer:

    https://github.com/bitcoin/bitcoin/blob/6762a627ecb89ba8d4ed81a049a5d802e6dd75c2/src/test/fuzz/deserialize.cpp#L118-L122

  6. pstratem commented at 4:27 AM on June 11, 2020: contributor

    for anybody else wondering this doesn't look like a consensus change as the script interpreter uses the CPubKey constructor which calls Set.

  7. laanwj commented at 6:01 PM on June 11, 2020: member

    Concept ACK. I think it's good to assure the correctness of deserialized data. Especially as you say, a size() > len could potentially end up with uninitialized data in the key.

  8. luke-jr approved
  9. luke-jr commented at 9:34 PM on June 11, 2020: member

    utACK

  10. luke-jr referenced this in commit 3c6999414d on Jun 12, 2020
  11. elichai commented at 12:29 PM on June 15, 2020: contributor

    Added a few tests, these tests should fail before the fix commit and should trigger valgrind before the fix commit.

  12. practicalswift commented at 12:56 PM on June 15, 2020: contributor

    Thanks for adding tests!

    ACK eab8ee3211e661dfb41f0363f6bf6bcabfc521fa -- patch looks correct

  13. jonatack commented at 1:34 PM on June 15, 2020: member

    ACK eab8ee3211e661dfb41f0363f6bf6bcabfc521fa code review, verified new tests fail on master but pass with this patch, both with and without valgrind.

    <details><summary>valgrind unit test with this patch rebased on master</summary><p>

    $ valgrind src/test/test_bitcoin -t key_tests -l test_suite
    ==27199== Memcheck, a memory error detector
    ==27199== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
    ==27199== Using Valgrind-3.16.0.GIT and LibVEX; rerun with -h for copyright info
    ==27199== Command: src/test/test_bitcoin -t key_tests -l test_suite
    ==27199== 
    Running 4 test cases...
    Entering test module "Bitcoin Core Test Suite"
    test/key_tests.cpp(32): Entering test suite "key_tests"
    test/key_tests.cpp(34): Entering test case "key_test1"
    test/key_tests.cpp(34): Leaving test case "key_test1"; testing time: 7488280us
    test/key_tests.cpp(156): Entering test case "key_signature_tests"
    test/key_tests.cpp(156): Leaving test case "key_signature_tests"; testing time: 1860096us
    test/key_tests.cpp(192): Entering test case "key_key_negation"
    test/key_tests.cpp(192): Leaving test case "key_key_negation"; testing time: 314970us
    test/key_tests.cpp(251): Entering test case "pubkey_unserialize"
    test/key_tests.cpp(251): Leaving test case "pubkey_unserialize"; testing time: 297818us
    test/key_tests.cpp(32): Leaving test suite "key_tests"; testing time: 9969383us
    Leaving test module "Bitcoin Core Test Suite"; testing time: 9975082us
    
    *** No errors detected
    ==27199== 
    ==27199== HEAP SUMMARY:
    ==27199==     in use at exit: 505 bytes in 5 blocks
    ==27199==   total heap usage: 16,462 allocs, 16,457 frees, 41,640,410 bytes allocated
    ==27199== 
    ==27199== LEAK SUMMARY:
    ==27199==    definitely lost: 0 bytes in 0 blocks
    ==27199==    indirectly lost: 0 bytes in 0 blocks
    ==27199==      possibly lost: 0 bytes in 0 blocks
    ==27199==    still reachable: 505 bytes in 5 blocks
    ==27199==         suppressed: 0 bytes in 0 blocks
    ==27199== Rerun with --leak-check=full to see details of leaked memory
    ==27199== 
    ==27199== For lists of detected and suppressed errors, rerun with: -s
    ==27199== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
    

    </p></details>

    <details><summary>unit test failures without this patch</summary><p>

    src/test/test_bitcoin -t key_tests -l test_suite
    Running 4 test cases...
    Entering test module "Bitcoin Core Test Suite"
    test/key_tests.cpp(32): Entering test suite "key_tests"
    test/key_tests.cpp(34): Entering test case "key_test1"
    test/key_tests.cpp(34): Leaving test case "key_test1"; testing time: 72983us
    test/key_tests.cpp(156): Entering test case "key_signature_tests"
    test/key_tests.cpp(156): Leaving test case "key_signature_tests"; testing time: 46559us
    test/key_tests.cpp(192): Entering test case "key_key_negation"
    test/key_tests.cpp(192): Leaving test case "key_key_negation"; testing time: 10107us
    test/key_tests.cpp(251): Entering test case "pubkey_unserialize"
    test/key_tests.cpp(255): error: in "key_tests/pubkey_unserialize": check !key.IsValid() has failed
    test/key_tests.cpp(255): error: in "key_tests/pubkey_unserialize": check !key.IsValid() has failed
    test/key_tests.cpp(255): error: in "key_tests/pubkey_unserialize": check !key.IsValid() has failed
    test/key_tests.cpp(255): error: in "key_tests/pubkey_unserialize": check !key.IsValid() has failed
    test/key_tests.cpp(255): error: in "key_tests/pubkey_unserialize": check !key.IsValid() has failed
    test/key_tests.cpp(255): error: in "key_tests/pubkey_unserialize": check !key.IsValid() has failed
    test/key_tests.cpp(251): Leaving test case "pubkey_unserialize"; testing time: 7067us
    test/key_tests.cpp(32): Leaving test suite "key_tests"; testing time: 136897us
    Leaving test module "Bitcoin Core Test Suite"; testing time: 137038us
    
    *** 6 failures are detected in the test module "Bitcoin Core Test Suite"
    

    </p></details>

    <details><summary>valgrind unit test failures without this patch</summary><p>

    $ valgrind src/test/test_bitcoin -t key_tests -l test_suite
    ==25033== Memcheck, a memory error detector
    ==25033== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
    ==25033== Using Valgrind-3.16.0.GIT and LibVEX; rerun with -h for copyright info
    ==25033== Command: src/test/test_bitcoin -t key_tests -l test_suite
    ==25033== 
    Running 4 test cases...
    Entering test module "Bitcoin Core Test Suite"
    test/key_tests.cpp(32): Entering test suite "key_tests"
    test/key_tests.cpp(34): Entering test case "key_test1"
    test/key_tests.cpp(34): Leaving test case "key_test1"; testing time: 6917131us
    test/key_tests.cpp(156): Entering test case "key_signature_tests"
    test/key_tests.cpp(156): Leaving test case "key_signature_tests"; testing time: 1514039us
    test/key_tests.cpp(192): Entering test case "key_key_negation"
    test/key_tests.cpp(192): Leaving test case "key_key_negation"; testing time: 300821us
    test/key_tests.cpp(251): Entering test case "pubkey_unserialize"
    test/key_tests.cpp(255): error: in "key_tests/pubkey_unserialize": check !key.IsValid() has failed
    ==25033== Conditional jump or move depends on uninitialised value(s)
    ==25033==    at 0x483BDFF: bcmp (vg_replace_strmem.c:1111)
    ==25033==    by 0x285948: operator==(CPubKey const&, CPubKey const&) (pubkey.h:119)
    ==25033==    by 0x439B11: key_tests::CmpSerializationPubkey(CPubKey) (key_tests.cpp:248)
    ==25033==    by 0x43937C: key_tests::pubkey_unserialize::test_method() (key_tests.cpp:256)
    ==25033==    by 0x438D45: key_tests::pubkey_unserialize_invoker() (key_tests.cpp:251)
    ==25033==    by 0x20A369: boost::detail::function::void_function_invoker0<void (*)(), void>::invoke(boost::detail::function::function_buffer&) (function_template.hpp:118)
    ==25033==    by 0x4936DBD: boost::detail::function::function_obj_invoker0<boost::detail::forward, int>::invoke(boost::detail::function::function_buffer&) (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.67.0)
    ==25033==    by 0x49369A4: boost::execution_monitor::catch_signals(boost::function<int ()> const&) (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.67.0)
    ==25033==    by 0x4936A70: boost::execution_monitor::execute(boost::function<int ()> const&) (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.67.0)
    ==25033==    by 0x4936B3C: boost::execution_monitor::vexecute(boost::function<void ()> const&) (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.67.0)
    ==25033==    by 0x495E538: boost::unit_test::unit_test_monitor_t::execute_and_translate(boost::function<void ()> const&, unsigned int) (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.67.0)
    ==25033==    by 0x49392AA: ??? (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.67.0)
    ==25033== 
    ==25033== Conditional jump or move depends on uninitialised value(s)
    ==25033==    at 0x483BE0E: bcmp (vg_replace_strmem.c:1111)
    ==25033==    by 0x285948: operator==(CPubKey const&, CPubKey const&) (pubkey.h:119)
    ==25033==    by 0x439B11: key_tests::CmpSerializationPubkey(CPubKey) (key_tests.cpp:248)
    ==25033==    by 0x43937C: key_tests::pubkey_unserialize::test_method() (key_tests.cpp:256)
    ==25033==    by 0x438D45: key_tests::pubkey_unserialize_invoker() (key_tests.cpp:251)
    ==25033==    by 0x20A369: boost::detail::function::void_function_invoker0<void (*)(), void>::invoke(boost::detail::function::function_buffer&) (function_template.hpp:118)
    ==25033==    by 0x4936DBD: boost::detail::function::function_obj_invoker0<boost::detail::forward, int>::invoke(boost::detail::function::function_buffer&) (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.67.0)
    ==25033==    by 0x49369A4: boost::execution_monitor::catch_signals(boost::function<int ()> const&) (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.67.0)
    ==25033==    by 0x4936A70: boost::execution_monitor::execute(boost::function<int ()> const&) (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.67.0)
    ==25033==    by 0x4936B3C: boost::execution_monitor::vexecute(boost::function<void ()> const&) (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.67.0)
    ==25033==    by 0x495E538: boost::unit_test::unit_test_monitor_t::execute_and_translate(boost::function<void ()> const&, unsigned int) (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.67.0)
    ==25033==    by 0x49392AA: ??? (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.67.0)
    ==25033== 
    ==25033== Conditional jump or move depends on uninitialised value(s)
    ==25033==    at 0x483BE37: bcmp (vg_replace_strmem.c:1111)
    ==25033==    by 0x285948: operator==(CPubKey const&, CPubKey const&) (pubkey.h:119)
    ==25033==    by 0x439B11: key_tests::CmpSerializationPubkey(CPubKey) (key_tests.cpp:248)
    ==25033==    by 0x43937C: key_tests::pubkey_unserialize::test_method() (key_tests.cpp:256)
    ==25033==    by 0x438D45: key_tests::pubkey_unserialize_invoker() (key_tests.cpp:251)
    ==25033==    by 0x20A369: boost::detail::function::void_function_invoker0<void (*)(), void>::invoke(boost::detail::function::function_buffer&) (function_template.hpp:118)
    ==25033==    by 0x4936DBD: boost::detail::function::function_obj_invoker0<boost::detail::forward, int>::invoke(boost::detail::function::function_buffer&) (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.67.0)
    ==25033==    by 0x49369A4: boost::execution_monitor::catch_signals(boost::function<int ()> const&) (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.67.0)
    ==25033==    by 0x4936A70: boost::execution_monitor::execute(boost::function<int ()> const&) (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.67.0)
    ==25033==    by 0x4936B3C: boost::execution_monitor::vexecute(boost::function<void ()> const&) (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.67.0)
    ==25033==    by 0x495E538: boost::unit_test::unit_test_monitor_t::execute_and_translate(boost::function<void ()> const&, unsigned int) (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.67.0)
    ==25033==    by 0x49392AA: ??? (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.67.0)
    ==25033== 
    ==25033== Conditional jump or move depends on uninitialised value(s)
    ==25033==    at 0x494AE92: boost::test_tools::tt_detail::report_assertion(boost::test_tools::assertion_result const&, boost::unit_test::lazy_ostream const&, boost::unit_test::basic_cstring<char const>, unsigned long, boost::test_tools::tt_detail::tool_level, boost::test_tools::tt_detail::check_type, unsigned long, ...) (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.67.0)
    ==25033==    by 0x439C0B: key_tests::CmpSerializationPubkey(CPubKey) (key_tests.cpp:248)
    ==25033==    by 0x43937C: key_tests::pubkey_unserialize::test_method() (key_tests.cpp:256)
    ==25033==    by 0x438D45: key_tests::pubkey_unserialize_invoker() (key_tests.cpp:251)
    ==25033==    by 0x20A369: boost::detail::function::void_function_invoker0<void (*)(), void>::invoke(boost::detail::function::function_buffer&) (function_template.hpp:118)
    ==25033==    by 0x4936DBD: boost::detail::function::function_obj_invoker0<boost::detail::forward, int>::invoke(boost::detail::function::function_buffer&) (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.67.0)
    ==25033==    by 0x49369A4: boost::execution_monitor::catch_signals(boost::function<int ()> const&) (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.67.0)
    ==25033==    by 0x4936A70: boost::execution_monitor::execute(boost::function<int ()> const&) (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.67.0)
    ==25033==    by 0x4936B3C: boost::execution_monitor::vexecute(boost::function<void ()> const&) (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.67.0)
    ==25033==    by 0x495E538: boost::unit_test::unit_test_monitor_t::execute_and_translate(boost::function<void ()> const&, unsigned int) (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.67.0)
    ==25033==    by 0x49392AA: ??? (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.67.0)
    ==25033==    by 0x49395A3: ??? (in /usr/lib/x86_64-linux-gnu/libboost_unit_test_framework.so.1.67.0)
    ==25033== 
    test/key_tests.cpp(255): error: in "key_tests/pubkey_unserialize": check !key.IsValid() has failed
    test/key_tests.cpp(255): error: in "key_tests/pubkey_unserialize": check !key.IsValid() has failed
    test/key_tests.cpp(255): error: in "key_tests/pubkey_unserialize": check !key.IsValid() has failed
    test/key_tests.cpp(255): error: in "key_tests/pubkey_unserialize": check !key.IsValid() has failed
    test/key_tests.cpp(255): error: in "key_tests/pubkey_unserialize": check !key.IsValid() has failed
    test/key_tests.cpp(251): Leaving test case "pubkey_unserialize"; testing time: 334009us
    test/key_tests.cpp(32): Leaving test suite "key_tests"; testing time: 9073960us
    Leaving test module "Bitcoin Core Test Suite"; testing time: 9080205us
    
    *** 6 failures are detected in the test module "Bitcoin Core Test Suite"
    ==25033== 
    ==25033== HEAP SUMMARY:
    ==25033==     in use at exit: 505 bytes in 5 blocks
    ==25033==   total heap usage: 16,485 allocs, 16,480 frees, 41,641,596 bytes allocated
    ==25033== 
    ==25033== LEAK SUMMARY:
    ==25033==    definitely lost: 0 bytes in 0 blocks
    ==25033==    indirectly lost: 0 bytes in 0 blocks
    ==25033==      possibly lost: 0 bytes in 0 blocks
    ==25033==    still reachable: 505 bytes in 5 blocks
    ==25033==         suppressed: 0 bytes in 0 blocks
    ==25033== Rerun with --leak-check=full to see details of leaked memory
    ==25033== 
    ==25033== Use --track-origins=yes to see where uninitialised values come from
    ==25033== For lists of detected and suppressed errors, rerun with: -s
    ==25033== ERROR SUMMARY: 6 errors from 4 contexts (suppressed: 0 from 0)
    

    </p></details>

    Thanks for adding the tests.

  14. DrahtBot added the label Tests on Jun 15, 2020
  15. MarcoFalke removed the label Tests on Jun 15, 2020
  16. MarcoFalke added the label Wallet on Jun 15, 2020
  17. MarcoFalke renamed this:
    Check size after unserializing a pubkey
    wallet: Check size after unserializing a pubkey
    on Jun 15, 2020
  18. MarcoFalke commented at 11:47 PM on June 15, 2020: member

    To determine which label to apply I patched as follows and checked which files won't compile:

    diff --git a/src/pubkey.h b/src/pubkey.h
    index 4c28af4a4d..35ccfe304d 100644
    --- a/src/pubkey.h
    +++ b/src/pubkey.h
    @@ -137,7 +137,7 @@ public:
             s.write((char*)vch, len);
         }
         template <typename Stream>
    -    void Unserialize(Stream& s)
    +    void Unserializee(Stream& s)
         {
             unsigned int len = ::ReadCompactSize(s);
             if (len <= SIZE) {
    

    The result was:

      CXX      test/test_bitcoin-key_tests.o
      CXX      wallet/libbitcoin_wallet_a-walletdb.o
    ...
    make[2]: *** [Makefile:17241: test/test_bitcoin-key_tests.o] Error 1
    ...
    make[2]: *** [Makefile:12299: wallet/libbitcoin_wallet_a-walletdb.o] Error 1
    
  19. MarcoFalke commented at 11:48 PM on June 15, 2020: member

    So I applied the wallet label. Hope that makes sense and let me know if I should change it.

  20. in src/test/key_tests.cpp:236 in eab8ee3211 outdated
     231 | +}
     232 | +
     233 | +static unsigned int GetLen(unsigned char chHeader)
     234 | +{
     235 | +    if (chHeader == 2 || chHeader == 3)
     236 | +        return CPubKey::COMPRESSED_SIZE;
    


    MarcoFalke commented at 11:50 PM on June 15, 2020:

    nit: Either single-line or with { }


    elichai commented at 6:45 PM on June 16, 2020:

    I thought about changing that but I decided not to because it's a straight copy out of the CPubKey class (a private function) I'm fine changing it though


    MarcoFalke commented at 7:07 PM on June 16, 2020:

    Yeah, no worries its just the tests.

  21. in src/test/key_tests.cpp:242 in eab8ee3211 outdated
     237 | +    if (chHeader == 4 || chHeader == 6 || chHeader == 7)
     238 | +        return CPubKey::SIZE;
     239 | +    return 0;
     240 | +}
     241 | +
     242 | +static void CmpSerializationPubkey(CPubKey pubkey)
    


    MarcoFalke commented at 11:50 PM on June 15, 2020:

    nit:

    static void CmpSerializationPubkey(const CPubKey& pubkey)
    
  22. MarcoFalke commented at 11:52 PM on June 15, 2020: member

    Concept ACK. Feel free to ignore the style nits in the test.

  23. Add tests for CPubKey serialization/unserialization 37ae687f95
  24. elichai force-pushed on Jun 17, 2020
  25. practicalswift commented at 1:26 PM on June 17, 2020: contributor

    re-ACK 37ae687f95c82f2d64ed880533d158060d4fc3de

  26. jonatack commented at 2:08 PM on June 17, 2020: member

    Code review re-ACK 37ae687 per git diff eab8ee3 37ae687 only change since last review at eab8ee3 is passing the pubkey param by reference to const instead of by value in src/test/key_tests.cpp::CmpSerializationPubkey

  27. in src/pubkey.h:146 in 37ae687f95
     141 | @@ -142,6 +142,9 @@ class CPubKey
     142 |          unsigned int len = ::ReadCompactSize(s);
     143 |          if (len <= SIZE) {
     144 |              s.read((char*)vch, len);
     145 | +            if (len != size()) {
     146 | +                Invalidate();
    


    MarcoFalke commented at 12:01 PM on June 25, 2020:

    Instead of enumerating what could go wrong, what do you think about having one path for a valid deserialization and let all other paths end in an invalid deserialization?

    The diff would be:

    diff --git a/src/pubkey.h b/src/pubkey.h
    index 261842b7f7..0f4787bc90 100644
    --- a/src/pubkey.h
    +++ b/src/pubkey.h
    @@ -142,13 +142,14 @@ public:
             unsigned int len = ::ReadCompactSize(s);
             if (len <= SIZE) {
                 s.read((char*)vch, len);
    +            if (len == size()) return;
             } else {
                 // invalid pubkey, skip available data
                 char dummy;
                 while (len--)
                     s.read(&dummy, 1);
    -            Invalidate();
             }
    +        Invalidate();
         }
     
         //! Get the KeyID of this public key (hash of its serialization)
    
  28. MarcoFalke commented at 12:07 PM on June 25, 2020: member

    ACK 37ae687f95c82f2d64ed880533d158060d4fc3de

  29. MarcoFalke merged this on Jun 25, 2020
  30. MarcoFalke closed this on Jun 25, 2020

  31. elichai deleted the branch on Jul 5, 2020
  32. sidhujag referenced this in commit 6b2e80699a on Jul 8, 2020
  33. luke-jr referenced this in commit b14efe62be on Aug 15, 2020
  34. MarcoFalke referenced this in commit 8cb43077b3 on Jun 17, 2021
  35. sidhujag referenced this in commit 1d67f858c6 on Jun 18, 2021
  36. Fabcien referenced this in commit 6c2ae4f5de on Aug 27, 2021
  37. DrahtBot locked this on Feb 15, 2022

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bitcoin. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-04-14 21:14 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me