From 9bcedede452c1f37dd790f86bc587353cc455e3f Mon Sep 17 00:00:00 2001 From: Thomas Munro Date: Tue, 10 Aug 2021 22:05:00 +1200 Subject: [PATCH] Try to make EXEC_BACKEND more convenient on macOS. Use posix_spawn() instead of fork() + execv(), with a special undocumented flag that disables ASLR, if you build with -DEXEC_BACKEND -DUSE_POSIX_SPAWN -DUSE_POSIX_SPAWN_DISABLE_ASLR. XXX Experiment only... XXX Still fails make check occasionally :-( --- src/backend/postmaster/postmaster.c | 33 +++++++++++++++++++ src/bin/pg_ctl/pg_ctl.c | 51 ++++++++++++++++++++++++++++- 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index fc0bc8d99e..3a1e9ae8f8 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -93,6 +93,10 @@ #include #endif +#ifdef USE_POSIX_SPAWN +#include +#endif + #include "access/transam.h" #include "access/xlog.h" #include "catalog/pg_control.h" @@ -4585,6 +4589,10 @@ internal_forkexec(int argc, char *argv[], Port *port) char tmpfilename[MAXPGPATH]; BackendParameters param; FILE *fp; +#ifdef USE_POSIX_SPAWN + posix_spawn_file_actions_t spawn_file_actions; + posix_spawnattr_t spawnattrs; +#endif if (!save_backend_variables(¶m, port)) return -1; /* log made by save_backend_variables */ @@ -4642,6 +4650,30 @@ internal_forkexec(int argc, char *argv[], Port *port) /* Insert temp file name after --fork argument */ argv[2] = tmpfilename; +#ifdef USE_POSIX_SPAWN + posix_spawn_file_actions_init(&spawn_file_actions); + posix_spawnattr_init(&spawnattrs); +#ifdef USE_POSIX_SPAWN_DISABLE_ASLR + /* + * Undocumented magic. See bsd/sys/spawn.h and bsd/kern/kern_exec.c in the + * Darwin sources at https://github.com/apple/darwin-xnu. + */ + if ((errno = posix_spawnattr_setflags(&spawnattrs, 0x0100)) != 0) + elog(ERROR, "could not set ASLR disable flag when spawning backend: %m"); +#endif + errno = posix_spawn(&pid, + postgres_exec_path, + &spawn_file_actions, + &spawnattrs, + argv, + NULL); + if (errno != 0) + { + ereport(LOG, + (errmsg("could not spawn server process \"%s\": %m", + postgres_exec_path))); + } +#else /* Fire off execv in child */ if ((pid = fork_process()) == 0) { @@ -4654,6 +4686,7 @@ internal_forkexec(int argc, char *argv[], Port *port) exit(1); } } +#endif return pid; /* Parent returns pid, or -1 on fork failure */ } diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c index 7985da0a94..f105e483c4 100644 --- a/src/bin/pg_ctl/pg_ctl.c +++ b/src/bin/pg_ctl/pg_ctl.c @@ -18,6 +18,10 @@ #include #include +#ifdef USE_POSIX_SPAWN +#include +#endif + #ifdef HAVE_SYS_RESOURCE_H #include #include @@ -442,15 +446,59 @@ free_readfile(char **optlines) static pgpid_t start_postmaster(void) { +#ifdef USE_POSIX_SPAWN + posix_spawn_file_actions_t spawn_file_actions; + posix_spawnattr_t spawnattrs; +#else char cmd[MAXPGPATH]; +#endif #ifndef WIN32 - pgpid_t pm_pid; + pid_t pm_pid; /* Flush stdio channels just before fork, to avoid double-output problems */ fflush(stdout); fflush(stderr); +#ifdef USE_POSIX_SPAWN + posix_spawn_file_actions_init(&spawn_file_actions); + posix_spawnattr_init(&spawnattrs); +#ifdef USE_POSIX_SPAWN_DISABLE_ASLR + /* + * Undocumented magic. See bsd/sys/spawn.h and bsd/kern/kern_exec.c in the + * Darwin sources at https://github.com/apple/darwin-xnu. + */ + if ((errno = posix_spawnattr_setflags(&spawnattrs, 0x0100)) != 0) + write_stderr(_("could not set undocumented ASLR disable flag when spawning postmaster: %s"), + strerror(errno)); +#endif + { + /* XXX:HACK this is incomplete, doesn't include the postopts... */ + /* XXX Theory here was that shell exec style used by the exec code + * might drop the flag, hence spawning executable directly, but doing + * that properly would involve unpicking the options and their quotes + * etc... */ + char *args[] = { + exec_path, + "-D", + getenv("PGDATA"), + NULL + }; + errno = posix_spawn(&pm_pid, + exec_path, + &spawn_file_actions, + &spawnattrs, + args, + NULL); + } + if (errno != 0) + { + write_stderr(_("%s: could not start server: %s\n"), + progname, strerror(errno)); + exit(1); + } + return pm_pid; +#else pm_pid = fork(); if (pm_pid < 0) { @@ -502,6 +550,7 @@ start_postmaster(void) exit(1); return 0; /* keep dumb compilers quiet */ +#endif #else /* WIN32 */ -- 2.30.1 (Apple Git-130)