diff --git a/src/backend/utils/misc/guc-file.l b/src/backend/utils/misc/guc-file.l index afe4fe6d775..581507a7696 100644 --- a/src/backend/utils/misc/guc-file.l +++ b/src/backend/utils/misc/guc-file.l @@ -567,6 +567,22 @@ ParseConfigFile(const char *config_file, bool strict, bool OK = true; FILE *fp; + /* + * Reject file name that is all-blank (including empty), as that leads to + * confusion --- we'd try to read the containing directory as a file. + */ + if (strspn(config_file, " \t\r\n") == strlen(config_file)) + { + ereport(elevel, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("empty configuration file name: \"%s\"", + config_file))); + record_config_file_error("empty configuration file name", + calling_file, calling_lineno, + head_p, tail_p); + return false; + } + /* * Reject too-deep include nesting depth. This is just a safety check to * avoid dumping core due to stack overflow if an include file loops back @@ -585,6 +601,26 @@ ParseConfigFile(const char *config_file, bool strict, } abs_path = AbsoluteConfigLocation(config_file, calling_file); + + /* + * Reject direct recursion. Indirect recursion is also possible, but it's + * harder to detect and so doesn't seem worth the trouble. (We test at + * this step because the canonicalization done by AbsoluteConfigLocation + * makes it more likely that a simple strcmp comparison will match.) + */ + if (calling_file && strcmp(abs_path, calling_file) == 0) + { + ereport(elevel, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("configuration file recursion in \"%s\"", + calling_file))); + record_config_file_error("configuration file recursion", + calling_file, calling_lineno, + head_p, tail_p); + pfree(abs_path); + return false; + } + fp = AllocateFile(abs_path, "r"); if (!fp) { @@ -933,6 +969,28 @@ ParseConfigDirectory(const char *includedir, int size_filenames; bool status; + /* + * Reject directory name that is all-blank (including empty), as that + * leads to confusion --- we'd read the containing directory, typically + * resulting in recursive inclusion of the same file(s). + */ + if (strspn(includedir, " \t\r\n") == strlen(includedir)) + { + ereport(elevel, + (errcode(ERRCODE_INVALID_PARAMETER_VALUE), + errmsg("empty configuration directory name: \"%s\"", + includedir))); + record_config_file_error("empty configuration directory name", + calling_file, calling_lineno, + head_p, tail_p); + return false; + } + + /* + * We don't check for recursion or too-deep nesting depth here; the + * subsequent calls to ParseConfigFile will take care of that. + */ + directory = AbsoluteConfigLocation(includedir, calling_file); d = AllocateDir(directory); if (d == NULL) diff --git a/src/backend/utils/misc/postgresql.conf.sample b/src/backend/utils/misc/postgresql.conf.sample index 179869f1d9c..41191d4f457 100644 --- a/src/backend/utils/misc/postgresql.conf.sample +++ b/src/backend/utils/misc/postgresql.conf.sample @@ -675,12 +675,13 @@ #------------------------------------------------------------------------------ # These options allow settings to be loaded from files other than the -# default postgresql.conf. +# default postgresql.conf. Note that these are directives, not variable +# assignments, so they can usefully be given more than once. -#include_dir = '' # include files ending in '.conf' from +#include_dir = '...' # include files ending in '.conf' from # a directory, e.g., 'conf.d' -#include_if_exists = '' # include file only if it exists -#include = '' # include file +#include_if_exists = '...' # include file only if it exists +#include = '...' # include file #------------------------------------------------------------------------------