Fix strtod security bug.

To avoid introducing NULL checks everytime a Bigint computation
is performed, introduce a special value (BIGINT_INVALID) and only
check for it when absolutely needed (which means when the code
needs to access the Bigint's internal structure fields).

Change-Id: Ie3954523b0985b6a8cb62340802d8dcf63cbf16f
This commit is contained in:
David 'Digit' Turner 2010-03-04 11:51:42 -08:00
parent 92e712f60d
commit 8132626b71

View File

@ -378,6 +378,24 @@ Bigint {
#endif
#endif
/* Special value used to indicate an invalid Bigint value,
* e.g. when a memory allocation fails. The idea is that we
* want to avoid introducing NULL checks everytime a bigint
* computation is performed. Also the NULL value can also be
* already used to indicate "value not initialized yet" and
* returning NULL might alter the execution code path in
* case of OOM.
*/
#define BIGINT_INVALID ((Bigint *)&bigint_invalid_value)
static const Bigint bigint_invalid_value;
/* Return BIGINT_INVALID on allocation failure.
*
* Most of the code here depends on the fact that this function
* never returns NULL.
*/
static Bigint *
Balloc
#ifdef KR_headers
@ -397,11 +415,15 @@ Balloc
else {
x = 1 << k;
rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(Long));
if (rv == NULL) {
rv = BIGINT_INVALID;
goto EXIT;
}
rv->k = k;
rv->maxwds = x;
}
rv->sign = rv->wds = 0;
EXIT:
mutex_unlock(&freelist_mutex);
return rv;
@ -415,7 +437,7 @@ Bfree
(Bigint *v)
#endif
{
if (v) {
if (v && v != BIGINT_INVALID) {
mutex_lock(&freelist_mutex);
v->next = freelist[v->k];
@ -425,8 +447,23 @@ Bfree
}
}
#define Bcopy(x,y) memcpy(&x->sign, &y->sign, \
y->wds*sizeof(Long) + 2*sizeof(int))
#define Bcopy_valid(x,y) memcpy(&(x)->sign, &(y)->sign, \
(y)->wds*sizeof(Long) + 2*sizeof(int))
#define Bcopy(x,y) Bcopy_ptr(&(x),(y))
static void
Bcopy_ptr(Bigint **px, Bigint *y)
{
if (*px == BIGINT_INVALID)
return; /* no space to store copy */
if (y == BIGINT_INVALID) {
Bfree(*px); /* invalid input */
*px = BIGINT_INVALID;
} else {
Bcopy_valid(*px,y);
}
}
static Bigint *
multadd
@ -443,6 +480,9 @@ multadd
#endif
Bigint *b1;
if (b == BIGINT_INVALID)
return b;
wds = b->wds;
x = b->x;
i = 0;
@ -463,7 +503,11 @@ multadd
if (a) {
if (wds >= b->maxwds) {
b1 = Balloc(b->k+1);
Bcopy(b1, b);
if (b1 == BIGINT_INVALID) {
Bfree(b);
return b1;
}
Bcopy_valid(b1, b);
Bfree(b);
b = b1;
}
@ -489,10 +533,15 @@ s2b
for(k = 0, y = 1; x > y; y <<= 1, k++) ;
#ifdef Pack_32
b = Balloc(k);
if (b == BIGINT_INVALID)
return b;
b->x[0] = y9;
b->wds = 1;
#else
b = Balloc(k+1);
if (b == BIGINT_INVALID)
return b;
b->x[0] = y9 & 0xffff;
b->wds = (b->x[1] = y9 >> 16) ? 2 : 1;
#endif
@ -604,8 +653,10 @@ i2b
Bigint *b;
b = Balloc(1);
b->x[0] = i;
b->wds = 1;
if (b != BIGINT_INVALID) {
b->x[0] = i;
b->wds = 1;
}
return b;
}
@ -625,6 +676,9 @@ mult
ULong z2;
#endif
if (a == BIGINT_INVALID || b == BIGINT_INVALID)
return BIGINT_INVALID;
if (a->wds < b->wds) {
c = a;
a = b;
@ -637,6 +691,8 @@ mult
if (wc > a->maxwds)
k++;
c = Balloc(k);
if (c == BIGINT_INVALID)
return c;
for(x = c->x, xa = x + wc; x < xa; x++)
*x = 0;
xa = a->x;
@ -711,6 +767,9 @@ pow5mult
int i;
static const int p05[3] = { 5, 25, 125 };
if (b == BIGINT_INVALID)
return b;
if ((i = k & 3) != 0)
b = multadd(b, p05[i-1], 0);
@ -718,7 +777,12 @@ pow5mult
return b;
if (!(p5 = p5s)) {
/* first time */
p5 = p5s = i2b(625);
p5 = i2b(625);
if (p5 == BIGINT_INVALID) {
Bfree(b);
return p5;
}
p5s = p5;
p5->next = 0;
}
for(;;) {
@ -730,7 +794,12 @@ pow5mult
if (!(k = (unsigned int) k >> 1))
break;
if (!(p51 = p5->next)) {
p51 = p5->next = mult(p5,p5);
p51 = mult(p5,p5);
if (p51 == BIGINT_INVALID) {
Bfree(b);
return p51;
}
p5->next = p51;
p51->next = 0;
}
p5 = p51;
@ -750,6 +819,9 @@ lshift
Bigint *b1;
ULong *x, *x1, *xe, z;
if (b == BIGINT_INVALID)
return b;
#ifdef Pack_32
n = (unsigned int)k >> 5;
#else
@ -760,6 +832,10 @@ lshift
for(i = b->maxwds; n1 > i; i <<= 1)
k1++;
b1 = Balloc(k1);
if (b1 == BIGINT_INVALID) {
Bfree(b);
return b1;
}
x1 = b1->x;
for(i = 0; i < n; i++)
*x1++ = 0;
@ -809,6 +885,13 @@ cmp
ULong *xa, *xa0, *xb, *xb0;
int i, j;
if (a == BIGINT_INVALID || b == BIGINT_INVALID)
#ifdef DEBUG
Bug("cmp called with a or b invalid");
#else
return 0; /* equal - the best we can do right now */
#endif
i = a->wds;
j = b->wds;
#ifdef DEBUG
@ -848,11 +931,16 @@ diff
Long z;
#endif
if (a == BIGINT_INVALID || b == BIGINT_INVALID)
return BIGINT_INVALID;
i = cmp(a,b);
if (!i) {
c = Balloc(0);
c->wds = 1;
c->x[0] = 0;
if (c != BIGINT_INVALID) {
c->wds = 1;
c->x[0] = 0;
}
return c;
}
if (i < 0) {
@ -864,6 +952,8 @@ diff
else
i = 0;
c = Balloc(a->k);
if (c == BIGINT_INVALID)
return c;
c->sign = i;
wa = a->wds;
xa = a->x;
@ -972,6 +1062,9 @@ b2d
#define d1 word1(d)
#endif
if (a == BIGINT_INVALID)
return NAN;
xa0 = a->x;
xa = xa0 + a->wds;
y = *--xa;
@ -1054,6 +1147,8 @@ d2b
#else
b = Balloc(2);
#endif
if (b == BIGINT_INVALID)
return b;
x = b->x;
z = d0 & Frac_mask;
@ -1169,6 +1264,9 @@ ratio
_double da, db;
int k, ka, kb;
if (a == BIGINT_INVALID || b == BIGINT_INVALID)
return NAN; /* for lack of better value ? */
value(da) = b2d(a, &ka);
value(db) = b2d(b, &kb);
#ifdef Pack_32
@ -1821,6 +1919,9 @@ quorem
ULong si, zs;
#endif
if (b == BIGINT_INVALID || S == BIGINT_INVALID)
return 0;
n = S->wds;
#ifdef DEBUG
/*debug*/ if (b->wds > n)
@ -2046,15 +2147,17 @@ __dtoa
!word1(d) && !(word0(d) & 0xfffff) ? "Infinity" :
#endif
"NaN";
result = Balloc(strlen(s)+1);
s0 = (char *)(void *)result;
strcpy(s0, s);
if (rve)
*rve =
result = Balloc(strlen(s)+1);
if (result == BIGINT_INVALID)
return NULL;
s0 = (char *)(void *)result;
strcpy(s0, s);
if (rve)
*rve =
#ifdef IEEE_Arith
s0[3] ? s0 + 8 :
s0[3] ? s0 + 8 :
#endif
s0 + 3;
s0 + 3;
return s0;
}
#endif
@ -2063,12 +2166,14 @@ __dtoa
#endif
if (!value(d)) {
*decpt = 1;
result = Balloc(2);
s0 = (char *)(void *)result;
strcpy(s0, "0");
if (rve)
*rve = s0 + 1;
return s0;
result = Balloc(2);
if (result == BIGINT_INVALID)
return NULL;
s0 = (char *)(void *)result;
strcpy(s0, "0");
if (rve)
*rve = s0 + 1;
return s0;
}
b = d2b(value(d), &be, &bbits);
@ -2199,6 +2304,10 @@ __dtoa
// complicated way the block size need to be computed
// buuurk....
result = Balloc(result_k);
if (result == BIGINT_INVALID) {
Bfree(b);
return NULL;
}
s = s0 = (char *)(void *)result;
if (ilim >= 0 && ilim <= Quick_max && try_quick) {
@ -2426,13 +2535,18 @@ __dtoa
* and for all and pass them and a shift to quorem, so it
* can do shifts and ors to compute the numerator for q.
*/
if (S == BIGINT_INVALID) {
i = 0;
} else {
#ifdef Pack_32
if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f) != 0)
i = 32 - i;
if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f) != 0)
i = 32 - i;
#else
if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf)
i = 16 - i;
if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf)
i = 16 - i;
#endif
}
if (i > 4) {
i -= 4;
b2 += i;