Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit815172b

Browse files
committed
Avoid using unsafe search_path settings during dump and restore.
Historically, pg_dump has "set search_path = foo, pg_catalog" whendumping an object in schema "foo", and has also caused that settingto be used while restoring the object. This is problematic becausefunctions and operators in schema "foo" could capture references meantto refer to pg_catalog entries, both in the queries issued by pg_dumpand those issued during the subsequent restore run. That couldresult in dump/restore misbehavior, or in privilege escalation if anefarious user installs trojan-horse functions or operators.This patch changes pg_dump so that it does not change the search_pathdynamically. The emitted restore script sets the search_path to whatwas used at dump time, and then leaves it alone thereafter. Createdobjects are placed in the correct schema, regardless of the activesearch_path, by dint of schema-qualifying their names in the CREATEcommands, as well as in subsequent ALTER and ALTER-like commands.Since this change requires a change in the behavior of pg_restorewhen processing an archive file made according to this new convention,bump the archive file version number; old versions of pg_restore willtherefore refuse to process files made with new versions of pg_dump.Security:CVE-2018-1058
1 parentbcce4c3 commit815172b

File tree

14 files changed

+1002
-1261
lines changed

14 files changed

+1002
-1261
lines changed

‎src/backend/utils/adt/ruleutils.c

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -82,15 +82,17 @@
8282
#definePRETTYINDENT_LIMIT40/* wrap limit */
8383

8484
/* Pretty flags */
85-
#definePRETTYFLAG_PAREN1
86-
#definePRETTYFLAG_INDENT2
85+
#definePRETTYFLAG_PAREN0x0001
86+
#definePRETTYFLAG_INDENT0x0002
87+
#definePRETTYFLAG_SCHEMA0x0004
8788

8889
/* Default line length for pretty-print wrapping: 0 means wrap always */
8990
#defineWRAP_COLUMN_DEFAULT0
9091

91-
/*macro to test if pretty action needed */
92+
/*macros to test if pretty action needed */
9293
#definePRETTY_PAREN(context)((context)->prettyFlags & PRETTYFLAG_PAREN)
9394
#definePRETTY_INDENT(context)((context)->prettyFlags & PRETTYFLAG_INDENT)
95+
#definePRETTY_SCHEMA(context)((context)->prettyFlags & PRETTYFLAG_SCHEMA)
9496

9597

9698
/* ----------
@@ -489,7 +491,7 @@ pg_get_ruledef_ext(PG_FUNCTION_ARGS)
489491
intprettyFlags;
490492
char*res;
491493

492-
prettyFlags=pretty ?PRETTYFLAG_PAREN |PRETTYFLAG_INDENT :PRETTYFLAG_INDENT;
494+
prettyFlags=pretty ?(PRETTYFLAG_PAREN |PRETTYFLAG_INDENT |PRETTYFLAG_SCHEMA) :PRETTYFLAG_INDENT;
493495

494496
res=pg_get_ruledef_worker(ruleoid,prettyFlags);
495497

@@ -610,7 +612,7 @@ pg_get_viewdef_ext(PG_FUNCTION_ARGS)
610612
intprettyFlags;
611613
char*res;
612614

613-
prettyFlags=pretty ?PRETTYFLAG_PAREN |PRETTYFLAG_INDENT :PRETTYFLAG_INDENT;
615+
prettyFlags=pretty ?(PRETTYFLAG_PAREN |PRETTYFLAG_INDENT |PRETTYFLAG_SCHEMA) :PRETTYFLAG_INDENT;
614616

615617
res=pg_get_viewdef_worker(viewoid,prettyFlags,WRAP_COLUMN_DEFAULT);
616618

@@ -630,7 +632,7 @@ pg_get_viewdef_wrap(PG_FUNCTION_ARGS)
630632
char*res;
631633

632634
/* calling this implies we want pretty printing */
633-
prettyFlags=PRETTYFLAG_PAREN |PRETTYFLAG_INDENT;
635+
prettyFlags=PRETTYFLAG_PAREN |PRETTYFLAG_INDENT |PRETTYFLAG_SCHEMA;
634636

635637
res=pg_get_viewdef_worker(viewoid,prettyFlags,wrap);
636638

@@ -676,7 +678,7 @@ pg_get_viewdef_name_ext(PG_FUNCTION_ARGS)
676678
Oidviewoid;
677679
char*res;
678680

679-
prettyFlags=pretty ?PRETTYFLAG_PAREN |PRETTYFLAG_INDENT :PRETTYFLAG_INDENT;
681+
prettyFlags=pretty ?(PRETTYFLAG_PAREN |PRETTYFLAG_INDENT |PRETTYFLAG_SCHEMA) :PRETTYFLAG_INDENT;
680682

681683
/* Look up view name. Can't lock it - we might not have privileges. */
682684
viewrel=makeRangeVarFromNameList(textToQualifiedNameList(viewname));
@@ -910,8 +912,15 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty)
910912
appendStringInfoString(&buf," TRUNCATE");
911913
findx++;
912914
}
915+
916+
/*
917+
* In non-pretty mode, always schema-qualify the target table name for
918+
* safety. In pretty mode, schema-qualify only if not visible.
919+
*/
913920
appendStringInfo(&buf," ON %s ",
914-
generate_relation_name(trigrec->tgrelid,NIL));
921+
pretty ?
922+
generate_relation_name(trigrec->tgrelid,NIL) :
923+
generate_qualified_relation_name(trigrec->tgrelid));
915924

916925
if (OidIsValid(trigrec->tgconstraint))
917926
{
@@ -984,7 +993,7 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty)
984993
context.windowClause=NIL;
985994
context.windowTList=NIL;
986995
context.varprefix= true;
987-
context.prettyFlags=pretty ?PRETTYFLAG_PAREN |PRETTYFLAG_INDENT :PRETTYFLAG_INDENT;
996+
context.prettyFlags=pretty ?(PRETTYFLAG_PAREN |PRETTYFLAG_INDENT |PRETTYFLAG_SCHEMA) :PRETTYFLAG_INDENT;
988997
context.wrapColumn=WRAP_COLUMN_DEFAULT;
989998
context.indentLevel=PRETTYINDENT_STD;
990999
context.special_exprkind=EXPR_KIND_NONE;
@@ -1071,7 +1080,7 @@ pg_get_indexdef_ext(PG_FUNCTION_ARGS)
10711080
intprettyFlags;
10721081
char*res;
10731082

1074-
prettyFlags=pretty ?PRETTYFLAG_PAREN |PRETTYFLAG_INDENT :PRETTYFLAG_INDENT;
1083+
prettyFlags=pretty ?(PRETTYFLAG_PAREN |PRETTYFLAG_INDENT |PRETTYFLAG_SCHEMA) :PRETTYFLAG_INDENT;
10751084

10761085
res=pg_get_indexdef_worker(indexrelid,colno,NULL,colno!=0, false,
10771086
prettyFlags, true);
@@ -1099,7 +1108,8 @@ pg_get_indexdef_columns(Oid indexrelid, bool pretty)
10991108
{
11001109
intprettyFlags;
11011110

1102-
prettyFlags=pretty ?PRETTYFLAG_PAREN |PRETTYFLAG_INDENT :PRETTYFLAG_INDENT;
1111+
prettyFlags=pretty ? (PRETTYFLAG_PAREN |PRETTYFLAG_INDENT |PRETTYFLAG_SCHEMA) :PRETTYFLAG_INDENT;
1112+
11031113
returnpg_get_indexdef_worker(indexrelid,0,NULL, true, false,
11041114
prettyFlags, false);
11051115
}
@@ -1229,7 +1239,9 @@ pg_get_indexdef_worker(Oid indexrelid, int colno,
12291239
appendStringInfo(&buf,"CREATE %sINDEX %s ON %s USING %s (",
12301240
idxrec->indisunique ?"UNIQUE " :"",
12311241
quote_identifier(NameStr(idxrelrec->relname)),
1232-
generate_relation_name(indrelid,NIL),
1242+
(prettyFlags&PRETTYFLAG_SCHEMA) ?
1243+
generate_relation_name(indrelid,NIL) :
1244+
generate_qualified_relation_name(indrelid),
12331245
quote_identifier(NameStr(amrec->amname)));
12341246
else/* currently, must be EXCLUDE constraint */
12351247
appendStringInfo(&buf,"EXCLUDE USING %s (",
@@ -1427,7 +1439,7 @@ pg_get_constraintdef_ext(PG_FUNCTION_ARGS)
14271439
intprettyFlags;
14281440
char*res;
14291441

1430-
prettyFlags=pretty ?PRETTYFLAG_PAREN |PRETTYFLAG_INDENT :PRETTYFLAG_INDENT;
1442+
prettyFlags=pretty ?(PRETTYFLAG_PAREN |PRETTYFLAG_INDENT |PRETTYFLAG_SCHEMA) :PRETTYFLAG_INDENT;
14311443

14321444
res=pg_get_constraintdef_worker(constraintId, false,prettyFlags, true);
14331445

@@ -1869,7 +1881,7 @@ pg_get_expr_ext(PG_FUNCTION_ARGS)
18691881
intprettyFlags;
18701882
char*relname;
18711883

1872-
prettyFlags=pretty ?PRETTYFLAG_PAREN |PRETTYFLAG_INDENT :PRETTYFLAG_INDENT;
1884+
prettyFlags=pretty ?(PRETTYFLAG_PAREN |PRETTYFLAG_INDENT |PRETTYFLAG_SCHEMA) :PRETTYFLAG_INDENT;
18731885

18741886
if (OidIsValid(relid))
18751887
{
@@ -4300,7 +4312,10 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc,
43004312
}
43014313

43024314
/* The relation the rule is fired on */
4303-
appendStringInfo(buf," TO %s",generate_relation_name(ev_class,NIL));
4315+
appendStringInfo(buf," TO %s",
4316+
(prettyFlags&PRETTYFLAG_SCHEMA) ?
4317+
generate_relation_name(ev_class,NIL) :
4318+
generate_qualified_relation_name(ev_class));
43044319

43054320
/* If the rule has an event qualification, add it */
43064321
if (ev_qual==NULL)

‎src/bin/pg_dump/dumputils.c

Lines changed: 71 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ static void AddAcl(PQExpBuffer aclbuf, const char *keyword,
3434
*
3535
*name: the object name, in the form to use in the commands (already quoted)
3636
*subname: the sub-object name, if any (already quoted); NULL if none
37+
*nspname: the namespace the object is in (NULL if none); not pre-quoted
3738
*type: the object type (as seen in GRANT command: must be one of
3839
*TABLE, SEQUENCE, FUNCTION, LANGUAGE, SCHEMA, DATABASE, TABLESPACE,
3940
*FOREIGN DATA WRAPPER, SERVER, or LARGE OBJECT)
@@ -54,7 +55,7 @@ static void AddAcl(PQExpBuffer aclbuf, const char *keyword,
5455
* since this routine uses fmtId() internally.
5556
*/
5657
bool
57-
buildACLCommands(constchar*name,constchar*subname,
58+
buildACLCommands(constchar*name,constchar*subname,constchar*nspname,
5859
constchar*type,constchar*acls,constchar*racls,
5960
constchar*owner,constchar*prefix,intremoteVersion,
6061
PQExpBuffersql)
@@ -154,7 +155,10 @@ buildACLCommands(const char *name, const char *subname,
154155
appendPQExpBuffer(firstsql,"%sREVOKE ALL",prefix);
155156
if (subname)
156157
appendPQExpBuffer(firstsql,"(%s)",subname);
157-
appendPQExpBuffer(firstsql," ON %s %s FROM PUBLIC;\n",type,name);
158+
appendPQExpBuffer(firstsql," ON %s ",type);
159+
if (nspname&&*nspname)
160+
appendPQExpBuffer(firstsql,"%s.",fmtId(nspname));
161+
appendPQExpBuffer(firstsql,"%s FROM PUBLIC;\n",name);
158162
}
159163
else
160164
{
@@ -172,8 +176,11 @@ buildACLCommands(const char *name, const char *subname,
172176
{
173177
if (privs->len>0)
174178
{
175-
appendPQExpBuffer(firstsql,"%sREVOKE %s ON %s %s FROM ",
176-
prefix,privs->data,type,name);
179+
appendPQExpBuffer(firstsql,"%sREVOKE %s ON %s ",
180+
prefix,privs->data,type);
181+
if (nspname&&*nspname)
182+
appendPQExpBuffer(firstsql,"%s.",fmtId(nspname));
183+
appendPQExpBuffer(firstsql,"%s FROM ",name);
177184
if (grantee->len==0)
178185
appendPQExpBufferStr(firstsql,"PUBLIC;\n");
179186
elseif (strncmp(grantee->data,"group ",
@@ -187,8 +194,11 @@ buildACLCommands(const char *name, const char *subname,
187194
if (privswgo->len>0)
188195
{
189196
appendPQExpBuffer(firstsql,
190-
"%sREVOKE GRANT OPTION FOR %s ON %s %s FROM ",
191-
prefix,privswgo->data,type,name);
197+
"%sREVOKE GRANT OPTION FOR %s ON %s ",
198+
prefix,privswgo->data,type);
199+
if (nspname&&*nspname)
200+
appendPQExpBuffer(firstsql,"%s.",fmtId(nspname));
201+
appendPQExpBuffer(firstsql,"%s FROM ",name);
192202
if (grantee->len==0)
193203
appendPQExpBufferStr(firstsql,"PUBLIC");
194204
elseif (strncmp(grantee->data,"group ",
@@ -255,18 +265,33 @@ buildACLCommands(const char *name, const char *subname,
255265
appendPQExpBuffer(firstsql,"%sREVOKE ALL",prefix);
256266
if (subname)
257267
appendPQExpBuffer(firstsql,"(%s)",subname);
258-
appendPQExpBuffer(firstsql," ON %s %s FROM %s;\n",
259-
type,name,fmtId(grantee->data));
268+
appendPQExpBuffer(firstsql," ON %s ",type);
269+
if (nspname&&*nspname)
270+
appendPQExpBuffer(firstsql,"%s.",fmtId(nspname));
271+
appendPQExpBuffer(firstsql,"%s FROM %s;\n",
272+
name,fmtId(grantee->data));
260273
if (privs->len>0)
274+
{
261275
appendPQExpBuffer(firstsql,
262-
"%sGRANT %s ON %s %s TO %s;\n",
263-
prefix,privs->data,type,name,
264-
fmtId(grantee->data));
276+
"%sGRANT %s ON %s ",
277+
prefix,privs->data,type);
278+
if (nspname&&*nspname)
279+
appendPQExpBuffer(firstsql,"%s.",fmtId(nspname));
280+
appendPQExpBuffer(firstsql,
281+
"%s TO %s;\n",
282+
name,fmtId(grantee->data));
283+
}
265284
if (privswgo->len>0)
285+
{
266286
appendPQExpBuffer(firstsql,
267-
"%sGRANT %s ON %s %s TO %s WITH GRANT OPTION;\n",
268-
prefix,privswgo->data,type,name,
269-
fmtId(grantee->data));
287+
"%sGRANT %s ON %s ",
288+
prefix,privswgo->data,type);
289+
if (nspname&&*nspname)
290+
appendPQExpBuffer(firstsql,"%s.",fmtId(nspname));
291+
appendPQExpBuffer(firstsql,
292+
"%s TO %s WITH GRANT OPTION;\n",
293+
name,fmtId(grantee->data));
294+
}
270295
}
271296
}
272297
else
@@ -288,8 +313,11 @@ buildACLCommands(const char *name, const char *subname,
288313

289314
if (privs->len>0)
290315
{
291-
appendPQExpBuffer(secondsql,"%sGRANT %s ON %s %s TO ",
292-
prefix,privs->data,type,name);
316+
appendPQExpBuffer(secondsql,"%sGRANT %s ON %s ",
317+
prefix,privs->data,type);
318+
if (nspname&&*nspname)
319+
appendPQExpBuffer(secondsql,"%s.",fmtId(nspname));
320+
appendPQExpBuffer(secondsql,"%s TO ",name);
293321
if (grantee->len==0)
294322
appendPQExpBufferStr(secondsql,"PUBLIC;\n");
295323
elseif (strncmp(grantee->data,"group ",
@@ -301,8 +329,11 @@ buildACLCommands(const char *name, const char *subname,
301329
}
302330
if (privswgo->len>0)
303331
{
304-
appendPQExpBuffer(secondsql,"%sGRANT %s ON %s %s TO ",
305-
prefix,privswgo->data,type,name);
332+
appendPQExpBuffer(secondsql,"%sGRANT %s ON %s ",
333+
prefix,privswgo->data,type);
334+
if (nspname&&*nspname)
335+
appendPQExpBuffer(secondsql,"%s.",fmtId(nspname));
336+
appendPQExpBuffer(secondsql,"%s TO ",name);
306337
if (grantee->len==0)
307338
appendPQExpBufferStr(secondsql,"PUBLIC");
308339
elseif (strncmp(grantee->data,"group ",
@@ -332,8 +363,11 @@ buildACLCommands(const char *name, const char *subname,
332363
appendPQExpBuffer(firstsql,"%sREVOKE ALL",prefix);
333364
if (subname)
334365
appendPQExpBuffer(firstsql,"(%s)",subname);
335-
appendPQExpBuffer(firstsql," ON %s %s FROM %s;\n",
336-
type,name,fmtId(owner));
366+
appendPQExpBuffer(firstsql," ON %s ",type);
367+
if (nspname&&*nspname)
368+
appendPQExpBuffer(firstsql,"%s.",fmtId(nspname));
369+
appendPQExpBuffer(firstsql,"%s FROM %s;\n",
370+
name,fmtId(owner));
337371
}
338372

339373
destroyPQExpBuffer(grantee);
@@ -392,7 +426,8 @@ buildDefaultACLCommands(const char *type, const char *nspname,
392426
if (strlen(initacls)!=0||strlen(initracls)!=0)
393427
{
394428
appendPQExpBuffer(sql,"SELECT pg_catalog.binary_upgrade_set_record_init_privs(true);\n");
395-
if (!buildACLCommands("",NULL,type,initacls,initracls,owner,
429+
if (!buildACLCommands("",NULL,NULL,type,
430+
initacls,initracls,owner,
396431
prefix->data,remoteVersion,sql))
397432
{
398433
destroyPQExpBuffer(prefix);
@@ -401,7 +436,8 @@ buildDefaultACLCommands(const char *type, const char *nspname,
401436
appendPQExpBuffer(sql,"SELECT pg_catalog.binary_upgrade_set_record_init_privs(false);\n");
402437
}
403438

404-
if (!buildACLCommands("",NULL,type,acls,racls,owner,
439+
if (!buildACLCommands("",NULL,NULL,type,
440+
acls,racls,owner,
405441
prefix->data,remoteVersion,sql))
406442
{
407443
destroyPQExpBuffer(prefix);
@@ -645,26 +681,32 @@ AddAcl(PQExpBuffer aclbuf, const char *keyword, const char *subname)
645681
* buildShSecLabelQuery
646682
*
647683
* Build a query to retrieve security labels for a shared object.
684+
* The object is identified by its OID plus the name of the catalog
685+
* it can be found in (e.g., "pg_database" for database names).
686+
* The query is appended to "sql". (We don't execute it here so as to
687+
* keep this file free of assumptions about how to deal with SQL errors.)
648688
*/
649689
void
650-
buildShSecLabelQuery(PGconn*conn,constchar*catalog_name,uint32objectId,
690+
buildShSecLabelQuery(PGconn*conn,constchar*catalog_name,OidobjectId,
651691
PQExpBuffersql)
652692
{
653693
appendPQExpBuffer(sql,
654694
"SELECT provider, label FROM pg_catalog.pg_shseclabel "
655-
"WHERE classoid = '%s'::pg_catalog.regclass AND "
656-
"objoid =%u",catalog_name,objectId);
695+
"WHERE classoid = 'pg_catalog.%s'::pg_catalog.regclass "
696+
"ANDobjoid ='%u'",catalog_name,objectId);
657697
}
658698

659699
/*
660700
* emitShSecLabels
661701
*
662-
* Format security label data retrieved by the query generated in
663-
* buildShSecLabelQuery.
702+
* Construct SECURITY LABEL commands using the data retrieved by the query
703+
* generated by buildShSecLabelQuery, and append them to "buffer".
704+
* Here, the target object is identified by its type name (e.g. "DATABASE")
705+
* and its name (not pre-quoted).
664706
*/
665707
void
666708
emitShSecLabels(PGconn*conn,PGresult*res,PQExpBufferbuffer,
667-
constchar*target,constchar*objname)
709+
constchar*objtype,constchar*objname)
668710
{
669711
inti;
670712

@@ -676,7 +718,7 @@ emitShSecLabels(PGconn *conn, PGresult *res, PQExpBuffer buffer,
676718
/* must use fmtId result before calling it again */
677719
appendPQExpBuffer(buffer,
678720
"SECURITY LABEL FOR %s ON %s",
679-
fmtId(provider),target);
721+
fmtId(provider),objtype);
680722
appendPQExpBuffer(buffer,
681723
" %s IS ",
682724
fmtId(objname));

‎src/bin/pg_dump/dumputils.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@
3636
#endif
3737

3838

39-
externboolbuildACLCommands(constchar*name,constchar*subname,
39+
externboolbuildACLCommands(constchar*name,constchar*subname,constchar*nspname,
4040
constchar*type,constchar*acls,constchar*racls,
4141
constchar*owner,constchar*prefix,intremoteVersion,
4242
PQExpBuffersql);
@@ -47,9 +47,9 @@ extern bool buildDefaultACLCommands(const char *type, const char *nspname,
4747
intremoteVersion,
4848
PQExpBuffersql);
4949
externvoidbuildShSecLabelQuery(PGconn*conn,constchar*catalog_name,
50-
uint32objectId,PQExpBuffersql);
50+
OidobjectId,PQExpBuffersql);
5151
externvoidemitShSecLabels(PGconn*conn,PGresult*res,
52-
PQExpBufferbuffer,constchar*target,constchar*objname);
52+
PQExpBufferbuffer,constchar*objtype,constchar*objname);
5353

5454
externvoidbuildACLQueries(PQExpBufferacl_subquery,PQExpBufferracl_subquery,
5555
PQExpBufferinit_acl_subquery,PQExpBufferinit_racl_subquery,

‎src/bin/pg_dump/pg_backup.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,9 @@ typedef struct Archive
186186
/* info needed for string escaping */
187187
intencoding;/* libpq code for client_encoding */
188188
boolstd_strings;/* standard_conforming_strings */
189+
190+
/* other important stuff */
191+
char*searchpath;/* search_path to set during restore */
189192
char*use_role;/* Issue SET ROLE to this */
190193

191194
/* error handling */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp