mirror of
https://github.com/postgres/postgres.git
synced 2025-11-09 06:21:09 +03:00
Refactor dir/file permissions
Consolidate directory and file create permissions for tools which work with the PG data directory by adding a new module (common/file_perm.c) that contains variables (pg_file_create_mode, pg_dir_create_mode) and constants to initialize them (0600 for files and 0700 for directories). Convert mkdir() calls in the backend to MakePGDirectory() if the original call used default permissions (always the case for regular PG directories). Add tests to make sure permissions in PGDATA are set correctly by the tools which modify the PG data directory. Authors: David Steele <david@pgmasters.net>, Adam Brightwell <adam.brightwell@crunchydata.com> Reviewed-By: Michael Paquier, with discussion amongst many others. Discussion: https://postgr.es/m/ad346fe6-b23e-59f1-ecb7-0e08390ad629%40pgmasters.net
This commit is contained in:
@@ -4107,7 +4107,7 @@ ValidateXLOGDirectoryStructure(void)
|
||||
{
|
||||
ereport(LOG,
|
||||
(errmsg("creating missing WAL directory \"%s\"", path)));
|
||||
if (mkdir(path, S_IRWXU) < 0)
|
||||
if (MakePGDirectory(path) < 0)
|
||||
ereport(FATAL,
|
||||
(errmsg("could not create missing directory \"%s\": %m",
|
||||
path)));
|
||||
|
||||
@@ -68,6 +68,7 @@
|
||||
#include "commands/seclabel.h"
|
||||
#include "commands/tablecmds.h"
|
||||
#include "commands/tablespace.h"
|
||||
#include "common/file_perm.h"
|
||||
#include "miscadmin.h"
|
||||
#include "postmaster/bgwriter.h"
|
||||
#include "storage/fd.h"
|
||||
@@ -151,7 +152,7 @@ TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo)
|
||||
else
|
||||
{
|
||||
/* Directory creation failed? */
|
||||
if (mkdir(dir, S_IRWXU) < 0)
|
||||
if (MakePGDirectory(dir) < 0)
|
||||
{
|
||||
char *parentdir;
|
||||
|
||||
@@ -173,7 +174,7 @@ TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo)
|
||||
get_parent_directory(parentdir);
|
||||
get_parent_directory(parentdir);
|
||||
/* Can't create parent and it doesn't already exist? */
|
||||
if (mkdir(parentdir, S_IRWXU) < 0 && errno != EEXIST)
|
||||
if (MakePGDirectory(parentdir) < 0 && errno != EEXIST)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not create directory \"%s\": %m",
|
||||
@@ -184,7 +185,7 @@ TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo)
|
||||
parentdir = pstrdup(dir);
|
||||
get_parent_directory(parentdir);
|
||||
/* Can't create parent and it doesn't already exist? */
|
||||
if (mkdir(parentdir, S_IRWXU) < 0 && errno != EEXIST)
|
||||
if (MakePGDirectory(parentdir) < 0 && errno != EEXIST)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not create directory \"%s\": %m",
|
||||
@@ -192,7 +193,7 @@ TablespaceCreateDbspace(Oid spcNode, Oid dbNode, bool isRedo)
|
||||
pfree(parentdir);
|
||||
|
||||
/* Create database directory */
|
||||
if (mkdir(dir, S_IRWXU) < 0)
|
||||
if (MakePGDirectory(dir) < 0)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not create directory \"%s\": %m",
|
||||
@@ -279,7 +280,8 @@ CreateTableSpace(CreateTableSpaceStmt *stmt)
|
||||
/*
|
||||
* Check that location isn't too long. Remember that we're going to append
|
||||
* 'PG_XXX/<dboid>/<relid>_<fork>.<nnn>'. FYI, we never actually
|
||||
* reference the whole path here, but mkdir() uses the first two parts.
|
||||
* reference the whole path here, but MakePGDirectory() uses the first two
|
||||
* parts.
|
||||
*/
|
||||
if (strlen(location) + 1 + strlen(TABLESPACE_VERSION_DIRECTORY) + 1 +
|
||||
OIDCHARS + 1 + OIDCHARS + 1 + FORKNAMECHARS + 1 + OIDCHARS > MAXPGPATH)
|
||||
@@ -574,7 +576,7 @@ create_tablespace_directories(const char *location, const Oid tablespaceoid)
|
||||
* Attempt to coerce target directory to safe permissions. If this fails,
|
||||
* it doesn't exist or has the wrong owner.
|
||||
*/
|
||||
if (chmod(location, S_IRWXU) != 0)
|
||||
if (chmod(location, pg_dir_create_mode) != 0)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
ereport(ERROR,
|
||||
@@ -599,7 +601,7 @@ create_tablespace_directories(const char *location, const Oid tablespaceoid)
|
||||
if (stat(location_with_version_dir, &st) == 0 && S_ISDIR(st.st_mode))
|
||||
{
|
||||
if (!rmtree(location_with_version_dir, true))
|
||||
/* If this failed, mkdir() below is going to error. */
|
||||
/* If this failed, MakePGDirectory() below is going to error. */
|
||||
ereport(WARNING,
|
||||
(errmsg("some useless files may be left behind in old database directory \"%s\"",
|
||||
location_with_version_dir)));
|
||||
@@ -610,7 +612,7 @@ create_tablespace_directories(const char *location, const Oid tablespaceoid)
|
||||
* The creation of the version directory prevents more than one tablespace
|
||||
* in a single location.
|
||||
*/
|
||||
if (mkdir(location_with_version_dir, S_IRWXU) < 0)
|
||||
if (MakePGDirectory(location_with_version_dir) < 0)
|
||||
{
|
||||
if (errno == EEXIST)
|
||||
ereport(ERROR,
|
||||
|
||||
@@ -97,6 +97,7 @@
|
||||
#include "access/xlog.h"
|
||||
#include "bootstrap/bootstrap.h"
|
||||
#include "catalog/pg_control.h"
|
||||
#include "common/file_perm.h"
|
||||
#include "common/ip.h"
|
||||
#include "lib/ilist.h"
|
||||
#include "libpq/auth.h"
|
||||
@@ -589,7 +590,7 @@ PostmasterMain(int argc, char *argv[])
|
||||
/*
|
||||
* for security, no dir or file created can be group or other accessible
|
||||
*/
|
||||
umask(S_IRWXG | S_IRWXO);
|
||||
umask(PG_MODE_MASK_OWNER);
|
||||
|
||||
/*
|
||||
* Initialize random(3) so we don't get the same values in every run.
|
||||
@@ -4490,9 +4491,9 @@ internal_forkexec(int argc, char *argv[], Port *port)
|
||||
{
|
||||
/*
|
||||
* As in OpenTemporaryFileInTablespace, try to make the temp-file
|
||||
* directory
|
||||
* directory, ignoring errors.
|
||||
*/
|
||||
mkdir(PG_TEMP_FILES_DIR, S_IRWXU);
|
||||
(void) MakePGDirectory(PG_TEMP_FILES_DIR);
|
||||
|
||||
fp = AllocateFile(tmpfilename, PG_BINARY_W);
|
||||
if (!fp)
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "postmaster/postmaster.h"
|
||||
#include "postmaster/syslogger.h"
|
||||
#include "storage/dsm.h"
|
||||
#include "storage/fd.h"
|
||||
#include "storage/ipc.h"
|
||||
#include "storage/latch.h"
|
||||
#include "storage/pg_shmem.h"
|
||||
@@ -322,7 +323,7 @@ SysLoggerMain(int argc, char *argv[])
|
||||
/*
|
||||
* Also, create new directory if not present; ignore errors
|
||||
*/
|
||||
mkdir(Log_directory, S_IRWXU);
|
||||
(void) MakePGDirectory(Log_directory);
|
||||
}
|
||||
if (strcmp(Log_filename, currentLogFilename) != 0)
|
||||
{
|
||||
@@ -564,7 +565,7 @@ SysLogger_Start(void)
|
||||
/*
|
||||
* Create log directory if not present; ignore errors
|
||||
*/
|
||||
mkdir(Log_directory, S_IRWXU);
|
||||
(void) MakePGDirectory(Log_directory);
|
||||
|
||||
/*
|
||||
* The initial logfile is created right in the postmaster, to verify that
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "access/xlog_internal.h" /* for pg_start/stop_backup */
|
||||
#include "catalog/catalog.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "common/file_perm.h"
|
||||
#include "lib/stringinfo.h"
|
||||
#include "libpq/libpq.h"
|
||||
#include "libpq/pqformat.h"
|
||||
@@ -930,7 +931,7 @@ sendFileWithContent(const char *filename, const char *content)
|
||||
statbuf.st_gid = getegid();
|
||||
#endif
|
||||
statbuf.st_mtime = time(NULL);
|
||||
statbuf.st_mode = S_IRUSR | S_IWUSR;
|
||||
statbuf.st_mode = pg_file_create_mode;
|
||||
statbuf.st_size = len;
|
||||
|
||||
_tarWriteHeader(filename, NULL, &statbuf, false);
|
||||
@@ -1628,7 +1629,7 @@ _tarWriteDir(const char *pathbuf, int basepathlen, struct stat *statbuf,
|
||||
#else
|
||||
if (pgwin32_is_junction(pathbuf))
|
||||
#endif
|
||||
statbuf->st_mode = S_IFDIR | S_IRWXU;
|
||||
statbuf->st_mode = S_IFDIR | pg_dir_create_mode;
|
||||
|
||||
return _tarWriteHeader(pathbuf + basepathlen + 1, NULL, statbuf, sizeonly);
|
||||
}
|
||||
|
||||
@@ -1166,13 +1166,14 @@ CreateSlotOnDisk(ReplicationSlot *slot)
|
||||
* It's just barely possible that some previous effort to create or drop a
|
||||
* slot with this name left a temp directory lying around. If that seems
|
||||
* to be the case, try to remove it. If the rmtree() fails, we'll error
|
||||
* out at the mkdir() below, so we don't bother checking success.
|
||||
* out at the MakePGDirectory() below, so we don't bother checking
|
||||
* success.
|
||||
*/
|
||||
if (stat(tmppath, &st) == 0 && S_ISDIR(st.st_mode))
|
||||
rmtree(tmppath, true);
|
||||
|
||||
/* Create and fsync the temporary slot directory. */
|
||||
if (mkdir(tmppath, S_IRWXU) < 0)
|
||||
if (MakePGDirectory(tmppath) < 0)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not create directory \"%s\": %m",
|
||||
|
||||
@@ -41,7 +41,7 @@ copydir(char *fromdir, char *todir, bool recurse)
|
||||
char fromfile[MAXPGPATH * 2];
|
||||
char tofile[MAXPGPATH * 2];
|
||||
|
||||
if (mkdir(todir, S_IRWXU) != 0)
|
||||
if (MakePGDirectory(todir) != 0)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("could not create directory \"%s\": %m", todir)));
|
||||
|
||||
@@ -84,6 +84,7 @@
|
||||
#include "access/xlog.h"
|
||||
#include "catalog/catalog.h"
|
||||
#include "catalog/pg_tablespace.h"
|
||||
#include "common/file_perm.h"
|
||||
#include "pgstat.h"
|
||||
#include "portability/mem.h"
|
||||
#include "storage/fd.h"
|
||||
@@ -124,12 +125,6 @@
|
||||
*/
|
||||
#define FD_MINFREE 10
|
||||
|
||||
/*
|
||||
* Default mode for created files, unless something else is specified using
|
||||
* the *Perm() function variants.
|
||||
*/
|
||||
#define PG_FILE_MODE_DEFAULT (S_IRUSR | S_IWUSR)
|
||||
|
||||
/*
|
||||
* A number of platforms allow individual processes to open many more files
|
||||
* than they can really support when *many* processes do the same thing.
|
||||
@@ -937,7 +932,7 @@ set_max_safe_fds(void)
|
||||
int
|
||||
BasicOpenFile(const char *fileName, int fileFlags)
|
||||
{
|
||||
return BasicOpenFilePerm(fileName, fileFlags, PG_FILE_MODE_DEFAULT);
|
||||
return BasicOpenFilePerm(fileName, fileFlags, pg_file_create_mode);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1356,7 +1351,7 @@ FileInvalidate(File file)
|
||||
File
|
||||
PathNameOpenFile(const char *fileName, int fileFlags)
|
||||
{
|
||||
return PathNameOpenFilePerm(fileName, fileFlags, PG_FILE_MODE_DEFAULT);
|
||||
return PathNameOpenFilePerm(fileName, fileFlags, pg_file_create_mode);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -1434,7 +1429,7 @@ PathNameOpenFilePerm(const char *fileName, int fileFlags, mode_t fileMode)
|
||||
void
|
||||
PathNameCreateTemporaryDir(const char *basedir, const char *directory)
|
||||
{
|
||||
if (mkdir(directory, S_IRWXU) < 0)
|
||||
if (MakePGDirectory(directory) < 0)
|
||||
{
|
||||
if (errno == EEXIST)
|
||||
return;
|
||||
@@ -1444,14 +1439,14 @@ PathNameCreateTemporaryDir(const char *basedir, const char *directory)
|
||||
* EEXIST to close a race against another process following the same
|
||||
* algorithm.
|
||||
*/
|
||||
if (mkdir(basedir, S_IRWXU) < 0 && errno != EEXIST)
|
||||
if (MakePGDirectory(basedir) < 0 && errno != EEXIST)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("cannot create temporary directory \"%s\": %m",
|
||||
basedir)));
|
||||
|
||||
/* Try again. */
|
||||
if (mkdir(directory, S_IRWXU) < 0 && errno != EEXIST)
|
||||
if (MakePGDirectory(directory) < 0 && errno != EEXIST)
|
||||
ereport(ERROR,
|
||||
(errcode_for_file_access(),
|
||||
errmsg("cannot create temporary subdirectory \"%s\": %m",
|
||||
@@ -1601,11 +1596,11 @@ OpenTemporaryFileInTablespace(Oid tblspcOid, bool rejectError)
|
||||
* We might need to create the tablespace's tempfile directory, if no
|
||||
* one has yet done so.
|
||||
*
|
||||
* Don't check for error from mkdir; it could fail if someone else
|
||||
* just did the same thing. If it doesn't work then we'll bomb out on
|
||||
* the second create attempt, instead.
|
||||
* Don't check for an error from MakePGDirectory; it could fail if
|
||||
* someone else just did the same thing. If it doesn't work then
|
||||
* we'll bomb out on the second create attempt, instead.
|
||||
*/
|
||||
mkdir(tempdirpath, S_IRWXU);
|
||||
(void) MakePGDirectory(tempdirpath);
|
||||
|
||||
file = PathNameOpenFile(tempfilepath,
|
||||
O_RDWR | O_CREAT | O_TRUNC | PG_BINARY);
|
||||
@@ -2401,7 +2396,7 @@ TryAgain:
|
||||
int
|
||||
OpenTransientFile(const char *fileName, int fileFlags)
|
||||
{
|
||||
return OpenTransientFilePerm(fileName, fileFlags, PG_FILE_MODE_DEFAULT);
|
||||
return OpenTransientFilePerm(fileName, fileFlags, pg_file_create_mode);
|
||||
}
|
||||
|
||||
/*
|
||||
@@ -3554,3 +3549,27 @@ fsync_parent_path(const char *fname, int elevel)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Create a PostgreSQL data sub-directory
|
||||
*
|
||||
* The data directory itself, along with most other directories, are created at
|
||||
* initdb-time, but we do have some occations where we create directories from
|
||||
* the backend (CREATE TABLESPACE, for example). In those cases, we want to
|
||||
* make sure that those directories are created consistently. Today, that means
|
||||
* making sure that the created directory has the correct permissions, which is
|
||||
* what pg_dir_create_mode tracks for us.
|
||||
*
|
||||
* Note that we also set the umask() based on what we understand the correct
|
||||
* permissions to be (see file_perm.c).
|
||||
*
|
||||
* For permissions other than the default mkdir() can be used directly, but be
|
||||
* sure to consider carefully such cases -- a directory with incorrect
|
||||
* permissions in a PostgreSQL data directory could cause backups and other
|
||||
* processes to fail.
|
||||
*/
|
||||
int
|
||||
MakePGDirectory(const char *directoryName)
|
||||
{
|
||||
return mkdir(directoryName, pg_dir_create_mode);
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@
|
||||
#ifdef HAVE_SYS_SHM_H
|
||||
#include <sys/shm.h>
|
||||
#endif
|
||||
#include "common/file_perm.h"
|
||||
#include "pgstat.h"
|
||||
|
||||
#include "portability/mem.h"
|
||||
@@ -285,7 +286,7 @@ dsm_impl_posix(dsm_op op, dsm_handle handle, Size request_size,
|
||||
* returning.
|
||||
*/
|
||||
flags = O_RDWR | (op == DSM_OP_CREATE ? O_CREAT | O_EXCL : 0);
|
||||
if ((fd = shm_open(name, flags, 0600)) == -1)
|
||||
if ((fd = shm_open(name, flags, PG_FILE_MODE_OWNER)) == -1)
|
||||
{
|
||||
if (errno != EEXIST)
|
||||
ereport(elevel,
|
||||
|
||||
@@ -137,6 +137,10 @@ proc_exit(int code)
|
||||
else
|
||||
snprintf(gprofDirName, 32, "gprof/%d", (int) getpid());
|
||||
|
||||
/*
|
||||
* Use mkdir() instead of MakePGDirectory() since we aren't making a
|
||||
* PG directory here.
|
||||
*/
|
||||
mkdir("gprof", S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
mkdir(gprofDirName, S_IRWXU | S_IRWXG | S_IRWXO);
|
||||
chdir(gprofDirName);
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
|
||||
#include "access/htup_details.h"
|
||||
#include "catalog/pg_authid.h"
|
||||
#include "common/file_perm.h"
|
||||
#include "libpq/libpq.h"
|
||||
#include "mb/pg_wchar.h"
|
||||
#include "miscadmin.h"
|
||||
@@ -831,7 +832,7 @@ CreateLockFile(const char *filename, bool amPostmaster,
|
||||
* Think not to make the file protection weaker than 0600. See
|
||||
* comments below.
|
||||
*/
|
||||
fd = open(filename, O_RDWR | O_CREAT | O_EXCL, 0600);
|
||||
fd = open(filename, O_RDWR | O_CREAT | O_EXCL, pg_file_create_mode);
|
||||
if (fd >= 0)
|
||||
break; /* Success; exit the retry loop */
|
||||
|
||||
@@ -848,7 +849,7 @@ CreateLockFile(const char *filename, bool amPostmaster,
|
||||
* Read the file to get the old owner's PID. Note race condition
|
||||
* here: file might have been deleted since we tried to create it.
|
||||
*/
|
||||
fd = open(filename, O_RDONLY, 0600);
|
||||
fd = open(filename, O_RDONLY, pg_file_create_mode);
|
||||
if (fd < 0)
|
||||
{
|
||||
if (errno == ENOENT)
|
||||
|
||||
Reference in New Issue
Block a user