diff options
author | Jonathan Reams <jbreams@mongodb.com> | 2018-10-19 14:26:52 -0400 |
---|---|---|
committer | Jonathan Reams <jbreams@mongodb.com> | 2018-11-30 13:25:44 -0500 |
commit | e2aff9fe8ac530d215917d35efcc179b9b6996e2 (patch) | |
tree | 4354fd9d59fe1590e0787e3727771878f83e8ddb | |
parent | 5e74cc18e7165e40d209ab7de41a527d0f6f0e31 (diff) | |
download | mongo-e2aff9fe8ac530d215917d35efcc179b9b6996e2.tar.gz |
SERVER-36977 Set process umask before creating log file
(cherry picked from commit a15cf62de1d5de973160ec1a23609aaf6f0f500f)
-rw-r--r-- | jstests/noPassthrough/umask.js | 78 | ||||
-rw-r--r-- | src/mongo/db/initialize_server_global_state.cpp | 13 | ||||
-rw-r--r-- | src/mongo/shell/shell_utils_extended.cpp | 39 |
3 files changed, 124 insertions, 6 deletions
diff --git a/jstests/noPassthrough/umask.js b/jstests/noPassthrough/umask.js new file mode 100644 index 00000000000..94787f973a0 --- /dev/null +++ b/jstests/noPassthrough/umask.js @@ -0,0 +1,78 @@ +/* + * This test makes sure that the log files created by the server correctly honor the server's umask + * as set in SERVER-22829 + */ +(function() { + 'use strict'; + // We only test this on POSIX since that's the only platform where umasks make sense + if (_isWindows()) { + return; + } + + const oldUmask = new Number(umask(0)); + jsTestLog("Setting umask to really permissive 000 mode, old mode was " + oldUmask.toString(8)); + + const defaultUmask = Number.parseInt("600", 8); + const permissiveUmask = Number.parseInt("666", 8); + + // Any files that have some explicit permissions set on them should be added to this list + const exceptions = [ + // The lock file gets created with explicit 644 permissions + 'mongod.lock', + // Mobile se files get created with 644 permissions when honoring the system umask + 'mobile.sqlite', + 'mobile.sqlite-shm', + 'mobile.sqlite-wal', + ]; + + let mongodOptions = MongoRunner.mongodOptions({ + useLogFiles: true, + cleanData: true, + }); + + if (buildInfo()["modules"].some((mod) => { + return mod == "enterprise"; + })) { + mongodOptions.auditDestination = "file"; + mongodOptions.auditPath = mongodOptions.dbpath + "/audit.log"; + mongodOptions.auditFormat = "JSON"; + } + + const checkMask = (topDir, expected, honoringUmask) => { + const maybeNot = honoringUmask ? "" : " not"; + const processDirectory = (dir) => { + jsTestLog(`Checking ${dir}`); + ls(dir).forEach((file) => { + if (file.endsWith("/")) { + return processDirectory(file); + } else if (exceptions.some((exception) => { + return file.endsWith(exception); + })) { + return; + } + const mode = new Number(getFileMode(file)); + const modeStr = mode.toString(8); + const msg = `Mode for ${file} is ${modeStr} when${maybeNot} honoring system umask`; + assert.eq(mode.valueOf(), expected, msg); + }); + }; + + processDirectory(topDir); + }; + + // First we start up the mongod normally, all the files except mongod.lock should have the mode + // 0600 + let conn = MongoRunner.runMongod(mongodOptions); + + checkMask(conn.fullOptions.dbpath, defaultUmask, false); + + MongoRunner.stopMongod(conn); + + // Restart the mongod with honorSystemUmask, all files should have the mode 0666 + mongodOptions.setParameter = {honorSystemUmask: true}; + conn = MongoRunner.runMongod(mongodOptions); + checkMask(conn.fullOptions.dbpath, permissiveUmask, false); + + MongoRunner.stopMongod(conn); + umask(oldUmask.valueOf()); +})(); diff --git a/src/mongo/db/initialize_server_global_state.cpp b/src/mongo/db/initialize_server_global_state.cpp index e1a4c159eed..cb0f45b8be9 100644 --- a/src/mongo/db/initialize_server_global_state.cpp +++ b/src/mongo/db/initialize_server_global_state.cpp @@ -209,7 +209,7 @@ void forkServerOrDie() { } MONGO_INITIALIZER_GENERAL(ServerLogRedirection, - ("GlobalLogManager", "EndStartupOptionHandling", "ForkServer"), + ("GlobalLogManager", "EndStartupOptionHandling", "ForkServer", "MungeUmask"), ("default")) (InitializerContext*) { using logger::LogManager; @@ -347,17 +347,22 @@ MONGO_INITIALIZER(RegisterShortCircuitExitHandler)(InitializerContext*) { // restrictions we want to apply and set it back. The overall effect // is to set the bits for 'other' and 'group', but leave umask bits // bits for 'user' unaltered. -#ifndef _WIN32 namespace { +#ifndef _WIN32 MONGO_EXPORT_STARTUP_SERVER_PARAMETER(honorSystemUmask, bool, false); -MONGO_INITIALIZER(MungeUmask)(InitializerContext*) { +#endif + +MONGO_INITIALIZER_WITH_PREREQUISITES(MungeUmask, ("EndStartupOptionHandling")) +(InitializerContext*) { +#ifndef _WIN32 if (!honorSystemUmask) { umask(umask(S_IRWXU | S_IRWXG | S_IRWXO) | S_IRWXG | S_IRWXO); } +#endif + return Status::OK(); } } // namespace -#endif bool initializeServerGlobalState() { Listener::globalTicketHolder.resize(serverGlobalParams.maxConns).transitional_ignore(); diff --git a/src/mongo/shell/shell_utils_extended.cpp b/src/mongo/shell/shell_utils_extended.cpp index 5ec4692cb9f..acb6ce04234 100644 --- a/src/mongo/shell/shell_utils_extended.cpp +++ b/src/mongo/shell/shell_utils_extended.cpp @@ -33,8 +33,12 @@ #include "mongo/platform/basic.h" -#include <boost/filesystem/convenience.hpp> -#include <boost/filesystem/fstream.hpp> +#ifndef _WIN32 +#include <sys/stat.h> +#include <sys/types.h> +#endif + +#include <boost/filesystem.hpp> #include <fstream> #include "mongo/scripting/engine.h" @@ -302,6 +306,35 @@ BSONObj getHostName(const BSONObj& a, void* data) { return BSON("" << buf); } +BSONObj changeUmask(const BSONObj& a, void* data) { +#ifdef _WIN32 + uasserted(50977, "umask is not supported on windows"); +#else + uassert(50976, + "umask takes 1 argument, the octal mode of the umask", + a.nFields() == 1 && isNumericBSONType(a.firstElementType())); + auto val = a.firstElement().Number(); + return BSON("" << umask(static_cast<mode_t>(val))); +#endif +} + +BSONObj getFileMode(const BSONObj& a, void* data) { + uassert(50975, + "getFileMode() takes one argument, the absolute path to a file", + a.nFields() == 1 && a.firstElementType() == String); + auto pathStr = a.firstElement().checkAndGetStringData(); + boost::filesystem::path path(pathStr.rawData()); + boost::system::error_code ec; + auto fileStatus = boost::filesystem::status(path, ec); + if (ec) { + uasserted(50974, + str::stream() << "Unable to get status for file \"" << pathStr << "\": " + << ec.message()); + } + + return BSON("" << fileStatus.permissions()); +} + void installShellUtilsExtended(Scope& scope) { scope.injectNative("getHostName", getHostName); scope.injectNative("removeFile", removeFile); @@ -315,6 +348,8 @@ void installShellUtilsExtended(Scope& scope) { scope.injectNative("hostname", hostname); scope.injectNative("md5sumFile", md5sumFile); scope.injectNative("mkdir", mkdir); + scope.injectNative("umask", changeUmask); + scope.injectNative("getFileMode", getFileMode); } } } |