summaryrefslogtreecommitdiff
path: root/src/mongo
diff options
context:
space:
mode:
authorSara Golemon <sara.golemon@mongodb.com>2020-02-20 17:01:35 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2020-02-21 16:38:50 +0000
commit7d5a7b2afe99c12ff8260835bb6d80cbdc0ef48d (patch)
treeb05f3a241ee5f1133ea173e3e45cf0102b31d065 /src/mongo
parent428ac6507118e58b6709e3dbae9fb4657e377637 (diff)
downloadmongo-7d5a7b2afe99c12ff8260835bb6d80cbdc0ef48d.tar.gz
SERVER-46071 Handle nan/inf/out-of-range inputs to integral set parameter values
Diffstat (limited to 'src/mongo')
-rw-r--r--src/mongo/bson/bsonelement.h58
-rw-r--r--src/mongo/idl/server_parameter_with_storage.h5
2 files changed, 61 insertions, 2 deletions
diff --git a/src/mongo/bson/bsonelement.h b/src/mongo/bson/bsonelement.h
index e3a0e37a2bc..5ad7635ed25 100644
--- a/src/mongo/bson/bsonelement.h
+++ b/src/mongo/bson/bsonelement.h
@@ -771,6 +771,9 @@ public:
bool coerce(Decimal128* out) const;
bool coerce(std::vector<std::string>* out) const;
+ template <typename T>
+ Status tryCoerce(T* out) const;
+
/**
* Constant double representation of 2^63, the smallest value that will overflow a long long.
*
@@ -947,6 +950,61 @@ inline long long BSONElement::safeNumberLong() const {
}
/**
+ * Attempt to coerce the BSONElement to a primitive type.
+ * For integral targets, we do additional checking that the
+ * source file is a finite real number and fits within the
+ * target type.
+ */
+template <typename T>
+Status BSONElement::tryCoerce(T* out) const {
+ if constexpr (std::is_integral<T>::value && !std::is_same<bool, T>::value) {
+ if (type() == NumberDouble) {
+ double d = numberDouble();
+ if (!std::isfinite(d)) {
+ return {ErrorCodes::BadValue, "Unable to coerce NaN/Inf to integral type"};
+ }
+ if ((d > std::numeric_limits<T>::max()) || (d < std::numeric_limits<T>::lowest())) {
+ return {ErrorCodes::BadValue, "Out of bounds coercing to integral value"};
+ }
+ } else if (type() == NumberDecimal) {
+ Decimal128 d = numberDecimal();
+ if (!d.isFinite()) {
+ return {ErrorCodes::BadValue, "Unable to coerce NaN/Inf to integral type"};
+ }
+ if (d.isGreater(Decimal128(std::numeric_limits<T>::max())) ||
+ d.isLess(Decimal128(std::numeric_limits<T>::lowest()))) {
+ return {ErrorCodes::BadValue, "Out of bounds coercing to integral value"};
+ }
+ } else if (type() == mongo::Bool) {
+ *out = Bool();
+ return Status::OK();
+ }
+
+ long long val;
+ if (!coerce(&val)) {
+ return {ErrorCodes::BadValue, "Unable to coerce value to integral type"};
+ }
+
+ if (std::is_same<long long, T>::value) {
+ *out = val;
+ return Status::OK();
+ }
+
+ if ((val > std::numeric_limits<T>::max()) || (val < std::numeric_limits<T>::lowest())) {
+ return {ErrorCodes::BadValue, "Out of bounds coercing to integral value"};
+ }
+
+ *out = static_cast<T>(val);
+ return Status::OK();
+ }
+
+ if (!coerce(out)) {
+ return {ErrorCodes::BadValue, "Unable to coerce value to correct type"};
+ }
+
+ return Status::OK();
+}
+/**
* This safeNumberLongForHash() function does the same thing as safeNumberLong, but it preserves
* edge-case behavior from older versions. It's provided for use by hash functions that need to
* maintain compatibility with older versions. Don't make any changes to safeNumberLong() without
diff --git a/src/mongo/idl/server_parameter_with_storage.h b/src/mongo/idl/server_parameter_with_storage.h
index 480983f4ad2..1871aa6156a 100644
--- a/src/mongo/idl/server_parameter_with_storage.h
+++ b/src/mongo/idl/server_parameter_with_storage.h
@@ -248,8 +248,9 @@ public:
Status set(const BSONElement& newValueElement) final {
element_type newValue;
- if (!newValueElement.coerce(&newValue)) {
- return Status(ErrorCodes::BadValue, "Can't coerce value");
+ if (auto status = newValueElement.tryCoerce(&newValue); !status.isOK()) {
+ return {status.code(),
+ str::stream() << "Failed setting " << name() << ": " << status.reason()};
}
return setValue(newValue);