From 737baf54467255c09db0a73181176dae33851f6e Mon Sep 17 00:00:00 2001 From: Areg Hayrapetian Date: Tue, 2 Aug 2022 17:19:14 -0700 Subject: [PATCH 1/2] Add subjective limit to mod_exp host function. Also adds test case to test that the subjective limit is enforced. --- libraries/chain/webassembly/crypto.cpp | 8 ++++ libraries/fc | 2 +- unittests/crypto_primitives_tests.cpp | 54 ++++++++++++++++++++++++++ 3 files changed, 63 insertions(+), 1 deletion(-) diff --git a/libraries/chain/webassembly/crypto.cpp b/libraries/chain/webassembly/crypto.cpp index ba3b21d9af..f18b326f37 100644 --- a/libraries/chain/webassembly/crypto.cpp +++ b/libraries/chain/webassembly/crypto.cpp @@ -158,6 +158,14 @@ namespace eosio { namespace chain { namespace webassembly { span exp, span modulus, span out) const { + if (context.control.is_producing_block()) { + static constexpr int byte_size_limit = 256; // Allow up to 2048-bit values for base, exp, and modulus. + + if (std::max(std::max(base.size(), exp.size()), modulus.size()) > byte_size_limit) { + EOS_THROW(subjective_block_production_exception, "Bit size too large for values passed into mod_exp"); + } + } + bytes bbase(base.data(), base.data() + base.size()); bytes bexp(exp.data(), exp.data() + exp.size()); bytes bmod(modulus.data(), modulus.data() + modulus.size()); diff --git a/libraries/fc b/libraries/fc index cc9e62bd95..0cc2b8c2db 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit cc9e62bd9569b436b545ad46c06e991ca9177bcf +Subproject commit 0cc2b8c2db9343ba5258adde868c76d15b921edf diff --git a/unittests/crypto_primitives_tests.cpp b/unittests/crypto_primitives_tests.cpp index 5247f3b0f3..ccf933f6f1 100644 --- a/unittests/crypto_primitives_tests.cpp +++ b/unittests/crypto_primitives_tests.cpp @@ -386,6 +386,7 @@ BOOST_AUTO_TEST_CASE( modexp_test ) { try { return_code::failure, "", }, + }; for(const auto& test : tests) { @@ -409,6 +410,59 @@ BOOST_AUTO_TEST_CASE( modexp_test ) { try { } FC_LOG_AND_RETHROW() } +BOOST_AUTO_TEST_CASE( modexp_subjective_limit_test ) { try { + + // Given the need to respect the deadline timer and the current limitation that the deadline timer is not plumbed into the + // inner loops of the implementation of mod_exp (which currently exists in the gmp shared library), only a small enough duration for + // mod_exp can be tolerated to avoid going over the deadline timer by too much. A good threshold for small may be less than 5 ms. + // Then based on benchmarks within the test_modular_arithmetic test within fc, it seems safe to limit the bit size to 2048 bits. + + // This test case verifies that the subjective bit size limit for mod_exp is properly enforced within libchain. + + // To allow mod_exp to be more useful, the limits on bit size need to be removed and the deadline timer plumbing into the implementation + // needs to occur. When that happens, this test case can be removed. + + tester c( setup_policy::preactivate_feature_and_new_bios ); + + const auto& tester1_account = account_name("tester1"); + c.create_accounts( {tester1_account} ); + c.produce_block(); + + const auto& pfm = c.control->get_protocol_feature_manager(); + const auto& d = pfm.get_builtin_digest( builtin_protocol_feature_t::crypto_primitives ); + BOOST_REQUIRE( d ); + + c.preactivate_protocol_features( {*d} ); + c.produce_block(); + + c.set_code( tester1_account, contracts::crypto_primitives_test_wasm() ); + c.set_abi( tester1_account, contracts::crypto_primitives_test_abi().data() ); + c.produce_block(); + + bytes exponent(256); // 2048 bits of all zeros is fine + + c.push_action( tester1_account, "testmodexp"_n, tester1_account, mutable_variant_object() + ("base", h2bin("01")) + ("exp", exponent) + ("modulo", h2bin("0F")) + ("expected_error", static_cast(return_code::success)) + ("expected_result", h2bin("01")) + ); + + exponent.push_back(0); // But 2056 bits of all zeros crosses the subjective limit (even if the value is still technically only zero). + + BOOST_CHECK_EXCEPTION(c.push_action( tester1_account, "testmodexp"_n, tester1_account, mutable_variant_object() + ("base", h2bin("01")) + ("exp", exponent) + ("modulo", h2bin("0F")) + ("expected_error", static_cast(return_code::success)) + ("expected_result", h2bin("01"))), + eosio::chain::subjective_block_production_exception, + fc_exception_message_is("Bit size too large for values passed into mod_exp") + ); + +} FC_LOG_AND_RETHROW() } + BOOST_AUTO_TEST_CASE( blake2f_test ) { try { tester c( setup_policy::preactivate_feature_and_new_bios ); From 8cbd077d9fb913edb9cb240d437e468d5cadf17a Mon Sep 17 00:00:00 2001 From: Areg Hayrapetian Date: Tue, 2 Aug 2022 21:41:17 -0700 Subject: [PATCH 2/2] Update fc submodule. --- libraries/fc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libraries/fc b/libraries/fc index 0cc2b8c2db..12898316ae 160000 --- a/libraries/fc +++ b/libraries/fc @@ -1 +1 @@ -Subproject commit 0cc2b8c2db9343ba5258adde868c76d15b921edf +Subproject commit 12898316ae323deb4a928614d1b4fb456853453a