Skip to content

Commit ffa2d37

Browse files
committed
Require the schema qualification in pg_temp.type_name(arg).
Commit aa27977 introduced this restriction for pg_temp.function_name(arg); do likewise for types created in temporary schemas. Programs that this breaks should add "pg_temp." schema qualification or switch to arg::type_name syntax. Back-patch to 9.4 (all supported versions). Reviewed by Tom Lane. Reported by Tom Lane. Security: CVE-2019-10208
1 parent a76cfba commit ffa2d37

File tree

9 files changed

+83
-5
lines changed

9 files changed

+83
-5
lines changed

doc/src/sgml/config.sgml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7236,6 +7236,10 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
72367236
be searched <emphasis>before</emphasis> searching any of the path items.
72377237
</para>
72387238

7239+
<!-- To further split hairs, funcname('foo') does not use the temporary
7240+
schema, even when it considers typname='funcname'. This paragraph
7241+
refers to function names in a loose sense, "pg_proc.proname or
7242+
func_name grammar production". -->
72397243
<para>
72407244
Likewise, the current session's temporary-table schema,
72417245
<literal>pg_temp_<replaceable>nnn</replaceable></literal>, is always searched if it

src/backend/catalog/namespace.c

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -757,13 +757,23 @@ RelationIsVisible(Oid relid)
757757

758758
/*
759759
* TypenameGetTypid
760+
* Wrapper for binary compatibility.
761+
*/
762+
Oid
763+
TypenameGetTypid(const char *typname)
764+
{
765+
return TypenameGetTypidExtended(typname, true);
766+
}
767+
768+
/*
769+
* TypenameGetTypidExtended
760770
* Try to resolve an unqualified datatype name.
761771
* Returns OID if type found in search path, else InvalidOid.
762772
*
763773
* This is essentially the same as RelnameGetRelid.
764774
*/
765775
Oid
766-
TypenameGetTypid(const char *typname)
776+
TypenameGetTypidExtended(const char *typname, bool temp_ok)
767777
{
768778
Oid typid;
769779
ListCell *l;
@@ -774,6 +784,9 @@ TypenameGetTypid(const char *typname)
774784
{
775785
Oid namespaceId = lfirst_oid(l);
776786

787+
if (!temp_ok && namespaceId == myTempNamespace)
788+
continue; /* do not look in temp namespace */
789+
777790
typid = GetSysCacheOid2(TYPENAMENSP, Anum_pg_type_oid,
778791
PointerGetDatum(typname),
779792
ObjectIdGetDatum(namespaceId));

src/backend/parser/parse_func.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1869,7 +1869,12 @@ FuncNameAsType(List *funcname)
18691869
Oid result;
18701870
Type typtup;
18711871

1872-
typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL, false);
1872+
/*
1873+
* temp_ok=false protects the <refsect1 id="sql-createfunction-security">
1874+
* contract for writing SECURITY DEFINER functions safely.
1875+
*/
1876+
typtup = LookupTypeNameExtended(NULL, makeTypeNameFromNameList(funcname),
1877+
NULL, false, false);
18731878
if (typtup == NULL)
18741879
return InvalidOid;
18751880

src/backend/parser/parse_type.c

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,18 @@ static int32 typenameTypeMod(ParseState *pstate, const TypeName *typeName,
3333

3434
/*
3535
* LookupTypeName
36+
* Wrapper for typical case.
37+
*/
38+
Type
39+
LookupTypeName(ParseState *pstate, const TypeName *typeName,
40+
int32 *typmod_p, bool missing_ok)
41+
{
42+
return LookupTypeNameExtended(pstate,
43+
typeName, typmod_p, true, missing_ok);
44+
}
45+
46+
/*
47+
* LookupTypeNameExtended
3648
* Given a TypeName object, lookup the pg_type syscache entry of the type.
3749
* Returns NULL if no such type can be found. If the type is found,
3850
* the typmod value represented in the TypeName struct is computed and
@@ -51,11 +63,17 @@ static int32 typenameTypeMod(ParseState *pstate, const TypeName *typeName,
5163
* found but is a shell, and there is typmod decoration, an error will be
5264
* thrown --- this is intentional.
5365
*
66+
* If temp_ok is false, ignore types in the temporary namespace. Pass false
67+
* when the caller will decide, using goodness of fit criteria, whether the
68+
* typeName is actually a type or something else. If typeName always denotes
69+
* a type (or denotes nothing), pass true.
70+
*
5471
* pstate is only used for error location info, and may be NULL.
5572
*/
5673
Type
57-
LookupTypeName(ParseState *pstate, const TypeName *typeName,
58-
int32 *typmod_p, bool missing_ok)
74+
LookupTypeNameExtended(ParseState *pstate,
75+
const TypeName *typeName, int32 *typmod_p,
76+
bool temp_ok, bool missing_ok)
5977
{
6078
Oid typoid;
6179
HeapTuple tup;
@@ -172,7 +190,7 @@ LookupTypeName(ParseState *pstate, const TypeName *typeName,
172190
else
173191
{
174192
/* Unqualified type name, so search the search path */
175-
typoid = TypenameGetTypid(typname);
193+
typoid = TypenameGetTypidExtended(typname, temp_ok);
176194
}
177195

178196
/* If an array reference, return the array type instead */

src/backend/utils/adt/ruleutils.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9475,6 +9475,14 @@ get_coercion_expr(Node *arg, deparse_context *context,
94759475
if (!PRETTY_PAREN(context))
94769476
appendStringInfoChar(buf, ')');
94779477
}
9478+
9479+
/*
9480+
* Never emit resulttype(arg) functional notation. A pg_proc entry could
9481+
* take precedence, and a resulttype in pg_temp would require schema
9482+
* qualification that format_type_with_typemod() would usually omit. We've
9483+
* standardized on arg::resulttype, but CAST(arg AS resulttype) notation
9484+
* would work fine.
9485+
*/
94789486
appendStringInfo(buf, "::%s",
94799487
format_type_with_typemod(resulttype, resulttypmod));
94809488
}

src/include/catalog/namespace.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ extern Oid RelnameGetRelid(const char *relname);
7777
extern bool RelationIsVisible(Oid relid);
7878

7979
extern Oid TypenameGetTypid(const char *typname);
80+
extern Oid TypenameGetTypidExtended(const char *typname, bool temp_ok);
8081
extern bool TypeIsVisible(Oid typid);
8182

8283
extern FuncCandidateList FuncnameGetCandidates(List *names,

src/include/parser/parse_type.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ typedef HeapTuple Type;
2121

2222
extern Type LookupTypeName(ParseState *pstate, const TypeName *typeName,
2323
int32 *typmod_p, bool missing_ok);
24+
extern Type LookupTypeNameExtended(ParseState *pstate,
25+
const TypeName *typeName, int32 *typmod_p,
26+
bool temp_ok, bool missing_ok);
2427
extern Oid LookupTypeNameOid(ParseState *pstate, const TypeName *typeName,
2528
bool missing_ok);
2629
extern Type typenameType(ParseState *pstate, const TypeName *typeName,

src/test/regress/expected/temp.out

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,21 @@ select pg_temp.whoami();
199199
(1 row)
200200

201201
drop table public.whereami;
202+
-- types in temp schema
203+
set search_path = pg_temp, public;
204+
create domain pg_temp.nonempty as text check (value <> '');
205+
-- function-syntax invocation of types matches rules for functions
206+
select nonempty('');
207+
ERROR: function nonempty(unknown) does not exist
208+
LINE 1: select nonempty('');
209+
^
210+
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
211+
select pg_temp.nonempty('');
212+
ERROR: value for domain nonempty violates check constraint "nonempty_check"
213+
-- other syntax matches rules for tables
214+
select ''::nonempty;
215+
ERROR: value for domain nonempty violates check constraint "nonempty_check"
216+
reset search_path;
202217
-- For partitioned temp tables, ON COMMIT actions ignore storage-less
203218
-- partitioned tables.
204219
begin;

src/test/regress/sql/temp.sql

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,17 @@ select pg_temp.whoami();
152152

153153
drop table public.whereami;
154154

155+
-- types in temp schema
156+
set search_path = pg_temp, public;
157+
create domain pg_temp.nonempty as text check (value <> '');
158+
-- function-syntax invocation of types matches rules for functions
159+
select nonempty('');
160+
select pg_temp.nonempty('');
161+
-- other syntax matches rules for tables
162+
select ''::nonempty;
163+
164+
reset search_path;
165+
155166
-- For partitioned temp tables, ON COMMIT actions ignore storage-less
156167
-- partitioned tables.
157168
begin;

0 commit comments

Comments
 (0)