diff options
Diffstat (limited to 'src/mongo/db/fle_crud.cpp')
-rw-r--r-- | src/mongo/db/fle_crud.cpp | 143 |
1 files changed, 114 insertions, 29 deletions
diff --git a/src/mongo/db/fle_crud.cpp b/src/mongo/db/fle_crud.cpp index a847304b55f..58136f31c44 100644 --- a/src/mongo/db/fle_crud.cpp +++ b/src/mongo/db/fle_crud.cpp @@ -190,16 +190,20 @@ std::pair<FLEBatchResult, write_ops::InsertCommandReply> processInsert( auto edcNss = insertRequest.getNamespace(); auto ei = insertRequest.getEncryptionInformation().get(); + bool bypassDocumentValidation = + insertRequest.getWriteCommandRequestBase().getBypassDocumentValidation(); + auto efc = EncryptionInformationHelpers::getAndValidateSchema(edcNss, ei); auto documents = insertRequest.getDocuments(); // TODO - how to check if a document will be too large??? + uassert(6371202, "Only single insert batches are supported in Queryable Encryption", documents.size() == 1); auto document = documents[0]; - EDCServerCollection::validateEncryptedFieldInfo(document, efc); + EDCServerCollection::validateEncryptedFieldInfo(document, efc, bypassDocumentValidation); auto serverPayload = std::make_shared<std::vector<EDCServerPayloadInfo>>( EDCServerCollection::getEncryptedFieldInfo(document)); @@ -223,8 +227,8 @@ std::pair<FLEBatchResult, write_ops::InsertCommandReply> processInsert( auto swResult = trun->runNoThrow( opCtx, - [sharedInsertBlock, reply, ownedDocument](const txn_api::TransactionClient& txnClient, - ExecutorPtr txnExec) { + [sharedInsertBlock, reply, ownedDocument, bypassDocumentValidation]( + const txn_api::TransactionClient& txnClient, ExecutorPtr txnExec) { FLEQueryInterfaceImpl queryImpl(txnClient, getGlobalServiceContext()); auto [edcNss2, efc2, serverPayload2, stmtId2] = *sharedInsertBlock.get(); @@ -234,8 +238,13 @@ std::pair<FLEBatchResult, write_ops::InsertCommandReply> processInsert( fleCrudHangPreInsert.pauseWhileSet(); } - *reply = uassertStatusOK(processInsert( - &queryImpl, edcNss2, *serverPayload2.get(), efc2, stmtId2, ownedDocument)); + *reply = uassertStatusOK(processInsert(&queryImpl, + edcNss2, + *serverPayload2.get(), + efc2, + stmtId2, + ownedDocument, + bypassDocumentValidation)); if (MONGO_unlikely(fleCrudHangInsert.shouldFail())) { LOGV2(6371903, "Hanging due to fleCrudHangInsert fail point"); @@ -441,7 +450,8 @@ void processFieldsForInsert(FLEQueryInterface* queryImpl, const NamespaceString& edcNss, std::vector<EDCServerPayloadInfo>& serverPayload, const EncryptedFieldConfig& efc, - int32_t* pStmtId) { + int32_t* pStmtId, + bool bypassDocumentValidation) { NamespaceString nssEsc(edcNss.db(), efc.getEscCollection().get()); @@ -509,7 +519,8 @@ void processFieldsForInsert(FLEQueryInterface* queryImpl, ECOCCollection::generateDocument(payload.fieldPathName, payload.payload.getEncryptedTokens()), pStmtId, - false)); + false, + bypassDocumentValidation)); checkWriteErrors(ecocInsertReply); } } @@ -719,9 +730,11 @@ StatusWith<write_ops::InsertCommandReply> processInsert( std::vector<EDCServerPayloadInfo>& serverPayload, const EncryptedFieldConfig& efc, int32_t stmtId, - BSONObj document) { + BSONObj document, + bool bypassDocumentValidation) { - processFieldsForInsert(queryImpl, edcNss, serverPayload, efc, &stmtId); + processFieldsForInsert( + queryImpl, edcNss, serverPayload, efc, &stmtId, bypassDocumentValidation); auto finalDoc = EDCServerCollection::finalizeForInsert(document, serverPayload); @@ -792,6 +805,9 @@ write_ops::UpdateCommandReply processUpdate(FLEQueryInterface* queryImpl, auto tokenMap = EncryptionInformationHelpers::getDeleteTokens(edcNss, ei); const auto updateOpEntry = updateRequest.getUpdates()[0]; + auto bypassDocumentValidation = + updateRequest.getWriteCommandRequestBase().getBypassDocumentValidation(); + const auto updateModification = updateOpEntry.getU(); int32_t stmtId = getStmtIdForWriteAt(updateRequest, 0); @@ -799,16 +815,26 @@ write_ops::UpdateCommandReply processUpdate(FLEQueryInterface* queryImpl, // Step 1 ---- std::vector<EDCServerPayloadInfo> serverPayload; auto newUpdateOpEntry = updateRequest.getUpdates()[0]; - newUpdateOpEntry.setQ(fle::rewriteEncryptedFilterInsideTxn( - queryImpl, updateRequest.getDbName(), efc, expCtx, newUpdateOpEntry.getQ())); + + auto highCardinalityModeAllowed = newUpdateOpEntry.getUpsert() + ? fle::HighCardinalityModeAllowed::kDisallow + : fle::HighCardinalityModeAllowed::kAllow; + + newUpdateOpEntry.setQ(fle::rewriteEncryptedFilterInsideTxn(queryImpl, + updateRequest.getDbName(), + efc, + expCtx, + newUpdateOpEntry.getQ(), + highCardinalityModeAllowed)); if (updateModification.type() == write_ops::UpdateModification::Type::kModifier) { auto updateModifier = updateModification.getUpdateModifier(); auto setObject = updateModifier.getObjectField("$set"); - EDCServerCollection::validateEncryptedFieldInfo(setObject, efc); + EDCServerCollection::validateEncryptedFieldInfo(setObject, efc, bypassDocumentValidation); serverPayload = EDCServerCollection::getEncryptedFieldInfo(updateModifier); - processFieldsForInsert(queryImpl, edcNss, serverPayload, efc, &stmtId); + processFieldsForInsert( + queryImpl, edcNss, serverPayload, efc, &stmtId, bypassDocumentValidation); // Step 2 ---- auto pushUpdate = EDCServerCollection::finalizeForUpdate(updateModifier, serverPayload); @@ -817,10 +843,12 @@ write_ops::UpdateCommandReply processUpdate(FLEQueryInterface* queryImpl, pushUpdate, write_ops::UpdateModification::ClassicTag(), false)); } else { auto replacementDocument = updateModification.getUpdateReplacement(); - EDCServerCollection::validateEncryptedFieldInfo(replacementDocument, efc); + EDCServerCollection::validateEncryptedFieldInfo( + replacementDocument, efc, bypassDocumentValidation); serverPayload = EDCServerCollection::getEncryptedFieldInfo(replacementDocument); - processFieldsForInsert(queryImpl, edcNss, serverPayload, efc, &stmtId); + processFieldsForInsert( + queryImpl, edcNss, serverPayload, efc, &stmtId, bypassDocumentValidation); // Step 2 ---- auto safeContentReplace = @@ -835,6 +863,8 @@ write_ops::UpdateCommandReply processUpdate(FLEQueryInterface* queryImpl, newUpdateRequest.setUpdates({newUpdateOpEntry}); newUpdateRequest.getWriteCommandRequestBase().setStmtIds(boost::none); newUpdateRequest.getWriteCommandRequestBase().setStmtId(stmtId); + newUpdateRequest.getWriteCommandRequestBase().setBypassDocumentValidation( + bypassDocumentValidation); ++stmtId; auto [updateReply, originalDocument] = @@ -892,6 +922,10 @@ FLEBatchResult processFLEBatch(OperationContext* opCtx, BatchedCommandResponse* response, boost::optional<OID> targetEpoch) { + if (request.getWriteCommandRequestBase().getEncryptionInformation()->getCrudProcessed()) { + return FLEBatchResult::kNotProcessed; + } + // TODO (SERVER-65077): Remove FCV check once 6.0 is released uassert(6371209, "Queryable Encryption is only supported when FCV supports 6.0", @@ -970,19 +1004,25 @@ std::unique_ptr<BatchedCommandRequest> processFLEBatchExplain( request.getNS(), deleteRequest.getEncryptionInformation().get(), newDeleteOp.getQ(), - &getTransactionWithRetriesForMongoS)); + &getTransactionWithRetriesForMongoS, + fle::HighCardinalityModeAllowed::kAllow)); deleteRequest.setDeletes({newDeleteOp}); deleteRequest.getWriteCommandRequestBase().setEncryptionInformation(boost::none); return std::make_unique<BatchedCommandRequest>(deleteRequest); } else if (request.getBatchType() == BatchedCommandRequest::BatchType_Update) { auto updateRequest = request.getUpdateRequest(); auto newUpdateOp = updateRequest.getUpdates()[0]; + auto highCardinalityModeAllowed = newUpdateOp.getUpsert() + ? fle::HighCardinalityModeAllowed::kDisallow + : fle::HighCardinalityModeAllowed::kAllow; + newUpdateOp.setQ(fle::rewriteQuery(opCtx, getExpCtx(newUpdateOp), request.getNS(), updateRequest.getEncryptionInformation().get(), newUpdateOp.getQ(), - &getTransactionWithRetriesForMongoS)); + &getTransactionWithRetriesForMongoS, + highCardinalityModeAllowed)); updateRequest.setUpdates({newUpdateOp}); updateRequest.getWriteCommandRequestBase().setEncryptionInformation(boost::none); return std::make_unique<BatchedCommandRequest>(updateRequest); @@ -1005,10 +1045,22 @@ write_ops::FindAndModifyCommandReply processFindAndModify( auto newFindAndModifyRequest = findAndModifyRequest; + const auto bypassDocumentValidation = + findAndModifyRequest.getBypassDocumentValidation().value_or(false); + // Step 0 ---- // Rewrite filter - newFindAndModifyRequest.setQuery(fle::rewriteEncryptedFilterInsideTxn( - queryImpl, edcNss.db(), efc, expCtx, findAndModifyRequest.getQuery())); + auto highCardinalityModeAllowed = findAndModifyRequest.getUpsert().value_or(false) + ? fle::HighCardinalityModeAllowed::kDisallow + : fle::HighCardinalityModeAllowed::kAllow; + + newFindAndModifyRequest.setQuery( + fle::rewriteEncryptedFilterInsideTxn(queryImpl, + edcNss.db(), + efc, + expCtx, + findAndModifyRequest.getQuery(), + highCardinalityModeAllowed)); // Make sure not to inherit the command's writeConcern, this should be set at the transaction // level. @@ -1025,9 +1077,11 @@ write_ops::FindAndModifyCommandReply processFindAndModify( if (updateModification.type() == write_ops::UpdateModification::Type::kModifier) { auto updateModifier = updateModification.getUpdateModifier(); auto setObject = updateModifier.getObjectField("$set"); - EDCServerCollection::validateEncryptedFieldInfo(setObject, efc); + EDCServerCollection::validateEncryptedFieldInfo( + setObject, efc, bypassDocumentValidation); serverPayload = EDCServerCollection::getEncryptedFieldInfo(updateModifier); - processFieldsForInsert(queryImpl, edcNss, serverPayload, efc, &stmtId); + processFieldsForInsert( + queryImpl, edcNss, serverPayload, efc, &stmtId, bypassDocumentValidation); auto pushUpdate = EDCServerCollection::finalizeForUpdate(updateModifier, serverPayload); @@ -1036,10 +1090,12 @@ write_ops::FindAndModifyCommandReply processFindAndModify( pushUpdate, write_ops::UpdateModification::ClassicTag(), false); } else { auto replacementDocument = updateModification.getUpdateReplacement(); - EDCServerCollection::validateEncryptedFieldInfo(replacementDocument, efc); + EDCServerCollection::validateEncryptedFieldInfo( + replacementDocument, efc, bypassDocumentValidation); serverPayload = EDCServerCollection::getEncryptedFieldInfo(replacementDocument); - processFieldsForInsert(queryImpl, edcNss, serverPayload, efc, &stmtId); + processFieldsForInsert( + queryImpl, edcNss, serverPayload, efc, &stmtId, bypassDocumentValidation); // Step 2 ---- auto safeContentReplace = @@ -1131,8 +1187,17 @@ write_ops::FindAndModifyCommandRequest processFindAndModifyExplain( auto efc = EncryptionInformationHelpers::getAndValidateSchema(edcNss, ei); auto newFindAndModifyRequest = findAndModifyRequest; - newFindAndModifyRequest.setQuery(fle::rewriteEncryptedFilterInsideTxn( - queryImpl, edcNss.db(), efc, expCtx, findAndModifyRequest.getQuery())); + auto highCardinalityModeAllowed = findAndModifyRequest.getUpsert().value_or(false) + ? fle::HighCardinalityModeAllowed::kDisallow + : fle::HighCardinalityModeAllowed::kAllow; + + newFindAndModifyRequest.setQuery( + fle::rewriteEncryptedFilterInsideTxn(queryImpl, + edcNss.db(), + efc, + expCtx, + findAndModifyRequest.getQuery(), + highCardinalityModeAllowed)); newFindAndModifyRequest.setEncryptionInformation(boost::none); return newFindAndModifyRequest; @@ -1234,10 +1299,23 @@ uint64_t FLEQueryInterfaceImpl::countDocuments(const NamespaceString& nss) { } StatusWith<write_ops::InsertCommandReply> FLEQueryInterfaceImpl::insertDocument( - const NamespaceString& nss, BSONObj obj, StmtId* pStmtId, bool translateDuplicateKey) { + const NamespaceString& nss, + BSONObj obj, + StmtId* pStmtId, + bool translateDuplicateKey, + bool bypassDocumentValidation) { write_ops::InsertCommandRequest insertRequest(nss); insertRequest.setDocuments({obj}); + EncryptionInformation encryptionInformation; + encryptionInformation.setCrudProcessed(true); + + // We need to set an empty BSON object here for the schema. + encryptionInformation.setSchema(BSONObj()); + insertRequest.getWriteCommandRequestBase().setEncryptionInformation(encryptionInformation); + insertRequest.getWriteCommandRequestBase().setBypassDocumentValidation( + bypassDocumentValidation); + int32_t stmtId = *pStmtId; if (stmtId != kUninitializedStmtId) { (*pStmtId)++; @@ -1322,6 +1400,7 @@ std::pair<write_ops::UpdateCommandReply, BSONObj> FLEQueryInterfaceImpl::updateW findAndModifyRequest.setLet( mergeLetAndCVariables(updateRequest.getLet(), updateOpEntry.getC())); findAndModifyRequest.setStmtId(updateRequest.getStmtId()); + findAndModifyRequest.setBypassDocumentValidation(updateRequest.getBypassDocumentValidation()); auto ei2 = ei; ei2.setCrudProcessed(true); @@ -1363,9 +1442,15 @@ std::pair<write_ops::UpdateCommandReply, BSONObj> FLEQueryInterfaceImpl::updateW } write_ops::UpdateCommandReply FLEQueryInterfaceImpl::update( - const NamespaceString& nss, - int32_t stmtId, - const write_ops::UpdateCommandRequest& updateRequest) { + const NamespaceString& nss, int32_t stmtId, write_ops::UpdateCommandRequest& updateRequest) { + + invariant(!updateRequest.getWriteCommandRequestBase().getEncryptionInformation()); + + EncryptionInformation encryptionInformation; + encryptionInformation.setCrudProcessed(true); + + encryptionInformation.setSchema(BSONObj()); + updateRequest.getWriteCommandRequestBase().setEncryptionInformation(encryptionInformation); dassert(updateRequest.getStmtIds().value_or(std::vector<int32_t>()).empty()); |