changeset 13385:3d898cde151e

323 Need fix for glob() resource exhaustion Reviewed by: Garrett D'Amore <garrett@nexenta.com> Reviewed by: Dan McDonald <danmcd@nexenta.com> Approved by: Gordon Ross <gwr@nexenta.com>
author Gary Mills <mills@cc.umanitoba.ca>
date Tue, 07 Jun 2011 21:38:05 -0500
parents 0224f53de4de
children 2e5a34cc8a49
files usr/src/cmd/cmd-inet/usr.sbin/in.ftpd/glob.c
diffstat 1 files changed, 40 insertions(+), 8 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/cmd-inet/usr.sbin/in.ftpd/glob.c	Mon Jun 06 15:00:36 2011 -0700
+++ b/usr/src/cmd/cmd-inet/usr.sbin/in.ftpd/glob.c	Tue Jun 07 21:38:05 2011 -0500
@@ -1,4 +1,6 @@
 /*
+ * Copyright (c) 2011 Gary Mills
+ *
  * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
@@ -56,6 +58,14 @@
 #define	GAVSIZ		(1024 * 8)
 #define	isdir(d)	((d.st_mode & S_IFMT) == S_IFDIR)
 
+#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
+
 static char **gargv;		/* Pointer to the (stack) arglist */
 static char **agargv;
 static size_t agargv_size;
@@ -64,6 +74,9 @@
 static short gflag;
 static int tglob(register char);
 
+/* 0 = malloc(), 1 = stat(), 2 = readdir() */
+static size_t limits[] = { 0, 0, 0 };
+
 /* Prototypes */
 
 static char *strend(register char *);
@@ -112,7 +125,10 @@
     char *vv[2];
 
     if (agargv == NULL) {
-	agargv = (char **) malloc(GAVSIZ * sizeof (char *));
+	size_t inc = GAVSIZ * sizeof (char *);
+
+	agargv = (char **) malloc(inc);
+	limits[GLOB_INDEX_MALLOC] += inc;
 	if (agargv == NULL) {
 	    fatal("Out of memory");
 	}
@@ -235,6 +251,8 @@
 		Gcat(gpath, "", check_ncargs);
 		globcnt++;
 	    }
+	    if (limits[GLOB_INDEX_STAT]++ >= GLOB_LIMIT_STAT)
+	      globerr = "Arguments too long";
 	    goto endit;
 	}
 	addpath(*cs++);
@@ -279,6 +297,10 @@
     if (fstat(dirp->dd_fd, &stb) < 0)
 #endif /* HAVE_DIRFD */
 	goto patherr1;
+    if (limits[GLOB_INDEX_STAT]++ >= GLOB_LIMIT_STAT) {
+      globerr = "Arguments too long";
+      return;
+    }
     if (!isdir(stb)) {
 	errno = ENOTDIR;
 	goto patherr1;
@@ -286,7 +308,9 @@
     while (!globerr && ((dp = readdir(dirp)) != NULL)) {
 	if (dp->d_ino == 0)
 	    continue;
-	if (match(dp->d_name, pattern, check_ncargs)) {
+	if (limits[GLOB_INDEX_READDIR]++ >= GLOB_LIMIT_READDIR)
+	  globerr = "Arguments too long";
+	else if (match(dp->d_name, pattern, check_ncargs)) {
 	    Gcat(gpath, dp->d_name, check_ncargs);
 	    globcnt++;
 	}
@@ -491,6 +515,8 @@
 		}
 		else
 		    expand(p, check_ncargs);
+	    if (limits[GLOB_INDEX_STAT]++ >= GLOB_LIMIT_STAT)
+	      globerr = "Arguments too long";
 	    gpathp = sgpathp;
 	    *gpathp = 0;
 	    return (0);
@@ -514,10 +540,13 @@
     }
     if (gargc >= agargv_size - 1) {
 	char **tmp;
+	size_t inc = GAVSIZ * sizeof (char *);
 
 	tmp = (char **)realloc(agargv,
-		(agargv_size + GAVSIZ) * sizeof (char *));
-	if (tmp == NULL) {
+			       inc + (agargv_size * sizeof (char *)));
+	limits[GLOB_INDEX_MALLOC] += inc;
+	if ((tmp == NULL) ||
+	    (limits[GLOB_INDEX_MALLOC] >= GLOB_LIMIT_MALLOC)) {
 	    fatal("Out of memory");
 	} else {
 	    agargv = tmp;
@@ -616,7 +645,8 @@
     int bufsize = strlen(cp) + strlen(dp) + 1;
     char *ep = malloc(bufsize);
 
-    if (ep == NULL)
+    limits[GLOB_INDEX_MALLOC] += bufsize;
+    if ((ep == NULL) || (limits[GLOB_INDEX_MALLOC] >= GLOB_LIMIT_MALLOC))
 	fatal("Out of memory");
     (void) strlcpy(ep, cp, bufsize);
     (void) strlcat(ep, dp, bufsize);
@@ -625,9 +655,11 @@
 
 char **copyblk(register char **v)
 {
-    register char **nv = (char **) malloc((unsigned) ((blklen(v) + 1) *
-						      sizeof(char **)));
-    if (nv == (char **) 0)
+    size_t inc = (unsigned) ((blklen(v) + 1) * sizeof(char **));
+    char **nv = (char **) malloc(inc);
+
+    limits[GLOB_INDEX_MALLOC] += inc;
+    if ((nv == NULL) || (limits[GLOB_INDEX_MALLOC] >= GLOB_LIMIT_MALLOC))
 	fatal("Out of memory");
 
     return (blkcpy(nv, v));