commit 0aeb31f3e612202e75b88b858d01493139e2fef8
Author: Ian Barwick <barwick@gmail.com>
Date:   Mon Jul 15 23:25:55 2019 +0900

    Ensure "include" directives are only processed where appropriate
    
    This ensures any "include" directives present in postgresql.auto.conf
    or extension control files result in an error.

diff --git a/src/backend/utils/misc/guc-file.l b/src/backend/utils/misc/guc-file.l
index 9ebdd62923..6a4382b787 100644
--- a/src/backend/utils/misc/guc-file.l
+++ b/src/backend/utils/misc/guc-file.l
@@ -550,7 +550,7 @@ AbsoluteConfigLocation(const char *location, const char *calling_file)
 
 /*
  * Read and parse a single configuration file.  This function recurses
- * to handle "include" directives.
+ * to handle "include" directives, unless otherwise requested.
  *
  * If "strict" is true, treat failure to open the config file as an error,
  * otherwise just skip the file.
@@ -558,6 +558,10 @@ AbsoluteConfigLocation(const char *location, const char *calling_file)
  * calling_file/calling_lineno identify the source of the request.
  * Pass NULL/0 if not recursing from an inclusion request.
  *
+ * **files_seen is used to keep track of files which have already been parsed,
+ * to prevent circular inclusion. If set to NULL, it means the caller does
+ * not want include directives to be handled.
+ *
  * See ParseConfigFp for further details.  This one merely adds opening the
  * config file rather than working from a caller-supplied file descriptor,
  * and absolute-ifying the path name if necessary.
@@ -717,6 +721,10 @@ GUC_flex_fatal(const char *msg)
  * name-value pairs read from the input file(s) will be appended to the list.
  * Error reports will also be appended to the list, if elevel < ERROR.
  *
+ * **files_seen is used to keep track of files which have already been parsed,
+ * to prevent circular inclusion. If set to NULL, it means the caller does
+ * not want include directives to be handled.
+ *
  * Returns TRUE if successful, FALSE if an error occurred.  The error has
  * already been ereport'd, it is only necessary for the caller to clean up
  * its own state and release the ConfigVariable list.
@@ -819,7 +827,18 @@ ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
 			 * An include_dir directive isn't a variable and should be
 			 * processed immediately.
 			 */
-			if (opt_value[0] == '\0')
+			if (files_seen == NULL)
+			{
+				ereport(elevel,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("\"include_dir\" not permitted in file \"%s\" line %u",
+								config_file, ConfigFileLineno - 1)));
+				record_config_file_error("\"include_dir\" not permitted",
+										 config_file, ConfigFileLineno - 1,
+										 head_p, tail_p);
+				OK = false;
+			}
+			else if (opt_value[0] == '\0')
 			{
 				record_config_file_error("\"include_dir\" must not be empty",
 										 config_file, ConfigFileLineno - 1,
@@ -841,7 +860,18 @@ ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
 			 * An include_if_exists directive isn't a variable and should be
 			 * processed immediately.
 			 */
-			if (opt_value[0] == '\0')
+			if (files_seen == NULL)
+			{
+				ereport(elevel,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("\"include_if_exists\" not permitted in file \"%s\" line %u",
+								config_file, ConfigFileLineno - 1)));
+				record_config_file_error("\"include_if_exists\" not permitted",
+										 config_file, ConfigFileLineno - 1,
+										 head_p, tail_p);
+				OK = false;
+			}
+			else if (opt_value[0] == '\0')
 			{
 				record_config_file_error("\"include_if_exists\" must not be empty",
 										 config_file, ConfigFileLineno - 1,
@@ -863,7 +893,18 @@ ParseConfigFp(FILE *fp, const char *config_file, int depth, int elevel,
 			 * An include directive isn't a variable and should be processed
 			 * immediately.
 			 */
-			if (opt_value[0] == '\0')
+			if (files_seen == NULL)
+			{
+				ereport(elevel,
+						(errcode(ERRCODE_SYNTAX_ERROR),
+						 errmsg("\"include\" not permitted in file \"%s\" line %u",
+								config_file, ConfigFileLineno - 1)));
+				record_config_file_error("\"include\" not permitted",
+										 config_file, ConfigFileLineno - 1,
+										 head_p, tail_p);
+				OK = false;
+			}
+			else if (opt_value[0] == '\0')
 			{
 				record_config_file_error("\"include\" must not be empty",
 										 config_file, ConfigFileLineno - 1,
