From 6dff2a850dc583e012a58c31f682f64579946ce0 Mon Sep 17 00:00:00 2001 From: Adrian Dole Date: Mon, 22 Jul 2024 13:16:11 -0700 Subject: [PATCH] MONGOCRYPT-695 Remove upper bound assertions on FLE2 range precision (#858) * Remove precision assertions for decimal and double * Error if precision exceeds INT32_MAX * Error if precision results in an infinite double/decimal --------- Co-authored-by: Kevin Albertson --- src/mc-range-encoding.c | 38 ++++++++++++++++++++++++----------- test/test-mc-range-encoding.c | 29 ++++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 14 deletions(-) diff --git a/src/mc-range-encoding.c b/src/mc-range-encoding.c index d3eff1a5b..607b6ddb2 100644 --- a/src/mc-range-encoding.c +++ b/src/mc-range-encoding.c @@ -225,6 +225,19 @@ bool mc_getTypeInfoDouble(mc_getTypeInfoDouble_args_t args, } } + if (args.precision.set) { + if (args.precision.value > INT32_MAX) { + CLIENT_ERR("Precision cannot be greater than %" PRId32 ", got %" PRIu32, INT32_MAX, args.precision.value); + return false; + } + + double scaled = exp10Double(args.precision.value); + if (!mc_isfinite(scaled)) { + CLIENT_ERR("Precision is too large and cannot be used to calculate the scaled range bounds"); + return false; + } + } + const bool is_neg = args.value < 0.0; // Map negative 0 to zero so sign bit is 0. @@ -241,12 +254,6 @@ bool mc_getTypeInfoDouble(mc_getTypeInfoDouble_args_t args, bool use_precision_mode = false; uint32_t bits_range; if (args.precision.set) { - // Subnormal representations can support up to 5x10^-324 as a number - if (args.precision.value > 324) { - CLIENT_ERR("Precision must be between 0 and 324 inclusive, got: %" PRIu32, args.precision.value); - return false; - } - use_precision_mode = mc_canUsePrecisionModeDouble(args.min.value, args.max.value, args.precision.value, &bits_range); if (!use_precision_mode && use_range_v2) { @@ -393,6 +400,19 @@ bool mc_getTypeInfoDecimal128(mc_getTypeInfoDecimal128_args_t args, return false; } + if (args.precision.set) { + if (args.precision.value > INT32_MAX) { + CLIENT_ERR("Precision cannot be greater than %" PRId32 ", got %" PRIu32, INT32_MAX, args.precision.value); + return false; + } + + mc_dec128 scaled = mc_dec128_scale(MC_DEC128(1), args.precision.value); + if (!mc_dec128_is_finite(scaled)) { + CLIENT_ERR("Precision is too large and cannot be used to calculate the scaled range bounds"); + return false; + } + } + // We only accept normal numbers if (mc_dec128_is_inf(args.value) || mc_dec128_is_nan(args.value)) { CLIENT_ERR("Infinity and Nan Decimal128 values are not supported."); @@ -438,12 +458,6 @@ bool mc_getTypeInfoDecimal128(mc_getTypeInfoDecimal128_args_t args, // The number of bits required to hold the result (used for precision mode) uint32_t bits_range = 0; if (args.precision.set) { - // Subnormal representations can support up to 5x10^-6182 as a number - if (args.precision.value > 6182) { - CLIENT_ERR("Precision must be between 0 and 6182 inclusive, got: %" PRIu32, args.precision.value); - return false; - } - use_precision_mode = mc_canUsePrecisionModeDecimal(args.min.value, args.max.value, args.precision.value, &bits_range); diff --git a/test/test-mc-range-encoding.c b/test/test-mc-range-encoding.c index 905047ae1..075ec73e9 100644 --- a/test/test-mc-range-encoding.c +++ b/test/test-mc-range-encoding.c @@ -20,6 +20,7 @@ #include // DBL_MAX #include // INFINITY, NAN +#include typedef struct { mc_getTypeInfo32_args_t args; @@ -435,7 +436,20 @@ static void _test_RangeTest_Encode_Double(_mongocrypt_tester_t *tester) { .min = OPT_DOUBLE_C(0), .max = OPT_DOUBLE_C(201), .precision = OPT_U32_C(1), - .expectError = "less than or equal to the maximum value"}}; + .expectError = "less than or equal to the maximum value"}, + {// Expect error due to precision exceeding INT32_MAX. + .value = 1, + .min = OPT_DOUBLE_C(1), + .max = OPT_DOUBLE_C(2), + .precision = OPT_U32_C((uint32_t)INT32_MAX + 1), + .expectError = "Precision cannot be greater than 2147483647"}, + {// Expect error due to precision exceeding max finite double. + // The largest double value is 1.7976931348623157x10^308. 10^309 results in infinity. + .value = 1, + .min = OPT_DOUBLE_C(0), + .max = OPT_DOUBLE_C(1), + .precision = OPT_U32_C(309), + .expectError = "Precision is too large"}}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { DoubleTest *test = tests + i; @@ -767,7 +781,18 @@ static void _test_RangeTest_Encode_Decimal128(_mongocrypt_tester_t *tester) { #undef ASSERT_EIBB_OVERFLOW /* Test cases copied from Decimal128_Bounds_Precision ... end */ - }; + + {// Expect error due to precision exceeding INT32_MAX. + .min = OPT_MC_DEC128(MC_DEC128_C(1)), + .max = OPT_MC_DEC128(MC_DEC128_C(2)), + .precision = OPT_U32((uint32_t)INT32_MAX + 1), + .expectError = "Precision cannot be greater than 2147483647"}, + {// Expect error due to precision exceeding max finite Decimal128. + // The largest decimal128 value is 9.99999...x10^6144. 10^6145 results in infinity. + .min = OPT_MC_DEC128(MC_DEC128_C(0)), + .max = OPT_MC_DEC128(MC_DEC128_C(1)), + .precision = OPT_U32(6145), + .expectError = "Precision is too large"}}; for (size_t i = 0; i < sizeof(tests) / sizeof(tests[0]); i++) { Decimal128Test *test = tests + i;