From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 24155 invoked from network); 29 Dec 1996 02:21:45 -0000 Received: from euclid.skiles.gatech.edu (list@130.207.146.50) by coral.primenet.com.au with SMTP; 29 Dec 1996 02:21:45 -0000 Received: (from list@localhost) by euclid.skiles.gatech.edu (8.7.3/8.7.3) id VAA09782; Sat, 28 Dec 1996 21:19:21 -0500 (EST) Resent-Date: Sat, 28 Dec 1996 21:19:21 -0500 (EST) From: Zoltan Hidvegi Message-Id: <199612290207.DAA19457@hzoli.ppp.cs.elte.hu> Subject: Buffer overflow bug in globbing To: zsh-workers@math.gatech.edu (Zsh hacking and development) Date: Sun, 29 Dec 1996 03:07:37 +0100 (MET) X-Mailer: ELM [version 2.4ME+ PL17 (25)] MIME-Version: 1.0 Content-Type: text/plain; charset=US-ASCII Content-Transfer-Encoding: 7bit Resent-Message-ID: <"0m77M2.0.nO2.fKTno"@euclid> Resent-From: zsh-workers@math.gatech.edu X-Mailing-List: archive/latest/2659 X-Loop: zsh-workers@math.gatech.edu Precedence: list Resent-Sender: zsh-workers-request@math.gatech.edu Just try % echo *20600 (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 /**/