Skip to content

Commit 984022e

Browse files
CDRIVER-4657 Prohibit extra fields when matching command subdocuments (#1297)
* prohibit extra fields in command subdocuments * call visitor_fn when matching arrays To check documents in arrays for extra fields. * copy fle2v2-CreateCollection from specifications commit 11af5ba6f2fea610940ddc644d3cdef54a697e73 * skip check for on `multi` and `upsert` in updates * silence scan-build * Apply suggested comment rewordings Co-authored-by: Ezra Chung <[email protected]> * document handling of visitor_fn return * remove unnecessary `void*` cast --------- Co-authored-by: Ezra Chung <[email protected]>
1 parent 3165a35 commit 984022e

File tree

3 files changed

+132
-20
lines changed

3 files changed

+132
-20
lines changed

src/libmongoc/tests/json-test-monitoring.c

Lines changed: 114 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,47 @@ apm_match_visitor (match_ctx_t *ctx,
336336
visitor_ctx->command_name = bson_strdup (bson_iter_key (doc_iter));
337337
}
338338

339+
// Subdocuments in `command` should not have extra fields.
340+
if (NULL != strstr (ctx->path, ".command") && doc_iter) {
341+
if (BSON_ITER_HOLDS_DOCUMENT (doc_iter) &&
342+
BSON_ITER_HOLDS_DOCUMENT (pattern_iter)) {
343+
bson_t doc_subdoc;
344+
bson_iter_bson (doc_iter, &doc_subdoc);
345+
bson_iter_t doc_subdoc_iter;
346+
bson_iter_init (&doc_subdoc_iter, &doc_subdoc);
347+
while (bson_iter_next (&doc_subdoc_iter)) {
348+
const char *subdoc_key = bson_iter_key (&doc_subdoc_iter);
349+
350+
bson_t pattern_subdoc;
351+
bson_iter_bson (pattern_iter, &pattern_subdoc);
352+
bson_iter_t pattern_subdoc_iter;
353+
354+
bool skip = false;
355+
if (ends_with (ctx->path, "updates") &&
356+
(0 == strcmp ("multi", subdoc_key) ||
357+
0 == strcmp ("upsert", subdoc_key))) {
358+
// libmongoc includes `multi: false` and `upsert: false`.
359+
// Some tests do not include `multi: false` and `upsert: false`
360+
// in expectations. See DRIVERS-2271 and DRIVERS-976.
361+
skip = true;
362+
}
363+
364+
if (!skip && !bson_iter_init_find (&pattern_subdoc_iter,
365+
&pattern_subdoc,
366+
subdoc_key)) {
367+
match_err (
368+
ctx,
369+
"unexpected extra field '%s' in captured event "
370+
"command subdocument of field '%s'. pattern_subdoc=%s",
371+
subdoc_key,
372+
key,
373+
tmp_json (&pattern_subdoc));
374+
return MATCH_ACTION_ABORT;
375+
}
376+
}
377+
}
378+
}
379+
339380
if (IS_COMMAND ("find") || IS_COMMAND ("aggregate")) {
340381
/* New query. Next server reply or getMore will set cursor_id. */
341382
visitor_ctx->cursor_id = 0;
@@ -513,7 +554,7 @@ check_json_apm_events (json_test_ctx_t *ctx, const bson_t *expectations)
513554
match_ctx.retain_dots_in_keys = true;
514555
match_ctx.allow_placeholders = true;
515556
match_ctx.visitor_fn = apm_match_visitor;
516-
match_ctx.visitor_ctx = (void *) &apm_match_visitor_ctx;
557+
match_ctx.visitor_ctx = &apm_match_visitor_ctx;
517558

518559
allow_subset = ctx->config->command_monitoring_allow_subset;
519560

@@ -608,7 +649,7 @@ test_apm_matching (void)
608649
"}";
609650

610651
match_ctx.visitor_fn = apm_match_visitor;
611-
match_ctx.visitor_ctx = (void *) &match_visitor_ctx;
652+
match_ctx.visitor_ctx = &match_visitor_ctx;
612653

613654
BSON_ASSERT (match_bson_with_ctx (tmp_bson (e1), tmp_bson (e1), &match_ctx));
614655
BSON_ASSERT (
@@ -617,9 +658,80 @@ test_apm_matching (void)
617658
apm_match_visitor_ctx_reset (&match_visitor_ctx);
618659
}
619660

661+
// Test that documents in command_started_event.command do not permit extra
662+
// fields by default.
663+
static void
664+
test_apm_matching_extra_fields (void)
665+
{
666+
// Extra fields are permitted in `command`.
667+
{
668+
apm_match_visitor_ctx_t match_visitor_ctx = {0};
669+
match_ctx_t match_ctx = {{0}};
670+
671+
const char *event = BSON_STR (
672+
{"command_started_event" : {"command" : {"a" : 1, "b" : 2}}});
673+
const char *pattern =
674+
BSON_STR ({"command_started_event" : {"command" : {"a" : 1}}});
675+
676+
match_ctx.visitor_fn = apm_match_visitor;
677+
match_ctx.visitor_ctx = &match_visitor_ctx;
678+
679+
bool matched =
680+
match_bson_with_ctx (tmp_bson (event), tmp_bson (pattern), &match_ctx);
681+
ASSERT (matched);
682+
apm_match_visitor_ctx_reset (&match_visitor_ctx);
683+
}
684+
685+
// Extra fields are not permitted in `command` sub-documents.
686+
{
687+
apm_match_visitor_ctx_t match_visitor_ctx = {0};
688+
match_ctx_t match_ctx = {{0}};
689+
690+
const char *event = BSON_STR ({
691+
"command_started_event" : {"command" : {"subdoc" : {"a" : 1, "b" : 2}}}
692+
});
693+
const char *pattern = BSON_STR (
694+
{"command_started_event" : {"command" : {"subdoc" : {"a" : 1}}}});
695+
696+
match_ctx.visitor_fn = apm_match_visitor;
697+
match_ctx.visitor_ctx = &match_visitor_ctx;
698+
699+
bool matched =
700+
match_bson_with_ctx (tmp_bson (event), tmp_bson (pattern), &match_ctx);
701+
ASSERT (!matched);
702+
ASSERT_CONTAINS (match_ctx.errmsg, "unexpected extra field 'b'");
703+
apm_match_visitor_ctx_reset (&match_visitor_ctx);
704+
}
705+
706+
// Extra fields are not permitted in `command` sub-arrays.
707+
{
708+
apm_match_visitor_ctx_t match_visitor_ctx = {0};
709+
match_ctx_t match_ctx = {{0}};
710+
711+
const char *event = BSON_STR ({
712+
"command_started_event" :
713+
{"command" : {"subarray" : [ {"a" : 1, "b" : 2} ]}}
714+
});
715+
const char *pattern = BSON_STR ({
716+
"command_started_event" : {"command" : {"subarray" : [ {"a" : 1} ]}}
717+
});
718+
719+
match_ctx.visitor_fn = apm_match_visitor;
720+
match_ctx.visitor_ctx = &match_visitor_ctx;
721+
722+
bool matched =
723+
match_bson_with_ctx (tmp_bson (event), tmp_bson (pattern), &match_ctx);
724+
ASSERT (!matched);
725+
ASSERT_CONTAINS (match_ctx.errmsg, "unexpected extra field 'b'");
726+
apm_match_visitor_ctx_reset (&match_visitor_ctx);
727+
}
728+
}
729+
620730

621731
void
622732
test_apm_install (TestSuite *suite)
623733
{
624734
TestSuite_Add (suite, "/apm_test_matching", test_apm_matching);
735+
TestSuite_Add (
736+
suite, "/apm_test_matching/extra_fields", test_apm_matching_extra_fields);
625737
}

src/libmongoc/tests/json/client_side_encryption/legacy/fle2v2-CreateCollection.json

Lines changed: 0 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -158,9 +158,6 @@
158158
"command": {
159159
"create": "encryptedCollection",
160160
"encryptedFields": {
161-
"escCollection": null,
162-
"ecocCollection": null,
163-
"eccCollection": null,
164161
"fields": [
165162
{
166163
"path": "firstName",
@@ -343,9 +340,6 @@
343340
"command": {
344341
"create": "encryptedCollection",
345342
"encryptedFields": {
346-
"escCollection": null,
347-
"ecocCollection": null,
348-
"eccCollection": null,
349343
"fields": [
350344
{
351345
"path": "firstName",
@@ -851,9 +845,6 @@
851845
"command": {
852846
"create": "encryptedCollection",
853847
"encryptedFields": {
854-
"escCollection": null,
855-
"ecocCollection": null,
856-
"eccCollection": null,
857848
"fields": [
858849
{
859850
"path": "firstName",
@@ -1048,9 +1039,6 @@
10481039
"command": {
10491040
"create": "encryptedCollection",
10501041
"encryptedFields": {
1051-
"escCollection": null,
1052-
"ecocCollection": null,
1053-
"eccCollection": null,
10541042
"fields": [
10551043
{
10561044
"path": "firstName",
@@ -1367,9 +1355,6 @@
13671355
"command": {
13681356
"create": "encryptedCollection",
13691357
"encryptedFields": {
1370-
"escCollection": null,
1371-
"ecocCollection": null,
1372-
"eccCollection": null,
13731358
"fields": [
13741359
{
13751360
"path": "firstName",
@@ -1635,9 +1620,6 @@
16351620
"command": {
16361621
"create": "encryptedCollection",
16371622
"encryptedFields": {
1638-
"escCollection": null,
1639-
"ecocCollection": null,
1640-
"eccCollection": null,
16411623
"fields": [
16421624
{
16431625
"path": "firstName",

src/libmongoc/tests/test-conveniences.c

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -977,10 +977,14 @@ match_bson_with_ctx (const bson_t *doc, const bson_t *pattern, match_ctx_t *ctx)
977977
match_action_t action =
978978
ctx->visitor_fn (ctx, &pattern_iter, found ? &doc_iter : NULL);
979979
if (action == MATCH_ACTION_ABORT) {
980+
// Visitor encountered a match error.
980981
goto fail;
981982
} else if (action == MATCH_ACTION_SKIP) {
983+
// Visitor handled match of this field. Skip any additional matching
984+
// of this field.
982985
goto next;
983986
}
987+
ASSERT (action == MATCH_ACTION_CONTINUE);
984988
}
985989

986990
if (value->value_type == BSON_TYPE_NULL && found) {
@@ -1302,6 +1306,20 @@ match_bson_arrays (const bson_t *array, const bson_t *pattern, match_ctx_t *ctx)
13021306

13031307
derive (ctx, &derived, bson_iter_key (&array_iter));
13041308

1309+
if (ctx && ctx->visitor_fn) {
1310+
match_action_t action =
1311+
ctx->visitor_fn (ctx, &pattern_iter, &array_iter);
1312+
if (action == MATCH_ACTION_ABORT) {
1313+
// Visitor encountered a match error.
1314+
return false;
1315+
} else if (action == MATCH_ACTION_SKIP) {
1316+
// Visitor handled match of this field. Skip any additional matching
1317+
// of this field.
1318+
continue;
1319+
}
1320+
ASSERT (action == MATCH_ACTION_CONTINUE);
1321+
}
1322+
13051323
if (!match_bson_value (array_value, pattern_value, &derived)) {
13061324
return false;
13071325
}

0 commit comments

Comments
 (0)