diff options
author | Noah Misch <noah@leadboat.com> | 2018-02-26 07:39:44 -0800 |
---|---|---|
committer | Noah Misch <noah@leadboat.com> | 2018-02-26 07:39:48 -0800 |
commit | 3db38b0ceffd95be81573c884f4be21f79ca954a (patch) | |
tree | c89fd1c23a11a8b1825b4b16bb4eda08bf5a6127 /src/bin/pg_dump/pg_dump.c | |
parent | de8ffd6663fbe5a263ff1abc2820f7d6a00ba9a9 (diff) |
Empty search_path in Autovacuum and non-psql/pgbench clients.
This makes the client programs behave as documented regardless of the
connect-time search_path and regardless of user-created objects. Today,
a malicious user with CREATE permission on a search_path schema can take
control of certain of these clients' queries and invoke arbitrary SQL
functions under the client identity, often a superuser. This is
exploitable in the default configuration, where all users have CREATE
privilege on schema "public".
This changes behavior of user-defined code stored in the database, like
pg_index.indexprs and pg_extension_config_dump(). If they reach code
bearing unqualified names, "does not exist" or "no schema has been
selected to create in" errors might appear. Users may fix such errors
by schema-qualifying affected names. After upgrading, consider watching
server logs for these errors.
The --table arguments of src/bin/scripts clients have been lax; for
example, "vacuumdb -Zt pg_am\;CHECKPOINT" performed a checkpoint. That
now fails, but for now, "vacuumdb -Zt 'pg_am(amname);CHECKPOINT'" still
performs a checkpoint.
Back-patch to 9.3 (all supported versions).
Reviewed by Tom Lane, though this fix strategy was not his first choice.
Reported by Arseniy Sharoglazov.
Security: CVE-2018-1058
Diffstat (limited to 'src/bin/pg_dump/pg_dump.c')
-rw-r--r-- | src/bin/pg_dump/pg_dump.c | 17 |
1 files changed, 15 insertions, 2 deletions
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index c0a9d8b7c70..50c62ce7059 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -61,6 +61,7 @@ #include "pg_backup_db.h" #include "pg_backup_utils.h" #include "dumputils.h" +#include "fe_utils/connect.h" #include "parallel.h" extern char *optarg; @@ -969,6 +970,9 @@ setup_connection(Archive *AH, const char *dumpencoding, char *use_role) PGconn *conn = GetConnection(AH); const char *std_strings; + if (AH->remoteVersion >= 70300) + PQclear(ExecuteSqlQueryForSingleRow(AH, ALWAYS_SECURE_SEARCH_PATH_SQL)); + /* * Set the client encoding if requested. */ @@ -1235,13 +1239,20 @@ expand_table_name_patterns(Archive *fout, for (cell = patterns->head; cell; cell = cell->next) { + /* + * Query must remain ABSOLUTELY devoid of unqualified names. This + * would be unnecessary given a pg_table_is_visible() variant taking a + * search_path argument. + */ if (cell != patterns->head) appendPQExpBuffer(query, "UNION ALL\n"); appendPQExpBuffer(query, "SELECT c.oid" "\nFROM pg_catalog.pg_class c" - "\n LEFT JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace" - "\nWHERE c.relkind in ('%c', '%c', '%c', '%c', '%c')\n", + "\n LEFT JOIN pg_catalog.pg_namespace n" + "\n ON n.oid OPERATOR(pg_catalog.=) c.relnamespace" + "\nWHERE c.relkind OPERATOR(pg_catalog.=) ANY" + "\n (array['%c', '%c', '%c', '%c', '%c'])\n", RELKIND_RELATION, RELKIND_SEQUENCE, RELKIND_VIEW, RELKIND_MATVIEW, RELKIND_FOREIGN_TABLE); processSQLNamePattern(GetConnection(fout), query, cell->val, true, @@ -1249,7 +1260,9 @@ expand_table_name_patterns(Archive *fout, "pg_catalog.pg_table_is_visible(c.oid)"); } + ExecuteSqlStatement(fout, "RESET search_path"); res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK); + PQclear(ExecuteSqlQueryForSingleRow(fout, ALWAYS_SECURE_SEARCH_PATH_SQL)); for (i = 0; i < PQntuples(res); i++) { |