Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 18 Mar 2001 16:00:34 -0600
From:      Jonathan Lemon <jlemon@flugsvamp.com>
To:        Matt Dillon <dillon@earth.backplane.com>
Cc:        Jonathan Lemon <jlemon@flugsvamp.com>, stable@freebsd.org
Subject:   Re: Not only ftpd's problem with ls */../*.....
Message-ID:  <20010318160034.F82645@prism.flugsvamp.com>
In-Reply-To: <200103180543.f2I5hb398084@earth.backplane.com>
References:  <local.mail.freebsd-stable/200103172107.f2HL7Ea02611@cwsys.cwsent.com> <200103172253.f2HMrZ008412@prism.flugsvamp.com> <200103180027.f2I0RSn96769@earth.backplane.com> <20010317222918.B82645@prism.flugsvamp.com> <200103180543.f2I5hb398084@earth.backplane.com>

next in thread | previous in thread | raw e-mail | index | archive | help
On Sat, Mar 17, 2001 at 09:43:37PM -0800, Matt Dillon wrote:
> 
> :>     be set with a new api call, setgloblimit()?   Or perhaps even just
> :>     have the setgloblimit() API call and don't even bother with a new flag.
> :
> :I would think a better idea is to have the system default to a hard
> :limit, and then allow those programs that know better to override it.
> :This way, we catch most naive uses of glob, while allowing those users
> :who actually want to iterate over more paths to continue.  You'll also
> :note that the glob interface explicitly allows continuing from a previous
> :match (which is what gl_pathc is for), so this fits in nicely.  The
> :only additional change I can think of is to add a new error return to 
> :explicitly alert the user that the match limit was hit.
> :
> :Doing it this way also negates the need for a setgloblimit.
> 
>     Imposing a limit by default is no better then having the hard limit as
>     a default in the first place.  The goal of this fix should be to be as
>     non-intrusive as possible.  Having a hard limit by default is extremely
>     intrusive.  It would be almost as bad as putting a hard limit in, say,
>     'find'.  You don't know *what* type of program will be using the
>     interface.    Just because someone can D.O.S. ftpd doesn't mean that
>     you should suddenly impose an arbitrary limit on every single program
>     that might use the interface.  Nor would it be appropriate to impose an
>     additional burden on the programmers using the interface to require them
>     to explicitly turn off the hard limit if they don't want it... that is 
>     a terrible default API for something like glob!  It immediately imposes
>     the arbitrary limit on every single program using the interface... a limit
>     that the programmers using the interface probably assume doesn't exist.

And this differs in what way from having limit impose a hard resource
limit on various programs?  Like, say, openfiles, which limits the number
of open descriptors, a limit which "programmers using the interface probably
assume doesn't exist"?


>     It makes to try to protect programmers from themselves a little, but
>     it doesn't make sense to pollute the functionality and scaleability of
>     the default interfaces to reach that end.  We shouldn't be trying to
>     protect idiots from themselves... let them learn the hard way so the
>     rest of us can use these APIs without having to go through loops with
>     flags and options to make them act the way we want them to act.

We aren't trying to protect programmers from themselves, we are trying
to make it easier for them.  Or are you advocating that every single user
of glob should be required to sanity check the pattern before making
a glob() call?

Regardless, this close to -release, I will concur that there probably
isn't sufficient time to test this change, so I have a set of patches
to implement the limit on a per-call basis (as described earlier).

Patch attached.
--
Jonathan


Index: include/glob.h
===================================================================
RCS file: /ncvs/src/include/glob.h,v
retrieving revision 1.3
diff -u -r1.3 glob.h
--- include/glob.h	1998/02/25 02:15:59	1.3
+++ include/glob.h	2001/03/18 21:19:49
@@ -76,9 +76,11 @@
 #define	GLOB_NOMAGIC	0x0200	/* GLOB_NOCHECK without magic chars (csh). */
 #define	GLOB_QUOTE	0x0400	/* Quote special chars with \. */
 #define	GLOB_TILDE	0x0800	/* Expand tilde names from the passwd file. */
+#define	GLOB_MAXPATH	0x1000	/* limit number of returned paths */
 
 #define	GLOB_NOSPACE	(-1)	/* Malloc call failed. */
 #define	GLOB_ABEND	(-2)	/* Unignored error. */
+#define	GLOB_LIMIT	(-3)	/* Path limit was hit. */
 
 __BEGIN_DECLS
 int	glob __P((const char *, int, int (*)(const char *, int), glob_t *));
Index: lib/libc/gen//glob.c
===================================================================
RCS file: /ncvs/src/lib/libc/gen/glob.c,v
retrieving revision 1.13
diff -u -r1.13 glob.c
--- lib/libc/gen//glob.c	2001/03/16 19:05:20	1.13
+++ lib/libc/gen//glob.c	2001/03/18 21:46:06
@@ -80,14 +80,6 @@
 
 #include "collate.h"
 
-/*
- * XXX
- * Arbitrarily limit the number of pathnames that glob may
- * return, to prevent DoS attacks.  This should probably be
- * configurable by the user.
- */
-#define MAX_GLOBENTRIES		16384
-
 #define	DOLLAR		'$'
 #define	DOT		'.'
 #define	EOS		'\0'
@@ -147,14 +139,14 @@
 static Char	*g_strcat __P((Char *, const Char *));
 #endif
 static int	 g_stat __P((Char *, struct stat *, glob_t *));
-static int	 glob0 __P((const Char *, glob_t *));
-static int	 glob1 __P((Char *, glob_t *));
-static int	 glob2 __P((Char *, Char *, Char *, glob_t *));
-static int	 glob3 __P((Char *, Char *, Char *, Char *, glob_t *));
-static int	 globextend __P((const Char *, glob_t *));
+static int	 glob0 __P((const Char *, glob_t *, int *));
+static int	 glob1 __P((Char *, glob_t *, int *));
+static int	 glob2 __P((Char *, Char *, Char *, glob_t *, int *));
+static int	 glob3 __P((Char *, Char *, Char *, Char *, glob_t *, int *));
+static int	 globextend __P((const Char *, glob_t *, int *));
 static const Char *	 globtilde __P((const Char *, Char *, size_t, glob_t *));
-static int	 globexp1 __P((const Char *, glob_t *));
-static int	 globexp2 __P((const Char *, const Char *, glob_t *, int *));
+static int	 globexp1 __P((const Char *, glob_t *, int *));
+static int	 globexp2 __P((const Char *, const Char *, glob_t *, int *, int *));
 static int	 match __P((Char *, Char *, Char *));
 #ifdef DEBUG
 static void	 qprintf __P((const char *, Char *));
@@ -167,7 +159,7 @@
 	glob_t *pglob;
 {
 	const u_char *patnext;
-	int c;
+	int c, limit;
 	Char *bufnext, *bufend, patbuf[MAXPATHLEN+1];
 
 	patnext = (u_char *) pattern;
@@ -177,6 +169,10 @@
 		if (!(flags & GLOB_DOOFFS))
 			pglob->gl_offs = 0;
 	}
+	if (flags & GLOB_MAXPATH)
+		limit = pglob->gl_matchc;
+	else
+		limit = 0;
 	pglob->gl_flags = flags & ~GLOB_MAGCHAR;
 	pglob->gl_errfunc = errfunc;
 	pglob->gl_matchc = 0;
@@ -202,9 +198,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);
 }
 
 /*
@@ -212,22 +208,23 @@
  * invoke the standard globbing routine to glob the rest of the magic
  * characters
  */
-static int globexp1(pattern, pglob)
+static int globexp1(pattern, pglob, limit)
 	const Char *pattern;
 	glob_t *pglob;
+	int *limit;
 {
 	const Char* ptr = pattern;
 	int rv;
 
 	/* 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((Char *) 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);
 }
 
 
@@ -236,10 +233,10 @@
  * If it succeeds then it invokes globexp1 with the new pattern.
  * If it fails then it tries to glob the rest of the pattern and returns.
  */
-static int globexp2(ptr, pattern, pglob, rv)
+static int globexp2(ptr, pattern, pglob, rv, limit)
 	const Char *ptr, *pattern;
 	glob_t *pglob;
-	int *rv;
+	int *rv, *limit;
 {
 	int     i;
 	Char   *lm, *ls;
@@ -275,7 +272,7 @@
 
 	/* Non matching braces; just glob the pattern */
 	if (i != 0 || *pe == EOS) {
-		*rv = glob0(patbuf, pglob);
+		*rv = glob0(patbuf, pglob, limit);
 		return 0;
 	}
 
@@ -322,7 +319,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;
@@ -416,9 +413,10 @@
  * to find no matches.
  */
 static int
-glob0(pattern, pglob)
+glob0(pattern, pglob, limit)
 	const Char *pattern;
 	glob_t *pglob;
+	int *limit;
 {
 	const Char *qpatnext;
 	int c, err, oldpathc;
@@ -481,7 +479,7 @@
 	qprintf("glob0:", patbuf);
 #endif
 
-	if ((err = glob1(patbuf, pglob)) != 0)
+	if ((err = glob1(patbuf, pglob, limit)) != 0)
 		return(err);
 
 	/*
@@ -494,7 +492,7 @@
 	    ((pglob->gl_flags & GLOB_NOCHECK) ||
 	      ((pglob->gl_flags & GLOB_NOMAGIC) &&
 	       !(pglob->gl_flags & GLOB_MAGCHAR))))
-		return(globextend(pattern, pglob));
+		return(globextend(pattern, pglob, limit));
 	else if (!(pglob->gl_flags & GLOB_NOSORT))
 		qsort(pglob->gl_pathv + pglob->gl_offs + oldpathc,
 		    pglob->gl_pathc - oldpathc, sizeof(char *), compare);
@@ -509,16 +507,17 @@
 }
 
 static int
-glob1(pattern, pglob)
+glob1(pattern, pglob, limit)
 	Char *pattern;
 	glob_t *pglob;
+	int *limit;
 {
 	Char pathbuf[MAXPATHLEN+1];
 
 	/* A null pathname is invalid -- POSIX 1003.1 sect. 2.4. */
 	if (*pattern == EOS)
 		return(0);
-	return(glob2(pathbuf, pathbuf, pattern, pglob));
+	return(glob2(pathbuf, pathbuf, pattern, pglob, limit));
 }
 
 /*
@@ -527,9 +526,10 @@
  * meta characters.
  */
 static int
-glob2(pathbuf, pathend, pattern, pglob)
+glob2(pathbuf, pathend, pattern, pglob, limit)
 	Char *pathbuf, *pathend, *pattern;
 	glob_t *pglob;
+	int *limit;
 {
 	struct stat sb;
 	Char *p, *q;
@@ -554,7 +554,7 @@
 				*pathend = EOS;
 			}
 			++pglob->gl_matchc;
-			return(globextend(pathbuf, pglob));
+			return(globextend(pathbuf, pglob, limit));
 		}
 
 		/* Find end of next segment, copy tentatively to pathend. */
@@ -572,15 +572,17 @@
 			while (*pattern == SEP)
 				*pathend++ = *pattern++;
 		} else			/* Need expansion, recurse. */
-			return(glob3(pathbuf, pathend, pattern, p, pglob));
+			return(glob3(pathbuf, pathend, pattern, p, pglob,
+			    limit));
 	}
 	/* NOTREACHED */
 }
 
 static int
-glob3(pathbuf, pathend, pattern, restpattern, pglob)
+glob3(pathbuf, pathend, pattern, restpattern, pglob, limit)
 	Char *pathbuf, *pathend, *pattern, *restpattern;
 	glob_t *pglob;
+	int *limit;
 {
 	register struct dirent *dp;
 	DIR *dirp;
@@ -630,7 +632,7 @@
 			*pathend = EOS;
 			continue;
 		}
-		err = glob2(pathbuf, --dc, restpattern, pglob);
+		err = glob2(pathbuf, --dc, restpattern, pglob, limit);
 		if (err)
 			break;
 	}
@@ -658,9 +660,10 @@
  *	gl_pathv points to (gl_offs + gl_pathc + 1) items.
  */
 static int
-globextend(path, pglob)
+globextend(path, pglob, limit)
 	const Char *path;
 	glob_t *pglob;
+	int *limit;
 {
 	register char **pathv;
 	register int i;
@@ -668,8 +671,8 @@
 	char *copy;
 	const Char *p;
 
-	if (pglob->gl_pathc > MAX_GLOBENTRIES)
-		return (GLOB_ABEND);
+	if (*limit && pglob->gl_pathc > *limit)
+		return (GLOB_LIMIT);
 
 	newsize = sizeof(*pathv) * (2 + pglob->gl_pathc + pglob->gl_offs);
 	pathv = pglob->gl_pathv ?

To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-stable" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?20010318160034.F82645>