summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Storch <david.storch@10gen.com>2016-04-21 11:21:24 -0400
committerDavid Storch <david.storch@10gen.com>2016-04-21 15:56:09 -0400
commit957f73433f2cd97e756b307343798ae08c4bc8cb (patch)
treec543cb803600dcd8e7ecacc22bd93b175a97563b
parent1f8c150eb01db7c9c71142accd404457e2abdd83 (diff)
downloadmongo-957f73433f2cd97e756b307343798ae08c4bc8cb.tar.gz
SERVER-7005 reject embedded null bytes in $regex
(cherry picked from commit 33471d4424dd81e5310b27867ecb3647c60cf7a4)
-rw-r--r--jstests/core/regex.js51
-rw-r--r--src/mongo/db/matcher/expression_leaf.cpp10
-rw-r--r--src/mongo/db/matcher/expression_leaf_test.cpp130
3 files changed, 85 insertions, 106 deletions
diff --git a/jstests/core/regex.js b/jstests/core/regex.js
index 235c1936885..983ead6d733 100644
--- a/jstests/core/regex.js
+++ b/jstests/core/regex.js
@@ -1,24 +1,37 @@
-t = db.jstests_regex;
+(function() {
+ 'use strict';
-t.drop();
-t.save({a: "bcd"});
-assert.eq(1, t.count({a: /b/}), "A");
-assert.eq(1, t.count({a: /bc/}), "B");
-assert.eq(1, t.count({a: /bcd/}), "C");
-assert.eq(0, t.count({a: /bcde/}), "D");
+ var t = db.jstests_regex;
-t.drop();
-t.save({a: {b: "cde"}});
-assert.eq(1, t.count({'a.b': /de/}), "E");
+ t.drop();
+ t.save({a: "bcd"});
+ assert.eq(1, t.count({a: /b/}), "A");
+ assert.eq(1, t.count({a: /bc/}), "B");
+ assert.eq(1, t.count({a: /bcd/}), "C");
+ assert.eq(0, t.count({a: /bcde/}), "D");
-t.drop();
-t.save({a: {b: ["cde"]}});
-assert.eq(1, t.count({'a.b': /de/}), "F");
+ t.drop();
+ t.save({a: {b: "cde"}});
+ assert.eq(1, t.count({'a.b': /de/}), "E");
-t.drop();
-t.save({a: [{b: "cde"}]});
-assert.eq(1, t.count({'a.b': /de/}), "G");
+ t.drop();
+ t.save({a: {b: ["cde"]}});
+ assert.eq(1, t.count({'a.b': /de/}), "F");
-t.drop();
-t.save({a: [{b: ["cde"]}]});
-assert.eq(1, t.count({'a.b': /de/}), "H");
+ t.drop();
+ t.save({a: [{b: "cde"}]});
+ assert.eq(1, t.count({'a.b': /de/}), "G");
+
+ t.drop();
+ t.save({a: [{b: ["cde"]}]});
+ assert.eq(1, t.count({'a.b': /de/}), "H");
+
+ // Disallow embedded null bytes when using $regex syntax.
+ t.drop();
+ assert.throws(function() {
+ t.find({a: {$regex: "a\0b", $options: "i"}}).itcount();
+ });
+ assert.throws(function() {
+ t.find({a: {$regex: "ab", $options: "i\0"}}).itcount();
+ });
+})();
diff --git a/src/mongo/db/matcher/expression_leaf.cpp b/src/mongo/db/matcher/expression_leaf.cpp
index e271af3b2bb..cfcd3d03591 100644
--- a/src/mongo/db/matcher/expression_leaf.cpp
+++ b/src/mongo/db/matcher/expression_leaf.cpp
@@ -271,6 +271,16 @@ Status RegexMatchExpression::init(StringData path, StringData regex, StringData
return Status(ErrorCodes::BadValue, "Regular expression is too long");
}
+ if (regex.find('\0') != std::string::npos) {
+ return Status(ErrorCodes::BadValue,
+ "Regular expression cannot contain an embedded null byte");
+ }
+
+ if (options.find('\0') != std::string::npos) {
+ return Status(ErrorCodes::BadValue,
+ "Regular expression options string cannot contain an embedded null byte");
+ }
+
_regex = regex.toString();
_flags = options.toString();
_re.reset(new pcrecpp::RE(_regex.c_str(), flags2options(_flags.c_str())));
diff --git a/src/mongo/db/matcher/expression_leaf_test.cpp b/src/mongo/db/matcher/expression_leaf_test.cpp
index b2946f5f546..d4d01eb7325 100644
--- a/src/mongo/db/matcher/expression_leaf_test.cpp
+++ b/src/mongo/db/matcher/expression_leaf_test.cpp
@@ -854,57 +854,6 @@ TEST(ComparisonMatchExpression, ElemMatchKey) {
ASSERT_EQUALS("1", details.elemMatchKey());
}
-/**
- TEST( GteOp, MatchesIndexKeyScalar ) {
- BSONObj operand = BSON( "$gte" << 6 );
- GteOp gte;
- ASSERT( gte.init( "a", operand[ "$gte" ] ).isOK() );
- IndexSpec indexSpec( BSON( "a" << 1 ) );
- ASSERT( MatchMatchExpression::PartialMatchResult_True ==
- gte.matchesIndexKey( BSON( "" << 6 ), indexSpec ) );
- ASSERT( MatchMatchExpression::PartialMatchResult_False ==
- gte.matchesIndexKey( BSON( "" << 5 ), indexSpec ) );
- ASSERT( MatchMatchExpression::PartialMatchResult_False ==
- gte.matchesIndexKey( BSON( "" << BSON_ARRAY( 7 ) ), indexSpec ) );
- }
-
- TEST( GteOp, MatchesIndexKeyMissing ) {
- BSONObj operand = BSON( "$gte" << 6 );
- GteOp gte;
- ASSERT( gte.init( "a", operand[ "$gte" ] ).isOK() );
- IndexSpec indexSpec( BSON( "b" << 1 ) );
- ASSERT( MatchMatchExpression::PartialMatchResult_Unknown ==
- gte.matchesIndexKey( BSON( "" << 6 ), indexSpec ) );
- ASSERT( MatchMatchExpression::PartialMatchResult_Unknown ==
- gte.matchesIndexKey( BSON( "" << 4 ), indexSpec ) );
- ASSERT( MatchMatchExpression::PartialMatchResult_Unknown ==
- gte.matchesIndexKey( BSON( "" << BSON_ARRAY( 8 << 6 ) ), indexSpec ) );
- }
-
- TEST( GteOp, MatchesIndexKeyArray ) {
- BSONObj operand = BSON( "$gte" << BSON_ARRAY( 4 << 5 ) );
- GteOp gte;
- ASSERT( gte.init( "a", operand[ "$gte" ] ).isOK() );
- IndexSpec indexSpec( BSON( "a" << 1 ) );
- ASSERT( MatchMatchExpression::PartialMatchResult_Unknown ==
- gte.matchesIndexKey( BSON( "" << 6 ), indexSpec ) );
- }
-
- TEST( GteOp, MatchesIndexKeyArrayValue ) {
- BSONObj operand = BSON( "$gte" << 6 );
- GteOp gte;
- ASSERT( gte.init( "a", operand[ "$gte" ] ).isOK() );
- IndexSpec indexSpec( BSON( "loc" << "mockarrayvalue" << "a" << 1 ) );
- ASSERT( MatchMatchExpression::PartialMatchResult_True ==
- gte.matchesIndexKey( BSON( "" << "dummygeohash" << "" << 6 ), indexSpec ) );
- ASSERT( MatchMatchExpression::PartialMatchResult_False ==
- gte.matchesIndexKey( BSON( "" << "dummygeohash" << "" << 3 ), indexSpec ) );
- ASSERT( MatchMatchExpression::PartialMatchResult_True ==
- gte.matchesIndexKey( BSON( "" << "dummygeohash" <<
- "" << BSON_ARRAY( 8 << 6 << 4 ) ), indexSpec ) );
- }
-*/
-
TEST(RegexMatchExpression, MatchesElementExact) {
BSONObj match = BSON("a"
<< "b");
@@ -1140,44 +1089,51 @@ TEST(RegexMatchExpression, Equality1) {
ASSERT(!r1.equivalent(&r4));
}
-/**
- TEST( RegexMatchExpression, MatchesIndexKeyScalar ) {
- RegexMatchExpression regex;
- ASSERT( regex.init( "a", "xyz", "" ).isOK() );
- IndexSpec indexSpec( BSON( "a" << 1 ) );
- ASSERT( MatchMatchExpression::PartialMatchResult_True ==
- regex.matchesIndexKey( BSON( "" << "z xyz" ), indexSpec ) );
- ASSERT( MatchMatchExpression::PartialMatchResult_False ==
- regex.matchesIndexKey( BSON( "" << "xy" ), indexSpec ) );
- ASSERT( MatchMatchExpression::PartialMatchResult_False ==
- regex.matchesIndexKey( BSON( "" << BSON_ARRAY( "xyz" ) ), indexSpec ) );
- }
+TEST(RegexMatchExpression, RegexCannotContainEmbeddedNullByte) {
+ RegexMatchExpression regex;
+ {
+ StringData embeddedNull("a\0b", StringData::LiteralTag());
+ ASSERT_NOT_OK(regex.init("path", embeddedNull, ""));
+ }
- TEST( RegexMatchExpression, MatchesIndexKeyMissing ) {
- RegexMatchExpression regex;
- ASSERT( regex.init( "a", "xyz", "" ).isOK() );
- IndexSpec indexSpec( BSON( "b" << 1 ) );
- ASSERT( MatchMatchExpression::PartialMatchResult_Unknown ==
- regex.matchesIndexKey( BSON( "" << "z xyz" ), indexSpec ) );
- ASSERT( MatchMatchExpression::PartialMatchResult_Unknown ==
- regex.matchesIndexKey( BSON( "" << "xy" ), indexSpec ) );
- ASSERT( MatchMatchExpression::PartialMatchResult_Unknown ==
- regex.matchesIndexKey( BSON( "" << BSON_ARRAY( 8 << "xyz" ) ), indexSpec ) );
- }
+ {
+ StringData singleNullByte("\0", StringData::LiteralTag());
+ ASSERT_NOT_OK(regex.init("path", singleNullByte, ""));
+ }
- TEST( RegexMatchExpression, MatchesIndexKeyArrayValue ) {
- RegexMatchExpression regex;
- ASSERT( regex.init( "a", "xyz", "" ).isOK() );
- IndexSpec indexSpec( BSON( "loc" << "mockarrayvalue" << "a" << 1 ) );
- ASSERT( MatchMatchExpression::PartialMatchResult_True ==
- regex.matchesIndexKey( BSON( "" << "dummygeohash" << "" << "xyz" ), indexSpec ) );
- ASSERT( MatchMatchExpression::PartialMatchResult_False ==
- regex.matchesIndexKey( BSON( "" << "dummygeohash" << "" << "z" ), indexSpec ) );
- ASSERT( MatchMatchExpression::PartialMatchResult_True ==
- regex.matchesIndexKey( BSON( "" << "dummygeohash" <<
- "" << BSON_ARRAY( "r" << 6 << "xyz" ) ), indexSpec ) );
- }
-*/
+ {
+ StringData leadingNullByte("\0bbbb", StringData::LiteralTag());
+ ASSERT_NOT_OK(regex.init("path", leadingNullByte, ""));
+ }
+
+ {
+ StringData trailingNullByte("bbbb\0", StringData::LiteralTag());
+ ASSERT_NOT_OK(regex.init("path", trailingNullByte, ""));
+ }
+}
+
+TEST(RegexMatchExpression, RegexOptionsStringCannotContainEmbeddedNullByte) {
+ RegexMatchExpression regex;
+ {
+ StringData embeddedNull("a\0b", StringData::LiteralTag());
+ ASSERT_NOT_OK(regex.init("path", "pattern", embeddedNull));
+ }
+
+ {
+ StringData singleNullByte("\0", StringData::LiteralTag());
+ ASSERT_NOT_OK(regex.init("path", "pattern", singleNullByte));
+ }
+
+ {
+ StringData leadingNullByte("\0bbbb", StringData::LiteralTag());
+ ASSERT_NOT_OK(regex.init("path", "pattern", leadingNullByte));
+ }
+
+ {
+ StringData trailingNullByte("bbbb\0", StringData::LiteralTag());
+ ASSERT_NOT_OK(regex.init("path", "pattern", trailingNullByte));
+ }
+}
TEST(ModMatchExpression, MatchesElement) {
BSONObj match = BSON("a" << 1);