diff --git a/CVE-2020-7921.patch b/CVE-2020-7921.patch new file mode 100644 index 0000000000000000000000000000000000000000..8bb520d513c3abd793311e4d6f8156fe1cb7bf09 --- /dev/null +++ b/CVE-2020-7921.patch @@ -0,0 +1,159 @@ +From fb87cc88ecb5d300f14cda7bc238d7d5132118f5 Mon Sep 17 00:00:00 2001 +From: Spencer Jackson +Date: Wed, 15 Jan 2020 16:30:37 +0000 +Subject: [PATCH] SERVER-45472 Ensure RoleGraph can serialize authentication + restrictions to BSON + +(cherry picked from commit 521e56b407ac72bc69a97a24d1253f51a5b6e81b) +(cherry picked from commit a10d0a22d5d009d27664967181042933ec1bef36) +--- + .../auth/authentication_restrictions_role.js | 8 +++++ + src/mongo/db/auth/role_graph.cpp | 9 +++++ + src/mongo/db/auth/role_graph_test.cpp | 36 ++++++++++++++++++- + 3 files changed, 52 insertions(+), 1 deletion(-) + +diff --git a/jstests/auth/authentication_restrictions_role.js b/jstests/auth/authentication_restrictions_role.js +index 3f23cfdcb921..691491a0765c 100644 +--- a/jstests/auth/authentication_restrictions_role.js ++++ b/jstests/auth/authentication_restrictions_role.js +@@ -42,6 +42,14 @@ + assert.commandWorked(admin.runCommand({createRole: "role3", roles: [], privileges: []})); + + print("=== Role creation tests"); ++ print("When a role is updated, it retains authenticationRestrictions"); ++ assert.commandWorked(admin.runCommand({updateRole: "role2", roles: ["root"]})); ++ const role2Info = assert.commandWorked( ++ admin.runCommand({rolesInfo: "role2", showAuthenticationRestrictions: true})); ++ printjson(role2Info); ++ assert.eq(JSON.stringify([[{clientSource: ["127.0.0.1/32"]}]]), ++ JSON.stringify(role2Info.roles[0].authenticationRestrictions)); ++ + print( + "When a client creates roles with empty authenticationRestrictions, the operation succeeds, though it has no effect"); + assert.commandWorked(admin.runCommand( +diff --git a/src/mongo/db/auth/role_graph.cpp b/src/mongo/db/auth/role_graph.cpp +index fc55b6a1d43b..03776361e3ca 100644 +--- a/src/mongo/db/auth/role_graph.cpp ++++ b/src/mongo/db/auth/role_graph.cpp +@@ -590,6 +590,15 @@ Status RoleGraph::getBSONForRole(RoleGraph* graph, + uassertStatusOK(rolesArrayElement.pushBack(roleObj)); + } + ++ // Build authentication restrictions ++ auto restrictions = graph->getDirectAuthenticationRestrictions(roleName); ++ mutablebson::Element authenticationRestrictionsElement = ++ result.getDocument().makeElementArray("authenticationRestrictions"); ++ uassertStatusOK(result.pushBack(authenticationRestrictionsElement)); ++ if (restrictions) { ++ uassertStatusOK(authenticationRestrictionsElement.setValueArray(restrictions->toBSON())); ++ } ++ + return Status::OK(); + } catch (...) { + return exceptionToStatus(); +diff --git a/src/mongo/db/auth/role_graph_test.cpp b/src/mongo/db/auth/role_graph_test.cpp +index 0e22892f4ebf..e763b0929f99 100644 +--- a/src/mongo/db/auth/role_graph_test.cpp ++++ b/src/mongo/db/auth/role_graph_test.cpp +@@ -35,6 +35,7 @@ + #include + + #include "mongo/bson/mutable/document.h" ++#include "mongo/db/auth/address_restriction.h" + #include "mongo/db/auth/role_graph.h" + #include "mongo/unittest/unittest.h" + #include "mongo/util/mongoutils/str.h" +@@ -48,16 +49,21 @@ TEST(RoleParsingTest, BuildRoleBSON) { + RoleName roleA("roleA", "dbA"); + RoleName roleB("roleB", "dbB"); + RoleName roleC("roleC", "dbC"); ++ RoleName roleD("roleD", "dbD"); + ActionSet actions; + actions.addAction(ActionType::find); + actions.addAction(ActionType::insert); ++ SharedRestrictionDocument restrictions = uassertStatusOK(parseAuthenticationRestriction( ++ BSON_ARRAY(BSON("clientSource" << BSON_ARRAY("127.0.0.1"))))); + + ASSERT_OK(graph.createRole(roleA)); + ASSERT_OK(graph.createRole(roleB)); + ASSERT_OK(graph.createRole(roleC)); ++ ASSERT_OK(graph.createRole(roleD)); + + ASSERT_OK(graph.addRoleToRole(roleA, roleC)); + ASSERT_OK(graph.addRoleToRole(roleA, roleB)); ++ ASSERT_OK(graph.addRoleToRole(roleA, roleD)); + ASSERT_OK(graph.addRoleToRole(roleB, roleC)); + + ASSERT_OK(graph.addPrivilegeToRole( +@@ -66,6 +72,7 @@ TEST(RoleParsingTest, BuildRoleBSON) { + roleB, Privilege(ResourcePattern::forExactNamespace(NamespaceString("dbB.foo")), actions))); + ASSERT_OK( + graph.addPrivilegeToRole(roleC, Privilege(ResourcePattern::forClusterResource(), actions))); ++ ASSERT_OK(graph.replaceRestrictionsForRole(roleD, restrictions)); + ASSERT_OK(graph.recomputePrivilegeData()); + + +@@ -78,6 +85,8 @@ TEST(RoleParsingTest, BuildRoleBSON) { + ASSERT_EQUALS("roleA", roleDoc["role"].String()); + ASSERT_EQUALS("dbA", roleDoc["db"].String()); + ++ ASSERT_TRUE(roleDoc["authenticationRestrictions"].Array().empty()); ++ + std::vector privs = roleDoc["privileges"].Array(); + ASSERT_EQUALS(1U, privs.size()); + ASSERT_EQUALS("", privs[0].Obj()["resource"].Obj()["db"].String()); +@@ -89,7 +98,7 @@ TEST(RoleParsingTest, BuildRoleBSON) { + ASSERT_EQUALS("insert", actionElements[1].String()); + + std::vector roles = roleDoc["roles"].Array(); +- ASSERT_EQUALS(2U, roles.size()); ++ ASSERT_EQUALS(3U, roles.size()); + ASSERT_EQUALS("roleC", roles[0].Obj()["role"].String()); + ASSERT_EQUALS("dbC", roles[0].Obj()["db"].String()); + ASSERT_EQUALS("roleB", roles[1].Obj()["role"].String()); +@@ -104,6 +113,8 @@ TEST(RoleParsingTest, BuildRoleBSON) { + ASSERT_EQUALS("roleB", roleDoc["role"].String()); + ASSERT_EQUALS("dbB", roleDoc["db"].String()); + ++ ASSERT_TRUE(roleDoc["authenticationRestrictions"].Array().empty()); ++ + privs = roleDoc["privileges"].Array(); + ASSERT_EQUALS(1U, privs.size()); + ASSERT_EQUALS("dbB", privs[0].Obj()["resource"].Obj()["db"].String()); +@@ -128,6 +139,8 @@ TEST(RoleParsingTest, BuildRoleBSON) { + ASSERT_EQUALS("roleC", roleDoc["role"].String()); + ASSERT_EQUALS("dbC", roleDoc["db"].String()); + ++ ASSERT_TRUE(roleDoc["authenticationRestrictions"].Array().empty()); ++ + privs = roleDoc["privileges"].Array(); + ASSERT_EQUALS(1U, privs.size()); + ASSERT(privs[0].Obj()["resource"].Obj()["cluster"].Bool()); +@@ -140,6 +153,27 @@ TEST(RoleParsingTest, BuildRoleBSON) { + + roles = roleDoc["roles"].Array(); + ASSERT_EQUALS(0U, roles.size()); ++ ++ // Role D ++ doc.reset(); ++ ASSERT_OK(RoleGraph::getBSONForRole(&graph, roleD, doc.root())); ++ roleDoc = doc.getObject(); ++ ++ ASSERT_EQUALS("dbD.roleD", roleDoc["_id"].String()); ++ ASSERT_EQUALS("roleD", roleDoc["role"].String()); ++ ASSERT_EQUALS("dbD", roleDoc["db"].String()); ++ ++ ASSERT_FALSE(roleDoc["authenticationRestrictions"].Array().empty()); ++ auto restrictionObj = BSONArray(roleDoc["authenticationRestrictions"].Obj()); ++ SharedRestrictionDocument parsedRestrictions = ++ uassertStatusOK(parseAuthenticationRestriction(restrictionObj)); ++ ASSERT_EQ(restrictions->toString(), parsedRestrictions->toString()); ++ ++ privs = roleDoc["privileges"].Array(); ++ ASSERT_TRUE(privs.empty()); ++ ++ roles = roleDoc["roles"].Array(); ++ ASSERT_EQUALS(0U, roles.size()); + } + + // Tests adding and removing roles from other roles, the RoleNameIterator, and the diff --git a/mongodb.spec b/mongodb.spec index 62dd323657ca69129708ba8a302837f281dd432e..1efa8610482e02dc1d276a5c1edd6c77f82511a7 100644 --- a/mongodb.spec +++ b/mongodb.spec @@ -2,7 +2,7 @@ Name: mongodb Version: 4.0.1 -Release: 3 +Release: 4 Summary: The global cloud database service for modern applications License: AGPLv3 and zlib and ASL 2.0 URL: http://www.mongodb.org @@ -11,6 +11,7 @@ Source1: mongod.conf Source2: mongod.service Patch0000: inconsistent-tabs.patch Patch0001: python3-buildscripts-tests.patch +Patch6000: CVE-2020-7921.patch BuildRequires: gcc-c++ >= 5.3.0 boost-devel >= 1.56 gperftools-devel libpcap-devel libstemmer-devel BuildRequires: openssl-devel pcre-devel python3-scons snappy-devel yaml-cpp-devel zlib-devel systemd BuildRequires: valgrind-devel libcurl-devel python3-devel python3-yaml python3-requests python3-cheetah @@ -138,6 +139,12 @@ fi %{_mandir}/man1/{mongo.1*,mongod.1*,mongos.1*} %changelog +* Thu May 21 2020 yaokai13 - 4.0.1-4 +- Type: cves +- ID: CVE-2020-7921 +- SUG: restart +- DESC: fix CVE-2020-7921 + * Mon Feb 13 2020 Ling Yang - 4.0.1-3 - Fixed mongodb-test package build errors