diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2017-11-06 10:29:17 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2017-11-06 10:29:40 -0500 |
commit | d5fe5fb232a4e57c66779b8b6acdcb458e9b8b9c (patch) | |
tree | 0fd0c6f82e3fbbc1284c2139b22af31b5c2480fe /src/backend/utils/adt/jsonfuncs.c | |
parent | ed546dd06195c27d92ae46f2bb1a74261bcb49e6 (diff) | |
download | postgresql-d5fe5fb232a4e57c66779b8b6acdcb458e9b8b9c.tar.gz postgresql-d5fe5fb232a4e57c66779b8b6acdcb458e9b8b9c.zip |
Make json{b}_populate_recordset() use the right tuple descriptor.
json{b}_populate_recordset() used the tuple descriptor created from the
query-level AS clause without worrying about whether it matched the actual
input record type. If it didn't, that would usually result in a crash,
though disclosure of server memory contents seems possible as well, for a
skilled attacker capable of issuing crafted SQL commands. Instead, use
the query-supplied descriptor only when there is no input tuple to look at,
and otherwise get a tuple descriptor based on the input tuple's own type
marking. The core code will detect any type mismatch in the latter case.
Michael Paquier and Tom Lane, per a report from David Rowley.
Back-patch to 9.3 where this functionality was introduced.
Security: CVE-2017-15098
Diffstat (limited to 'src/backend/utils/adt/jsonfuncs.c')
-rw-r--r-- | src/backend/utils/adt/jsonfuncs.c | 36 |
1 files changed, 25 insertions, 11 deletions
diff --git a/src/backend/utils/adt/jsonfuncs.c b/src/backend/utils/adt/jsonfuncs.c index 77f94ee3ab4..9330a61ef4b 100644 --- a/src/backend/utils/adt/jsonfuncs.c +++ b/src/backend/utils/adt/jsonfuncs.c @@ -2695,26 +2695,37 @@ populate_recordset_worker(FunctionCallInfo fcinfo, const char *funcname, rsi->returnMode = SFRM_Materialize; - /* - * get the tupdesc from the result set info - it must be a record type - * because we already checked that arg1 is a record type, or we're in a - * to_record function which returns a setof record. - */ - if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) - ereport(ERROR, - (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("function returning record called in context " - "that cannot accept type record"))); - /* if the json is null send back an empty set */ if (PG_ARGISNULL(json_arg_num)) PG_RETURN_NULL(); if (!have_record_arg || PG_ARGISNULL(0)) + { rec = NULL; + + /* + * get the tupdesc from the result set info - it must be a record type + * because we already checked that arg1 is a record type, or we're in + * a to_record function which returns a setof record. + */ + if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("function returning record called in context " + "that cannot accept type record"))); + } else + { rec = PG_GETARG_HEAPTUPLEHEADER(0); + /* + * use the input record's own type marking to find a tupdesc for it. + */ + tupType = HeapTupleHeaderGetTypeId(rec); + tupTypmod = HeapTupleHeaderGetTypMod(rec); + tupdesc = lookup_rowtype_tupdesc(tupType, tupTypmod); + } + tupType = tupdesc->tdtypeid; tupTypmod = tupdesc->tdtypmod; ncolumns = tupdesc->natts; @@ -2758,6 +2769,9 @@ populate_recordset_worker(FunctionCallInfo fcinfo, const char *funcname, false, work_mem); MemoryContextSwitchTo(old_cxt); + /* unnecessary, but harmless, if tupdesc came from get_call_result_type: */ + ReleaseTupleDesc(tupdesc); + state->function_name = funcname; state->my_extra = my_extra; state->rec = rec; |