From nobody@FreeBSD.org  Sun Jul 18 15:10:56 2010
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:4f8:fff6::34])
	by hub.freebsd.org (Postfix) with ESMTP id 14E331065672
	for <freebsd-gnats-submit@FreeBSD.org>; Sun, 18 Jul 2010 15:10:56 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [IPv6:2001:4f8:fff6::21])
	by mx1.freebsd.org (Postfix) with ESMTP id DFB8E8FC1E
	for <freebsd-gnats-submit@FreeBSD.org>; Sun, 18 Jul 2010 15:10:55 +0000 (UTC)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.14.3/8.14.3) with ESMTP id o6IFAt9h031810
	for <freebsd-gnats-submit@FreeBSD.org>; Sun, 18 Jul 2010 15:10:55 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.14.3/8.14.3/Submit) id o6IFAtTZ031809;
	Sun, 18 Jul 2010 15:10:55 GMT
	(envelope-from nobody)
Message-Id: <201007181510.o6IFAtTZ031809@www.freebsd.org>
Date: Sun, 18 Jul 2010 15:10:55 GMT
From: Changming Sun <snnn119@gmail.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: a potential buffer overflow  in bin/sh
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         148733
>Category:       bin
>Synopsis:       a potential buffer overflow  in sh(1)
>Confidential:   no
>Severity:       serious
>Priority:       medium
>Responsible:    jilles
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Sun Jul 18 15:20:06 UTC 2010
>Closed-Date:    Thu Dec 02 23:28:10 UTC 2010
>Last-Modified:  Thu Dec 02 23:28:10 UTC 2010
>Originator:     Changming Sun
>Release:        FreeBSD 9
>Organization:
wanmei.inc
>Environment:
FreeBSD 9
>Description:
There is a invoke to "readdir" function in /usr/src/bin/sh/expand.c:expmeta(char *enddir, char *name),then the result of d_name has been copied to "enddir"  scopy(dp->d_name, enddir);

is enddir enough large to hold this ?

expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */

It seems like somebody has already known this problem,but nobody want to fix it!
>How-To-Repeat:
Get head source from svn,then review it.
>Fix:


>Release-Note:
>Audit-Trail:

From: Jilles Tjoelker <jilles@stack.nl>
To: bug-followup@FreeBSD.org, snnn119@gmail.com
Cc:  
Subject: Re: bin/148733: a potential buffer overflow  in sh(1)
Date: Thu, 29 Jul 2010 23:38:55 +0200

 > [buffer overflow in sh(1) pathname generation]
 
 You are right, there is a possible heap buffer overflow here. It is
 rather unlikely in normal usage because the kernel does not accept
 pathnames longer than 1023 bytes, but still possible.
 
 -- 
 Jilles Tjoelker
Responsible-Changed-From-To: freebsd-bugs->jilles 
Responsible-Changed-By: jilles 
Responsible-Changed-When: Sun Aug 1 14:16:56 UTC 2010 
Responsible-Changed-Why:  
I'm working on this. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=148733 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/148733: commit references a PR
Date: Tue, 10 Aug 2010 22:46:17 +0000 (UTC)

 Author: jilles
 Date: Tue Aug 10 22:45:59 2010
 New Revision: 211155
 URL: http://svn.freebsd.org/changeset/base/211155
 
 Log:
   sh: Fix heap-based buffer overflow in pathname generation.
   
   The buffer for generated pathnames could be too small in some cases. It
   happened to be always at least PATH_MAX long, so there was never an overflow
   if the resulting pathnames would be usable.
   
   This bug may be abused if a script subjects input from an untrusted source
   to pathname generation, which a bad idea anyhow. Most shell scripts do not
   work on untrusted data. secteam@ says no advisory is necessary.
   
   PR:		bin/148733
   Reported by:	Changming Sun snnn119 at gmail com
   MFC after:	10 days
 
 Added:
   head/tools/regression/bin/sh/expansion/pathname3.0   (contents, props changed)
 Modified:
   head/bin/sh/expand.c
 
 Modified: head/bin/sh/expand.c
 ==============================================================================
 --- head/bin/sh/expand.c	Tue Aug 10 19:50:51 2010	(r211154)
 +++ head/bin/sh/expand.c	Tue Aug 10 22:45:59 2010	(r211155)
 @@ -1082,8 +1082,8 @@ ifsbreakup(char *string, struct arglist 
   * should be escapes.  The results are stored in the list exparg.
   */
  
 -STATIC char *expdir;
 -
 +STATIC char expdir[PATH_MAX];
 +#define expdir_end (expdir + sizeof(expdir))
  
  STATIC void
  expandmeta(struct strlist *str, int flag __unused)
 @@ -1106,14 +1106,7 @@ expandmeta(struct strlist *str, int flag
  		}
  		savelastp = exparg.lastp;
  		INTOFF;
 -		if (expdir == NULL) {
 -			int i = strlen(str->text);
 -			expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
 -		}
 -
  		expmeta(expdir, str->text);
 -		ckfree(expdir);
 -		expdir = NULL;
  		INTON;
  		if (exparg.lastp == savelastp) {
  			/*
 @@ -1202,6 +1195,8 @@ expmeta(char *enddir, char *name)
  			*enddir++ = *p;
  			if (*p == '\0')
  				break;
 +			if (enddir == expdir_end)
 +				return;
  		}
  		if (metaflag == 0 || lstat(expdir, &statb) >= 0)
  			addfname(expdir);
 @@ -1216,6 +1211,8 @@ expmeta(char *enddir, char *name)
  			if (*p == CTLESC)
  				p++;
  			*enddir++ = *p++;
 +			if (enddir == expdir_end)
 +				return;
  		}
  	}
  	if (enddir == expdir) {
 @@ -1249,15 +1246,17 @@ expmeta(char *enddir, char *name)
  		if (dp->d_name[0] == '.' && ! matchdot)
  			continue;
  		if (patmatch(start, dp->d_name, 0)) {
 -			if (atend) {
 -				scopy(dp->d_name, enddir);
 +			if (enddir + dp->d_namlen + 1 > expdir_end)
 +				continue;
 +			memcpy(enddir, dp->d_name, dp->d_namlen + 1);
 +			if (atend)
  				addfname(expdir);
 -			} else {
 -				for (p = enddir, q = dp->d_name;
 -				     (*p++ = *q++) != '\0';)
 +			else {
 +				if (enddir + dp->d_namlen + 2 > expdir_end)
  					continue;
 -				p[-1] = '/';
 -				expmeta(p, endname);
 +				enddir[dp->d_namlen] = '/';
 +				enddir[dp->d_namlen + 1] = '\0';
 +				expmeta(enddir + dp->d_namlen + 1, endname);
  			}
  		}
  	}
 
 Added: head/tools/regression/bin/sh/expansion/pathname3.0
 ==============================================================================
 --- /dev/null	00:00:00 1970	(empty, because file is newly added)
 +++ head/tools/regression/bin/sh/expansion/pathname3.0	Tue Aug 10 22:45:59 2010	(r211155)
 @@ -0,0 +1,29 @@
 +# $FreeBSD$
 +
 +v=12345678
 +v=$v$v$v$v
 +v=$v$v$v$v
 +v=$v$v$v$v
 +v=$v$v$v$v
 +v=$v$v$v$v
 +# 8192 bytes
 +v=${v##???}
 +[ /*/$v = "/*/$v" ] || exit 1
 +
 +s=////
 +s=$s$s$s$s
 +s=$s$s$s$s
 +s=$s$s$s$s
 +s=$s$s$s$s
 +# 1024 bytes
 +s=${s##??????????}
 +[ /var/empt[y]/$s/$v = "/var/empt[y]/$s/$v" ] || exit 2
 +while [ ${#s} -lt 1034 ]; do
 +	set -- /.${s}et[c]
 +	[ ${#s} -gt 1018 ] || [ "$1" = /.${s}etc ] || exit 3
 +	set -- /.${s}et[c]/
 +	[ ${#s} -gt 1017 ] || [ "$1" = /.${s}etc/ ] || exit 4
 +	set -- /.${s}et[c]/.
 +	[ ${#s} -gt 1016 ] || [ "$1" = /.${s}etc/. ] || exit 5
 +	s=$s/
 +done
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: open->patched 
State-Changed-By: jilles 
State-Changed-When: Tue Aug 10 22:54:34 UTC 2010 
State-Changed-Why:  
Fixed in 9-CURRENT. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=148733 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/148733: commit references a PR
Date: Sat, 21 Aug 2010 20:48:18 +0000 (UTC)

 Author: jilles
 Date: Sat Aug 21 20:48:09 2010
 New Revision: 211592
 URL: http://svn.freebsd.org/changeset/base/211592
 
 Log:
   MFC r211155: sh: Fix heap-based buffer overflow in pathname generation.
   
   The buffer for generated pathnames could be too small in some cases. It
   happened to be always at least PATH_MAX long, so there was never an overflow
   if the resulting pathnames would be usable.
   
   This bug may be abused if a script subjects input from an untrusted source
   to pathname generation, which a bad idea anyhow. Most shell scripts do not
   work on untrusted data. secteam@ says no advisory is necessary.
   
   PR:		bin/148733
   Reported by:	Changming Sun snnn119 at gmail com
 
 Added:
   stable/8/tools/regression/bin/sh/expansion/pathname3.0
      - copied unchanged from r211155, head/tools/regression/bin/sh/expansion/pathname3.0
 Modified:
   stable/8/bin/sh/expand.c
 Directory Properties:
   stable/8/bin/sh/   (props changed)
   stable/8/tools/regression/bin/sh/   (props changed)
 
 Modified: stable/8/bin/sh/expand.c
 ==============================================================================
 --- stable/8/bin/sh/expand.c	Sat Aug 21 19:31:58 2010	(r211591)
 +++ stable/8/bin/sh/expand.c	Sat Aug 21 20:48:09 2010	(r211592)
 @@ -1074,8 +1074,8 @@ ifsbreakup(char *string, struct arglist 
   * should be escapes.  The results are stored in the list exparg.
   */
  
 -STATIC char *expdir;
 -
 +STATIC char expdir[PATH_MAX];
 +#define expdir_end (expdir + sizeof(expdir))
  
  STATIC void
  expandmeta(struct strlist *str, int flag __unused)
 @@ -1098,14 +1098,7 @@ expandmeta(struct strlist *str, int flag
  		}
  		savelastp = exparg.lastp;
  		INTOFF;
 -		if (expdir == NULL) {
 -			int i = strlen(str->text);
 -			expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
 -		}
 -
  		expmeta(expdir, str->text);
 -		ckfree(expdir);
 -		expdir = NULL;
  		INTON;
  		if (exparg.lastp == savelastp) {
  			/*
 @@ -1194,6 +1187,8 @@ expmeta(char *enddir, char *name)
  			*enddir++ = *p;
  			if (*p == '\0')
  				break;
 +			if (enddir == expdir_end)
 +				return;
  		}
  		if (metaflag == 0 || lstat(expdir, &statb) >= 0)
  			addfname(expdir);
 @@ -1208,6 +1203,8 @@ expmeta(char *enddir, char *name)
  			if (*p == CTLESC)
  				p++;
  			*enddir++ = *p++;
 +			if (enddir == expdir_end)
 +				return;
  		}
  	}
  	if (enddir == expdir) {
 @@ -1241,15 +1238,17 @@ expmeta(char *enddir, char *name)
  		if (dp->d_name[0] == '.' && ! matchdot)
  			continue;
  		if (patmatch(start, dp->d_name, 0)) {
 -			if (atend) {
 -				scopy(dp->d_name, enddir);
 +			if (enddir + dp->d_namlen + 1 > expdir_end)
 +				continue;
 +			memcpy(enddir, dp->d_name, dp->d_namlen + 1);
 +			if (atend)
  				addfname(expdir);
 -			} else {
 -				for (p = enddir, q = dp->d_name;
 -				     (*p++ = *q++) != '\0';)
 +			else {
 +				if (enddir + dp->d_namlen + 2 > expdir_end)
  					continue;
 -				p[-1] = '/';
 -				expmeta(p, endname);
 +				enddir[dp->d_namlen] = '/';
 +				enddir[dp->d_namlen + 1] = '\0';
 +				expmeta(enddir + dp->d_namlen + 1, endname);
  			}
  		}
  	}
 
 Copied: stable/8/tools/regression/bin/sh/expansion/pathname3.0 (from r211155, head/tools/regression/bin/sh/expansion/pathname3.0)
 ==============================================================================
 --- /dev/null	00:00:00 1970	(empty, because file is newly added)
 +++ stable/8/tools/regression/bin/sh/expansion/pathname3.0	Sat Aug 21 20:48:09 2010	(r211592, copy of r211155, head/tools/regression/bin/sh/expansion/pathname3.0)
 @@ -0,0 +1,29 @@
 +# $FreeBSD$
 +
 +v=12345678
 +v=$v$v$v$v
 +v=$v$v$v$v
 +v=$v$v$v$v
 +v=$v$v$v$v
 +v=$v$v$v$v
 +# 8192 bytes
 +v=${v##???}
 +[ /*/$v = "/*/$v" ] || exit 1
 +
 +s=////
 +s=$s$s$s$s
 +s=$s$s$s$s
 +s=$s$s$s$s
 +s=$s$s$s$s
 +# 1024 bytes
 +s=${s##??????????}
 +[ /var/empt[y]/$s/$v = "/var/empt[y]/$s/$v" ] || exit 2
 +while [ ${#s} -lt 1034 ]; do
 +	set -- /.${s}et[c]
 +	[ ${#s} -gt 1018 ] || [ "$1" = /.${s}etc ] || exit 3
 +	set -- /.${s}et[c]/
 +	[ ${#s} -gt 1017 ] || [ "$1" = /.${s}etc/ ] || exit 4
 +	set -- /.${s}et[c]/.
 +	[ ${#s} -gt 1016 ] || [ "$1" = /.${s}etc/. ] || exit 5
 +	s=$s/
 +done
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/148733: commit references a PR
Date: Wed,  1 Sep 2010 21:51:38 +0000 (UTC)

 Author: jilles
 Date: Wed Sep  1 21:51:29 2010
 New Revision: 212118
 URL: http://svn.freebsd.org/changeset/base/212118
 
 Log:
   MFC r211155: sh: Fix heap-based buffer overflow in pathname generation.
   
   The buffer for generated pathnames could be too small in some cases. It
   happened to be always at least PATH_MAX long, so there was never an overflow
   if the resulting pathnames would be usable.
   
   This bug may be abused if a script subjects input from an untrusted source
   to pathname generation, which a bad idea anyhow. Most shell scripts do not
   work on untrusted data. secteam@ says no advisory is necessary.
   
   PR:		bin/148733
   Reported by:	Changming Sun snnn119 at gmail com
 
 Added:
   stable/7/tools/regression/bin/sh/expansion/pathname3.0
      - copied unchanged from r211155, head/tools/regression/bin/sh/expansion/pathname3.0
 Modified:
   stable/7/bin/sh/expand.c
 Directory Properties:
   stable/7/bin/sh/   (props changed)
   stable/7/tools/regression/bin/sh/   (props changed)
 
 Modified: stable/7/bin/sh/expand.c
 ==============================================================================
 --- stable/7/bin/sh/expand.c	Wed Sep  1 21:44:36 2010	(r212117)
 +++ stable/7/bin/sh/expand.c	Wed Sep  1 21:51:29 2010	(r212118)
 @@ -1054,8 +1054,8 @@ ifsbreakup(char *string, struct arglist 
   * should be escapes.  The results are stored in the list exparg.
   */
  
 -STATIC char *expdir;
 -
 +STATIC char expdir[PATH_MAX];
 +#define expdir_end (expdir + sizeof(expdir))
  
  STATIC void
  expandmeta(struct strlist *str, int flag __unused)
 @@ -1078,14 +1078,7 @@ expandmeta(struct strlist *str, int flag
  		}
  		savelastp = exparg.lastp;
  		INTOFF;
 -		if (expdir == NULL) {
 -			int i = strlen(str->text);
 -			expdir = ckmalloc(i < 2048 ? 2048 : i); /* XXX */
 -		}
 -
  		expmeta(expdir, str->text);
 -		ckfree(expdir);
 -		expdir = NULL;
  		INTON;
  		if (exparg.lastp == savelastp) {
  			/*
 @@ -1174,6 +1167,8 @@ expmeta(char *enddir, char *name)
  			*enddir++ = *p;
  			if (*p == '\0')
  				break;
 +			if (enddir == expdir_end)
 +				return;
  		}
  		if (metaflag == 0 || lstat(expdir, &statb) >= 0)
  			addfname(expdir);
 @@ -1188,6 +1183,8 @@ expmeta(char *enddir, char *name)
  			if (*p == CTLESC)
  				p++;
  			*enddir++ = *p++;
 +			if (enddir == expdir_end)
 +				return;
  		}
  	}
  	if (enddir == expdir) {
 @@ -1221,15 +1218,17 @@ expmeta(char *enddir, char *name)
  		if (dp->d_name[0] == '.' && ! matchdot)
  			continue;
  		if (patmatch(start, dp->d_name, 0)) {
 -			if (atend) {
 -				scopy(dp->d_name, enddir);
 +			if (enddir + dp->d_namlen + 1 > expdir_end)
 +				continue;
 +			memcpy(enddir, dp->d_name, dp->d_namlen + 1);
 +			if (atend)
  				addfname(expdir);
 -			} else {
 -				for (p = enddir, q = dp->d_name;
 -				     (*p++ = *q++) != '\0';)
 +			else {
 +				if (enddir + dp->d_namlen + 2 > expdir_end)
  					continue;
 -				p[-1] = '/';
 -				expmeta(p, endname);
 +				enddir[dp->d_namlen] = '/';
 +				enddir[dp->d_namlen + 1] = '\0';
 +				expmeta(enddir + dp->d_namlen + 1, endname);
  			}
  		}
  	}
 
 Copied: stable/7/tools/regression/bin/sh/expansion/pathname3.0 (from r211155, head/tools/regression/bin/sh/expansion/pathname3.0)
 ==============================================================================
 --- /dev/null	00:00:00 1970	(empty, because file is newly added)
 +++ stable/7/tools/regression/bin/sh/expansion/pathname3.0	Wed Sep  1 21:51:29 2010	(r212118, copy of r211155, head/tools/regression/bin/sh/expansion/pathname3.0)
 @@ -0,0 +1,29 @@
 +# $FreeBSD$
 +
 +v=12345678
 +v=$v$v$v$v
 +v=$v$v$v$v
 +v=$v$v$v$v
 +v=$v$v$v$v
 +v=$v$v$v$v
 +# 8192 bytes
 +v=${v##???}
 +[ /*/$v = "/*/$v" ] || exit 1
 +
 +s=////
 +s=$s$s$s$s
 +s=$s$s$s$s
 +s=$s$s$s$s
 +s=$s$s$s$s
 +# 1024 bytes
 +s=${s##??????????}
 +[ /var/empt[y]/$s/$v = "/var/empt[y]/$s/$v" ] || exit 2
 +while [ ${#s} -lt 1034 ]; do
 +	set -- /.${s}et[c]
 +	[ ${#s} -gt 1018 ] || [ "$1" = /.${s}etc ] || exit 3
 +	set -- /.${s}et[c]/
 +	[ ${#s} -gt 1017 ] || [ "$1" = /.${s}etc/ ] || exit 4
 +	set -- /.${s}et[c]/.
 +	[ ${#s} -gt 1016 ] || [ "$1" = /.${s}etc/. ] || exit 5
 +	s=$s/
 +done
 _______________________________________________
 svn-src-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/svn-src-all
 To unsubscribe, send any mail to "svn-src-all-unsubscribe@freebsd.org"
 
State-Changed-From-To: patched->closed 
State-Changed-By: jilles 
State-Changed-When: Thu Dec 2 23:28:09 UTC 2010 
State-Changed-Why:  
Fixed in 7.x/8.x/9.x. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=148733 
>Unformatted:
