diff options
author | David Storch <david.storch@10gen.com> | 2016-02-09 11:20:09 -0500 |
---|---|---|
committer | David Storch <david.storch@10gen.com> | 2016-02-22 09:57:09 -0500 |
commit | cedea56a9fbd65ad8ecf42828ceb9cc639e03bc8 (patch) | |
tree | 3822dc930ec6122b4eb11c0d5cff905cb924d643 /src | |
parent | 148c13f77781373543063740e5ea7445c3978849 (diff) | |
download | mongo-cedea56a9fbd65ad8ecf42828ceb9cc639e03bc8.tar.gz |
SERVER-22532 fail cleanly for $type predicates with invalid numerical type codes
(cherry picked from commit c827c55f02b3a97f001f9935ffc5ddef0520b07a)
Diffstat (limited to 'src')
-rw-r--r-- | src/mongo/bson/bsontypes.cpp | 30 | ||||
-rw-r--r-- | src/mongo/bson/bsontypes.h | 5 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_leaf.cpp | 10 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_leaf.h | 4 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_parser.cpp | 6 | ||||
-rw-r--r-- | src/mongo/db/matcher/expression_parser_leaf_test.cpp | 33 |
6 files changed, 82 insertions, 6 deletions
diff --git a/src/mongo/bson/bsontypes.cpp b/src/mongo/bson/bsontypes.cpp index 53dd4c685b8..7b94028e996 100644 --- a/src/mongo/bson/bsontypes.cpp +++ b/src/mongo/bson/bsontypes.cpp @@ -92,4 +92,34 @@ const char* typeName(BSONType type) { } } +bool isValidBSONType(int type) { + switch (type) { + case MinKey: + case EOO: + case NumberDouble: + case String: + case Object: + case Array: + case BinData: + case Undefined: + case jstOID: + case Bool: + case Date: + case jstNULL: + case RegEx: + case DBRef: + case Code: + case Symbol: + case CodeWScope: + case NumberInt: + case bsonTimestamp: + case NumberLong: + case NumberDecimal: + case MaxKey: + return true; + default: + return false; + } +} + } // namespace mongo diff --git a/src/mongo/bson/bsontypes.h b/src/mongo/bson/bsontypes.h index d13bdc0344c..5305d7c0acb 100644 --- a/src/mongo/bson/bsontypes.h +++ b/src/mongo/bson/bsontypes.h @@ -106,6 +106,11 @@ enum BSONType { */ const char* typeName(BSONType type); +/** + * Returns whether or not 'type' can be converted to a valid BSONType. + */ +bool isValidBSONType(int type); + /* subtypes of BinData. bdtCustom and above are ones that the JS compiler understands, but are opaque to the database. diff --git a/src/mongo/db/matcher/expression_leaf.cpp b/src/mongo/db/matcher/expression_leaf.cpp index 903b8c434a1..e271af3b2bb 100644 --- a/src/mongo/db/matcher/expression_leaf.cpp +++ b/src/mongo/db/matcher/expression_leaf.cpp @@ -41,6 +41,7 @@ #include "mongo/db/jsobj.h" #include "mongo/db/matcher/path.h" #include "mongo/stdx/memory.h" +#include "mongo/util/mongoutils/str.h" namespace mongo { @@ -420,9 +421,14 @@ const std::unordered_map<std::string, BSONType> TypeMatchExpression::typeAliasMa {"maxKey", MaxKey}, {"minKey", MinKey}}; -Status TypeMatchExpression::initWithBSONType(StringData path, BSONType type) { +Status TypeMatchExpression::initWithBSONType(StringData path, int type) { + if (!isValidBSONType(type)) { + return Status(ErrorCodes::BadValue, + str::stream() << "Invalid numerical $type code: " << type); + } + _path = path; - _type = type; + _type = static_cast<BSONType>(type); return _elementPath.init(_path); } diff --git a/src/mongo/db/matcher/expression_leaf.h b/src/mongo/db/matcher/expression_leaf.h index 0d7ceeb214f..2b382768788 100644 --- a/src/mongo/db/matcher/expression_leaf.h +++ b/src/mongo/db/matcher/expression_leaf.h @@ -396,8 +396,10 @@ public: /** * Initialize as matching against a specific BSONType. + * + * Returns a non-OK status if 'type' cannot be converted to a valid BSONType. */ - Status initWithBSONType(StringData path, BSONType type); + Status initWithBSONType(StringData path, int type); /** * Initialize as matching against all number types (NumberDouble, NumberLong, and NumberInt). diff --git a/src/mongo/db/matcher/expression_parser.cpp b/src/mongo/db/matcher/expression_parser.cpp index 0c385c78d69..732211ccb44 100644 --- a/src/mongo/db/matcher/expression_parser.cpp +++ b/src/mongo/db/matcher/expression_parser.cpp @@ -622,14 +622,14 @@ StatusWithMatchExpression MatchExpressionParser::_parseType(const char* name, std::unique_ptr<TypeMatchExpression> temp = stdx::make_unique<TypeMatchExpression>(); - BSONType typeInt; + int typeInt; // The element can be a number (the BSON type number) or a string representing the name // of the type. if (elt.isNumber()) { - typeInt = static_cast<BSONType>(elt.numberInt()); + typeInt = elt.numberInt(); if (elt.type() != NumberInt && typeInt != elt.number()) { - typeInt = static_cast<BSONType>(-1); + typeInt = -1; } } else { invariant(elt.type() == BSONType::String); diff --git a/src/mongo/db/matcher/expression_parser_leaf_test.cpp b/src/mongo/db/matcher/expression_parser_leaf_test.cpp index c5650c25d67..6efc994a86b 100644 --- a/src/mongo/db/matcher/expression_parser_leaf_test.cpp +++ b/src/mongo/db/matcher/expression_parser_leaf_test.cpp @@ -776,6 +776,39 @@ TEST(MatchExpressionParserLeafTest, TypeStringnameNumber) { ASSERT_FALSE(tmeNumber->matchesBSON(fromjson("{a: ''}"))); } +TEST(MatchExpressionParserLeafTest, InvalidTypeCodeLessThanMinKeyFailsToParse) { + StatusWithMatchExpression typeNumber = + MatchExpressionParser::parse(fromjson("{a: {$type: -20}}")); + ASSERT_NOT_OK(typeNumber.getStatus()); +} + +TEST(MatchExpressionParserLeafTest, InvalidTypeCodeGreaterThanMaxKeyFailsToParse) { + StatusWithMatchExpression typeNumber = + MatchExpressionParser::parse(fromjson("{a: {$type: 400}}")); + ASSERT_NOT_OK(typeNumber.getStatus()); +} + +TEST(MatchExpressionParserLeafTest, InvalidTypeCodeUnusedBetweenMinAndMaxFailsToParse) { + StatusWithMatchExpression typeNumber = + MatchExpressionParser::parse(fromjson("{a: {$type: 62}}")); + ASSERT_NOT_OK(typeNumber.getStatus()); +} + +TEST(MatchExpressionParserLeafTest, ValidTypeCodesParseSuccessfully) { + std::vector<BSONType> validTypes{ + MinKey, EOO, NumberDouble, String, Object, Array, BinData, Undefined, + jstOID, Bool, Date, jstNULL, RegEx, DBRef, Code, Symbol, + CodeWScope, NumberInt, bsonTimestamp, NumberLong, NumberDecimal, MaxKey}; + + for (auto type : validTypes) { + BSONObj predicate = BSON("a" << BSON("$type" << type)); + auto expression = MatchExpressionParser::parse(predicate); + ASSERT_OK(expression.getStatus()); + auto typeExpression = static_cast<TypeMatchExpression*>(expression.getValue().get()); + ASSERT_EQ(type, typeExpression->getType()); + } +} + TEST(MatchExpressionParserTest, BitTestMatchExpressionValidMask) { const double k2Power53 = scalbn(1, 32); |