Require the schema qualification in pg_temp.type_name(arg).
Commit aa27977fe21a7dfa4da4376ad66ae37cb8f0d0b5 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
This commit is contained in:
parent
b0fb44eacd
commit
21f94c51f6
@ -6490,6 +6490,10 @@ COPY postgres_log FROM '/full/path/to/logfile.csv' WITH csv;
|
|||||||
be searched <emphasis>before</emphasis> searching any of the path items.
|
be searched <emphasis>before</emphasis> searching any of the path items.
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
|
<!-- To further split hairs, funcname('foo') does not use the temporary
|
||||||
|
schema, even when it considers typname='funcname'. This paragraph
|
||||||
|
refers to function names in a loose sense, "pg_proc.proname or
|
||||||
|
func_name grammar production". -->
|
||||||
<para>
|
<para>
|
||||||
Likewise, the current session's temporary-table schema,
|
Likewise, the current session's temporary-table schema,
|
||||||
<literal>pg_temp_<replaceable>nnn</replaceable></literal>, is always searched if it
|
<literal>pg_temp_<replaceable>nnn</replaceable></literal>, is always searched if it
|
||||||
|
@ -757,13 +757,23 @@ RelationIsVisible(Oid relid)
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* TypenameGetTypid
|
* TypenameGetTypid
|
||||||
|
* Wrapper for binary compatibility.
|
||||||
|
*/
|
||||||
|
Oid
|
||||||
|
TypenameGetTypid(const char *typname)
|
||||||
|
{
|
||||||
|
return TypenameGetTypidExtended(typname, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* TypenameGetTypidExtended
|
||||||
* Try to resolve an unqualified datatype name.
|
* Try to resolve an unqualified datatype name.
|
||||||
* Returns OID if type found in search path, else InvalidOid.
|
* Returns OID if type found in search path, else InvalidOid.
|
||||||
*
|
*
|
||||||
* This is essentially the same as RelnameGetRelid.
|
* This is essentially the same as RelnameGetRelid.
|
||||||
*/
|
*/
|
||||||
Oid
|
Oid
|
||||||
TypenameGetTypid(const char *typname)
|
TypenameGetTypidExtended(const char *typname, bool temp_ok)
|
||||||
{
|
{
|
||||||
Oid typid;
|
Oid typid;
|
||||||
ListCell *l;
|
ListCell *l;
|
||||||
@ -774,6 +784,9 @@ TypenameGetTypid(const char *typname)
|
|||||||
{
|
{
|
||||||
Oid namespaceId = lfirst_oid(l);
|
Oid namespaceId = lfirst_oid(l);
|
||||||
|
|
||||||
|
if (!temp_ok && namespaceId == myTempNamespace)
|
||||||
|
continue; /* do not look in temp namespace */
|
||||||
|
|
||||||
typid = GetSysCacheOid2(TYPENAMENSP,
|
typid = GetSysCacheOid2(TYPENAMENSP,
|
||||||
PointerGetDatum(typname),
|
PointerGetDatum(typname),
|
||||||
ObjectIdGetDatum(namespaceId));
|
ObjectIdGetDatum(namespaceId));
|
||||||
|
@ -1877,7 +1877,12 @@ FuncNameAsType(List *funcname)
|
|||||||
Oid result;
|
Oid result;
|
||||||
Type typtup;
|
Type typtup;
|
||||||
|
|
||||||
typtup = LookupTypeName(NULL, makeTypeNameFromNameList(funcname), NULL, false);
|
/*
|
||||||
|
* temp_ok=false protects the <refsect1 id="sql-createfunction-security">
|
||||||
|
* contract for writing SECURITY DEFINER functions safely.
|
||||||
|
*/
|
||||||
|
typtup = LookupTypeNameExtended(NULL, makeTypeNameFromNameList(funcname),
|
||||||
|
NULL, false, false);
|
||||||
if (typtup == NULL)
|
if (typtup == NULL)
|
||||||
return InvalidOid;
|
return InvalidOid;
|
||||||
|
|
||||||
|
@ -33,6 +33,18 @@ static int32 typenameTypeMod(ParseState *pstate, const TypeName *typeName,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* LookupTypeName
|
* LookupTypeName
|
||||||
|
* Wrapper for typical case.
|
||||||
|
*/
|
||||||
|
Type
|
||||||
|
LookupTypeName(ParseState *pstate, const TypeName *typeName,
|
||||||
|
int32 *typmod_p, bool missing_ok)
|
||||||
|
{
|
||||||
|
return LookupTypeNameExtended(pstate,
|
||||||
|
typeName, typmod_p, true, missing_ok);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* LookupTypeNameExtended
|
||||||
* Given a TypeName object, lookup the pg_type syscache entry of the type.
|
* Given a TypeName object, lookup the pg_type syscache entry of the type.
|
||||||
* Returns NULL if no such type can be found. If the type is found,
|
* Returns NULL if no such type can be found. If the type is found,
|
||||||
* the typmod value represented in the TypeName struct is computed and
|
* the typmod value represented in the TypeName struct is computed and
|
||||||
@ -51,11 +63,17 @@ static int32 typenameTypeMod(ParseState *pstate, const TypeName *typeName,
|
|||||||
* found but is a shell, and there is typmod decoration, an error will be
|
* found but is a shell, and there is typmod decoration, an error will be
|
||||||
* thrown --- this is intentional.
|
* thrown --- this is intentional.
|
||||||
*
|
*
|
||||||
|
* If temp_ok is false, ignore types in the temporary namespace. Pass false
|
||||||
|
* when the caller will decide, using goodness of fit criteria, whether the
|
||||||
|
* typeName is actually a type or something else. If typeName always denotes
|
||||||
|
* a type (or denotes nothing), pass true.
|
||||||
|
*
|
||||||
* pstate is only used for error location info, and may be NULL.
|
* pstate is only used for error location info, and may be NULL.
|
||||||
*/
|
*/
|
||||||
Type
|
Type
|
||||||
LookupTypeName(ParseState *pstate, const TypeName *typeName,
|
LookupTypeNameExtended(ParseState *pstate,
|
||||||
int32 *typmod_p, bool missing_ok)
|
const TypeName *typeName, int32 *typmod_p,
|
||||||
|
bool temp_ok, bool missing_ok)
|
||||||
{
|
{
|
||||||
Oid typoid;
|
Oid typoid;
|
||||||
HeapTuple tup;
|
HeapTuple tup;
|
||||||
@ -172,7 +190,7 @@ LookupTypeName(ParseState *pstate, const TypeName *typeName,
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
/* Unqualified type name, so search the search path */
|
/* Unqualified type name, so search the search path */
|
||||||
typoid = TypenameGetTypid(typname);
|
typoid = TypenameGetTypidExtended(typname, temp_ok);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If an array reference, return the array type instead */
|
/* If an array reference, return the array type instead */
|
||||||
|
@ -9400,6 +9400,14 @@ get_coercion_expr(Node *arg, deparse_context *context,
|
|||||||
if (!PRETTY_PAREN(context))
|
if (!PRETTY_PAREN(context))
|
||||||
appendStringInfoChar(buf, ')');
|
appendStringInfoChar(buf, ')');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Never emit resulttype(arg) functional notation. A pg_proc entry could
|
||||||
|
* take precedence, and a resulttype in pg_temp would require schema
|
||||||
|
* qualification that format_type_with_typemod() would usually omit. We've
|
||||||
|
* standardized on arg::resulttype, but CAST(arg AS resulttype) notation
|
||||||
|
* would work fine.
|
||||||
|
*/
|
||||||
appendStringInfo(buf, "::%s",
|
appendStringInfo(buf, "::%s",
|
||||||
format_type_with_typemod(resulttype, resulttypmod));
|
format_type_with_typemod(resulttype, resulttypmod));
|
||||||
}
|
}
|
||||||
|
@ -77,6 +77,7 @@ extern Oid RelnameGetRelid(const char *relname);
|
|||||||
extern bool RelationIsVisible(Oid relid);
|
extern bool RelationIsVisible(Oid relid);
|
||||||
|
|
||||||
extern Oid TypenameGetTypid(const char *typname);
|
extern Oid TypenameGetTypid(const char *typname);
|
||||||
|
extern Oid TypenameGetTypidExtended(const char *typname, bool temp_ok);
|
||||||
extern bool TypeIsVisible(Oid typid);
|
extern bool TypeIsVisible(Oid typid);
|
||||||
|
|
||||||
extern FuncCandidateList FuncnameGetCandidates(List *names,
|
extern FuncCandidateList FuncnameGetCandidates(List *names,
|
||||||
|
@ -21,6 +21,9 @@ typedef HeapTuple Type;
|
|||||||
|
|
||||||
extern Type LookupTypeName(ParseState *pstate, const TypeName *typeName,
|
extern Type LookupTypeName(ParseState *pstate, const TypeName *typeName,
|
||||||
int32 *typmod_p, bool missing_ok);
|
int32 *typmod_p, bool missing_ok);
|
||||||
|
extern Type LookupTypeNameExtended(ParseState *pstate,
|
||||||
|
const TypeName *typeName, int32 *typmod_p,
|
||||||
|
bool temp_ok, bool missing_ok);
|
||||||
extern Oid LookupTypeNameOid(ParseState *pstate, const TypeName *typeName,
|
extern Oid LookupTypeNameOid(ParseState *pstate, const TypeName *typeName,
|
||||||
bool missing_ok);
|
bool missing_ok);
|
||||||
extern Type typenameType(ParseState *pstate, const TypeName *typeName,
|
extern Type typenameType(ParseState *pstate, const TypeName *typeName,
|
||||||
|
@ -199,6 +199,21 @@ select pg_temp.whoami();
|
|||||||
(1 row)
|
(1 row)
|
||||||
|
|
||||||
drop table public.whereami;
|
drop table public.whereami;
|
||||||
|
-- types in temp schema
|
||||||
|
set search_path = pg_temp, public;
|
||||||
|
create domain pg_temp.nonempty as text check (value <> '');
|
||||||
|
-- function-syntax invocation of types matches rules for functions
|
||||||
|
select nonempty('');
|
||||||
|
ERROR: function nonempty(unknown) does not exist
|
||||||
|
LINE 1: select nonempty('');
|
||||||
|
^
|
||||||
|
HINT: No function matches the given name and argument types. You might need to add explicit type casts.
|
||||||
|
select pg_temp.nonempty('');
|
||||||
|
ERROR: value for domain nonempty violates check constraint "nonempty_check"
|
||||||
|
-- other syntax matches rules for tables
|
||||||
|
select ''::nonempty;
|
||||||
|
ERROR: value for domain nonempty violates check constraint "nonempty_check"
|
||||||
|
reset search_path;
|
||||||
-- For partitioned temp tables, ON COMMIT actions ignore storage-less
|
-- For partitioned temp tables, ON COMMIT actions ignore storage-less
|
||||||
-- partitioned tables.
|
-- partitioned tables.
|
||||||
begin;
|
begin;
|
||||||
|
@ -152,6 +152,17 @@ select pg_temp.whoami();
|
|||||||
|
|
||||||
drop table public.whereami;
|
drop table public.whereami;
|
||||||
|
|
||||||
|
-- types in temp schema
|
||||||
|
set search_path = pg_temp, public;
|
||||||
|
create domain pg_temp.nonempty as text check (value <> '');
|
||||||
|
-- function-syntax invocation of types matches rules for functions
|
||||||
|
select nonempty('');
|
||||||
|
select pg_temp.nonempty('');
|
||||||
|
-- other syntax matches rules for tables
|
||||||
|
select ''::nonempty;
|
||||||
|
|
||||||
|
reset search_path;
|
||||||
|
|
||||||
-- For partitioned temp tables, ON COMMIT actions ignore storage-less
|
-- For partitioned temp tables, ON COMMIT actions ignore storage-less
|
||||||
-- partitioned tables.
|
-- partitioned tables.
|
||||||
begin;
|
begin;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user