summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSara Golemon <sara.golemon@mongodb.com>2019-08-16 14:53:29 +0000
committerevergreen <evergreen@mongodb.com>2019-08-16 14:53:29 +0000
commitea1dd7a54b7b7bcae7f9ad15a547ed0ee3d4348b (patch)
tree11a9a25076dd431b76656d79dca575bbb7a04d59
parent4a1d30014c12bae57caf423b695378fdc6fea6c9 (diff)
downloadmongo-ea1dd7a54b7b7bcae7f9ad15a547ed0ee3d4348b.tar.gz
SERVER-41633 Allow overriding system umask for group/other from process startup
CodeReview: 488750005
-rw-r--r--jstests/noPassthrough/umask.js39
-rw-r--r--src/mongo/db/initialize_server_global_state.cpp143
-rw-r--r--src/mongo/db/initialize_server_global_state.idl20
3 files changed, 163 insertions, 39 deletions
diff --git a/jstests/noPassthrough/umask.js b/jstests/noPassthrough/umask.js
index 8d7234b15d3..7ffd93cf829 100644
--- a/jstests/noPassthrough/umask.js
+++ b/jstests/noPassthrough/umask.js
@@ -40,8 +40,7 @@ if (buildInfo()["modules"].some((mod) => {
mongodOptions.auditFormat = "JSON";
}
-const checkMask = (topDir, expected, honoringUmask) => {
- const maybeNot = honoringUmask ? "" : " not";
+function checkMask(topDir, expected, honoringUmask, customUmask = false) {
const processDirectory = (dir) => {
jsTestLog(`Checking ${dir}`);
ls(dir).forEach((file) => {
@@ -54,13 +53,18 @@ const checkMask = (topDir, expected, honoringUmask) => {
}
const mode = new Number(getFileMode(file));
const modeStr = mode.toString(8);
- const msg = `Mode for ${file} is ${modeStr} when${maybeNot} honoring system umask`;
+ let msg = `Mode for ${file} is ${modeStr} when `;
+ if (customUmask) {
+ msg += ' using custom umask';
+ } else {
+ msg += (honoringUmask ? '' : 'not ') + ' 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
@@ -74,7 +78,32 @@ mongodOptions.setParameter = {
};
conn = MongoRunner.runMongod(mongodOptions);
MongoRunner.stopMongod(conn);
-checkMask(conn.fullOptions.dbpath, permissiveUmask, false);
+checkMask(conn.fullOptions.dbpath, permissiveUmask, true);
+
+// Restart the mongod with custom umask as string, all files should have the mode 0644
+const worldReadableUmask = Number.parseInt("644", 8);
+mongodOptions.setParameter = {
+ processUmask: '022',
+};
+conn = MongoRunner.runMongod(mongodOptions);
+MongoRunner.stopMongod(conn);
+checkMask(conn.fullOptions.dbpath, worldReadableUmask, false, true);
+
+// Fail to start up with both honorSystemUmask and processUmask set.
+mongodOptions.setParameter = {
+ honorSystemUmask: true,
+ processUmask: '022',
+};
+assert.eq(null, MongoRunner.runMongod(mongodOptions));
+
+// Okay to start with both if honorSystemUmask is false.
+mongodOptions.setParameter = {
+ honorSystemUmask: false,
+ processUmask: '022',
+};
+conn = MongoRunner.runMongod(mongodOptions);
+MongoRunner.stopMongod(conn);
+checkMask(conn.fullOptions.dbpath, worldReadableUmask, false, true);
umask(oldUmask.valueOf());
})();
diff --git a/src/mongo/db/initialize_server_global_state.cpp b/src/mongo/db/initialize_server_global_state.cpp
index 7c48caa70b6..e09338d5d55 100644
--- a/src/mongo/db/initialize_server_global_state.cpp
+++ b/src/mongo/db/initialize_server_global_state.cpp
@@ -205,12 +205,9 @@ void forkServerOrDie() {
quickExit(EXIT_FAILURE);
}
-// On POSIX platforms we need to set our umask before opening any log files, so this
-// should depend on MungeUmask above, but not on Windows.
-MONGO_INITIALIZER_GENERAL(
- ServerLogRedirection,
- ("GlobalLogManager", "EndStartupOptionHandling", "ForkServer", "MungeUmask"),
- ("default"))
+MONGO_INITIALIZER_GENERAL(ServerLogRedirection,
+ ("GlobalLogManager", "EndStartupOptionHandling", "ForkServer"),
+ ("default"))
(InitializerContext*) {
using logger::LogManager;
using logger::MessageEventDetailsEncoder;
@@ -337,27 +334,6 @@ MONGO_INITIALIZER(RegisterShortCircuitExitHandler)(InitializerContext*) {
return Status::OK();
}
-// On non-windows platforms, drop rwx for group and other unless the
-// user has opted into using the system umask. To do so, we first read
-// out the current umask (by temporarily setting it to
-// no-permissions), and then or the returned umask with the
-// 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.
-namespace {
-
-MONGO_INITIALIZER_WITH_PREREQUISITES(MungeUmask, ("EndStartupOptionHandling"))
-(InitializerContext*) {
-#ifndef _WIN32
- if (!gHonorSystemUmask) {
- umask(umask(S_IRWXU | S_IRWXG | S_IRWXO) | S_IRWXG | S_IRWXO);
- }
-#endif
-
- return Status::OK();
-}
-} // namespace
-
bool initializeServerGlobalState(ServiceContext* service, PidFileWrite pidWrite) {
#ifndef _WIN32
if (!serverGlobalParams.noUnixSocket && !fs::is_directory(serverGlobalParams.socket)) {
@@ -376,4 +352,117 @@ bool initializeServerGlobalState(ServiceContext* service, PidFileWrite pidWrite)
return true;
}
+#ifndef _WIN32
+namespace {
+// Handling for `honorSystemUmask` and `processUmask` setParameters.
+// Non-Windows platforms only.
+//
+// If honorSystemUmask is true, processUmask may not be set
+// and the umask will be left exactly as set by the OS.
+//
+// If honorSystemUmask is false, then we will still honor the 'user'
+// portion of the current umask, but the group/other bits will be
+// set to 1, or whatever value is provided by processUmask if specified.
+
+// processUmask set parameter may only override group/other bits.
+constexpr mode_t kValidUmaskBits = S_IRWXG | S_IRWXO;
+
+// By default, honorSystemUmask==false masks all group/other bits.
+constexpr mode_t kDefaultProcessUmask = S_IRWXG | S_IRWXO;
+
+bool honorSystemUmask = false;
+boost::optional<mode_t> umaskOverride;
+
+mode_t getUmaskOverride() {
+ return umaskOverride ? *umaskOverride : kDefaultProcessUmask;
+}
+
+// We need to set our umask before opening any log files.
+MONGO_INITIALIZER_GENERAL(MungeUmask, ("EndStartupOptionHandling"), ("ServerLogRedirection"))
+(InitializerContext*) {
+ if (!honorSystemUmask) {
+ // POSIX does not provide a mechanism for reading the current umask
+ // without modifying it.
+ // Do this conservatively by setting a short-lived umask of 0777
+ // in order to pull out the user portion of the current umask.
+ umask((umask(S_IRWXU | S_IRWXG | S_IRWXO) & S_IRWXU) | getUmaskOverride());
+ }
+
+ return Status::OK();
+}
+} // namespace
+#endif
+
+// --setParameter honorSystemUmask
+Status HonorSystemUMaskServerParameter::setFromString(const std::string& value) {
+#ifndef _WIN32
+ if ((value == "0") || (value == "false")) {
+ // false may be specified with processUmask
+ // since it defines precisely how we're not honoring system umask.
+ honorSystemUmask = false;
+ return Status::OK();
+ }
+
+ if ((value == "1") || (value == "true")) {
+ if (umaskOverride) {
+ return {ErrorCodes::BadValue,
+ "honorSystemUmask and processUmask may not be specified together"};
+ } else {
+ honorSystemUmask = true;
+ return Status::OK();
+ }
+ }
+
+ return {ErrorCodes::BadValue, "honorSystemUmask must be 'true' or 'false'"};
+#else
+ return {ErrorCodes::InternalError, "honerSystemUmask is not available on windows"};
+#endif
+}
+
+void HonorSystemUMaskServerParameter::append(OperationContext*,
+ BSONObjBuilder& b,
+ const std::string& name) {
+#ifndef _WIN32
+ b << name << honorSystemUmask;
+#endif
+}
+
+// --setParameter processUmask
+Status ProcessUMaskServerParameter::setFromString(const std::string& value) {
+#ifndef _WIN32
+ if (honorSystemUmask) {
+ return {ErrorCodes::BadValue,
+ "honorSystemUmask and processUmask may not be specified together"};
+ }
+
+ // Convert base from octal
+ const char* val = value.c_str();
+ char* end = nullptr;
+
+ auto mask = std::strtoul(val, &end, 8);
+ if (end && (end != (val + value.size()))) {
+ return {ErrorCodes::BadValue,
+ str::stream() << "'" << value << "' is not a valid octal value"};
+ }
+
+ if ((mask & kValidUmaskBits) != mask) {
+ return {ErrorCodes::BadValue,
+ str::stream() << "'" << value << "' attempted to set invalid umask bits"};
+ }
+
+ umaskOverride = static_cast<mode_t>(mask);
+ return Status::OK();
+#else
+ return {ErrorCodes::InternalError, "processUmask is not available on windows"};
+#endif
+}
+
+void ProcessUMaskServerParameter::append(OperationContext*,
+ BSONObjBuilder& b,
+ const std::string& name) {
+#ifndef _WIN32
+ b << name << static_cast<int>(getUmaskOverride());
+#endif
+}
+
} // namespace mongo
diff --git a/src/mongo/db/initialize_server_global_state.idl b/src/mongo/db/initialize_server_global_state.idl
index 5b697ac1ac3..c25d78fa07f 100644
--- a/src/mongo/db/initialize_server_global_state.idl
+++ b/src/mongo/db/initialize_server_global_state.idl
@@ -40,12 +40,18 @@ server_parameters:
set_at: [ startup, runtime ]
honorSystemUmask:
- cpp_varname: gHonorSystemUmask
- cpp_vartype: bool
+ description: 'Use the system provided umask, rather than overriding with processUmask config value'
+ set_at: startup
+ cpp_class: HonorSystemUMaskServerParameter
condition:
preprocessor: '!defined(_WIN32)'
- default: false
- description: 'Max log size in kilobytes'
- set_at: [ startup ]
-
-
+
+ processUmask:
+ description: >
+ Override system umask for group/other permissions when honorSystemUmask is false.
+ User umask is always preserved.
+ set_at: startup
+ cpp_class: ProcessUMaskServerParameter
+ condition:
+ preprocessor: '!defined(_WIN32)'
+