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-22 10:44:56 -0400
commita878b57a5f5e45fb68560e8a9eb2247cf1e0d4b8 (patch)
tree1ba4c4376055e9cc74f171ff722cfd99f71ca43c
parentbb063b938570345f22a74fa75bbfb04ac0ea85de (diff)
downloadmongo-a878b57a5f5e45fb68560e8a9eb2247cf1e0d4b8.tar.gz
SERVER-7005 reject embedded null bytes in $regex
(cherry picked from commit 33471d4424dd81e5310b27867ecb3647c60cf7a4) Conflicts: jstests/core/regex.js
-rw-r--r--jstests/core/regex.js54
-rw-r--r--src/mongo/db/matcher/expression_leaf.cpp10
-rw-r--r--src/mongo/db/matcher/expression_leaf_test.cpp130
3 files changed, 88 insertions, 106 deletions
diff --git a/jstests/core/regex.js b/jstests/core/regex.js
index f431d506ea6..d6982678f97 100644
--- a/jstests/core/regex.js
+++ b/jstests/core/regex.js
@@ -1,24 +1,40 @@
-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();
+ });
+ assert.throws(function() {
+ t.find({key: {$regex: 'abcd\0xyz'}}).explain();
+ });
+})();
diff --git a/src/mongo/db/matcher/expression_leaf.cpp b/src/mongo/db/matcher/expression_leaf.cpp
index 2316ef278b5..05edbdd094b 100644
--- a/src/mongo/db/matcher/expression_leaf.cpp
+++ b/src/mongo/db/matcher/expression_leaf.cpp
@@ -269,6 +269,16 @@ Status RegexMatchExpression::init(const StringData& path,
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 10ae1e8bc10..cb7217c1363 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);