diff --git a/Documentation/Changelog.md b/Documentation/Changelog.md index 90397a074..593f2ecfe 100644 --- a/Documentation/Changelog.md +++ b/Documentation/Changelog.md @@ -23,6 +23,7 @@ * Binlog router supports MariaDB 10 GTID at both ends. * KILL CONNECTION can now be used through MaxScale. * Environment variables can now be used in the MaxScale configuration file. +* By default, MaxScale can no longer be run as root. For more details, please refer to: * [MariaDB MaxScale 2.2.1 Release Notes](Release-Notes/MaxScale-2.2.1-Release-Notes.md) diff --git a/Documentation/Release-Notes/MaxScale-2.2.1-Release-Notes.md b/Documentation/Release-Notes/MaxScale-2.2.1-Release-Notes.md index b0adad25b..dbf0efae8 100644 --- a/Documentation/Release-Notes/MaxScale-2.2.1-Release-Notes.md +++ b/Documentation/Release-Notes/MaxScale-2.2.1-Release-Notes.md @@ -10,6 +10,21 @@ report at [Jira](https://jira.mariadb.org). ## Changed Features +### Process identity + +By default, MaxScale can no longer be run as `root`, but must be run as some +other user. However, it is possible to start MaxScale as `root`, as long as +the user to run MaxScale as is provided as a command line argument: +``` +root@host:~# maxscale --user=maxuser ... +``` +If it is imperative to run MaxScale as root, e.g. in a Docker container, it +can be achieved by invoking MaxScale as root and by explicitly specifying +the user to also be root: +``` +root@host:~# maxscale --user=root ... +``` + ### Binlog server * The `mariadb10_slave_gtid` parameter was removed and slave connections can now diff --git a/server/core/gateway.cc b/server/core/gateway.cc index 60789f34c..ed6bae1a2 100644 --- a/server/core/gateway.cc +++ b/server/core/gateway.cc @@ -185,6 +185,7 @@ static void modules_process_finish(); static void disable_module_unloading(const char* arg); static void enable_module_unloading(const char* arg); static void redirect_output_to_file(const char* arg); +static bool user_is_acceptable(const char* specified_user); struct DEBUG_ARGUMENT { @@ -1371,6 +1372,7 @@ int main(int argc, char **argv) int numlocks = 0; bool pid_file_created = false; Worker* worker; + const char* specified_user = NULL; *syslog_enabled = 1; *maxlog_enabled = 1; @@ -1653,7 +1655,8 @@ int main(int argc, char **argv) } break; case 'U': - if (set_user(optarg) != 0) + specified_user = optarg; + if (set_user(specified_user) != 0) { succp = false; } @@ -1690,6 +1693,13 @@ int main(int argc, char **argv) } } + if (!user_is_acceptable(specified_user)) + { + // Error was logged in user_is_acceptable(). + rc = MAXSCALE_INTERNALERROR; + goto return_main; + } + if (config_check) { daemon_mode = false; @@ -3203,3 +3213,41 @@ static bool handle_debug_args(char* args) } return !arg_error; } + +static bool user_is_acceptable(const char* specified_user) +{ + bool acceptable = false; + + // This is very early, so we do not have logging available, but write to stderr. + // As this is security related, we want to do as little as possible. + + uid_t uid = getuid(); // Always succeeds + errno = 0; + struct passwd *pw = getpwuid(uid); + if (pw) + { + if (strcmp(pw->pw_name, "root") == 0) + { + if (specified_user && (strcmp(specified_user, "root") == 0)) + { + // MaxScale was invoked as root and with --user=root. + acceptable = true; + } + else + { + fprintf(stderr, "Error: MaxScale cannot be run as root.\n"); + } + } + else + { + acceptable = true; + } + } + else + { + fprintf(stderr, "Error: Could not obtain user information, MaxScale will not run: %s", + strerror(errno)); + } + + return acceptable; +}