]> granicus.if.org Git - postgresql/commitdiff
Fix assorted integer-overflow hazards in varbit.c.
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 14 Oct 2016 20:28:34 +0000 (16:28 -0400)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 14 Oct 2016 20:28:34 +0000 (16:28 -0400)
bitshiftright() and bitshiftleft() would recursively call each other
infinitely if the user passed INT_MIN for the shift amount, due to integer
overflow in negating the shift amount.  To fix, clamp to -VARBITMAXLEN.
That doesn't change the results since any shift distance larger than the
input bit string's length produces an all-zeroes result.

Also fix some places that seemed inadequately paranoid about input typmods
exceeding VARBITMAXLEN.  While a typmod accepted by anybit_typmodin() will
certainly be much less than that, at least some of these spots are
reachable with user-chosen integer values.

Andreas Seltenreich and Tom Lane

Discussion: <87d1j2zqtz.fsf@credativ.de>

src/backend/utils/adt/varbit.c

index 75e6a4647636b414a8870dc25174f6e90211c297..397eecc5649e2a0e161056fc47790ca89b61c676 100644 (file)
@@ -305,7 +305,7 @@ bit_recv(PG_FUNCTION_ARGS)
        bits8           mask;
 
        bitlen = pq_getmsgint(buf, sizeof(int32));
-       if (bitlen < 0)
+       if (bitlen < 0 || bitlen > VARBITMAXLEN)
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
                                 errmsg("invalid length in external bit string")));
@@ -368,7 +368,7 @@ bit(PG_FUNCTION_ARGS)
        bits8           mask;
 
        /* No work if typmod is invalid or supplied data matches it already */
-       if (len <= 0 || len == VARBITLEN(arg))
+       if (len <= 0 || len > VARBITMAXLEN || len == VARBITLEN(arg))
                PG_RETURN_VARBIT_P(arg);
 
        if (!isExplicit)
@@ -621,7 +621,7 @@ varbit_recv(PG_FUNCTION_ARGS)
        bits8           mask;
 
        bitlen = pq_getmsgint(buf, sizeof(int32));
-       if (bitlen < 0)
+       if (bitlen < 0 || bitlen > VARBITMAXLEN)
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
                                 errmsg("invalid length in external bit string")));
@@ -1387,9 +1387,14 @@ bitshiftleft(PG_FUNCTION_ARGS)
 
        /* Negative shift is a shift to the right */
        if (shft < 0)
+       {
+               /* Prevent integer overflow in negation */
+               if (shft < -VARBITMAXLEN)
+                       shft = -VARBITMAXLEN;
                PG_RETURN_DATUM(DirectFunctionCall2(bitshiftright,
                                                                                        VarBitPGetDatum(arg),
                                                                                        Int32GetDatum(-shft)));
+       }
 
        result = (VarBit *) palloc(VARSIZE(arg));
        SET_VARSIZE(result, VARSIZE(arg));
@@ -1447,9 +1452,14 @@ bitshiftright(PG_FUNCTION_ARGS)
 
        /* Negative shift is a shift to the left */
        if (shft < 0)
+       {
+               /* Prevent integer overflow in negation */
+               if (shft < -VARBITMAXLEN)
+                       shft = -VARBITMAXLEN;
                PG_RETURN_DATUM(DirectFunctionCall2(bitshiftleft,
                                                                                        VarBitPGetDatum(arg),
                                                                                        Int32GetDatum(-shft)));
+       }
 
        result = (VarBit *) palloc(VARSIZE(arg));
        SET_VARSIZE(result, VARSIZE(arg));
@@ -1507,7 +1517,7 @@ bitfromint4(PG_FUNCTION_ARGS)
        int                     destbitsleft,
                                srcbitsleft;
 
-       if (typmod <= 0)
+       if (typmod <= 0 || typmod > VARBITMAXLEN)
                typmod = 1;                             /* default bit length */
 
        rlen = VARBITTOTALLEN(typmod);
@@ -1587,7 +1597,7 @@ bitfromint8(PG_FUNCTION_ARGS)
        int                     destbitsleft,
                                srcbitsleft;
 
-       if (typmod <= 0)
+       if (typmod <= 0 || typmod > VARBITMAXLEN)
                typmod = 1;                             /* default bit length */
 
        rlen = VARBITTOTALLEN(typmod);