Module Name: src Committed By: riz Date: Mon Jul 19 18:14:09 UTC 2010
Modified Files: src/crypto/dist/ssh [netbsd-5]: sftp-glob.c sftp.c src/lib/libc/gen [netbsd-5]: glob.3 glob.c Log Message: Pull up following revision(s) (requested by christos in ticket #1430): lib/libc/gen/glob.c: revision 1.25 lib/libc/gen/glob.c: revision 1.26 lib/libc/gen/glob.3: revision 1.37 crypto/dist/ssh/sftp.c: patch crypto/dist/ssh/sftp-glob.c: patch Add GLOB_LIMIT to the glob calls to prevent DoS attacks. Apply more limits to GLOB_LIMIT, number of stat(2) calls from me and number of readdir(3) calls from Maksymilian Arciemowicz. Also reduce the memory used by matches strings from Maksymilian Arciemowicz. Avoid DoS attacks for patterns that have braces. Noted by Maksymilian Arciemowicz. XXX: Pullup to 5.x To generate a diff of this commit: cvs rdiff -u -r1.13 -r1.13.24.1 src/crypto/dist/ssh/sftp-glob.c cvs rdiff -u -r1.23 -r1.23.8.1 src/crypto/dist/ssh/sftp.c cvs rdiff -u -r1.32 -r1.32.8.1 src/lib/libc/gen/glob.3 cvs rdiff -u -r1.23 -r1.23.4.1 src/lib/libc/gen/glob.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/crypto/dist/ssh/sftp-glob.c diff -u src/crypto/dist/ssh/sftp-glob.c:1.13 src/crypto/dist/ssh/sftp-glob.c:1.13.24.1 --- src/crypto/dist/ssh/sftp-glob.c:1.13 Thu Sep 28 21:22:15 2006 +++ src/crypto/dist/ssh/sftp-glob.c Mon Jul 19 18:14:09 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: sftp-glob.c,v 1.13 2006/09/28 21:22:15 christos Exp $ */ +/* $NetBSD: sftp-glob.c,v 1.13.24.1 2010/07/19 18:14:09 riz Exp $ */ /* $OpenBSD: sftp-glob.c,v 1.22 2006/08/03 03:34:42 deraadt Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller <d...@openbsd.org> @@ -17,7 +17,7 @@ */ #include "includes.h" -__RCSID("$NetBSD: sftp-glob.c,v 1.13 2006/09/28 21:22:15 christos Exp $"); +__RCSID("$NetBSD: sftp-glob.c,v 1.13.24.1 2010/07/19 18:14:09 riz Exp $"); #include <sys/types.h> #include <sys/stat.h> @@ -121,5 +121,5 @@ memset(&cur, 0, sizeof(cur)); cur.conn = conn; - return(glob(pattern, flags | GLOB_ALTDIRFUNC, errfunc, pglob)); + return(glob(pattern, flags|GLOB_ALTDIRFUNC|GLOB_LIMIT, errfunc, pglob)); } Index: src/crypto/dist/ssh/sftp.c diff -u src/crypto/dist/ssh/sftp.c:1.23 src/crypto/dist/ssh/sftp.c:1.23.8.1 --- src/crypto/dist/ssh/sftp.c:1.23 Sun Apr 6 23:38:19 2008 +++ src/crypto/dist/ssh/sftp.c Mon Jul 19 18:14:09 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: sftp.c,v 1.23 2008/04/06 23:38:19 christos Exp $ */ +/* $NetBSD: sftp.c,v 1.23.8.1 2010/07/19 18:14:09 riz Exp $ */ /* $OpenBSD: sftp.c,v 1.99 2008/01/20 00:38:30 djm Exp $ */ /* * Copyright (c) 2001-2004 Damien Miller <d...@openbsd.org> @@ -17,7 +17,7 @@ */ #include "includes.h" -__RCSID("$NetBSD: sftp.c,v 1.23 2008/04/06 23:38:19 christos Exp $"); +__RCSID("$NetBSD: sftp.c,v 1.23.8.1 2010/07/19 18:14:09 riz Exp $"); #include <sys/types.h> #include <sys/ioctl.h> #include <sys/wait.h> @@ -521,7 +521,7 @@ memset(&g, 0, sizeof(g)); debug3("Looking up %s", src); - if (glob(src, GLOB_NOCHECK, NULL, &g)) { + if (glob(src, GLOB_NOCHECK|GLOB_LIMIT, NULL, &g)) { error("File \"%s\" not found.", src); err = -1; goto out; Index: src/lib/libc/gen/glob.3 diff -u src/lib/libc/gen/glob.3:1.32 src/lib/libc/gen/glob.3:1.32.8.1 --- src/lib/libc/gen/glob.3:1.32 Fri Feb 22 18:33:51 2008 +++ src/lib/libc/gen/glob.3 Mon Jul 19 18:14:09 2010 @@ -1,4 +1,4 @@ -.\" $NetBSD: glob.3,v 1.32 2008/02/22 18:33:51 christos Exp $ +.\" $NetBSD: glob.3,v 1.32.8.1 2010/07/19 18:14:09 riz Exp $ .\" .\" Copyright (c) 1989, 1991, 1993, 1994 .\" The Regents of the University of California. All rights reserved. @@ -31,7 +31,7 @@ .\" .\" @(#)glob.3 8.3 (Berkeley) 4/16/94 .\" -.Dd February 22, 2008 +.Dd July 6, 2010 .Dt GLOB 3 .Os .Sh NAME @@ -253,8 +253,13 @@ .Ql ~ to user name home directories. .It Dv GLOB_LIMIT -Limit the amount of memory used by matches to -.Li ARG_MAX . +Limit the amount of memory used to store matched strings to +.Li 64K , +the number of +.Xr stat 2 +calls to 128, and the number of +.Xr readdir 3 +calls to 16K. This option should be set for programs that can be coerced to a denial of service attack via patterns that expand to a very large number of matches, such as a long string of Index: src/lib/libc/gen/glob.c diff -u src/lib/libc/gen/glob.c:1.23 src/lib/libc/gen/glob.c:1.23.4.1 --- src/lib/libc/gen/glob.c:1.23 Mon May 26 13:06:38 2008 +++ src/lib/libc/gen/glob.c Mon Jul 19 18:14:08 2010 @@ -1,4 +1,4 @@ -/* $NetBSD: glob.c,v 1.23 2008/05/26 13:06:38 ad Exp $ */ +/* $NetBSD: glob.c,v 1.23.4.1 2010/07/19 18:14:08 riz Exp $ */ /* * Copyright (c) 1989, 1993 @@ -37,7 +37,7 @@ #if 0 static char sccsid[] = "@(#)glob.c 8.3 (Berkeley) 10/13/93"; #else -__RCSID("$NetBSD: glob.c,v 1.23 2008/05/26 13:06:38 ad Exp $"); +__RCSID("$NetBSD: glob.c,v 1.23.4.1 2010/07/19 18:14:08 riz Exp $"); #endif #endif /* LIBC_SCCS and not lint */ @@ -87,10 +87,13 @@ #define NO_GETPW_R #endif -#if !defined(ARG_MAX) -#include <limits.h> -#define ARG_MAX _POSIX_ARG_MAX -#endif +#define GLOB_LIMIT_MALLOC 65536 +#define GLOB_LIMIT_STAT 128 +#define GLOB_LIMIT_READDIR 16384 + +#define GLOB_INDEX_MALLOC 0 +#define GLOB_INDEX_STAT 1 +#define GLOB_INDEX_READDIR 2 /* * XXX: For NetBSD 1.4.x compatibility. (kill me l8r) @@ -155,7 +158,7 @@ static DIR *g_opendir(Char *, glob_t *); static Char *g_strchr(const Char *, int); static int g_stat(Char *, __gl_stat_t *, glob_t *); -static int glob0(const Char *, glob_t *); +static int glob0(const Char *, glob_t *, size_t *); static int glob1(Char *, glob_t *, size_t *); static int glob2(Char *, Char *, Char *, Char *, glob_t *, size_t *); @@ -163,8 +166,9 @@ size_t *); static int globextend(const Char *, glob_t *, size_t *); static const Char *globtilde(const Char *, Char *, size_t, glob_t *); -static int globexp1(const Char *, glob_t *); -static int globexp2(const Char *, const Char *, glob_t *, int *); +static int globexp1(const Char *, glob_t *, size_t *); +static int globexp2(const Char *, const Char *, glob_t *, int *, + size_t *); static int match(Char *, Char *, Char *); #ifdef DEBUG static void qprintf(const char *, Char *); @@ -177,6 +181,8 @@ const u_char *patnext; int c; Char *bufnext, *bufend, patbuf[MAXPATHLEN+1]; + /* 0 = malloc(), 1 = stat(), 2 = readdir() */ + size_t limit[] = { 0, 0, 0 }; _DIAGASSERT(pattern != NULL); @@ -212,9 +218,9 @@ *bufnext = EOS; if (flags & GLOB_BRACE) - return globexp1(patbuf, pglob); + return globexp1(patbuf, pglob, limit); else - return glob0(patbuf, pglob); + return glob0(patbuf, pglob, limit); } /* @@ -223,7 +229,7 @@ * characters */ static int -globexp1(const Char *pattern, glob_t *pglob) +globexp1(const Char *pattern, glob_t *pglob, size_t *limit) { const Char* ptr = pattern; int rv; @@ -233,13 +239,13 @@ /* Protect a single {}, for find(1), like csh */ if (pattern[0] == LBRACE && pattern[1] == RBRACE && pattern[2] == EOS) - return glob0(pattern, pglob); + return glob0(pattern, pglob, limit); while ((ptr = (const Char *) g_strchr(ptr, LBRACE)) != NULL) - if (!globexp2(ptr, pattern, pglob, &rv)) + if (!globexp2(ptr, pattern, pglob, &rv, limit)) return rv; - return glob0(pattern, pglob); + return glob0(pattern, pglob, limit); } @@ -249,7 +255,8 @@ * If it fails then it tries to glob the rest of the pattern and returns. */ static int -globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv) +globexp2(const Char *ptr, const Char *pattern, glob_t *pglob, int *rv, + size_t *limit) { int i; Char *lm, *ls; @@ -294,7 +301,7 @@ * we use `pattern', not `patbuf' here so that that * unbalanced braces are passed to the match */ - *rv = glob0(pattern, pglob); + *rv = glob0(pattern, pglob, limit); return 0; } @@ -341,7 +348,7 @@ #ifdef DEBUG qprintf("globexp2:", patbuf); #endif - *rv = globexp1(patbuf, pglob); + *rv = globexp1(patbuf, pglob, limit); /* move after the comma, to the next string */ pl = pm + 1; @@ -454,13 +461,12 @@ * to find no matches. */ static int -glob0(const Char *pattern, glob_t *pglob) +glob0(const Char *pattern, glob_t *pglob, size_t *limit) { const Char *qpatnext; int c, error; __gl_size_t oldpathc; Char *bufnext, patbuf[MAXPATHLEN+1]; - size_t limit = 0; _DIAGASSERT(pattern != NULL); _DIAGASSERT(pglob != NULL); @@ -523,7 +529,7 @@ qprintf("glob0:", patbuf); #endif - if ((error = glob1(patbuf, pglob, &limit)) != 0) + if ((error = glob1(patbuf, pglob, limit)) != 0) return error; if (pglob->gl_pathc == oldpathc) { @@ -537,7 +543,7 @@ if ((pglob->gl_flags & GLOB_NOCHECK) || ((pglob->gl_flags & (GLOB_NOMAGIC|GLOB_MAGCHAR)) == GLOB_NOMAGIC)) { - return globextend(pattern, pglob, &limit); + return globextend(pattern, pglob, limit); } else { return GLOB_NOMATCH; } @@ -610,6 +616,13 @@ if (g_lstat(pathbuf, &sb, pglob)) return 0; + if ((pglob->gl_flags & GLOB_LIMIT) && + limit[GLOB_INDEX_STAT]++ >= GLOB_LIMIT_STAT) { + errno = 0; + *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) && @@ -726,6 +739,14 @@ u_char *sc; Char *dc; + if ((pglob->gl_flags & GLOB_LIMIT) && + limit[GLOB_INDEX_READDIR]++ >= GLOB_LIMIT_READDIR) { + errno = 0; + *pathend++ = SEP; + *pathend = EOS; + return GLOB_NOSPACE; + } + /* * Initial DOT must be matched literally, unless we have * GLOB_PERIOD set. @@ -772,7 +793,8 @@ *pathend = EOS; continue; } - error = glob2(pathbuf, --dc, pathlim, restpattern, pglob, limit); + error = glob2(pathbuf, --dc, pathlim, restpattern, pglob, + limit); if (error) break; } @@ -834,7 +856,7 @@ for (p = path; *p++;) continue; len = (size_t)(p - path); - *limit += len; + limit[GLOB_INDEX_MALLOC] += len; if ((copy = malloc(len)) != NULL) { if (g_Ctoc(path, copy, len)) { free(copy); @@ -844,7 +866,8 @@ } pathv[pglob->gl_offs + pglob->gl_pathc] = NULL; - if ((pglob->gl_flags & GLOB_LIMIT) && (newsize + *limit) >= ARG_MAX) { + if ((pglob->gl_flags & GLOB_LIMIT) && + (newsize + limit[GLOB_INDEX_MALLOC]) >= GLOB_LIMIT_MALLOC) { errno = 0; return GLOB_NOSPACE; }