Skip to content

Commit

Permalink
Handle zero-length sublist correctly in Python -> SQL array conversion.
Browse files Browse the repository at this point in the history
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 94aceed, so back-patch to all supported branches.

Discussion: https://postgr.es/m/17912-82ceed78731d9cdc@postgresql.org
  • Loading branch information
tglsfdc committed Apr 28, 2023
1 parent d29eba1 commit a1d9aac
Show file tree
Hide file tree
Showing 4 changed files with 32 additions and 16 deletions.
9 changes: 9 additions & 0 deletions src/pl/plpython/expected/plpython_types.out
Expand Up @@ -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;
Expand Down
9 changes: 9 additions & 0 deletions src/pl/plpython/expected/plpython_types_3.out
Expand Up @@ -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;
Expand Down
23 changes: 7 additions & 16 deletions src/pl/plpython/plpy_typeio.c
Expand Up @@ -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];
Expand All @@ -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);

Expand All @@ -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 */
Expand Down Expand Up @@ -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,
Expand Down
7 changes: 7 additions & 0 deletions src/pl/plpython/sql/plpython_types.sql
Expand Up @@ -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;
Expand Down

0 comments on commit a1d9aac

Please sign in to comment.