summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorDavid Storch <david.storch@10gen.com>2016-02-09 11:20:09 -0500
committerDavid Storch <david.storch@10gen.com>2016-02-22 09:57:09 -0500
commitcedea56a9fbd65ad8ecf42828ceb9cc639e03bc8 (patch)
tree3822dc930ec6122b4eb11c0d5cff905cb924d643 /src
parent148c13f77781373543063740e5ea7445c3978849 (diff)
downloadmongo-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.cpp30
-rw-r--r--src/mongo/bson/bsontypes.h5
-rw-r--r--src/mongo/db/matcher/expression_leaf.cpp10
-rw-r--r--src/mongo/db/matcher/expression_leaf.h4
-rw-r--r--src/mongo/db/matcher/expression_parser.cpp6
-rw-r--r--src/mongo/db/matcher/expression_parser_leaf_test.cpp33
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);