This is an automated email from the ASF dual-hosted git repository. reshke pushed a commit to branch backport_cve in repository https://gitbox.apache.org/repos/asf/cloudberry.git
commit 732f2a87ca48007cebfc183445a2ac2a6e9bfc0a Author: Tom Lane <[email protected]> AuthorDate: Mon Aug 10 06:38:23 2026 -0700 Reject calls from SQL to functions that take or return type internal. Allowing that is a security hole, since there are many different functions with different ideas of what their "internal" argument or result is. We already had a defense against the easy case of "'foo'::internal", but that turns out to be insufficient. Lock down both function and operator syntax. Also disallow attempts to cast to or from type internal; those would mostly fail anyway, but we have created some holes with features such as CoerceViaIO. Reported-by: Amy Burnett (OpenAI Codex Security) Author: Tom Lane <[email protected]> Reviewed-by: Robert Haas <[email protected]> Backpatch-through: 14 Security: CVE-2026-14680 --- src/backend/parser/parse_coerce.c | 8 ++++++++ src/backend/parser/parse_func.c | 26 ++++++++++++++++++++++++++ src/backend/parser/parse_oper.c | 22 ++++++++++++++++++++++ src/pl/plpgsql/src/pl_exec.c | 12 ++++++++++-- 4 files changed, 66 insertions(+), 2 deletions(-) diff --git a/src/backend/parser/parse_coerce.c b/src/backend/parser/parse_coerce.c index 4af519f5a9a..cf59ef1f5c3 100644 --- a/src/backend/parser/parse_coerce.c +++ b/src/backend/parser/parse_coerce.c @@ -615,6 +615,10 @@ can_coerce_type(int nargs, const Oid *input_typeids, const Oid *target_typeids, if (targetTypeId == ANYTABLEOID || inputTypeId == ANYTABLEOID) return false; + /* reject all cases of casting something else to/from "internal" */ + if (inputTypeId == INTERNALOID || targetTypeId == INTERNALOID) + return false; + /* accept if target is ANY */ if (targetTypeId == ANYOID) continue; @@ -3215,6 +3219,10 @@ find_coercion_pathway(Oid targetTypeId, Oid sourceTypeId, if (sourceTypeId == targetTypeId) return COERCION_PATH_RELABELTYPE; + /* Reject all cases of casting something else to/from "internal" */ + if (sourceTypeId == INTERNALOID || targetTypeId == INTERNALOID) + return COERCION_PATH_NONE; + /* Look in pg_cast */ tuple = SearchSysCache2(CASTSOURCETARGET, ObjectIdGetDatum(sourceTypeId), diff --git a/src/backend/parser/parse_func.c b/src/backend/parser/parse_func.c index 6e120bb8614..3054b2f56d9 100644 --- a/src/backend/parser/parse_func.c +++ b/src/backend/parser/parse_func.c @@ -680,6 +680,32 @@ ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, rettype, false); + /* + * Reject any attempt to call a function that takes or returns type + * internal from SQL. (The FUNCDETAIL_COERCION case does not reach this + * check because of the early return above, but that's okay because we + * disallow coercions to or from type internal.) Note that we are + * checking the resolved argument and result types, so this will reject + * calls to polymorphic functions that pass internal-type arguments. The + * casting rules should prevent that anyway, since we won't cast internal + * to any polymorphic type, but no harm in being doubly sure. + */ + for (int i = 0; i < nargsplusdefs; i++) + { + if (declared_arg_types[i] == INTERNALOID) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("functions accepting type \"%s\" cannot be called explicitly", + "internal"), + parser_errposition(pstate, location))); + } + if (rettype == INTERNALOID) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("functions returning type \"%s\" cannot be called explicitly", + "internal"), + parser_errposition(pstate, location))); + /* perform the necessary typecasting of arguments */ make_fn_arguments(pstate, fargs, actual_arg_types, declared_arg_types); diff --git a/src/backend/parser/parse_oper.c b/src/backend/parser/parse_oper.c index bdc8f8e26af..bac0fe4ad09 100644 --- a/src/backend/parser/parse_oper.c +++ b/src/backend/parser/parse_oper.c @@ -749,6 +749,28 @@ make_op(ParseState *pstate, List *opname, Node *ltree, Node *rtree, opform->oprresult, false); + /* + * Reject any attempt to call a function that takes or returns type + * internal from SQL. This is just like the check in ParseFuncOrColumn, + * but for operator syntax. (Despite that, we say "function" in the error + * messages; doesn't seem worth having two sets of translatable strings.) + */ + for (int i = 0; i < nargs; i++) + { + if (declared_arg_types[i] == INTERNALOID) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("functions accepting type \"%s\" cannot be called explicitly", + "internal"), + parser_errposition(pstate, location))); + } + if (rettype == INTERNALOID) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("functions returning type \"%s\" cannot be called explicitly", + "internal"), + parser_errposition(pstate, location))); + /* perform the necessary typecasting of arguments */ make_fn_arguments(pstate, args, actual_arg_types, declared_arg_types); diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 78a57328852..f14d5ce2ccf 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -7896,13 +7896,21 @@ get_cast_hashentry(PLpgSQL_execstate *estate, * If there's no cast path according to the parser, fall back to using * an I/O coercion; this is semantically dubious but matches plpgsql's * historical behavior. We would need something of the sort for - * UNKNOWN literals in any case. (This is probably now only reachable - * in the case where srctype is UNKNOWN/RECORD.) + * UNKNOWN literals in any case. The only case we reject is casting + * to/from INTERNAL. (Other than that case, this is probably now only + * reachable in the case where srctype is UNKNOWN/RECORD.) */ if (cast_expr == NULL) { CoerceViaIO *iocoerce = makeNode(CoerceViaIO); + if (srctype == INTERNALOID || dsttype == INTERNALOID) + ereport(ERROR, + (errcode(ERRCODE_CANNOT_COERCE), + errmsg("cannot cast type %s to %s", + format_type_be(srctype), + format_type_be(dsttype)))); + iocoerce->arg = (Expr *) placeholder; iocoerce->resulttype = dsttype; iocoerce->resultcollid = InvalidOid; --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
