summaryrefslogtreecommitdiff
path: root/jstests/noPassthrough
diff options
context:
space:
mode:
authorYoonsoo Kim <yoonsoo.kim@mongodb.com>2022-11-29 19:38:33 +0000
committerEvergreen Agent <no-reply@evergreen.mongodb.com>2022-11-29 20:49:24 +0000
commit2b5b114046850fc63d030876b9b8330043c5b6fa (patch)
treecbb301f3450c54d2caa0d18a660d9225eb9ecd12 /jstests/noPassthrough
parentdf59dfb0bc2db603fea6e1e3a0fe27059578ba4b (diff)
downloadmongo-2b5b114046850fc63d030876b9b8330043c5b6fa.tar.gz
SERVER-70011 Restrict named pipe path using start-up parameter
Diffstat (limited to 'jstests/noPassthrough')
-rw-r--r--jstests/noPassthrough/external_data_source.js316
1 files changed, 194 insertions, 122 deletions
diff --git a/jstests/noPassthrough/external_data_source.js b/jstests/noPassthrough/external_data_source.js
index 6ab905cc458..b41599732da 100644
--- a/jstests/noPassthrough/external_data_source.js
+++ b/jstests/noPassthrough/external_data_source.js
@@ -1,14 +1,18 @@
/**
- * Tests basic syntax check of $_externalDataSources aggregate command option.
+ * Tests $_externalDataSources aggregate command option.
*/
(function() {
"use strict";
// Runs tests on a standalone mongod.
-const conn = MongoRunner.runMongod({setParameter: {enableComputeMode: true}});
-const db = conn.getDB(jsTestName());
+let conn = MongoRunner.runMongod({setParameter: {enableComputeMode: true}});
+let db = conn.getDB(jsTestName());
const kUrlProtocolFile = "file://";
+const hostInfo = assert.commandWorked(db.hostInfo());
+const kDefaultPipePath = (() => {
+ return hostInfo.os.type == "Windows" ? "//./pipe/" : "/tmp/";
+})();
// Create two random pipe names to avoid collisions with tests running concurrently on the same box.
const randomNum = Math.floor(1000 * 1000 * 1000 * Math.random()); // 0-999,999,999
@@ -75,7 +79,7 @@ assert.throwsWithCode(() => {
});
}, 40414);
-// Invalid url
+// Invalid url #1: Unsupported protocol for 'pipe'
assert.throwsWithCode(() => {
db.coll.aggregate([{$match: {a: 1}}], {
$_externalDataSources: [{
@@ -85,6 +89,17 @@ assert.throwsWithCode(() => {
});
}, 6968500);
+// Invalid url #2: '..' in the url
+assert.throwsWithCode(() => {
+ db.coll.aggregate([{$match: {a: 1}}], {
+ $_externalDataSources: [{
+ collName: "coll",
+ dataSources:
+ [{url: kUrlProtocolFile + "../name1", storageType: "pipe", fileType: "bson"}]
+ }]
+ });
+}, [7001100, 7001101]);
+
// The source namespace is not an external data source
assert.throwsWithCode(() => {
db.unknown.aggregate([{$match: {a: 1}}], {
@@ -112,16 +127,22 @@ assert.throwsWithCode(() => {
});
}, 7039004);
-// Non-existing external data source
-assert.throwsWithCode(() => {
- db.coll.aggregate([{$match: {a: 1}}], {
- $_externalDataSources: [{
- collName: "coll",
- dataSources:
- [{url: kUrlProtocolFile + pipeName1, storageType: "pipe", fileType: "bson"}]
- }]
- });
-}, ErrorCodes.FileNotOpen);
+// Not a pipe
+if (hostInfo.os.type != "Windows") {
+ const notPipe = "not_a_pipe";
+ const notPipeFullPath = kDefaultPipePath + notPipe;
+ assert(mkdir(notPipeFullPath).created, `Failed to create ${notPipeFullPath}`);
+ assert.throwsWithCode(() => {
+ db.coll.aggregate([], {
+ $_externalDataSources: [{
+ collName: "coll",
+ dataSources:
+ [{url: kUrlProtocolFile + notPipe, storageType: "pipe", fileType: "bson"}]
+ }]
+ });
+ }, ErrorCodes.FileNotOpen);
+ assert(removeFile(notPipeFullPath));
+}
//
// Named Pipes success test cases follow.
@@ -139,120 +160,171 @@ assert.eq((2 * objsPerPipe),
bsonObjToArray(result)[0], // "objects" first field contains the count of objects read
"_readTestPipes read wrong number of objects: " + bsonObjToArray(result)[0]);
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Test that $_externalDataSource can read and aggregate multiple named pipes.
-////////////////////////////////////////////////////////////////////////////////////////////////////
-objsPerPipe = 100;
-_writeTestPipe(pipeName1, objsPerPipe);
-_writeTestPipe(pipeName2, objsPerPipe);
-result = db.coll.aggregate([{$count: "objects"}], {
- $_externalDataSources: [{
- collName: "coll",
- dataSources: [
- {url: kUrlProtocolFile + pipeName1, storageType: "pipe", fileType: "bson"},
- {url: kUrlProtocolFile + pipeName2, storageType: "pipe", fileType: "bson"}
- ]
- }]
-});
-assert.eq((2 * objsPerPipe),
- result._batch[0].objects, // shell puts agg result in "_batch"[0] field of a wrapper obj
- "$_externalDataSources read wrong number of objects: " + result._batch[0].objects);
+function testSimpleAggregationsOverNamedPipes(pipeDir) {
+ ////////////////////////////////////////////////////////////////////////////////////////////////
+ // Test that $_externalDataSource can read and aggregate multiple named pipes.
+ ////////////////////////////////////////////////////////////////////////////////////////////////
+ objsPerPipe = 100;
+ _writeTestPipe(pipeName1, objsPerPipe, 0, 2048, pipeDir);
+ _writeTestPipe(pipeName2, objsPerPipe, 0, 2048, pipeDir);
+ result = db.coll.aggregate([{$count: "objects"}], {
+ $_externalDataSources: [{
+ collName: "coll",
+ dataSources: [
+ {url: kUrlProtocolFile + pipeName1, storageType: "pipe", fileType: "bson"},
+ {url: kUrlProtocolFile + pipeName2, storageType: "pipe", fileType: "bson"}
+ ]
+ }]
+ });
+ assert.eq(
+ (2 * objsPerPipe),
+ result._batch[0].objects, // shell puts agg result in "_batch"[0] field of a wrapper obj
+ "$_externalDataSources read wrong number of objects: " + result._batch[0].objects);
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Test correctness by verifying reading from the pipes returns the same objects written to them.
-////////////////////////////////////////////////////////////////////////////////////////////////////
-const kObjsToWrite = [
- {"Zero": "zero zero zero zero zero zero zero zero zero zero zero zero zero zero zero zero"},
- {"One": "one one one one one one one one one one one one one one one one one one one one one"},
- {"Two": "two two two two two two two two two two two two two two two two two two two two two"},
- {"Three": "three three three three three three three three three three three three three"},
- {"Four": "four four four four four four four four four four four four four four four four"},
- {"Five": "five five five five five five five five five five five five five five five five"},
- {"Six": "six six six six six six six six six six six six six six six six six six six six six"}
-];
-const kNumObjs = kObjsToWrite.length; // number of different objects for round-robin
-const kPipes = 2; // number of pipes to write
-_writeTestPipeObjects(pipeName1, objsPerPipe, kObjsToWrite);
-_writeTestPipeObjects(pipeName2, objsPerPipe, kObjsToWrite);
-let cursor = db.coll.aggregate([], {
- $_externalDataSources: [{
- collName: "coll",
- dataSources: [
- {url: kUrlProtocolFile + pipeName1, storageType: "pipe", fileType: "bson"},
- {url: kUrlProtocolFile + pipeName2, storageType: "pipe", fileType: "bson"}
- ]
- }]
-});
-// Verify the objects read from the pipes match what was written to them.
-for (let pipe = 0; pipe < kPipes; ++pipe) {
- for (let obj = 0; obj < objsPerPipe; ++obj) {
- assert.eq(cursor.next(),
- kObjsToWrite[obj % kNumObjs],
- "Object read from pipe does not match expected.");
+ ////////////////////////////////////////////////////////////////////////////////////////////////
+ // Test correctness by verifying reading from the pipes returns the same objects written to
+ // them.
+ ////////////////////////////////////////////////////////////////////////////////////////////////
+ const kObjsToWrite = [
+ {"Zero": "zero zero zero zero zero zero zero zero zero zero zero zero zero zero zero zero"},
+ {"One": "one one one one one one one one one one one one one one one one one one one one"},
+ {"Two": "two two two two two two two two two two two two two two two two two two two two"},
+ {"Three": "three three three three three three three three three three three three three"},
+ {"Four": "four four four four four four four four four four four four four four four four"},
+ {"Five": "five five five five five five five five five five five five five five five five"},
+ {"Six": "six six six six six six six six six six six six six six six six six six six six"}
+ ];
+ const kNumObjs = kObjsToWrite.length; // number of different objects for round-robin
+ const kPipes = 2; // number of pipes to write
+ _writeTestPipeObjects(pipeName1, objsPerPipe, kObjsToWrite, pipeDir);
+ _writeTestPipeObjects(pipeName2, objsPerPipe, kObjsToWrite, pipeDir);
+ let cursor = db.coll.aggregate([], {
+ $_externalDataSources: [{
+ collName: "coll",
+ dataSources: [
+ {url: kUrlProtocolFile + pipeName1, storageType: "pipe", fileType: "bson"},
+ {url: kUrlProtocolFile + pipeName2, storageType: "pipe", fileType: "bson"}
+ ]
+ }]
+ });
+ // Verify the objects read from the pipes match what was written to them.
+ for (let pipe = 0; pipe < kPipes; ++pipe) {
+ for (let obj = 0; obj < objsPerPipe; ++obj) {
+ assert.eq(cursor.next(),
+ kObjsToWrite[obj % kNumObjs],
+ "Object read from pipe does not match expected.");
+ }
}
-}
-////////////////////////////////////////////////////////////////////////////////////////////////////
-// Test successful lookup between two external data sources.
-////////////////////////////////////////////////////////////////////////////////////////////////////
-const kObjsToWrite1 = [{"localKey": 0}, {"localKey": 1}, {"localKey": 2}];
-const kObjsToWrite2 =
- [{"foreignKey": 0, "foreignVal": "Zero"}, {"foreignKey": 2, "foreignVal": "Two"}];
-const kExpectedLookup = [
- {"localKey": 0, "out": [{"foreignKey": 0, "foreignVal": "Zero"}]},
- {"localKey": 1, "out": []},
- {"localKey": 2, "out": [{"foreignKey": 2, "foreignVal": "Two"}]}
-];
+ ////////////////////////////////////////////////////////////////////////////////////////////////
+ // Test successful lookup between two external data sources.
+ ////////////////////////////////////////////////////////////////////////////////////////////////
+ const kObjsToWrite1 = [{"localKey": 0}, {"localKey": 1}, {"localKey": 2}];
+ const kObjsToWrite2 =
+ [{"foreignKey": 0, "foreignVal": "Zero"}, {"foreignKey": 2, "foreignVal": "Two"}];
+ const kExpectedLookup = [
+ {"localKey": 0, "out": [{"foreignKey": 0, "foreignVal": "Zero"}]},
+ {"localKey": 1, "out": []},
+ {"localKey": 2, "out": [{"foreignKey": 2, "foreignVal": "Two"}]}
+ ];
-// $_externalDataSources specified in order (local, foreign).
-_writeTestPipeObjects(pipeName1, kObjsToWrite1.length, kObjsToWrite1); // local
-_writeTestPipeObjects(pipeName2, kObjsToWrite2.length, kObjsToWrite2); // foreign
-let cursor1 = db.local.aggregate(
- [{$lookup: {from: "foreign", localField: "localKey", foreignField: "foreignKey", as: "out"}}], {
- $_externalDataSources: [
- {
- collName: "local",
- dataSources:
- [{url: kUrlProtocolFile + pipeName1, storageType: "pipe", fileType: "bson"}]
- },
- {
- collName: "foreign",
- dataSources:
- [{url: kUrlProtocolFile + pipeName2, storageType: "pipe", fileType: "bson"}]
- }
- ]
- });
-// Verify the $lookup result.
-for (let expected = 0; expected < kExpectedLookup.length; ++expected) {
- assert.eq(cursor1.next(),
- kExpectedLookup[expected],
- "Lookup result " + expected + " does not match expected.");
-}
+ // $_externalDataSources specified in order (local, foreign).
+ _writeTestPipeObjects(pipeName1, kObjsToWrite1.length, kObjsToWrite1, pipeDir); // local
+ _writeTestPipeObjects(pipeName2, kObjsToWrite2.length, kObjsToWrite2, pipeDir); // foreign
+ let cursor1 = db.local.aggregate(
+ [{
+ $lookup:
+ {from: "foreign", localField: "localKey", foreignField: "foreignKey", as: "out"}
+ }],
+ {
+ $_externalDataSources: [
+ {
+ collName: "local",
+ dataSources:
+ [{url: kUrlProtocolFile + pipeName1, storageType: "pipe", fileType: "bson"}]
+ },
+ {
+ collName: "foreign",
+ dataSources:
+ [{url: kUrlProtocolFile + pipeName2, storageType: "pipe", fileType: "bson"}]
+ }
+ ]
+ });
+ // Verify the $lookup result.
+ for (let expected = 0; expected < kExpectedLookup.length; ++expected) {
+ assert.eq(cursor1.next(),
+ kExpectedLookup[expected],
+ "Lookup result " + expected + " does not match expected.");
+ }
-// $_externalDataSources specified in order (foreign, local).
-_writeTestPipeObjects(pipeName1, kObjsToWrite1.length, kObjsToWrite1); // local
-_writeTestPipeObjects(pipeName2, kObjsToWrite2.length, kObjsToWrite2); // foreign
-let cursor2 = db.local.aggregate(
- [{$lookup: {from: "foreign", localField: "localKey", foreignField: "foreignKey", as: "out"}}], {
- $_externalDataSources: [
- {
- collName: "foreign",
- dataSources:
- [{url: kUrlProtocolFile + pipeName2, storageType: "pipe", fileType: "bson"}]
- },
- {
- collName: "local",
- dataSources:
- [{url: kUrlProtocolFile + pipeName1, storageType: "pipe", fileType: "bson"}]
- }
- ]
- });
-// Verify the $lookup result.
-for (let expected = 0; expected < kExpectedLookup.length; ++expected) {
- assert.eq(cursor2.next(),
- kExpectedLookup[expected],
- "Lookup result " + expected + " does not match expected.");
+ // $_externalDataSources specified in order (foreign, local).
+ _writeTestPipeObjects(pipeName1, kObjsToWrite1.length, kObjsToWrite1, pipeDir); // local
+ _writeTestPipeObjects(pipeName2, kObjsToWrite2.length, kObjsToWrite2, pipeDir); // foreign
+ let cursor2 = db.local.aggregate(
+ [{
+ $lookup:
+ {from: "foreign", localField: "localKey", foreignField: "foreignKey", as: "out"}
+ }],
+ {
+ $_externalDataSources: [
+ {
+ collName: "foreign",
+ dataSources:
+ [{url: kUrlProtocolFile + pipeName2, storageType: "pipe", fileType: "bson"}]
+ },
+ {
+ collName: "local",
+ dataSources:
+ [{url: kUrlProtocolFile + pipeName1, storageType: "pipe", fileType: "bson"}]
+ }
+ ]
+ });
+ // Verify the $lookup result.
+ for (let expected = 0; expected < kExpectedLookup.length; ++expected) {
+ assert.eq(cursor2.next(),
+ kExpectedLookup[expected],
+ "Lookup result " + expected + " does not match expected.");
+ }
}
+jsTestLog("Testing successful named pipe test cases");
+testSimpleAggregationsOverNamedPipes(kDefaultPipePath);
+
MongoRunner.stopMongod(conn);
+
+// The 'externalPipeDir' is effective only on POSIX-like system.
+if (hostInfo.os.type != "Windows") {
+ // Verfies that 'externalPipeDir' server parameter works with the same test cases.
+ (function testExternalPipeDirWorks() {
+ const pipeDir = MongoRunner.dataDir + "/tmp/";
+ assert(mkdir(pipeDir).created, `Failed to create ${pipeDir}`);
+
+ jsTestLog(`Testing named pipe test cases with externalPipeDir=${pipeDir}`);
+ conn = MongoRunner.runMongod(
+ {setParameter: {enableComputeMode: true, externalPipeDir: pipeDir}});
+ db = conn.getDB(jsTestName());
+
+ testSimpleAggregationsOverNamedPipes(pipeDir);
+
+ MongoRunner.stopMongod(conn);
+ })();
+
+ // Verifies that 'externalPipeDir' with '..' is rejected.
+ (function testInvalidExternalPipeDirRejected() {
+ const pipeDir = MongoRunner.dataDir + "/tmp/abc/../def/";
+ assert(mkdir(pipeDir).created, `Failed to create ${pipeDir}`);
+
+ jsTestLog(`Testing externalPipeDir=${pipeDir}`);
+ const pid = MongoRunner
+ .runMongod({
+ waitForConnect: false,
+ setParameter: {enableComputeMode: true, externalPipeDir: pipeDir}
+ })
+ .pid;
+ assert.soon(() => {
+ const runningStatus = checkProgram(pid);
+ return !runningStatus.alive && runningStatus.exitCode != 0;
+ }, "Expected mongod died", 120 * 1000);
+ })();
+}
})();