Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Buffer overflow bug in globbing



Just try

% echo *<ESC>2<ESC>0<ESC>6<ESC>00 <RETURN>

(echo * followed by 2060 zeros.)  You'll get a coredump.

Fix is included below.  This should be applied to zsh-3.0.2 as well.
It's a bit embarrasing that this bug together with the previous case bug
causes a coredump while running configure for bash-2.0.

This fixes an other minor bug:

% echo ([foo)bar

should print bad pattern error.

The patch adds the ztrduppfx() and dupstrpfx() function to utils.c to
duplicate the prefix of a string.  Only the later function is used now
but later I'll replace some

    sav = *s;
    *s = '\0';
    t = ztrdup(*p);
    *s = sav;

calls to ztrduppfx().  The advantage of these prefix dup functions is
that they are faster and can be used on const char * strings.

Zoltan


*** Src/glob.c	1996/12/25 16:04:45	3.1.1.2
--- Src/glob.c	1996/12/29 01:34:59
***************
*** 1924,1933 ****
  parsecomp(void)
  {
      Comp c = (Comp) alloc(sizeof *c), c1, c2;
!     char cstr[PATH_MAX * 2], *s = cstr, *ls = NULL;
  
      /* In case of alternatives, code coming up is stored in tail. */
      c->next = tail;
  
      while (*pptr && (mode || *pptr != '/') && *pptr != Bar &&
  	   (unset(EXTENDEDGLOB) || *pptr != Tilde ||
--- 1924,1934 ----
  parsecomp(void)
  {
      Comp c = (Comp) alloc(sizeof *c), c1, c2;
!     char *cstr, *ls = NULL;
  
      /* In case of alternatives, code coming up is stored in tail. */
      c->next = tail;
+     cstr = pptr;
  
      while (*pptr && (mode || *pptr != '/') && *pptr != Bar &&
  	   (unset(EXTENDEDGLOB) || *pptr != Tilde ||
***************
*** 1938,1949 ****
  	 */
  	if (*pptr == Hat && isset(EXTENDEDGLOB)) {
  	    /* negate remaining pattern */
- 	    *s++ = Hat;
- 	    *s++ = '\0';
  	    pptr++;
  	    if (!(c->next = parsecomp()))
  		return NULL;
- 	    c->str = dupstring(cstr);
  	    return c;
  	}
  	if (*pptr == Star && pptr[1] &&
--- 1939,1948 ----
  	 */
  	if (*pptr == Hat && isset(EXTENDEDGLOB)) {
  	    /* negate remaining pattern */
  	    pptr++;
+ 	    c->str = dupstrpfx(cstr, pptr - cstr);
  	    if (!(c->next = parsecomp()))
  		return NULL;
  	    return c;
  	}
  	if (*pptr == Star && pptr[1] &&
***************
*** 1954,1960 ****
  	     * (zero or more repetitions) of the single character pattern
  	     * operator `?'.
  	     */
! 	    *s++ = '\0';
  	    pptr++;
  	    c1 = (Comp) alloc(sizeof *c1);
  	    *(c1->str = dupstring("?")) = Quest;
--- 1953,1959 ----
  	     * (zero or more repetitions) of the single character pattern
  	     * operator `?'.
  	     */
! 	    c->str = dupstrpfx(cstr, pptr - cstr);
  	    pptr++;
  	    c1 = (Comp) alloc(sizeof *c1);
  	    *(c1->str = dupstring("?")) = Quest;
***************
*** 1963,1969 ****
  		return NULL;
  	    c1->next = c2;
  	    c->next = c1;
- 	    c->str = dupstring(cstr);
  	    return c;
  	}
  	if (*pptr == Inpar) {
--- 1962,1967 ----
***************
*** 1994,2068 ****
  	    /* ...before going back and parsing inside the group. */
  	    endp = pptr;
  	    pptr = startp;
  	    pptr++;
- 	    *s++ = '\0';
  	    c->next = (Comp) alloc(sizeof *c);
! 	    c->next->left = parsecompsw(0);
  	    /* Remember closures for group. */
  	    if (dpnd)
  		c->next->stat |= (dpnd == 2) ? C_TWOHASH : C_ONEHASH;
  	    c->next->next = dpnd ? c1 : (Comp) alloc(sizeof *c);
  	    pptr = endp;
  	    tail = stail;
- 	    c->str = dupstring(cstr);
  	    return c;
  	}
  	if (*pptr == Pound && isset(EXTENDEDGLOB)) {
  	    /* repeat whatever we've just had (ls) zero or more times */
- 	    *s = '\0';
- 	    pptr++;
  	    if (!ls)
  		return NULL;
  	    if (*pptr == Pound) {
  		/* need one or more matches: cheat by copying previous char */
  		pptr++;
  		c->next = c1 = (Comp) alloc(sizeof *c);
! 		c1->str = dupstring(ls);
  	    } else
  		c1 = c;
! 	    c1->next = c2 = (Comp) alloc(sizeof *c);
! 	    c2->str = dupstring(ls);
  	    c2->stat |= C_ONEHASH;
  	    /* parse the rest of the pattern and return. */
  	    c2->next = parsecomp();
  	    if (!c2->next)
  		return NULL;
! 	    *ls++ = '\0';
! 	    c->str = dupstring(cstr);
  	    return c;
  	}
! 	ls = s;			/* whatever we just parsed */
  	if (*pptr == Inang) {
  	    /* Numeric glob */
  	    int dshct;
  
  	    dshct = (pptr[1] == Outang);
! 	    *s++ = *pptr++;
! 	    while (*pptr && (*s++ = *pptr++) != Outang)
! 		if (s[-1] == '-')
! 		    dshct++;
! 		else if (!idigit(s[-1]))
  		    break;
! 	    if (s[-1] != Outang)
  		return NULL;
  	} else if (*pptr == Inbrack) {
  	    /* Character set: brackets had better match */
! 	    while (*pptr && (*s++ = *pptr++) != Outbrack);
! 	    if (s[-1] != Outbrack)
  		return NULL;
! 	} else if (itok(*pptr) && *pptr != Star && *pptr != Quest) {
  	    /* something that can be tokenised which isn't otherwise special */
! 	    *s++ = ztokens[*pptr++ - Pound];
! 	} else {
! 	    /* any other character */
! 	    *s++ = *pptr++;
! 	}
      }
      /* mark if last pattern component in path component or pattern */
      if (*pptr == '/' || !*pptr)
  	c->stat |= C_LAST;
!     *s++ = '\0';
!     c->str = dupstring(cstr);
      return c;
  }
  
--- 1992,2062 ----
  	    /* ...before going back and parsing inside the group. */
  	    endp = pptr;
  	    pptr = startp;
+ 	    c->str = dupstrpfx(cstr, pptr - cstr);
  	    pptr++;
  	    c->next = (Comp) alloc(sizeof *c);
! 	    if (!(c->next->left = parsecompsw(0)))
! 		return NULL;
  	    /* Remember closures for group. */
  	    if (dpnd)
  		c->next->stat |= (dpnd == 2) ? C_TWOHASH : C_ONEHASH;
  	    c->next->next = dpnd ? c1 : (Comp) alloc(sizeof *c);
  	    pptr = endp;
  	    tail = stail;
  	    return c;
  	}
  	if (*pptr == Pound && isset(EXTENDEDGLOB)) {
  	    /* repeat whatever we've just had (ls) zero or more times */
  	    if (!ls)
  		return NULL;
+ 	    c2 = (Comp) alloc(sizeof *c);
+ 	    c2->str = dupstrpfx(ls, pptr - ls);
+ 	    pptr++;
  	    if (*pptr == Pound) {
  		/* need one or more matches: cheat by copying previous char */
  		pptr++;
  		c->next = c1 = (Comp) alloc(sizeof *c);
! 		c1->str = c2->str;
  	    } else
  		c1 = c;
! 	    c1->next = c2;
  	    c2->stat |= C_ONEHASH;
  	    /* parse the rest of the pattern and return. */
  	    c2->next = parsecomp();
  	    if (!c2->next)
  		return NULL;
! 	    c->str = dupstrpfx(cstr, ls - cstr);
  	    return c;
  	}
! 	ls = pptr;		/* whatever we just parsed */
  	if (*pptr == Inang) {
  	    /* Numeric glob */
  	    int dshct;
  
  	    dshct = (pptr[1] == Outang);
! 	    while (*++pptr && *pptr != Outang)
! 		if (*pptr == '-' && !dshct)
! 		    dshct = 1;
! 		else if (!idigit(*pptr))
  		    break;
! 	    if (*pptr != Outang)
  		return NULL;
  	} else if (*pptr == Inbrack) {
  	    /* Character set: brackets had better match */
! 	    while (*++pptr && *pptr != Outbrack)
! 		if (itok(*pptr))
! 		    *pptr = ztokens[*pptr - Pound];
! 	    if (*pptr != Outbrack)
  		return NULL;
! 	} else if (itok(*pptr) && *pptr != Star && *pptr != Quest)
  	    /* something that can be tokenised which isn't otherwise special */
! 	    *pptr = ztokens[*pptr - Pound];
! 	pptr++;
      }
      /* mark if last pattern component in path component or pattern */
      if (*pptr == '/' || !*pptr)
  	c->stat |= C_LAST;
!     c->str = dupstrpfx(cstr, pptr - cstr);
      return c;
  }
  
*** Src/utils.c	1996/12/26 22:43:13	3.1.1.4
--- Src/utils.c	1996/12/29 01:00:41
***************
*** 3185,3190 ****
--- 3185,3212 ----
      return 0;
  }
  
+ /**/
+ char *
+ dupstrpfx(const char *s, int len)
+ {
+     char *r = ncalloc(len + 1);
+ 
+     memcpy(r, s, len);
+     r[len] = '\0';
+     return r;
+ }
+ 
+ /**/
+ char *
+ ztrduppfx(const char *s, int len)
+ {
+     char *r = zalloc(len + 1);
+ 
+     memcpy(r, s, len);
+     r[len] = '\0';
+     return r;
+ }
+ 
  #ifdef DEBUG
  
  /**/



Messages sorted by: Reverse Date, Date, Thread, Author