]> git.sur5r.net Git - openldap/commitdiff
Replace recursive get_stringbvr with iterative get_stringbvl to avoid
authorHoward Chu <hyc@openldap.org>
Mon, 3 Mar 2003 15:54:49 +0000 (15:54 +0000)
committerHoward Chu <hyc@openldap.org>
Mon, 3 Mar 2003 15:54:49 +0000 (15:54 +0000)
stack overrun when parsing large groups

libraries/liblber/decode.c

index fe4bbd0c1cbe716b60d929129c7efed084e088f9..33f33b4c6d5efb2ad252ef1fe949fb714b15efa7 100644 (file)
@@ -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 );
-
-       if ( b->tag == LBER_DEFAULT )
-       {
-               b->len = n;
+       orig = b->ber->ber_ptr;
 
-               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;
+       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;
                }
-               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 ));
+       if ( rlen ) *rlen = i;
 
-       if ( ber_get_stringbv( b->ber, &bv, b->alloc ) == LBER_DEFAULT ) {
-               if ( bvp ) LBER_FREE( bvp );
-               return LBER_DEFAULT;
+       if ( i == 0 )
+       {
+               *b->res.c = NULL;
+               return 0;
        }
 
-       b->tag = ber_get_stringbvr( b, n+1 );
+       n = i;
+
+       /* 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->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;
+               }
+       }
+       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;
+                       }
                }
-       } 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;
+       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;
                }