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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy