From nobody@FreeBSD.org  Wed Feb 25 17:27:39 2009
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 C520010656BA
	for <freebsd-gnats-submit@FreeBSD.org>; Wed, 25 Feb 2009 17:27:39 +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 98C2C8FC0A
	for <freebsd-gnats-submit@FreeBSD.org>; Wed, 25 Feb 2009 17:27:39 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.14.3/8.14.3) with ESMTP id n1PHRddn053325
	for <freebsd-gnats-submit@FreeBSD.org>; Wed, 25 Feb 2009 17:27:39 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.14.3/8.14.3/Submit) id n1PHRdJX053324;
	Wed, 25 Feb 2009 17:27:39 GMT
	(envelope-from nobody)
Message-Id: <200902251727.n1PHRdJX053324@www.freebsd.org>
Date: Wed, 25 Feb 2009 17:27:39 GMT
From: Dylan Cochran <a134qaed@gmail.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: kenv buffer overflow
X-Send-Pr-Version: www-3.1
X-GNATS-Notify:

>Number:         132104
>Category:       kern
>Synopsis:       [kernel] [patch] kenv(1) buffer overflow
>Confidential:   no
>Severity:       serious
>Priority:       low
>Responsible:    jh
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Wed Feb 25 17:30:01 UTC 2009
>Closed-Date:    Tue Jul 26 19:31:21 UTC 2011
>Last-Modified:  Tue Jul 26 19:31:21 UTC 2011
>Originator:     Dylan Cochran
>Release:        7.1-RELEASE
>Organization:
Evoke Project
>Environment:
FreeBSD  7.1-RELEASE-p3 FreeBSD 7.1-RELEASE-p3 #0: Wed Dec 31 19:00:00 EST 1969     root@dummy:/root/evoke-head/obj/obj/13a419ec44df0f8e7392ecf9be07334a/i386/root/evoke-head/obj/13a419ec44df0f8e7392ecf9be07334a/usr/src/sys/kernel  i386
>Description:
The kenv syscall, when called with the KENV_GET action, first allocates a static size buffer, holds the kenv mutex, copies the data in the pointer to the buffer. It then releases the mutex, and runs strlen over the buffer, malloc's a return buffer the size of strlen's return value, and copies from the initial buffer to the return buffer. This usage case only works with environment variables defined by the KENV_SET action, which restricts the length of a value to 128 bytes.
>How-To-Repeat:
loader has no such restriction, and attempting to KENV_GET a variable set by loader that is longer then 128bytes causes an immediate page fault. Add a long string value to /boot/loader.conf and then kenv the name of the variable.
>Fix:
Remove the statically allocated buffer, and move the mutex back to the point where the return buffer is allocated and the data moved. This prevents the panic condition, but also increases the amount of time the mutex is held. Comments?

Patch attached with submission follows:

--- sys/kern/kern_environment.c	2009-02-20 12:31:36.000000000 -0500
+++ sys/kern/kern_environment.c	2009-02-24 23:26:43.000000000 -0500
@@ -293,7 +293,6 @@
 char *
 getenv(const char *name)
 {
-	char buf[KENV_MNAMELEN + 1 + KENV_MVALLEN + 1];
 	char *ret, *cp;
 	int len;
 
@@ -301,11 +300,10 @@
 		mtx_lock(&kenv_lock);
 		cp = _getenv_dynamic(name, NULL);
 		if (cp != NULL) {
-			strcpy(buf, cp);
-			mtx_unlock(&kenv_lock);
-			len = strlen(buf) + 1;
+			len = strlen(cp) + 1;
 			ret = malloc(len, M_KENV, M_WAITOK);
-			strcpy(ret, buf);
+			strcpy(ret, cp);
+			mtx_unlock(&kenv_lock);
 		} else {
 			mtx_unlock(&kenv_lock);
 			ret = NULL;


>Release-Note:
>Audit-Trail:

From: Jaakko Heinonen <jh@saunalahti.fi>
To: Dylan Cochran <a134qaed@gmail.com>
Cc: bug-followup@FreeBSD.org
Subject: Re: kern/132104: kenv buffer overflow
Date: Wed, 25 Feb 2009 20:56:26 +0200

 Hi,
 
 On 2009-02-25, Dylan Cochran wrote:
 > This prevents the panic condition, but also increases the amount of
 > time the mutex is held. Comments?
 > 
 >  		mtx_lock(&kenv_lock);
 >  		cp = _getenv_dynamic(name, NULL);
 >  		if (cp != NULL) {
 > -			strcpy(buf, cp);
 > -			mtx_unlock(&kenv_lock);
 > -			len = strlen(buf) + 1;
 > +			len = strlen(cp) + 1;
 >  			ret = malloc(len, M_KENV, M_WAITOK);
 > -			strcpy(ret, buf);
 > +			strcpy(ret, cp);
 > +			mtx_unlock(&kenv_lock);
 
 malloc(9) with M_WAITOK flag could sleep. You are not allowed to sleep
 while holding a mutex.
 
 -- 
 Jaakko

From: Dylan Cochran <a134qaed@gmail.com>
To: Jaakko Heinonen <jh@saunalahti.fi>
Cc: bug-followup@freebsd.org
Subject: Re: kern/132104: kenv buffer overflow
Date: Wed, 25 Feb 2009 16:36:32 -0500

 On Wed, Feb 25, 2009 at 1:56 PM, Jaakko Heinonen <jh@saunalahti.fi> wrote:
 >
 > Hi,
 >
 > On 2009-02-25, Dylan Cochran wrote:
 >> This prevents the panic condition, but also increases the amount of
 >> time the mutex is held. Comments?
 >>
 >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 mtx_lock(&kenv_lock);
 >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 cp =3D _getenv_dynamic(name, NULL);
 >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 if (cp !=3D NULL) {
 >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 strcpy(buf, cp);
 >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 mtx_unlock(&kenv_lock);
 >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 len =3D strlen(buf) + 1;
 >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 len =3D strlen(cp) + 1;
 >> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 ret =3D malloc(len, M_KENV, =
 M_WAITOK);
 >> - =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 strcpy(ret, buf);
 >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 strcpy(ret, cp);
 >> + =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 mtx_unlock(&kenv_lock);
 >
 > malloc(9) with M_WAITOK flag could sleep. You are not allowed to sleep
 > while holding a mutex.
 So if I modify it to use M_NOWAIT, I should unlock if it returns null,
 then sleep, then relock, and repeat? I'd rather not just bump up the
 *LEN values, or truncate it by adding a trailing 0 byte to the end.
 Not in 2009 anyway.
 >
 > --
 > Jaakko
 >

From: Dylan Cochran <a134qaed@gmail.com>
To: bug-followup <bug-followup@freebsd.org>
Cc: Jaakko Heinonen <jh@saunalahti.fi>
Subject: Re: kern/132104: kenv buffer overflow
Date: Fri, 6 Mar 2009 13:13:54 -0500

 --00163616451b6c31690464773f1a
 Content-Type: text/plain; charset=ISO-8859-1
 Content-Transfer-Encoding: 7bit
 
 Second patch, after a conversation with rwatson about locking on
 malloc, I decided to allow a race condition to occur, and bounded it
 with an incrementing counter. If we lose the race, we loop up to 6
 times, then return null. Since the values chosen for the sleep time
 and count are arbitrary, I added printf's so I could view the
 frequencies when races were lost. So far it never happens, so I
 believe that to be sufficient.
 
 Please note I am not a C language expert, nor am I intimately familiar
 with kernel programming. I appreciate any pointers. :)
 
 --00163616451b6c31690464773f1a
 Content-Type: application/octet-stream; name="kenv.diff"
 Content-Disposition: attachment; filename="kenv.diff"
 Content-Transfer-Encoding: base64
 X-Attachment-Id: f_frz6npga0
 
 LS0tIHN5cy9rZXJuL2tlcm5fZW52aXJvbm1lbnQuYwkyMDA5LTAyLTIwIDEyOjMxOjM2LjAwMDAw
 MDAwMCAtMDUwMAorKysgc3lzL2tlcm4va2Vybl9lbnZpcm9ubWVudC5jCTIwMDktMDMtMDMgMjI6
 NDU6MTkuMDAwMDAwMDAwIC0wNTAwCkBAIC0yOTMsMjIgKzI5MywzNCBAQAogY2hhciAqCiBnZXRl
 bnYoY29uc3QgY2hhciAqbmFtZSkKIHsKLQljaGFyIGJ1ZltLRU5WX01OQU1FTEVOICsgMSArIEtF
 TlZfTVZBTExFTiArIDFdOwogCWNoYXIgKnJldCwgKmNwOwotCWludCBsZW47CisJaW50IGxlbiA9
 IDA7CisJaW50IGNvdW50ID0gMDsKIAogCWlmIChkeW5hbWljX2tlbnYpIHsKLQkJbXR4X2xvY2so
 JmtlbnZfbG9jayk7Ci0JCWNwID0gX2dldGVudl9keW5hbWljKG5hbWUsIE5VTEwpOwotCQlpZiAo
 Y3AgIT0gTlVMTCkgewotCQkJc3RyY3B5KGJ1ZiwgY3ApOwotCQkJbXR4X3VubG9jaygma2Vudl9s
 b2NrKTsKLQkJCWxlbiA9IHN0cmxlbihidWYpICsgMTsKLQkJCXJldCA9IG1hbGxvYyhsZW4sIE1f
 S0VOViwgTV9XQUlUT0spOwotCQkJc3RyY3B5KHJldCwgYnVmKTsKLQkJfSBlbHNlIHsKLQkJCW10
 eF91bmxvY2soJmtlbnZfbG9jayk7CisJCXdoaWxlIChjb3VudCA8PSA1KSB7CiAJCQlyZXQgPSBO
 VUxMOworCQkJbXR4X2xvY2soJmtlbnZfbG9jayk7CisJCQljcCA9IF9nZXRlbnZfZHluYW1pYyhu
 YW1lLCBOVUxMKTsKKwkJCWlmIChjcCAhPSBOVUxMKSB7CisJCQkJbGVuID0gc3RybGVuKGNwKSAr
 IDE7CisJCQkJbXR4X3VubG9jaygma2Vudl9sb2NrKTsKKwkJCQlyZXQgPSBtYWxsb2MobGVuLCBN
 X0tFTlYsIE1fV0FJVE9LIHwgTV9aRVJPKTsKKwkJCQlzdHJuY3B5KHJldCwgY3AsIGxlbik7CisJ
 CQkJLyogSWYgdGhlIGxhc3QgYnl0ZSBvZiByZXQgaXMgemVybywgdGhlbiB3ZSB3b24gdGhlIHJh
 Y2UsIHNsZWVwIGFuZCB0cnkgYWdhaW4uICovCisJCQkJcHJpbnRmKCJrZW52MDogbmFtZT0lcyBs
 ZW5ndGg9JWQgY291bnQ9JXhcbiIsIG5hbWUsIGxlbiwgY291bnQpOworCQkJCWlmIChyZXRbbGVu
 XSA9PSAnXHgwMCcpIHsKKwkJCQkJcHJpbnRmKCJrZW52MDogZGF0YT0lc1xuIiwgcmV0KTsKKwkJ
 CQkJYnJlYWs7CisJCQkJfQorCQkJfSBlbHNlIHsKKwkJCQltdHhfdW5sb2NrKCZrZW52X2xvY2sp
 OworCQkJCXJldCA9IE5VTEw7CisJCQkJYnJlYWs7CisJCQl9CisJCQljb3VudCsrOworCQkJZnJl
 ZShyZXQsIE1fS0VOVik7CisJCQl0c2xlZXAoY3AsIDAsICJrZW52c2wiLCAxKTsKIAkJfQogCX0g
 ZWxzZQogCQlyZXQgPSBfZ2V0ZW52X3N0YXRpYyhuYW1lKTsK
 --00163616451b6c31690464773f1a--

From: Dylan Cochran <a134qaed@gmail.com>
To: bug-followup <bug-followup@freebsd.org>
Cc:  
Subject: Re: kern/132104: kenv buffer overflow
Date: Sun, 8 Mar 2009 12:25:18 -0400

 Since the patch seems mangled on the webpage, I will also provide a
 url to the patch.
 
 http://code.google.com/p/evoke/source/browse/trunk/builder/targets/FreeBSD/7.1/share/patches/kenv.diff
Responsible-Changed-From-To: freebsd-bugs->jh 
Responsible-Changed-By: jh 
Responsible-Changed-When: Wed May 18 13:00:51 UTC 2011 
Responsible-Changed-Why:  
Take. 

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

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/132104: commit references a PR
Date: Mon, 23 May 2011 16:40:59 +0000 (UTC)

 Author: jh
 Date: Mon May 23 16:40:44 2011
 New Revision: 222216
 URL: http://svn.freebsd.org/changeset/base/222216
 
 Log:
   In init_dynamic_kenv(), ignore environment strings exceeding the
   KENV_MNAMELEN + 1 + KENV_MVALLEN + 1 length limit to avoid buffer
   overflow in getenv(). Currenly loader(8) doesn't limit the length of
   environment strings.
   
   PR:		kern/132104
   MFC after:	1 month
 
 Modified:
   head/sys/kern/kern_environment.c
 
 Modified: head/sys/kern/kern_environment.c
 ==============================================================================
 --- head/sys/kern/kern_environment.c	Mon May 23 15:23:18 2011	(r222215)
 +++ head/sys/kern/kern_environment.c	Mon May 23 16:40:44 2011	(r222216)
 @@ -225,13 +225,19 @@ static void
  init_dynamic_kenv(void *data __unused)
  {
  	char *cp;
 -	int len, i;
 +	size_t len;
 +	int i;
  
  	kenvp = malloc((KENV_SIZE + 1) * sizeof(char *), M_KENV,
  		M_WAITOK | M_ZERO);
  	i = 0;
  	for (cp = kern_envp; cp != NULL; cp = kernenv_next(cp)) {
  		len = strlen(cp) + 1;
 +		if (len > KENV_MNAMELEN + 1 + KENV_MVALLEN + 1) {
 +			printf("WARNING: too long kenv string, ignoring %s\n",
 +			    cp);
 +			continue;
 +		}
  		if (i < KENV_SIZE) {
  			kenvp[i] = malloc(len, M_KENV, M_WAITOK);
  			strcpy(kenvp[i++], cp);
 _______________________________________________
 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: jh 
State-Changed-When: Mon May 23 18:35:21 UTC 2011 
State-Changed-Why:  
Patched in head (r222216). 

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

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/132104: commit references a PR
Date: Wed, 13 Jul 2011 06:20:24 +0000 (UTC)

 Author: jh
 Date: Wed Jul 13 06:20:00 2011
 New Revision: 223977
 URL: http://svn.freebsd.org/changeset/base/223977
 
 Log:
   MFC r222216:
   
   In init_dynamic_kenv(), ignore environment strings exceeding the
   KENV_MNAMELEN + 1 + KENV_MVALLEN + 1 length limit to avoid buffer
   overflow in getenv(). Currenly loader(8) doesn't limit the length of
   environment strings.
   
   PR:		kern/132104
 
 Modified:
   stable/8/sys/kern/kern_environment.c
 Directory Properties:
   stable/8/sys/   (props changed)
   stable/8/sys/amd64/include/xen/   (props changed)
   stable/8/sys/cddl/contrib/opensolaris/   (props changed)
   stable/8/sys/contrib/dev/acpica/   (props changed)
   stable/8/sys/contrib/pf/   (props changed)
 
 Modified: stable/8/sys/kern/kern_environment.c
 ==============================================================================
 --- stable/8/sys/kern/kern_environment.c	Wed Jul 13 05:56:51 2011	(r223976)
 +++ stable/8/sys/kern/kern_environment.c	Wed Jul 13 06:20:00 2011	(r223977)
 @@ -215,13 +215,19 @@ static void
  init_dynamic_kenv(void *data __unused)
  {
  	char *cp;
 -	int len, i;
 +	size_t len;
 +	int i;
  
  	kenvp = malloc((KENV_SIZE + 1) * sizeof(char *), M_KENV,
  		M_WAITOK | M_ZERO);
  	i = 0;
  	for (cp = kern_envp; cp != NULL; cp = kernenv_next(cp)) {
  		len = strlen(cp) + 1;
 +		if (len > KENV_MNAMELEN + 1 + KENV_MVALLEN + 1) {
 +			printf("WARNING: too long kenv string, ignoring %s\n",
 +			    cp);
 +			continue;
 +		}
  		if (i < KENV_SIZE) {
  			kenvp[i] = malloc(len, M_KENV, M_WAITOK);
  			strcpy(kenvp[i++], cp);
 _______________________________________________
 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: kern/132104: commit references a PR
Date: Tue, 26 Jul 2011 18:59:51 +0000 (UTC)

 Author: jh
 Date: Tue Jul 26 18:59:38 2011
 New Revision: 224458
 URL: http://svn.freebsd.org/changeset/base/224458
 
 Log:
   MFC r222216:
   
   In init_dynamic_kenv(), ignore environment strings exceeding the
   KENV_MNAMELEN + 1 + KENV_MVALLEN + 1 length limit to avoid buffer
   overflow in getenv(). Currenly loader(8) doesn't limit the length of
   environment strings.
   
   PR:		kern/132104
 
 Modified:
   stable/7/sys/kern/kern_environment.c
 Directory Properties:
   stable/7/sys/   (props changed)
   stable/7/sys/cddl/contrib/opensolaris/   (props changed)
   stable/7/sys/contrib/dev/acpica/   (props changed)
   stable/7/sys/contrib/pf/   (props changed)
 
 Modified: stable/7/sys/kern/kern_environment.c
 ==============================================================================
 --- stable/7/sys/kern/kern_environment.c	Tue Jul 26 17:39:40 2011	(r224457)
 +++ stable/7/sys/kern/kern_environment.c	Tue Jul 26 18:59:38 2011	(r224458)
 @@ -217,13 +217,19 @@ static void
  init_dynamic_kenv(void *data __unused)
  {
  	char *cp;
 -	int len, i;
 +	size_t len;
 +	int i;
  
  	kenvp = malloc((KENV_SIZE + 1) * sizeof(char *), M_KENV,
  		M_WAITOK | M_ZERO);
  	i = 0;
  	for (cp = kern_envp; cp != NULL; cp = kernenv_next(cp)) {
  		len = strlen(cp) + 1;
 +		if (len > KENV_MNAMELEN + 1 + KENV_MVALLEN + 1) {
 +			printf("WARNING: too long kenv string, ignoring %s\n",
 +			    cp);
 +			continue;
 +		}
  		if (i < KENV_SIZE) {
  			kenvp[i] = malloc(len, M_KENV, M_WAITOK);
  			strcpy(kenvp[i++], cp);
 _______________________________________________
 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: jh 
State-Changed-When: Tue Jul 26 19:31:19 UTC 2011 
State-Changed-Why:  
Fixed in head, stable/8 and stable/7. 

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