[CXX-2028] Explicit write concern is incorrectly applied to collection::find_one_and_* methods Created: 27/May/20  Updated: 28/Oct/23  Resolved: 01/Jun/20

Status: Closed
Project: C++ Driver
Component/s: None
Affects Version/s: 3.2.0-rc0
Fix Version/s: 3.2.1, 3.3.2, 3.4.2, 3.5.1, 3.6.0-rc0, 3.6.0

Type: Bug Priority: Critical - P2
Reporter: Wan Bachtiar Assignee: Clyde Bazile III (Inactive)
Resolution: Fixed Votes: 1
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Issue Links:
Related
is related to CXX-1085 Inconsistent API for operation level ... Closed
is related to CXX-1349 Implement manual read/write concern t... Closed
Case:

 Description   

CVE ID: CVE-2021-32050

Title: Some MongoDB Drivers may publish events containing authentication-related data to a command listener configured by an application

Description:

Some MongoDB Drivers may erroneously publish events containing authentication-related data to a command listener configured by an application. The published events may contain security-sensitive data when specific authentication-related commands are executed.

Without due care, an application may inadvertently expose this sensitive information, e.g., by writing it to a log file. This issue only arises if an application enables the command listener feature (this is not enabled by default).

This issue affects the MongoDB C Driver 1.0.0 prior to 1.17.7, MongoDB PHP Driver 1.0.0 prior to 1.9.2, MongoDB Swift Driver 1.0.0 prior to 1.1.1, MongoDB Node.js Driver 3.6 prior to 3.6.10, MongoDB Node.js Driver 4.0 prior to 4.17.0 and MongoDB Node.js Driver 5.0 prior to 5.8.0. This issue also affects users of the MongoDB C++ Driver dependent on the C driver 1.0.0 prior to 1.17.7 (C++ driver prior to 3.7.0).

CVSS Score: 4.2

CVSS:3.1/AV:L/AC:L/PR:H/UI:R/S:U/C:H/I:N/A:N 

CWE ID: CWE-200 Exposure of Sensitive Information to an Unauthorized Actor 

Exact affected versions:
MongoDB C Driver 1.0.0 prior to 1.17.7

MongoDB C++ Driver 3.0.0 prior to 3.7.0

MongoDB PHP Driver 1.0.0 prior to 1.9.2

MongoDB Swift Driver 1.0.0 prior to 1.1.1

MongoDB Node.js Driver 3.6 prior to  3.6.10

MongoDB Node.js Driver 4.0 prior to 4.17.0

MongoDB Node.js Driver 5.0 prior to 5.8.0 

Is fixed version available:  Yes

How the issue was discovered: Internally



 Comments   
Comment by Githook User [ 01/Jun/20 ]

Author:

{'name': 'Mohammad Ghazanfar', 'email': 'ghazanfar.isc@gmail.com', 'username': 'MohammadGhazanfar'}

Message: CXX-2028 fix writeConcern population in find_and_modify
Branch: master
https://github.com/mongodb/mongo-cxx-driver/commit/cf4faedfa96c2b63e846a0ec169d458dfc84dbd4

Comment by Mohammad Ghazanfar [ 01/Jun/20 ]

Hi @kevin

I have submitted a PR here: https://github.com/mongodb/mongo-cxx-driver/pull/657

Comment by Mohammad Ghazanfar [ 29/May/20 ]

Thanks for verifying this Kevin !
Yes, I will go ahead and submit a fix for this and leave an update here.

Comment by Kevin Albertson [ 28/May/20 ]

Hello mohammad.ghazanfar@nutanix.com,

Thank you for the detailed report! I agree with your analysis. Your proposed fix looks right to me. Other code paths that append a write concern appear to do the same (example). If you would like to submit a PR with the fix, we'd be happy to take a look. Otherwise we will fix and test this as soon as we are able to.

Comment by Mohammad Ghazanfar [ 28/May/20 ]

I was able to fix this with the below change to this file: https://github.com/mongodb/mongo-cxx-driver/blob/b82fda7ab308a9c072701c9ab278cd4fe81bbb28/src/mongocxx/collection.cpp

 

116 -        extra.append(concatenate(options.write_concern()->to_document()));
116 +        extra.append(kvp("writeConcern", options.write_concern()->to_document()));

 

Feel free to let me know if a similar change is needed else where.

 

Comment by Mohammad Ghazanfar [ 28/May/20 ]

Hi !

I will document my findings here. Feel free to reach out to me for any questions or clarifications.

TL;DR: Mongo C++ Driver doesn’t populate the `writeConcern` properly while sending a `find_one_and_update` request to the mongo server. This was silently happening up until mongo 4.2 introduced stricter checks on the received payload. After which, a failure is seen. 

MONGO 4.0

C++ Driver 3.4 invoking find_one_and_update

With my server not being replicated, I would expect the below code to fail,

      auto criteria = make_document(kvp("x", "foo"));
      auto update = make_document(kvp("$set", make_document(kvp("x", "bar"))));
 
      auto write_concern = mongocxx::write_concern{};
      write_concern.journal(true);
      write_concern.nodes(3);     // Server has only one node.
 
      std::cout << "Setting options" << std::endl;
      auto options = mongocxx::options::find_one_and_update()
        .write_concern(std::move(write_concern))
        .return_document(mongocxx::options::return_document::k_before);
 
      std::cout << "Invoking find_one_and_update" << std::endl;
      coll.find_one_and_update(
        criteria.view(),
        update.view(),
        options);

However, the above code executes without any issues. An inspection of the mongo server logs shows, that the payload received by the server doesn’t seem to conform to the format reported here: https://docs.mongodb.com/manual/reference/method/db.collection.findAndModify/

Specifically, writeConcern, which is expected to be of the form,

...writeConcern: {w: 3, j: true}... is received as ...w: 3, j: true…

Log messages from the mongo server.

Below are log messages from the mongo server.

2020-05-27T16:29:42.091+0000 D COMMAND  [conn2] run command mydb.$cmd { findAndModify: "my_collection", query:

Unknown macro: { x}

, update: { $set:

Unknown macro: { x}

}, w: 3, j: true, $db: "mydb", lsid: { id: UUID("302d30ec-8de7-4681-b26a-17ce371db241") } }

2020-05-27T16:29:42.091+0000 D STORAGE  [conn2] NamespaceUUIDCache: registered namespace mydb.my_collection with UUID 4f8571d6-3dea-4ff7-b1d8-58eb7d0b46d5

2020-05-27T16:29:42.091+0000 D QUERY    [conn2] Beginning planning...

=============================

...

2020-05-27T16:29:42.091+0000 D REPL     [conn2] Waiting for write concern. OpTime: { ts: Timestamp(0, 0), t: -1 }, write concern: { w: 1, wtimeout: 0 }

From the logs, it looks like mongo went ahead with the operation while ignoring the wrongly populated writeConcern - this has been fixed with mongo 4.2. However, it is a concern because it used values for j and w different from what I explicitly provided.

 

Verifications using pymongo 3.10

The pymongo driver seems to be working as expected. The below snippet was used for verification.

>>> import pymongo
>>> client = pymongo.MongoClient()
>>> db = client.mydb
>>> collection = db.get_collection('my_collection', write_concern=pymongo.write_concern.WriteConcern(w=3, j=True))
>>> collection.find_one_and_update(filter=\{'x':'foo'}, update=\{'$set':{'x':'bar'}})
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
...
    raise OperationFailure(msg % errmsg, code, response)
pymongo.errors.OperationFailure: cannot use 'w' > 1 when a host is not replicated

Messages from mongo logs show the difference in the payload received by the server when using the python driver and the C++ driver.

Below are log messages from the mongo server.

2020-05-27T16:17:00.687+0000 D COMMAND  [conn4] run command mydb.$cmd { findAndModify: "my_collection", query:

Unknown macro: { x}

, new: false, update: { $set:

Unknown macro: { x}

}, upsert: false, writeConcern: { j: true, w: 3 }, lsid: { id: UUID("784ac2cd-a4a1-4027-868a-30b9abefcaa3") }, $db: "mydb", $readPreference: { mode: "primary" } }

2020-05-27T16:17:00.687+0000 D -        [conn4] User Assertion: BadValue: cannot use 'w' > 1 when a host is not replicated src/mongo/db/service_entry_point_common.cpp 509

 


MONGO 4.2.6

Mongo 4.2 has added checks on the received payload. These added checks expose the above discussed problem.

The below code, which wrongly succeeds with mongo server 4.0, fails as expected against mongo server 4.2. This was compiled with the Mongo C++ 3.5 driver.

      auto criteria = make_document(kvp("x", "foo"));
      auto update = make_document(kvp("$set", make_document(kvp("x", "bar"))));
 
      auto write_concern = mongocxx::write_concern{};
      write_concern.journal(true);
      write_concern.acknowledge_level(
        mongocxx::write_concern::level::k_majority);
 
      std::cout << "Setting options" << std::endl;
      auto options = mongocxx::options::find_one_and_update()
        .write_concern(std::move(write_concern))
        .return_document(mongocxx::options::return_document::k_before);
 
      std::cout << "Invoking find_one_and_update" << std::endl;
      coll.find_one_and_update(
        criteria.view(),
        update.view(),
        options);

Error message:

terminate called after throwing an instance of 'mongocxx::v_noabi::write_exception'
  what():  BSON field 'j' is an unknown field.: generic server error
Aborted

Logs messages show that the writeConcern isn’t populated correctly,

Below are log messages from the mongo server.

2020-05-28T19:47:16.824+0000 D2 COMMAND  [conn7] run command mydb.$cmd { findAndModify: "my_collection", query:

Unknown macro: { x}

, update: { $set:

Unknown macro: { x}

}, w: "majority", j: true, $db: "mydb", lsid: { id: UUID("cbb0073c-e491-4e29-8593-3c5c5c934712") } }

2020-05-28T19:47:16.824+0000 D1 -        [conn7] User Assertion: Location51177: BSON field 'j' is an unknown field. src/mongo/db/commands/find_and_modify.cpp 315

2020-05-28T19:47:16.831+0000 D1 COMMAND  [conn7] assertion while executing command 'findAndModify' on database 'mydb' with arguments '{ findAndModify: "my_collection", query:

Unknown macro: { x}

, update: { $set:

Unknown macro: { x}

}, w: "majority", j: true, $db: "mydb", lsid: { id: UUID("cbb0073c-e491-4e29-8593-3c5c5c934712") } }': Location51177: BSON field 'j' is an unknown field.

Env Details,

Comment by Wan Bachtiar [ 27/May/20 ]

Worth noting that since server v3.2 write concern "majority" implies j:true if the writeConcernMajorityJournalDefault is true (default value)

Generated at Wed Feb 07 22:04:39 UTC 2024 using Jira 9.7.1#970001-sha1:2222b88b221c4928ef0de3161136cc90c8356a66.