From a1d9aacc4128302129349cb1c86c7807f1555901 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 28 Apr 2023 12:24:29 -0400 Subject: [PATCH] Handle zero-length sublist correctly in Python -> SQL array conversion. If PLySequence_ToArray came across a zero-length sublist, it'd compute the overall array size as zero, possibly leading to a memory clobber. (This would likely qualify as a security bug, were it not that plpython is an untrusted language already.) I think there are other corner-case issues in this code as well, notably that the error messages don't match the core code and for some ranges of array sizes you'd get "invalid memory alloc request size" rather than the intended message about array size. Really this code has no business doing its own array size calculation at all, so remove the faulty code in favor of using ArrayGetNItems(). Per bug #17912 from Alexander Lakhin. Bug seems to have come in with commit 94aceed31, so back-patch to all supported branches. Discussion: https://postgr.es/m/17912-82ceed78731d9cdc@postgresql.org --- src/pl/plpython/expected/plpython_types.out | 9 ++++++++ src/pl/plpython/expected/plpython_types_3.out | 9 ++++++++ src/pl/plpython/plpy_typeio.c | 23 ++++++------------- src/pl/plpython/sql/plpython_types.sql | 7 ++++++ 4 files changed, 32 insertions(+), 16 deletions(-) diff --git a/src/pl/plpython/expected/plpython_types.out b/src/pl/plpython/expected/plpython_types.out index 0a2659fe29..052b53cd4c 100644 --- a/src/pl/plpython/expected/plpython_types.out +++ b/src/pl/plpython/expected/plpython_types.out @@ -687,6 +687,15 @@ SELECT * FROM test_type_conversion_array_mixed2(); ERROR: invalid input syntax for type integer: "abc" CONTEXT: while creating return value PL/Python function "test_type_conversion_array_mixed2" +CREATE FUNCTION test_type_conversion_array_mixed3() RETURNS text[] AS $$ +return [[], 'a'] +$$ LANGUAGE plpythonu; +SELECT * FROM test_type_conversion_array_mixed3(); + test_type_conversion_array_mixed3 +----------------------------------- + {[],a} +(1 row) + CREATE FUNCTION test_type_conversion_mdarray_malformed() RETURNS int[] AS $$ return [[1,2,3],[4,5]] $$ LANGUAGE plpythonu; diff --git a/src/pl/plpython/expected/plpython_types_3.out b/src/pl/plpython/expected/plpython_types_3.out index a6ec10d5e1..4f72a626e1 100644 --- a/src/pl/plpython/expected/plpython_types_3.out +++ b/src/pl/plpython/expected/plpython_types_3.out @@ -687,6 +687,15 @@ SELECT * FROM test_type_conversion_array_mixed2(); ERROR: invalid input syntax for type integer: "abc" CONTEXT: while creating return value PL/Python function "test_type_conversion_array_mixed2" +CREATE FUNCTION test_type_conversion_array_mixed3() RETURNS text[] AS $$ +return [[], 'a'] +$$ LANGUAGE plpython3u; +SELECT * FROM test_type_conversion_array_mixed3(); + test_type_conversion_array_mixed3 +----------------------------------- + {[],a} +(1 row) + CREATE FUNCTION test_type_conversion_mdarray_malformed() RETURNS int[] AS $$ return [[1,2,3],[4,5]] $$ LANGUAGE plpython3u; diff --git a/src/pl/plpython/plpy_typeio.c b/src/pl/plpython/plpy_typeio.c index 5e807b139f..8572bd86a1 100644 --- a/src/pl/plpython/plpy_typeio.c +++ b/src/pl/plpython/plpy_typeio.c @@ -1144,7 +1144,7 @@ PLySequence_ToArray(PLyObToDatum *arg, PyObject *plrv, int i; Datum *elems; bool *nulls; - int64 len; + int len; int ndim; int dims[MAXDIM]; int lbs[MAXDIM]; @@ -1163,7 +1163,6 @@ PLySequence_ToArray(PLyObToDatum *arg, PyObject *plrv, * Determine the number of dimensions, and their sizes. */ ndim = 0; - len = 1; Py_INCREF(plrv); @@ -1182,17 +1181,6 @@ PLySequence_ToArray(PLyObToDatum *arg, PyObject *plrv, if (dims[ndim] < 0) PLy_elog(ERROR, "could not determine sequence length for function return value"); - if (dims[ndim] > MaxAllocSize) - ereport(ERROR, - (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), - errmsg("array size exceeds the maximum allowed"))); - - len *= dims[ndim]; - if (len > MaxAllocSize) - ereport(ERROR, - (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), - errmsg("array size exceeds the maximum allowed"))); - if (dims[ndim] == 0) { /* empty sequence */ @@ -1222,15 +1210,18 @@ PLySequence_ToArray(PLyObToDatum *arg, PyObject *plrv, errmsg("return value of function with array return type is not a Python sequence"))); ndim = 1; - len = dims[0] = PySequence_Length(plrv); + dims[0] = PySequence_Length(plrv); } + /* Allocate space for work arrays, after detecting array size overflow */ + len = ArrayGetNItems(ndim, dims); + elems = palloc(sizeof(Datum) * len); + nulls = palloc(sizeof(bool) * len); + /* * Traverse the Python lists, in depth-first order, and collect all the * elements at the bottom level into 'elems'/'nulls' arrays. */ - elems = palloc(sizeof(Datum) * len); - nulls = palloc(sizeof(bool) * len); currelem = 0; PLySequence_ToArray_recurse(arg->u.array.elm, plrv, dims, ndim, 0, diff --git a/src/pl/plpython/sql/plpython_types.sql b/src/pl/plpython/sql/plpython_types.sql index 0d207d9c01..065d887f43 100644 --- a/src/pl/plpython/sql/plpython_types.sql +++ b/src/pl/plpython/sql/plpython_types.sql @@ -328,6 +328,13 @@ $$ LANGUAGE plpythonu; SELECT * FROM test_type_conversion_array_mixed2(); +CREATE FUNCTION test_type_conversion_array_mixed3() RETURNS text[] AS $$ +return [[], 'a'] +$$ LANGUAGE plpythonu; + +SELECT * FROM test_type_conversion_array_mixed3(); + + CREATE FUNCTION test_type_conversion_mdarray_malformed() RETURNS int[] AS $$ return [[1,2,3],[4,5]] $$ LANGUAGE plpythonu;