Skip to content

Commit 253e30c

Browse files
committed
Fix assorted integer-overflow hazards in varbit.c.
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>
1 parent fb6825f commit 253e30c

File tree

1 file changed

+15
-5
lines changed

1 file changed

+15
-5
lines changed

src/backend/utils/adt/varbit.c

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -304,7 +304,7 @@ bit_recv(PG_FUNCTION_ARGS)
304304
bits8 mask;
305305

306306
bitlen = pq_getmsgint(buf, sizeof(int32));
307-
if (bitlen < 0)
307+
if (bitlen < 0 || bitlen > VARBITMAXLEN)
308308
ereport(ERROR,
309309
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
310310
errmsg("invalid length in external bit string")));
@@ -367,7 +367,7 @@ bit(PG_FUNCTION_ARGS)
367367
bits8 mask;
368368

369369
/* No work if typmod is invalid or supplied data matches it already */
370-
if (len <= 0 || len == VARBITLEN(arg))
370+
if (len <= 0 || len > VARBITMAXLEN || len == VARBITLEN(arg))
371371
PG_RETURN_VARBIT_P(arg);
372372

373373
if (!isExplicit)
@@ -620,7 +620,7 @@ varbit_recv(PG_FUNCTION_ARGS)
620620
bits8 mask;
621621

622622
bitlen = pq_getmsgint(buf, sizeof(int32));
623-
if (bitlen < 0)
623+
if (bitlen < 0 || bitlen > VARBITMAXLEN)
624624
ereport(ERROR,
625625
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
626626
errmsg("invalid length in external bit string")));
@@ -1353,9 +1353,14 @@ bitshiftleft(PG_FUNCTION_ARGS)
13531353

13541354
/* Negative shift is a shift to the right */
13551355
if (shft < 0)
1356+
{
1357+
/* Prevent integer overflow in negation */
1358+
if (shft < -VARBITMAXLEN)
1359+
shft = -VARBITMAXLEN;
13561360
PG_RETURN_DATUM(DirectFunctionCall2(bitshiftright,
13571361
VarBitPGetDatum(arg),
13581362
Int32GetDatum(-shft)));
1363+
}
13591364

13601365
result = (VarBit *) palloc(VARSIZE(arg));
13611366
SET_VARSIZE(result, VARSIZE(arg));
@@ -1413,9 +1418,14 @@ bitshiftright(PG_FUNCTION_ARGS)
14131418

14141419
/* Negative shift is a shift to the left */
14151420
if (shft < 0)
1421+
{
1422+
/* Prevent integer overflow in negation */
1423+
if (shft < -VARBITMAXLEN)
1424+
shft = -VARBITMAXLEN;
14161425
PG_RETURN_DATUM(DirectFunctionCall2(bitshiftleft,
14171426
VarBitPGetDatum(arg),
14181427
Int32GetDatum(-shft)));
1428+
}
14191429

14201430
result = (VarBit *) palloc(VARSIZE(arg));
14211431
SET_VARSIZE(result, VARSIZE(arg));
@@ -1473,7 +1483,7 @@ bitfromint4(PG_FUNCTION_ARGS)
14731483
int destbitsleft,
14741484
srcbitsleft;
14751485

1476-
if (typmod <= 0)
1486+
if (typmod <= 0 || typmod > VARBITMAXLEN)
14771487
typmod = 1; /* default bit length */
14781488

14791489
rlen = VARBITTOTALLEN(typmod);
@@ -1553,7 +1563,7 @@ bitfromint8(PG_FUNCTION_ARGS)
15531563
int destbitsleft,
15541564
srcbitsleft;
15551565

1556-
if (typmod <= 0)
1566+
if (typmod <= 0 || typmod > VARBITMAXLEN)
15571567
typmod = 1; /* default bit length */
15581568

15591569
rlen = VARBITTOTALLEN(typmod);

0 commit comments

Comments
 (0)