Prevent stack overflow in container-type functions.
authorNoah Misch
Mon, 5 Oct 2015 14:06:29 +0000 (10:06 -0400)
committerNoah Misch
Mon, 5 Oct 2015 14:06:34 +0000 (10:06 -0400)
A range type can name another range type as its subtype, and a record
type can bear a column of another record type.  Consequently, functions
like range_cmp() and record_recv() are recursive.  Functions at risk
include operator family members and referents of pg_type regproc
columns.  Treat as recursive any such function that looks up and calls
the same-purpose function for a record column type or the range subtype.
Back-patch to 9.0 (all supported versions).

An array type's element type is never itself an array type, so array
functions are unaffected.  Recursion depth proportional to array
dimensionality, found in array_dim_to_jsonb(), is fine thanks to MAXDIM.

src/backend/utils/adt/rangetypes.c
src/backend/utils/adt/rowtypes.c

index 96e686e6d693e0f44cece142fccb3130b8297297..429bc8f2b12a6b9d97861ba514f5b79f007039c7 100644 (file)
@@ -33,6 +33,7 @@
 #include "access/hash.h"
 #include "lib/stringinfo.h"
 #include "libpq/pqformat.h"
+#include "miscadmin.h"
 #include "utils/builtins.h"
 #include "utils/date.h"
 #include "utils/int8.h"
@@ -89,6 +90,8 @@ range_in(PG_FUNCTION_ARGS)
    RangeBound  lower;
    RangeBound  upper;
 
+   check_stack_depth();        /* recurses when subtype is a range type */
+
    cache = get_range_io_data(fcinfo, rngtypoid, IOFunc_input);
 
    /* parse */
@@ -128,6 +131,8 @@ range_out(PG_FUNCTION_ARGS)
    RangeBound  upper;
    bool        empty;
 
+   check_stack_depth();        /* recurses when subtype is a range type */
+
    cache = get_range_io_data(fcinfo, RangeTypeGetOid(range), IOFunc_output);
 
    /* deserialize */
@@ -165,6 +170,8 @@ range_recv(PG_FUNCTION_ARGS)
    RangeBound  lower;
    RangeBound  upper;
 
+   check_stack_depth();        /* recurses when subtype is a range type */
+
    cache = get_range_io_data(fcinfo, rngtypoid, IOFunc_receive);
 
    /* receive the flags... */
@@ -245,6 +252,8 @@ range_send(PG_FUNCTION_ARGS)
    RangeBound  upper;
    bool        empty;
 
+   check_stack_depth();        /* recurses when subtype is a range type */
+
    cache = get_range_io_data(fcinfo, RangeTypeGetOid(range), IOFunc_send);
 
    /* deserialize */
@@ -1114,6 +1123,8 @@ range_cmp(PG_FUNCTION_ARGS)
                empty2;
    int         cmp;
 
+   check_stack_depth();        /* recurses when subtype is a range type */
+
    /* Different types should be prevented by ANYRANGE matching rules */
    if (RangeTypeGetOid(r1) != RangeTypeGetOid(r2))
        elog(ERROR, "range types do not match");
@@ -1193,6 +1204,8 @@ hash_range(PG_FUNCTION_ARGS)
    uint32      lower_hash;
    uint32      upper_hash;
 
+   check_stack_depth();        /* recurses when subtype is a range type */
+
    typcache = range_get_typcache(fcinfo, RangeTypeGetOid(r));
 
    /* deserialize */
index 9c82603fefa3c3c45ad2cf3e5a80bb9e349e36f8..2e1fb32b372661558872485b1be6bfa1db25f23b 100644 (file)
@@ -20,6 +20,7 @@
 #include "catalog/pg_type.h"
 #include "funcapi.h"
 #include "libpq/pqformat.h"
+#include "miscadmin.h"
 #include "utils/builtins.h"
 #include "utils/lsyscache.h"
 #include "utils/typcache.h"
@@ -85,6 +86,8 @@ record_in(PG_FUNCTION_ARGS)
    bool       *nulls;
    StringInfoData buf;
 
+   check_stack_depth();        /* recurses for record-type columns */
+
    /*
     * Give a friendly error message if we did not get enough info to identify
     * the target record type.  (lookup_rowtype_tupdesc would fail anyway, but
@@ -308,6 +311,8 @@ record_out(PG_FUNCTION_ARGS)
    bool       *nulls;
    StringInfoData buf;
 
+   check_stack_depth();        /* recurses for record-type columns */
+
    /* Extract type info from the tuple itself */
    tupType = HeapTupleHeaderGetTypeId(rec);
    tupTypmod = HeapTupleHeaderGetTypMod(rec);
@@ -457,6 +462,8 @@ record_recv(PG_FUNCTION_ARGS)
    Datum      *values;
    bool       *nulls;
 
+   check_stack_depth();        /* recurses for record-type columns */
+
    /*
     * Give a friendly error message if we did not get enough info to identify
     * the target record type.  (lookup_rowtype_tupdesc would fail anyway, but
@@ -649,6 +656,8 @@ record_send(PG_FUNCTION_ARGS)
    bool       *nulls;
    StringInfoData buf;
 
+   check_stack_depth();        /* recurses for record-type columns */
+
    /* Extract type info from the tuple itself */
    tupType = HeapTupleHeaderGetTypeId(rec);
    tupTypmod = HeapTupleHeaderGetTypMod(rec);
@@ -792,6 +801,8 @@ record_cmp(FunctionCallInfo fcinfo)
    int         i2;
    int         j;
 
+   check_stack_depth();        /* recurses for record-type columns */
+
    /* Extract type info from the tuples */
    tupType1 = HeapTupleHeaderGetTypeId(record1);
    tupTypmod1 = HeapTupleHeaderGetTypMod(record1);
@@ -1027,6 +1038,8 @@ record_eq(PG_FUNCTION_ARGS)
    int         i2;
    int         j;
 
+   check_stack_depth();        /* recurses for record-type columns */
+
    /* Extract type info from the tuples */
    tupType1 = HeapTupleHeaderGetTypeId(record1);
    tupTypmod1 = HeapTupleHeaderGetTypMod(record1);