List:Commits« Previous MessageNext Message »
From:Chad MILLER Date:December 3 2008 4:29pm
Subject:bzr commit into mysql-5.1-bugteam branch (chad:2725) Bug#30261
View as plain text  
#At file:///home/cmiller/work/mysqlbzr/mysql-5.1-bugteam--bug30261/

 2725 Chad MILLER	2008-12-03
      Bug#30261: "mysqld --help" no longer possible for root
      
      Asking for the program's parameters and defaults now must execute 
      plugin code, which we don't trust to be run as root.
      
      So, now if the server is going to print stuff and exit, first become
      another user.
modified:
  sql/mysqld.cc

=== modified file 'sql/mysqld.cc'
--- a/sql/mysqld.cc	2008-11-28 15:27:12 +0000
+++ b/sql/mysqld.cc	2008-12-03 15:24:32 +0000
@@ -1176,10 +1176,10 @@ extern "C" void unireg_abort(int exit_co
 {
   DBUG_ENTER("unireg_abort");
 
+  if (opt_help)
+    usage();
   if (exit_code)
     sql_print_error("Aborting\n");
-  else if (opt_help)
-    usage();
   clean_up(!opt_help && (exit_code || !opt_bootstrap)); /* purecov: inspected */
   DBUG_PRINT("quit",("done with cleanup in unireg_abort"));
   wait_for_signal_thread_to_end();
@@ -1491,11 +1491,18 @@ err:
   return NULL;
 }
 
-static void set_user(const char *user, struct passwd *user_info_arg)
+/**
+  Set the process to be owned by some other user, as a means of 
+  reducing privileges.  Does not call other functions to exit.
+
+  @todo  Param "user" is redundant with "user_info_arg->pw_name".
+  
+  @returns  Was there an error?
+*/
+static bool set_user(const char *user, struct passwd *user_info_arg)
 {
   /* purecov: begin tested */
 #if !defined(__WIN__) && !defined(__NETWARE__)
-  DBUG_ASSERT(user_info_arg != 0);
 #ifdef HAVE_INITGROUPS
   /*
     We can get a SIGSEGV when calling initgroups() on some systems when NSS
@@ -1510,18 +1517,55 @@ static void set_user(const char *user, s
   if (setgid(user_info_arg->pw_gid) == -1)
   {
     sql_perror("setgid");
-    unireg_abort(1);
+    return true;
   }
   if (setuid(user_info_arg->pw_uid) == -1)
   {
     sql_perror("setuid");
-    unireg_abort(1);
+    return true;
   }
 #endif
   /* purecov: end */
+  return false;
 }
 
 
+/**
+  Become some non-superuser or exit, real and effective.  This is
+  one directional, and rootness can not directly be gained again.
+
+  This is not thread-safe, and should not be called except in server
+  initialization as a way to drop some privileges before executing 
+  questionable code, e.g., plugins.
+*/
+static void become_unprivileged()
+{
+  const char *try_usernames[] = { "nobody", "mysql", "_mysql", "mysqld", NULL };
+  struct passwd *pwent;
+
+  if (getuid() != 0) return;  /* Already unprivileged. */
+
+  if (mysqld_user != NULL)
+  {
+    pwent = getpwnam(mysqld_user);
+    if (pwent != NULL)
+      (void) set_user(pwent->pw_name, pwent);
+    if (getuid() != 0) return;
+  }
+
+  for (uint i = 0; try_usernames[i] != NULL; i++)
+  {
+    const char *username = try_usernames[i];
+    pwent = getpwnam(username);
+    if (pwent != NULL)
+      (void) set_user(pwent->pw_name, pwent);
+    if (getuid() != 0) return;
+  }
+
+  fprintf(stderr, "Could not drop privileges.\n");
+  exit(1);
+}
+
 static void set_effective_user(struct passwd *user_info_arg)
 {
 #if !defined(__WIN__) && !defined(__NETWARE__)
@@ -4022,7 +4066,10 @@ server.");
       locked_in_memory= 0;
     }
     if (user_info)
-      set_user(mysqld_user, user_info);
+    {
+      if (set_user(mysqld_user, user_info)) /* is error? */
+        unireg_abort(1);
+    }
   }
   else
 #endif
@@ -4249,6 +4296,12 @@ int main(int argc, char **argv)
   mysql_data_home[1]=0;
   mysql_data_home_len= 2;
 
+  if (opt_help && (getuid() == 0))
+  {
+    sql_print_warning("Dropping root privileges to show help.");
+    become_unprivileged();  /* Guaranteed to succeed or exit. */
+  }
+
   if ((user_info= check_user(mysqld_user)))
   {
 #if defined(HAVE_MLOCKALL) && defined(MCL_CURRENT)
@@ -4256,7 +4309,10 @@ int main(int argc, char **argv)
       set_effective_user(user_info);
     else
 #endif
-      set_user(mysqld_user, user_info);
+    {
+      if (set_user(mysqld_user, user_info)) /* is error? */
+        unireg_abort(1);
+    }
   }
 
   if (opt_bin_log && !server_id)
@@ -7378,7 +7434,8 @@ static void usage(void)
     default_collation_name= (char*) default_charset_info->name;
   print_version();
   puts("\
-Copyright (C) 2000 MySQL AB, by Monty and others\n\
+Copyright (C) 2000-2008 MySQL AB, by Monty and others\n\
+Copyright (C) 2008 Sun Microsystems, Inc.\n\
 This software comes with ABSOLUTELY NO WARRANTY. This is free software,\n\
 and you are welcome to modify and redistribute it under the GPL license\n\n\
 Starts the MySQL database server\n");

Thread
bzr commit into mysql-5.1-bugteam branch (chad:2725) Bug#30261Chad MILLER3 Dec