Skip to content

Commit 32fdf42

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: <[email protected]>
1 parent 13d3180 commit 32fdf42

File tree

1 file changed

+15
-5
lines changed

1 file changed

+15
-5
lines changed

src/backend/utils/adt/varbit.c

+15-5
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,7 @@ bit_recv(PG_FUNCTION_ARGS)
305305
bits8 mask;
306306

307307
bitlen = pq_getmsgint(buf, sizeof(int32));
308-
if (bitlen < 0)
308+
if (bitlen < 0 || bitlen > VARBITMAXLEN)
309309
ereport(ERROR,
310310
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
311311
errmsg("invalid length in external bit string")));
@@ -368,7 +368,7 @@ bit(PG_FUNCTION_ARGS)
368368
bits8 mask;
369369

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

374374
if (!isExplicit)
@@ -621,7 +621,7 @@ varbit_recv(PG_FUNCTION_ARGS)
621621
bits8 mask;
622622

623623
bitlen = pq_getmsgint(buf, sizeof(int32));
624-
if (bitlen < 0)
624+
if (bitlen < 0 || bitlen > VARBITMAXLEN)
625625
ereport(ERROR,
626626
(errcode(ERRCODE_INVALID_BINARY_REPRESENTATION),
627627
errmsg("invalid length in external bit string")));
@@ -1387,9 +1387,14 @@ bitshiftleft(PG_FUNCTION_ARGS)
13871387

13881388
/* Negative shift is a shift to the right */
13891389
if (shft < 0)
1390+
{
1391+
/* Prevent integer overflow in negation */
1392+
if (shft < -VARBITMAXLEN)
1393+
shft = -VARBITMAXLEN;
13901394
PG_RETURN_DATUM(DirectFunctionCall2(bitshiftright,
13911395
VarBitPGetDatum(arg),
13921396
Int32GetDatum(-shft)));
1397+
}
13931398

13941399
result = (VarBit *) palloc(VARSIZE(arg));
13951400
SET_VARSIZE(result, VARSIZE(arg));
@@ -1447,9 +1452,14 @@ bitshiftright(PG_FUNCTION_ARGS)
14471452

14481453
/* Negative shift is a shift to the left */
14491454
if (shft < 0)
1455+
{
1456+
/* Prevent integer overflow in negation */
1457+
if (shft < -VARBITMAXLEN)
1458+
shft = -VARBITMAXLEN;
14501459
PG_RETURN_DATUM(DirectFunctionCall2(bitshiftleft,
14511460
VarBitPGetDatum(arg),
14521461
Int32GetDatum(-shft)));
1462+
}
14531463

14541464
result = (VarBit *) palloc(VARSIZE(arg));
14551465
SET_VARSIZE(result, VARSIZE(arg));
@@ -1507,7 +1517,7 @@ bitfromint4(PG_FUNCTION_ARGS)
15071517
int destbitsleft,
15081518
srcbitsleft;
15091519

1510-
if (typmod <= 0)
1520+
if (typmod <= 0 || typmod > VARBITMAXLEN)
15111521
typmod = 1; /* default bit length */
15121522

15131523
rlen = VARBITTOTALLEN(typmod);
@@ -1587,7 +1597,7 @@ bitfromint8(PG_FUNCTION_ARGS)
15871597
int destbitsleft,
15881598
srcbitsleft;
15891599

1590-
if (typmod <= 0)
1600+
if (typmod <= 0 || typmod > VARBITMAXLEN)
15911601
typmod = 1; /* default bit length */
15921602

15931603
rlen = VARBITTOTALLEN(typmod);

0 commit comments

Comments
 (0)