Skip to content

Instantly share code, notes, and snippets.

@tie
Created July 3, 2024 14:00
Show Gist options
  • Save tie/9fd9c75fb1fdf87d48352bb2bd1d2cb0 to your computer and use it in GitHub Desktop.
Save tie/9fd9c75fb1fdf87d48352bb2bd1d2cb0 to your computer and use it in GitHub Desktop.
PostgreSQL patch to allow running as root user (e.g. in containers).
diff --git a/src/backend/main/main.c b/src/backend/main/main.c
index 51ffb8e773..c92d25c77b 100644
--- a/src/backend/main/main.c
+++ b/src/backend/main/main.c
@@ -49,7 +49,6 @@ static bool reached_main = false;
static void startup_hacks(const char *progname);
static void init_locale(const char *categoryname, int category, const char *locale);
static void help(const char *progname);
-static void check_root(const char *progname);
/*
@@ -58,8 +57,6 @@ static void check_root(const char *progname);
int
main(int argc, char *argv[])
{
- bool do_check_root = true;
-
reached_main = true;
/*
@@ -153,30 +150,8 @@ main(int argc, char *argv[])
fputs(PG_BACKEND_VERSIONSTR, stdout);
exit(0);
}
-
- /*
- * In addition to the above, we allow "--describe-config" and "-C var"
- * to be called by root. This is reasonably safe since these are
- * read-only activities. The -C case is important because pg_ctl may
- * try to invoke it while still holding administrator privileges on
- * Windows. Note that while -C can normally be in any argv position,
- * if you want to bypass the root check you must put it first. This
- * reduces the risk that we might misinterpret some other mode's -C
- * switch as being the postmaster/postgres one.
- */
- if (strcmp(argv[1], "--describe-config") == 0)
- do_check_root = false;
- else if (argc > 2 && strcmp(argv[1], "-C") == 0)
- do_check_root = false;
}
- /*
- * Make sure we are not running as root, unless it's safe for the selected
- * option.
- */
- if (do_check_root)
- check_root(progname);
-
/*
* Dispatch to one of various subprograms depending on first argument.
*/
@@ -376,46 +351,6 @@ help(const char *progname)
-static void
-check_root(const char *progname)
-{
-#ifndef WIN32
- if (geteuid() == 0)
- {
- write_stderr("\"root\" execution of the PostgreSQL server is not permitted.\n"
- "The server must be started under an unprivileged user ID to prevent\n"
- "possible system security compromise. See the documentation for\n"
- "more information on how to properly start the server.\n");
- exit(1);
- }
-
- /*
- * Also make sure that real and effective uids are the same. Executing as
- * a setuid program from a root shell is a security hole, since on many
- * platforms a nefarious subroutine could setuid back to root if real uid
- * is root. (Since nobody actually uses postgres as a setuid program,
- * trying to actively fix this situation seems more trouble than it's
- * worth; we'll just expend the effort to check for it.)
- */
- if (getuid() != geteuid())
- {
- write_stderr("%s: real and effective user IDs must match\n",
- progname);
- exit(1);
- }
-#else /* WIN32 */
- if (pgwin32_is_admin())
- {
- write_stderr("Execution of PostgreSQL by a user with administrative permissions is not\n"
- "permitted.\n"
- "The server must be started under an unprivileged user ID to prevent\n"
- "possible system security compromises. See the documentation for\n"
- "more information on how to properly start the server.\n");
- exit(1);
- }
-#endif /* WIN32 */
-}
-
/*
* At least on linux, set_ps_display() breaks /proc/$pid/environ. The
* sanitizer library uses /proc/$pid/environ to implement getenv() as it wants
diff --git a/src/bin/initdb/initdb.c b/src/bin/initdb/initdb.c
index ac409b0006..e2d79bc922 100644
--- a/src/bin/initdb/initdb.c
+++ b/src/bin/initdb/initdb.c
@@ -751,15 +751,6 @@ get_id(void)
{
const char *username;
-#ifndef WIN32
- if (geteuid() == 0) /* 0 is root's uid */
- {
- pg_log_error("cannot be run as root");
- pg_log_error_hint("Please log in (using, e.g., \"su\") as the (unprivileged) user that will own the server process.");
- exit(1);
- }
-#endif
-
username = get_user_name_or_exit(progname);
return pg_strdup(username);
diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c
index 6900b27675..cdea841733 100644
--- a/src/bin/pg_ctl/pg_ctl.c
+++ b/src/bin/pg_ctl/pg_ctl.c
@@ -2240,21 +2240,6 @@ main(int argc, char **argv)
}
}
- /*
- * Disallow running as root, to forestall any possible security holes.
- */
-#ifndef WIN32
- if (geteuid() == 0)
- {
- write_stderr(_("%s: cannot be run as root\n"
- "Please log in (using, e.g., \"su\") as the "
- "(unprivileged) user that will\n"
- "own the server process.\n"),
- progname);
- exit(1);
- }
-#endif
-
env_wait = getenv("PGCTLTIMEOUT");
if (env_wait != NULL)
wait_seconds = atoi(env_wait);
diff --git a/src/bin/pg_resetwal/pg_resetwal.c b/src/bin/pg_resetwal/pg_resetwal.c
index e9dcb5a6d8..1772cee522 100644
--- a/src/bin/pg_resetwal/pg_resetwal.c
+++ b/src/bin/pg_resetwal/pg_resetwal.c
@@ -328,22 +328,6 @@ main(int argc, char *argv[])
exit(1);
}
- /*
- * Don't allow pg_resetwal to be run as root, to avoid overwriting the
- * ownership of files in the data directory. We need only check for root
- * -- any other user won't have sufficient permissions to modify files in
- * the data directory.
- */
-#ifndef WIN32
- if (geteuid() == 0)
- {
- pg_log_error("cannot be executed by \"root\"");
- pg_log_error_hint("You must run %s as the PostgreSQL superuser.",
- progname);
- exit(1);
- }
-#endif
-
get_restricted_token();
/* Set mask based on PGDATA permissions */
diff --git a/src/bin/pg_rewind/pg_rewind.c b/src/bin/pg_rewind/pg_rewind.c
index 57a168fea2..aa84020e78 100644
--- a/src/bin/pg_rewind/pg_rewind.c
+++ b/src/bin/pg_rewind/pg_rewind.c
@@ -270,22 +270,6 @@ main(int argc, char **argv)
exit(1);
}
- /*
- * Don't allow pg_rewind to be run as root, to avoid overwriting the
- * ownership of files in the data directory. We need only check for root
- * -- any other user won't have sufficient permissions to modify files in
- * the data directory.
- */
-#ifndef WIN32
- if (geteuid() == 0)
- {
- pg_log_error("cannot be executed by \"root\"");
- pg_log_error_hint("You must run %s as the PostgreSQL superuser.",
- progname);
- exit(1);
- }
-#endif
-
get_restricted_token();
/* Set mask based on PGDATA permissions */
diff --git a/src/bin/pg_upgrade/option.c b/src/bin/pg_upgrade/option.c
index 2917ec2329..64f5f17339 100644
--- a/src/bin/pg_upgrade/option.c
+++ b/src/bin/pg_upgrade/option.c
@@ -76,8 +76,8 @@ parseCommandLine(int argc, char *argv[])
old_cluster.port = getenv("PGPORTOLD") ? atoi(getenv("PGPORTOLD")) : DEF_PGUPORT;
new_cluster.port = getenv("PGPORTNEW") ? atoi(getenv("PGPORTNEW")) : DEF_PGUPORT;
- os_user_effective_id = get_user_info(&os_info.user);
- /* we override just the database user name; we got the OS id above */
+ get_user_info(&os_info.user);
+ /* we override just the database user name */
if (getenv("PGUSER"))
{
pg_free(os_info.user);
@@ -99,10 +99,6 @@ parseCommandLine(int argc, char *argv[])
}
}
- /* Allow help and version to be run as root, so do the test here. */
- if (os_user_effective_id == 0)
- pg_fatal("%s: cannot be run as root", os_info.progname);
-
while ((option = getopt_long(argc, argv, "b:B:cd:D:j:kNo:O:p:P:rs:U:v",
long_options, &optindex)) != -1)
{
diff --git a/src/bin/pg_upgrade/pg_upgrade.h b/src/bin/pg_upgrade/pg_upgrade.h
index d9a848cbfd..829581b19a 100644
--- a/src/bin/pg_upgrade/pg_upgrade.h
+++ b/src/bin/pg_upgrade/pg_upgrade.h
@@ -461,7 +461,7 @@ void check_pghost_envvar(void);
/* util.c */
char *quote_identifier(const char *s);
-int get_user_info(char **user_name_p);
+void get_user_info(char **user_name_p);
void check_ok(void);
void report_status(eLogType type, const char *fmt,...) pg_attribute_printf(2, 3);
void pg_log(eLogType type, const char *fmt,...) pg_attribute_printf(2, 3);
diff --git a/src/bin/pg_upgrade/util.c b/src/bin/pg_upgrade/util.c
index 2478372992..ef3ec57b0e 100644
--- a/src/bin/pg_upgrade/util.c
+++ b/src/bin/pg_upgrade/util.c
@@ -319,27 +319,18 @@ quote_identifier(const char *s)
/*
* get_user_info()
*/
-int
+void
get_user_info(char **user_name_p)
{
- int user_id;
const char *user_name;
char *errstr;
-#ifndef WIN32
- user_id = geteuid();
-#else
- user_id = 1;
-#endif
-
user_name = get_user_name(&errstr);
if (!user_name)
pg_fatal("%s", errstr);
/* make a copy */
*user_name_p = pg_strdup(user_name);
-
- return user_id;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment