diff options
author | Yoonsoo Kim <yoonsoo.kim@mongodb.com> | 2022-11-29 19:38:33 +0000 |
---|---|---|
committer | Evergreen Agent <no-reply@evergreen.mongodb.com> | 2022-11-29 20:49:24 +0000 |
commit | 2b5b114046850fc63d030876b9b8330043c5b6fa (patch) | |
tree | cbb301f3450c54d2caa0d18a660d9225eb9ecd12 /jstests/noPassthrough | |
parent | df59dfb0bc2db603fea6e1e3a0fe27059578ba4b (diff) | |
download | mongo-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.js | 316 |
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); + })(); +} })(); |