From owner-svn-src-stable-6@FreeBSD.ORG Thu Feb 21 20:40:38 2013 Return-Path: Delivered-To: svn-src-stable-6@freebsd.org Received: from mx1.freebsd.org (mx1.FreeBSD.org [8.8.178.115]) by hub.freebsd.org (Postfix) with ESMTP id 0A67D9CA; Thu, 21 Feb 2013 20:40:38 +0000 (UTC) (envelope-from delphij@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id DBF499A3; Thu, 21 Feb 2013 20:40:37 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.5/8.14.5) with ESMTP id r1LKeb1n063220; Thu, 21 Feb 2013 20:40:37 GMT (envelope-from delphij@svn.freebsd.org) Received: (from delphij@localhost) by svn.freebsd.org (8.14.5/8.14.5/Submit) id r1LKebap063219; Thu, 21 Feb 2013 20:40:37 GMT (envelope-from delphij@svn.freebsd.org) Message-Id: <201302212040.r1LKebap063219@svn.freebsd.org> From: Xin LI Date: Thu, 21 Feb 2013 20:40:37 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-6@freebsd.org Subject: svn commit: r247126 - stable/6/lib/libc/gen X-SVN-Group: stable-6 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable-6@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: SVN commit messages for only the 6-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 21 Feb 2013 20:40:38 -0000 Author: delphij Date: Thu Feb 21 20:40:37 2013 New Revision: 247126 URL: http://svnweb.freebsd.org/changeset/base/247126 Log: MFC: r158812 (ache): Reflect size_t changes in glob.h Obtained from: NetBSD (mostly) r159294: - ANSIfy. - Remove two unnecessary casts. r243779 (marcel): Protect against DoS attacks, such as being described in CVE-2010-2632. The changes were derived from what has been committed to NetBSD, with modifications. This fixes FreeBSD-SA-13:02.libc for stable/6. Modified: stable/6/lib/libc/gen/glob.c Directory Properties: stable/6/lib/libc/ (props changed) Modified: stable/6/lib/libc/gen/glob.c ============================================================================== --- stable/6/lib/libc/gen/glob.c Thu Feb 21 20:29:43 2013 (r247125) +++ stable/6/lib/libc/gen/glob.c Thu Feb 21 20:40:37 2013 (r247126) @@ -93,6 +93,25 @@ __FBSDID("$FreeBSD$"); #include "collate.h" +/* + * glob(3) expansion limits. Stop the expansion if any of these limits + * is reached. This caps the runtime in the face of DoS attacks. See + * also CVE-2010-2632 + */ +#define GLOB_LIMIT_BRACE 128 /* number of brace calls */ +#define GLOB_LIMIT_PATH 65536 /* number of path elements */ +#define GLOB_LIMIT_READDIR 16384 /* number of readdirs */ +#define GLOB_LIMIT_STAT 1024 /* number of stat system calls */ +#define GLOB_LIMIT_STRING ARG_MAX /* maximum total size for paths */ + +struct glob_limit { + size_t l_brace_cnt; + size_t l_path_lim; + size_t l_readdir_cnt; + size_t l_stat_cnt; + size_t l_string_cnt; +}; + #define DOLLAR '$' #define DOT '.' #define EOS '\0' @@ -144,7 +163,7 @@ typedef char Char; static int compare(const void *, const void *); -static int g_Ctoc(const Char *, char *, u_int); +static int g_Ctoc(const Char *, char *, size_t); static int g_lstat(Char *, struct stat *, glob_t *); static DIR *g_opendir(Char *, glob_t *); static Char *g_strchr(Char *, wchar_t); @@ -152,34 +171,34 @@ static Char *g_strchr(Char *, wchar_t); static Char *g_strcat(Char *, const Char *); #endif static int g_stat(Char *, struct stat *, glob_t *); -static int glob0(const Char *, glob_t *, int *); -static int glob1(Char *, glob_t *, int *); -static int glob2(Char *, Char *, Char *, Char *, glob_t *, int *); -static int glob3(Char *, Char *, Char *, Char *, Char *, glob_t *, int *); -static int globextend(const Char *, glob_t *, int *); -static const Char * +static int glob0(const Char *, glob_t *, struct glob_limit *); +static int glob1(Char *, glob_t *, struct glob_limit *); +static int glob2(Char *, Char *, Char *, Char *, glob_t *, + struct glob_limit *); +static int glob3(Char *, Char *, Char *, Char *, Char *, glob_t *, + struct glob_limit *); +static int globextend(const Char *, glob_t *, struct glob_limit *); +static const Char * globtilde(const Char *, Char *, size_t, glob_t *); -static int globexp1(const Char *, glob_t *, int *); -static int globexp2(const Char *, const Char *, glob_t *, int *, int *); +static int globexp1(const Char *, glob_t *, struct glob_limit *); +static int globexp2(const Char *, const Char *, glob_t *, int *, + struct glob_limit *); static int match(Char *, Char *, Char *); #ifdef DEBUG static void qprintf(const char *, Char *); #endif int -glob(pattern, flags, errfunc, pglob) - const char *pattern; - int flags, (*errfunc)(const char *, int); - glob_t *pglob; +glob(const char *pattern, int flags, int (*errfunc)(const char *, int), glob_t *pglob) { - const u_char *patnext; - int limit; + struct glob_limit limit = { 0, 0, 0, 0, 0 }; + const char *patnext; Char *bufnext, *bufend, patbuf[MAXPATHLEN], prot; mbstate_t mbs; wchar_t wc; size_t clen; - patnext = (u_char *) pattern; + patnext = pattern; if (!(flags & GLOB_APPEND)) { pglob->gl_pathc = 0; pglob->gl_pathv = NULL; @@ -187,11 +206,10 @@ glob(pattern, flags, errfunc, pglob) pglob->gl_offs = 0; } if (flags & GLOB_LIMIT) { - limit = pglob->gl_matchc; - if (limit == 0) - limit = ARG_MAX; - } else - limit = 0; + limit.l_path_lim = pglob->gl_matchc; + if (limit.l_path_lim == 0) + limit.l_path_lim = GLOB_LIMIT_PATH; + } pglob->gl_flags = flags & ~GLOB_MAGCHAR; pglob->gl_errfunc = errfunc; pglob->gl_matchc = 0; @@ -244,14 +262,17 @@ glob(pattern, flags, errfunc, pglob) * characters */ static int -globexp1(pattern, pglob, limit) - const Char *pattern; - glob_t *pglob; - int *limit; +globexp1(const Char *pattern, glob_t *pglob, struct glob_limit *limit) { const Char* ptr = pattern; int rv; + if ((pglob->gl_flags & GLOB_LIMIT) && + limit->l_brace_cnt++ >= GLOB_LIMIT_BRACE) { + errno = 0; + return (GLOB_NOSPACE); + } + /* Protect a single {}, for find(1), like csh */ if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) return glob0(pattern, pglob, limit); @@ -270,10 +291,8 @@ globexp1(pattern, pglob, limit) * If it fails then it tries to glob the rest of the pattern and returns. */ static int -globexp2(ptr, pattern, pglob, rv, limit) - const Char *ptr, *pattern; - glob_t *pglob; - int *rv, *limit; +globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv, + struct glob_limit *limit) { int i; Char *lm, *ls; @@ -377,11 +396,7 @@ globexp2(ptr, pattern, pglob, rv, limit) * expand tilde from the passwd file. */ static const Char * -globtilde(pattern, patbuf, patbuf_len, pglob) - const Char *pattern; - Char *patbuf; - size_t patbuf_len; - glob_t *pglob; +globtilde(const Char *pattern, Char *patbuf, size_t patbuf_len, glob_t *pglob) { struct passwd *pwd; char *h; @@ -447,13 +462,11 @@ globtilde(pattern, patbuf, patbuf_len, p * if things went well, nonzero if errors occurred. */ static int -glob0(pattern, pglob, limit) - const Char *pattern; - glob_t *pglob; - int *limit; +glob0(const Char *pattern, glob_t *pglob, struct glob_limit *limit) { const Char *qpatnext; - int c, err, oldpathc; + int c, err; + size_t oldpathc; Char *bufnext, patbuf[MAXPATHLEN]; qpatnext = globtilde(pattern, patbuf, MAXPATHLEN, pglob); @@ -536,17 +549,13 @@ glob0(pattern, pglob, limit) } static int -compare(p, q) - const void *p, *q; +compare(const void *p, const void *q) { return(strcmp(*(char **)p, *(char **)q)); } static int -glob1(pattern, pglob, limit) - Char *pattern; - glob_t *pglob; - int *limit; +glob1(Char *pattern, glob_t *pglob, struct glob_limit *limit) { Char pathbuf[MAXPATHLEN]; @@ -563,10 +572,8 @@ glob1(pattern, pglob, limit) * meta characters. */ static int -glob2(pathbuf, pathend, pathend_last, pattern, pglob, limit) - Char *pathbuf, *pathend, *pathend_last, *pattern; - glob_t *pglob; - int *limit; +glob2(Char *pathbuf, Char *pathend, Char *pathend_last, Char *pattern, + glob_t *pglob, struct glob_limit *limit) { struct stat sb; Char *p, *q; @@ -582,6 +589,15 @@ glob2(pathbuf, pathend, pathend_last, pa if (g_lstat(pathbuf, &sb, pglob)) return(0); + if ((pglob->gl_flags & GLOB_LIMIT) && + limit->l_stat_cnt++ >= GLOB_LIMIT_STAT) { + errno = 0; + if (pathend + 1 > pathend_last) + return (GLOB_ABORTED); + *pathend++ = SEP; + *pathend = EOS; + return (GLOB_NOSPACE); + } if (((pglob->gl_flags & GLOB_MARK) && pathend[-1] != SEP) && (S_ISDIR(sb.st_mode) || (S_ISLNK(sb.st_mode) && @@ -623,10 +639,9 @@ glob2(pathbuf, pathend, pathend_last, pa } static int -glob3(pathbuf, pathend, pathend_last, pattern, restpattern, pglob, limit) - Char *pathbuf, *pathend, *pathend_last, *pattern, *restpattern; - glob_t *pglob; - int *limit; +glob3(Char *pathbuf, Char *pathend, Char *pathend_last, + Char *pattern, Char *restpattern, + glob_t *pglob, struct glob_limit *limit) { struct dirent *dp; DIR *dirp; @@ -666,18 +681,31 @@ glob3(pathbuf, pathend, pathend_last, pa else readdirfunc = readdir; while ((dp = (*readdirfunc)(dirp))) { - u_char *sc; + char *sc; Char *dc; wchar_t wc; size_t clen; mbstate_t mbs; + if ((pglob->gl_flags & GLOB_LIMIT) && + limit->l_readdir_cnt++ >= GLOB_LIMIT_READDIR) { + errno = 0; + if (pathend + 1 > pathend_last) + err = GLOB_ABORTED; + else { + *pathend++ = SEP; + *pathend = EOS; + err = GLOB_NOSPACE; + } + break; + } + /* Initial DOT must be matched literally. */ if (dp->d_name[0] == DOT && *pattern != DOT) continue; memset(&mbs, 0, sizeof(mbs)); dc = pathend; - sc = (u_char *) dp->d_name; + sc = dp->d_name; while (dc < pathend_last) { clen = mbrtowc(&wc, sc, MB_LEN_MAX, &mbs); if (clen == (size_t)-1 || clen == (size_t)-2) { @@ -722,18 +750,15 @@ glob3(pathbuf, pathend, pathend_last, pa * gl_pathv points to (gl_offs + gl_pathc + 1) items. */ static int -globextend(path, pglob, limit) - const Char *path; - glob_t *pglob; - int *limit; +globextend(const Char *path, glob_t *pglob, struct glob_limit *limit) { char **pathv; - int i; - u_int newsize, len; + size_t i, newsize, len; char *copy; const Char *p; - if (*limit && pglob->gl_pathc > *limit) { + if ((pglob->gl_flags & GLOB_LIMIT) && + pglob->gl_matchc > limit->l_path_lim) { errno = 0; return (GLOB_NOSPACE); } @@ -753,7 +778,7 @@ globextend(path, pglob, limit) if (pglob->gl_pathv == NULL && pglob->gl_offs > 0) { /* first time around -- clear initial gl_offs items */ pathv += pglob->gl_offs; - for (i = pglob->gl_offs; --i >= 0; ) + for (i = pglob->gl_offs + 1; --i > 0; ) *--pathv = NULL; } pglob->gl_pathv = pathv; @@ -761,6 +786,12 @@ globextend(path, pglob, limit) for (p = path; *p++;) continue; len = MB_CUR_MAX * (size_t)(p - path); /* XXX overallocation */ + limit->l_string_cnt += len; + if ((pglob->gl_flags & GLOB_LIMIT) && + limit->l_string_cnt >= GLOB_LIMIT_STRING) { + errno = 0; + return (GLOB_NOSPACE); + } if ((copy = malloc(len)) != NULL) { if (g_Ctoc(path, copy, len)) { free(copy); @@ -777,8 +808,7 @@ globextend(path, pglob, limit) * pattern causes a recursion level. */ static int -match(name, pat, patend) - Char *name, *pat, *patend; +match(Char *name, Char *pat, Char *patend) { int ok, negate_range; Char c, k; @@ -829,10 +859,9 @@ match(name, pat, patend) /* Free allocated data belonging to a glob_t structure. */ void -globfree(pglob) - glob_t *pglob; +globfree(glob_t *pglob) { - int i; + size_t i; char **pp; if (pglob->gl_pathv != NULL) { @@ -846,9 +875,7 @@ globfree(pglob) } static DIR * -g_opendir(str, pglob) - Char *str; - glob_t *pglob; +g_opendir(Char *str, glob_t *pglob) { char buf[MAXPATHLEN]; @@ -866,10 +893,7 @@ g_opendir(str, pglob) } static int -g_lstat(fn, sb, pglob) - Char *fn; - struct stat *sb; - glob_t *pglob; +g_lstat(Char *fn, struct stat *sb, glob_t *pglob) { char buf[MAXPATHLEN]; @@ -883,10 +907,7 @@ g_lstat(fn, sb, pglob) } static int -g_stat(fn, sb, pglob) - Char *fn; - struct stat *sb; - glob_t *pglob; +g_stat(Char *fn, struct stat *sb, glob_t *pglob) { char buf[MAXPATHLEN]; @@ -900,10 +921,9 @@ g_stat(fn, sb, pglob) } static Char * -g_strchr(str, ch) - Char *str; - wchar_t ch; +g_strchr(Char *str, wchar_t ch) { + do { if (*str == ch) return (str); @@ -912,10 +932,7 @@ g_strchr(str, ch) } static int -g_Ctoc(str, buf, len) - const Char *str; - char *buf; - u_int len; +g_Ctoc(const Char *str, char *buf, size_t len) { mbstate_t mbs; size_t clen; @@ -936,9 +953,7 @@ g_Ctoc(str, buf, len) #ifdef DEBUG static void -qprintf(str, s) - const char *str; - Char *s; +qprintf(const char *str, Char *s) { Char *p; From owner-svn-src-stable-6@FreeBSD.ORG Thu Feb 21 21:48:39 2013 Return-Path: Delivered-To: svn-src-stable-6@freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by hub.freebsd.org (Postfix) with ESMTP id 1A123E59; Thu, 21 Feb 2013 21:48:39 +0000 (UTC) (envelope-from markj@FreeBSD.org) Received: from svn.freebsd.org (svn.freebsd.org [IPv6:2001:1900:2254:2068::e6a:0]) by mx1.freebsd.org (Postfix) with ESMTP id E8101E59; Thu, 21 Feb 2013 21:48:38 +0000 (UTC) Received: from svn.freebsd.org ([127.0.1.70]) by svn.freebsd.org (8.14.5/8.14.5) with ESMTP id r1LLmc0f084901; Thu, 21 Feb 2013 21:48:38 GMT (envelope-from markj@svn.freebsd.org) Received: (from markj@localhost) by svn.freebsd.org (8.14.5/8.14.5/Submit) id r1LLmcoX084900; Thu, 21 Feb 2013 21:48:38 GMT (envelope-from markj@svn.freebsd.org) Message-Id: <201302212148.r1LLmcoX084900@svn.freebsd.org> From: Mark Johnston Date: Thu, 21 Feb 2013 21:48:38 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-stable@freebsd.org, svn-src-stable-6@freebsd.org Subject: svn commit: r247136 - stable/6/sys/netinet X-SVN-Group: stable-6 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-stable-6@freebsd.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: SVN commit messages for only the 6-stable src tree List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 21 Feb 2013 21:48:39 -0000 Author: markj Date: Thu Feb 21 21:48:38 2013 New Revision: 247136 URL: http://svnweb.freebsd.org/changeset/base/247136 Log: MFC r239672 (by rrs): This small change takes care of a race condition that can occur when both sides close at the same time. If that occurs, without this fix the connection enters FIN1 on both sides and they will forever send FIN|ACK at each other until the connection times out. This is because we stopped processing the FIN|ACK and thus did not advance the sequence and so never ACK'd each others FIN. This fix adjusts it so we *do* process the FIN properly and the race goes away ;-) Approved by: emaste (co-mentor) Modified: stable/6/sys/netinet/tcp_input.c Directory Properties: stable/6/sys/ (props changed) Modified: stable/6/sys/netinet/tcp_input.c ============================================================================== --- stable/6/sys/netinet/tcp_input.c Thu Feb 21 21:47:35 2013 (r247135) +++ stable/6/sys/netinet/tcp_input.c Thu Feb 21 21:48:38 2013 (r247136) @@ -1908,6 +1908,16 @@ trimthenstep6: } } else tp->snd_cwnd += tp->t_maxseg; + if ((thflags & TH_FIN) && + (TCPS_HAVERCVDFIN(tp->t_state) == 0)) { + /* + * If its a fin we need to process + * it to avoid a race where both + * sides enter FIN-WAIT and send FIN|ACK + * at the same time. + */ + break; + } (void) tcp_output(tp); goto drop; } else if (tp->t_dupacks == tcprexmtthresh) { @@ -1951,6 +1961,16 @@ trimthenstep6: } tp->snd_nxt = th->th_ack; tp->snd_cwnd = tp->t_maxseg; + if ((thflags & TH_FIN) && + (TCPS_HAVERCVDFIN(tp->t_state) == 0)) { + /* + * If its a fin we need to process + * it to avoid a race where both + * sides enter FIN-WAIT and send FIN|ACK + * at the same time. + */ + break; + } (void) tcp_output(tp); KASSERT(tp->snd_limited <= 2, ("tp->snd_limited too big")); @@ -1974,6 +1994,16 @@ trimthenstep6: (tp->snd_nxt - tp->snd_una) + (tp->t_dupacks - tp->snd_limited) * tp->t_maxseg; + if ((thflags & TH_FIN) && + (TCPS_HAVERCVDFIN(tp->t_state) == 0)) { + /* + * If its a fin we need to process + * it to avoid a race where both + * sides enter FIN-WAIT and send FIN|ACK + * at the same time. + */ + break; + } (void) tcp_output(tp); sent = tp->snd_max - oldsndmax; if (sent > tp->t_maxseg) {