Skip to content

Commit ec39911

Browse files
authored
CDRIVER-6125 fix GridFS chunk size handling (#2146)
* validate chunk size from server document * test negative and zero length * check for negative length * Not strictly needed. But gives an earlier error.
1 parent a2c33be commit ec39911

File tree

2 files changed

+196
-0
lines changed

2 files changed

+196
-0
lines changed

src/libmongoc/src/mongoc/mongoc-gridfs-bucket.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@ mongoc_gridfs_bucket_open_upload_stream_with_id(mongoc_gridfs_bucket_t *bucket,
182182
file->bucket = bucket;
183183
file->chunk_size = gridfs_opts.chunkSizeBytes;
184184
file->metadata = bson_copy(&gridfs_opts.metadata);
185+
BSON_ASSERT(gridfs_opts.chunkSizeBytes > 0); // Validated in _mongoc_gridfs_bucket_opts_parse.
185186
file->buffer = bson_malloc((size_t)gridfs_opts.chunkSizeBytes);
186187
file->in_buffer = 0;
187188

@@ -347,6 +348,26 @@ mongoc_gridfs_bucket_open_download_stream(mongoc_gridfs_bucket_t *bucket,
347348

348349
bson_destroy(&file_doc);
349350

351+
if (file->chunk_size <= 0) {
352+
_mongoc_set_error(error,
353+
MONGOC_ERROR_GRIDFS,
354+
MONGOC_ERROR_GRIDFS_CORRUPT,
355+
"File document contains invalid chunk size: %" PRId32,
356+
file->chunk_size);
357+
_mongoc_gridfs_bucket_file_destroy(file);
358+
return NULL;
359+
}
360+
361+
if (file->length < 0) {
362+
_mongoc_set_error(error,
363+
MONGOC_ERROR_GRIDFS,
364+
MONGOC_ERROR_GRIDFS_CORRUPT,
365+
"File document contains invalid length: %" PRId64,
366+
file->length);
367+
_mongoc_gridfs_bucket_file_destroy(file);
368+
return NULL;
369+
}
370+
350371
file->file_id = (bson_value_t *)bson_malloc0(sizeof *(file->file_id));
351372
bson_value_copy(file_id, file->file_id);
352373
file->bucket = bucket;

src/libmongoc/tests/test-mongoc-gridfs-bucket.c

Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,6 +1048,180 @@ test_gridfs_bucket_opts(void)
10481048
mongoc_client_destroy(client);
10491049
}
10501050

1051+
// Regression test for CDRIVER-6125
1052+
static void
1053+
test_bad_sizes(void)
1054+
{
1055+
mongoc_client_t *client = test_framework_new_default_client();
1056+
bson_error_t error;
1057+
1058+
mongoc_database_t *db = mongoc_client_get_database(client, "test_bad_sizes");
1059+
mongoc_database_drop(db, NULL);
1060+
1061+
// Test negative chunkSize:
1062+
{
1063+
bson_t *doc = tmp_bson(BSON_STR({
1064+
"_id" : 0,
1065+
"filename" : "foo.txt",
1066+
"length" : 1000,
1067+
"chunkSize" : -1, // Negative!
1068+
"uploadDate" : {"$date" : 1234567890000}
1069+
}));
1070+
1071+
bson_iter_t id_iter;
1072+
ASSERT(bson_iter_init_find(&id_iter, doc, "_id"));
1073+
const bson_value_t *id_value = bson_iter_value(&id_iter);
1074+
1075+
// Insert manually:
1076+
{
1077+
mongoc_collection_t *files = mongoc_database_get_collection(db, "fs.files");
1078+
mongoc_collection_insert_one(files, doc, NULL, NULL, &error);
1079+
mongoc_collection_destroy(files);
1080+
}
1081+
1082+
// Try to read:
1083+
{
1084+
mongoc_gridfs_bucket_t *bucket = mongoc_gridfs_bucket_new(db, NULL, NULL, &error);
1085+
ASSERT_OR_PRINT(bucket, error);
1086+
mongoc_stream_t *stream = mongoc_gridfs_bucket_open_download_stream(bucket, id_value, &error);
1087+
ASSERT(!stream);
1088+
ASSERT_ERROR_CONTAINS(error, MONGOC_ERROR_GRIDFS, MONGOC_ERROR_GRIDFS_CORRUPT, "invalid chunk size");
1089+
mongoc_gridfs_bucket_destroy(bucket);
1090+
}
1091+
1092+
// Try to write:
1093+
{
1094+
mongoc_gridfs_bucket_t *bucket = mongoc_gridfs_bucket_new(db, NULL, NULL, &error);
1095+
ASSERT_OR_PRINT(bucket, error);
1096+
bson_t *opts = tmp_bson(BSON_STR({"chunkSizeBytes" : 0}));
1097+
mongoc_stream_t *stream = mongoc_gridfs_bucket_open_upload_stream(bucket, "foo.txt", opts, NULL, &error);
1098+
ASSERT(!stream);
1099+
ASSERT_ERROR_CONTAINS(
1100+
error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "should be greater than 0");
1101+
mongoc_gridfs_bucket_destroy(bucket);
1102+
}
1103+
}
1104+
1105+
mongoc_database_drop(db, NULL);
1106+
1107+
// Test zero chunkSize:
1108+
{
1109+
bson_t *doc = tmp_bson(BSON_STR({
1110+
"_id" : 0,
1111+
"filename" : "foo.txt",
1112+
"length" : 1000,
1113+
"chunkSize" : 0, // Zero!
1114+
"uploadDate" : {"$date" : 1234567890000}
1115+
}));
1116+
1117+
bson_iter_t id_iter;
1118+
ASSERT(bson_iter_init_find(&id_iter, doc, "_id"));
1119+
const bson_value_t *id_value = bson_iter_value(&id_iter);
1120+
1121+
// Insert manually:
1122+
{
1123+
mongoc_collection_t *files = mongoc_database_get_collection(db, "fs.files");
1124+
mongoc_collection_insert_one(files, doc, NULL, NULL, &error);
1125+
mongoc_collection_destroy(files);
1126+
}
1127+
1128+
// Try to read:
1129+
{
1130+
mongoc_gridfs_bucket_t *bucket = mongoc_gridfs_bucket_new(db, NULL, NULL, &error);
1131+
ASSERT_OR_PRINT(bucket, error);
1132+
mongoc_stream_t *stream = mongoc_gridfs_bucket_open_download_stream(bucket, id_value, &error);
1133+
ASSERT(!stream);
1134+
ASSERT_ERROR_CONTAINS(error, MONGOC_ERROR_GRIDFS, MONGOC_ERROR_GRIDFS_CORRUPT, "invalid chunk size");
1135+
mongoc_gridfs_bucket_destroy(bucket);
1136+
}
1137+
1138+
// Try to write:
1139+
{
1140+
mongoc_gridfs_bucket_t *bucket = mongoc_gridfs_bucket_new(db, NULL, NULL, &error);
1141+
ASSERT_OR_PRINT(bucket, error);
1142+
bson_t *opts = tmp_bson(BSON_STR({"chunkSizeBytes" : -1}));
1143+
mongoc_stream_t *stream = mongoc_gridfs_bucket_open_upload_stream(bucket, "foo.txt", opts, NULL, &error);
1144+
ASSERT(!stream);
1145+
ASSERT_ERROR_CONTAINS(
1146+
error, MONGOC_ERROR_COMMAND, MONGOC_ERROR_COMMAND_INVALID_ARG, "should be greater than 0");
1147+
mongoc_gridfs_bucket_destroy(bucket);
1148+
}
1149+
}
1150+
1151+
mongoc_database_drop(db, NULL);
1152+
1153+
// Test negative length:
1154+
{
1155+
bson_t *doc = tmp_bson(BSON_STR({
1156+
"_id" : 0,
1157+
"filename" : "foo.txt",
1158+
"length" : -1, // Negative!
1159+
"chunkSize" : 10,
1160+
"uploadDate" : {"$date" : 1234567890000}
1161+
}));
1162+
1163+
bson_iter_t id_iter;
1164+
ASSERT(bson_iter_init_find(&id_iter, doc, "_id"));
1165+
const bson_value_t *id_value = bson_iter_value(&id_iter);
1166+
1167+
// Insert manually:
1168+
{
1169+
mongoc_collection_t *files = mongoc_database_get_collection(db, "fs.files");
1170+
mongoc_collection_insert_one(files, doc, NULL, NULL, &error);
1171+
mongoc_collection_destroy(files);
1172+
}
1173+
1174+
// Try to read:
1175+
{
1176+
mongoc_gridfs_bucket_t *bucket = mongoc_gridfs_bucket_new(db, NULL, NULL, &error);
1177+
mongoc_stream_t *stream = mongoc_gridfs_bucket_open_download_stream(bucket, id_value, &error);
1178+
ASSERT(!stream);
1179+
ASSERT_ERROR_CONTAINS(error, MONGOC_ERROR_GRIDFS, MONGOC_ERROR_GRIDFS_CORRUPT, "invalid length");
1180+
mongoc_gridfs_bucket_destroy(bucket);
1181+
}
1182+
}
1183+
1184+
mongoc_database_drop(db, NULL);
1185+
1186+
// Test a zero length (OK):
1187+
{
1188+
bson_t *doc = tmp_bson(BSON_STR({
1189+
"_id" : 0,
1190+
"filename" : "foo.txt",
1191+
"length" : 0, // Zero!
1192+
"chunkSize" : 10,
1193+
"uploadDate" : {"$date" : 1234567890000}
1194+
}));
1195+
1196+
bson_iter_t id_iter;
1197+
ASSERT(bson_iter_init_find(&id_iter, doc, "_id"));
1198+
const bson_value_t *id_value = bson_iter_value(&id_iter);
1199+
1200+
// Insert manually:
1201+
{
1202+
mongoc_collection_t *files = mongoc_database_get_collection(db, "fs.files");
1203+
mongoc_collection_insert_one(files, doc, NULL, NULL, &error);
1204+
mongoc_collection_destroy(files);
1205+
}
1206+
1207+
// Try to read:
1208+
{
1209+
mongoc_gridfs_bucket_t *bucket = mongoc_gridfs_bucket_new(db, NULL, NULL, &error);
1210+
mongoc_stream_t *stream = mongoc_gridfs_bucket_open_download_stream(bucket, id_value, &error);
1211+
ASSERT(stream);
1212+
// OK. Gets back an empty read.
1213+
uint8_t buf[64];
1214+
ssize_t r = mongoc_stream_read(stream, buf, sizeof buf, 0, 0);
1215+
ASSERT_CMPINT(r, ==, 0);
1216+
mongoc_stream_destroy(stream);
1217+
mongoc_gridfs_bucket_destroy(bucket);
1218+
}
1219+
}
1220+
1221+
mongoc_database_destroy(db);
1222+
mongoc_client_destroy(client);
1223+
}
1224+
10511225
void
10521226
test_gridfs_bucket_install(TestSuite *suite)
10531227
{
@@ -1070,4 +1244,5 @@ test_gridfs_bucket_install(TestSuite *suite)
10701244
test_framework_skip_if_no_sessions,
10711245
test_framework_skip_if_no_crypto);
10721246
TestSuite_AddLive(suite, "/gridfs/options", test_gridfs_bucket_opts);
1247+
TestSuite_AddLive(suite, "/gridfs/bad_sizes", test_bad_sizes);
10731248
}

0 commit comments

Comments
 (0)