mirror of
https://git.openldap.org/openldap/openldap.git
synced 2025-03-07 14:18:15 +08:00
Replace recursive get_stringbvr with iterative get_stringbvl to avoid
stack overrun when parsing large groups
This commit is contained in:
parent
3cbcf01cfd
commit
3cc07977fa
@ -282,7 +282,7 @@ ber_get_stringb(
|
||||
return tag;
|
||||
}
|
||||
|
||||
/* Definitions for recursive get_string
|
||||
/* Definitions for get_string vector
|
||||
*
|
||||
* ChArray, BvArray, and BvVec are self-explanatory.
|
||||
* BvOff is a struct berval embedded in an array of larger structures
|
||||
@ -296,9 +296,6 @@ enum bgbvc { ChArray, BvArray, BvVec, BvOff };
|
||||
typedef struct bgbvr {
|
||||
enum bgbvc choice;
|
||||
BerElement *ber;
|
||||
ber_tag_t tag;
|
||||
ber_len_t len;
|
||||
char *last;
|
||||
int alloc;
|
||||
ber_len_t siz;
|
||||
ber_len_t off;
|
||||
@ -309,74 +306,74 @@ typedef struct bgbvr {
|
||||
} res;
|
||||
} bgbvr;
|
||||
|
||||
/* Recursive get_string, for decoding a vector of strings. The number
|
||||
* of elements in the vector is limited only by available stack space.
|
||||
* Each invocation consumes 24 bytes of stack on a 32-bit machine.
|
||||
*/
|
||||
static ber_tag_t
|
||||
ber_get_stringbvr( bgbvr *b, int n )
|
||||
ber_get_stringbvl( bgbvr *b, ber_len_t *rlen )
|
||||
{
|
||||
int i = 0, n;
|
||||
ber_tag_t tag;
|
||||
ber_len_t len;
|
||||
char *last, *orig;
|
||||
struct berval bv, *bvp = NULL;
|
||||
|
||||
if ( n )
|
||||
b->tag = ber_next_element( b->ber, &b->len, b->last );
|
||||
else
|
||||
b->tag = ber_first_element( b->ber, &b->len, &b->last );
|
||||
orig = b->ber->ber_ptr;
|
||||
|
||||
if ( b->tag == LBER_DEFAULT )
|
||||
tag = ber_first_element( b->ber, &len, &last );
|
||||
if ( tag != LBER_DEFAULT ) {
|
||||
for ( ; b->ber->ber_ptr < last; i++ )
|
||||
{
|
||||
tag = ber_skip_tag( b->ber, &len );
|
||||
if (tag == LBER_DEFAULT) break;
|
||||
b->ber->ber_ptr += len;
|
||||
}
|
||||
}
|
||||
|
||||
if ( rlen ) *rlen = i;
|
||||
|
||||
if ( i == 0 )
|
||||
{
|
||||
b->len = n;
|
||||
|
||||
if ( n == 0 ) {
|
||||
*b->res.c = NULL;
|
||||
return 0;
|
||||
}
|
||||
/* Allocate the result vector */
|
||||
switch (b->choice) {
|
||||
case ChArray:
|
||||
*b->res.c = LBER_MALLOC( (n+1) * sizeof( char * ));
|
||||
if ( *b->res.c == NULL )
|
||||
return LBER_DEFAULT;
|
||||
(*b->res.c)[n] = NULL;
|
||||
break;
|
||||
case BvArray:
|
||||
*b->res.ba = LBER_MALLOC( (n+1) * sizeof( struct berval ));
|
||||
if ( *b->res.ba == NULL )
|
||||
return LBER_DEFAULT;
|
||||
(*b->res.ba)[n].bv_val = NULL;
|
||||
break;
|
||||
case BvVec:
|
||||
*b->res.bv = LBER_MALLOC( (n+1) * sizeof( struct berval *));
|
||||
if ( *b->res.bv == NULL )
|
||||
return LBER_DEFAULT;
|
||||
(*b->res.bv)[n] = NULL;
|
||||
break;
|
||||
case BvOff:
|
||||
*b->res.ba = LBER_MALLOC( (n+1) * b->siz );
|
||||
if ( *b->res.ba == NULL )
|
||||
return LBER_DEFAULT;
|
||||
((struct berval *)((long)(*b->res.ba) + n*b->siz +
|
||||
b->off))->bv_val = NULL;
|
||||
break;
|
||||
}
|
||||
*b->res.c = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Do all local allocs before the recursion. Then there
|
||||
* cannot possibly be any failures on the return trip.
|
||||
*/
|
||||
if ( b->choice == BvVec )
|
||||
bvp = LBER_MALLOC( sizeof( struct berval ));
|
||||
n = i;
|
||||
|
||||
if ( ber_get_stringbv( b->ber, &bv, b->alloc ) == LBER_DEFAULT ) {
|
||||
if ( bvp ) LBER_FREE( bvp );
|
||||
return LBER_DEFAULT;
|
||||
/* Allocate the result vector */
|
||||
switch (b->choice) {
|
||||
case ChArray:
|
||||
*b->res.c = LBER_MALLOC( (n+1) * sizeof( char * ));
|
||||
if ( *b->res.c == NULL )
|
||||
return LBER_DEFAULT;
|
||||
(*b->res.c)[n] = NULL;
|
||||
break;
|
||||
case BvArray:
|
||||
*b->res.ba = LBER_MALLOC( (n+1) * sizeof( struct berval ));
|
||||
if ( *b->res.ba == NULL )
|
||||
return LBER_DEFAULT;
|
||||
(*b->res.ba)[n].bv_val = NULL;
|
||||
break;
|
||||
case BvVec:
|
||||
*b->res.bv = LBER_MALLOC( (n+1) * sizeof( struct berval *));
|
||||
if ( *b->res.bv == NULL )
|
||||
return LBER_DEFAULT;
|
||||
(*b->res.bv)[n] = NULL;
|
||||
break;
|
||||
case BvOff:
|
||||
*b->res.ba = LBER_MALLOC( (n+1) * b->siz );
|
||||
if ( *b->res.ba == NULL )
|
||||
return LBER_DEFAULT;
|
||||
((struct berval *)((long)(*b->res.ba) + n*b->siz +
|
||||
b->off))->bv_val = NULL;
|
||||
break;
|
||||
}
|
||||
|
||||
b->tag = ber_get_stringbvr( b, n+1 );
|
||||
b->ber->ber_ptr = orig;
|
||||
ber_skip_tag( b->ber, &len );
|
||||
|
||||
if ( b->tag == 0 )
|
||||
for (n=0; n<i; n++)
|
||||
{
|
||||
tag = ber_next_element( b->ber, &len, last );
|
||||
if ( ber_get_stringbv( b->ber, &bv, b->alloc ) == LBER_DEFAULT )
|
||||
goto nomem;
|
||||
|
||||
/* store my result */
|
||||
switch (b->choice) {
|
||||
case ChArray:
|
||||
@ -386,20 +383,36 @@ ber_get_stringbvr( bgbvr *b, int n )
|
||||
(*b->res.ba)[n] = bv;
|
||||
break;
|
||||
case BvVec:
|
||||
bvp = LBER_MALLOC( sizeof( struct berval ));
|
||||
if ( !bvp ) {
|
||||
LBER_FREE(bv.bv_val);
|
||||
goto nomem;
|
||||
}
|
||||
(*b->res.bv)[n] = bvp;
|
||||
*bvp = bv;
|
||||
break;
|
||||
case BvOff:
|
||||
*(BerVarray)((long)(*b->res.ba)+n*b->siz+b->off) = bv;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
/* Failure will propagate up and free in reverse
|
||||
* order, which is actually ideal.
|
||||
*/
|
||||
if ( b->alloc ) LBER_FREE( bv.bv_val );
|
||||
if ( bvp ) LBER_FREE( bvp );
|
||||
}
|
||||
return b->tag;
|
||||
return tag;
|
||||
nomem:
|
||||
if (b->alloc || b->choice == BvVec)
|
||||
{
|
||||
for (--n; n>=0; n--)
|
||||
{
|
||||
switch(b->choice) {
|
||||
case ChArray: LBER_FREE((*b->res.c)[n]); break;
|
||||
case BvArray: LBER_FREE((*b->res.ba)[n].bv_val); break;
|
||||
case BvVec: LBER_FREE((*b->res.bv)[n]->bv_val);
|
||||
LBER_FREE((*b->res.bv)[n]); break;
|
||||
}
|
||||
}
|
||||
}
|
||||
LBER_FREE(*b->res.c);
|
||||
*b->res.c = NULL;
|
||||
return LBER_DEFAULT;
|
||||
}
|
||||
|
||||
ber_tag_t
|
||||
@ -723,7 +736,7 @@ ber_scanf ( BerElement *ber,
|
||||
cookie.ber = ber;
|
||||
cookie.res.c = va_arg( ap, char *** );
|
||||
cookie.alloc = 1;
|
||||
rc = ber_get_stringbvr( &cookie, 0 );
|
||||
rc = ber_get_stringbvl( &cookie, NULL );
|
||||
break;
|
||||
}
|
||||
|
||||
@ -733,7 +746,7 @@ ber_scanf ( BerElement *ber,
|
||||
cookie.ber = ber;
|
||||
cookie.res.bv = va_arg( ap, struct berval *** );
|
||||
cookie.alloc = 1;
|
||||
rc = ber_get_stringbvr( &cookie, 0 );
|
||||
rc = ber_get_stringbvl( &cookie, NULL );
|
||||
break;
|
||||
}
|
||||
|
||||
@ -743,7 +756,7 @@ ber_scanf ( BerElement *ber,
|
||||
cookie.ber = ber;
|
||||
cookie.res.ba = va_arg( ap, struct berval ** );
|
||||
cookie.alloc = 1;
|
||||
rc = ber_get_stringbvr( &cookie, 0 );
|
||||
rc = ber_get_stringbvl( &cookie, NULL );
|
||||
break;
|
||||
}
|
||||
|
||||
@ -760,8 +773,7 @@ ber_scanf ( BerElement *ber,
|
||||
l = va_arg( ap, ber_len_t * );
|
||||
cookie.siz = *l;
|
||||
cookie.off = va_arg( ap, ber_len_t );
|
||||
rc = ber_get_stringbvr( &cookie, 0 );
|
||||
*l = cookie.len;
|
||||
rc = ber_get_stringbvl( &cookie, l );
|
||||
break;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user