From dan@kulesh.obluda.cz  Thu Jul 14 15:23:33 2005
Return-Path: <dan@kulesh.obluda.cz>
Received: from mx1.FreeBSD.org (mx1.freebsd.org [216.136.204.125])
	by hub.freebsd.org (Postfix) with ESMTP id 6D18316A41C
	for <FreeBSD-gnats-submit@freebsd.org>; Thu, 14 Jul 2005 15:23:33 +0000 (GMT)
	(envelope-from dan@kulesh.obluda.cz)
Received: from kulesh.obluda.cz (kulesh.obluda.cz [193.179.22.243])
	by mx1.FreeBSD.org (Postfix) with ESMTP id 2516E43D53
	for <FreeBSD-gnats-submit@freebsd.org>; Thu, 14 Jul 2005 15:23:31 +0000 (GMT)
	(envelope-from dan@kulesh.obluda.cz)
Received: from kulesh.obluda.cz (localhost.eunet.cz [127.0.0.1])
	by kulesh.obluda.cz (8.13.3/8.13.3) with ESMTP id j6EFNTg6034021
	for <FreeBSD-gnats-submit@freebsd.org>; Thu, 14 Jul 2005 17:23:30 +0200 (CEST)
	(envelope-from dan@kulesh.obluda.cz)
Received: (from root@localhost)
	by kulesh.obluda.cz (8.13.3/8.13.1/Submit) id j6EFNTkl034020;
	Thu, 14 Jul 2005 17:23:29 +0200 (CEST)
	(envelope-from dan)
Message-Id: <200507141523.j6EFNTkl034020@kulesh.obluda.cz>
Date: Thu, 14 Jul 2005 17:23:29 +0200 (CEST)
From: Dan Lukes <dan@obluda.cz>
Reply-To: Dan Lukes <dan@obluda.cz>
To: FreeBSD-gnats-submit@freebsd.org
Cc:
Subject: [ PATCH ] Unhandled malloc failures within libgeom
X-Send-Pr-Version: 3.113
X-GNATS-Notify:

>Number:         83464
>Category:       kern
>Synopsis:       [geom] [patch] Unhandled malloc failures within libgeom
>Confidential:   no
>Severity:       serious
>Priority:       low
>Responsible:    lulf
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Jul 14 15:30:18 GMT 2005
>Closed-Date:    Tue Jul 08 17:36:42 UTC 2008
>Last-Modified:  Tue Jul  8 17:40:00 UTC 2008
>Originator:     Dan Lukes
>Release:        FreeBSD 5.4-STABLE i386
>Organization:
Obludarium
>Environment:
System: FreeBSD 5.4-STABLE #8: Sat Jul 9 16:31:08 CEST 2005 i386
lib/libgeom/geom_getxml.c,v 1.1 2003/02/10 00:11:43 phk
lib/libgeom/geom_xml2tree.c,v 1.4 2004/03/09 21:14:18 jhb

>Description:
	Unhandled malloc failures & typo within libgeom
>How-To-Repeat:
>Fix:
	Major problem is unhandlet malloc failures

	In advance, there are two typos within code - second invocation of
sysctlbyname within geom_getxml() seems to called to obtain len of sysctl
structure, so second argument should be NULL. We can't use (p) here as it
may not be NULL everytime.

	Before third invocation of sysctlbyname() the p is allocated
as 'l+4096', but the len is claimed to be 'l' only during sysctlbyname()
call.

	The reallocf should be used instead of realloc - just for sure. Or
we are pretty sure the shrinking realloc can't fail for any reason ?

	BTW, someone should decide if this code isn't so dirty. Now the
alghoritm:
1. alloc 1MB buffer for config
2. when failed, ask for structure length then alloc buffer for it +4kB

	IMHO, the step 1 is trying to save one invocation od sysctlbyname
(the query for structure len) for the price of allocating 1MB memory.

	It price seems to be so high for me. The calling of geom_getxml() 
seems not to be so time sensitive. I recomment delete the first part of
code, so remaining portion start at 'l = 0' statement.

	If current code need 1T or 3T then shorter version require 2T
everytime (saving overhead from allocating 1MB memory). If we are interested
on processing time then two sysctlbyname() should be rewritten as one
sysctlnametomig() and two sysctl(). The resulting time should be about 1,3T

	The patch attached doesn't contain those recomended change. It patch only real
bugs. 

	I can send other patch with recomended changes when a commiter decide I
should do it.

--- patch begins here ---
--- lib/libgeom/geom_getxml.c.ORIG	Mon Feb 10 01:11:43 2003
+++ lib/libgeom/geom_getxml.c	Thu Jul 14 16:32:19 2005
@@ -47,19 +47,20 @@
 	if (p) {
 		i = sysctlbyname("kern.geom.confxml", p, &l, NULL, 0);
 		if (i == 0) {
-			p = realloc(p, strlen(p) + 1);
+			p = reallocf(p, strlen(p) + 1);
 			return (p);
 		}
 		free(p);
 	}
 	l = 0;
-	i = sysctlbyname("kern.geom.confxml", p, &l, NULL, 0);
+	i = sysctlbyname("kern.geom.confxml", NULL, &l, NULL, 0);
 	if (i != 0)
 		return (NULL);
-	p = malloc(l + 4096);
+	l+=4096;
+	p = malloc(l);
 	i = sysctlbyname("kern.geom.confxml", p, &l, NULL, 0);
 	if (i == 0) {
-		p = realloc(p, strlen(p) + 1);
+		p = reallocf(p, strlen(p) + 1);
 		return (p);
 	}
 	return (NULL);
--- lib/libgeom/geom_xml2tree.c.ORIG	Wed Mar 17 01:03:34 2004
+++ lib/libgeom/geom_xml2tree.c	Thu Jul 14 16:53:36 2005
@@ -105,6 +105,10 @@
 	}
 	if (!strcmp(name, "consumer") && mt->consumer == NULL) {
 		mt->consumer = calloc(1, sizeof *mt->consumer);
+		if (mt->consumer == NULL) {
+			warn("Problem during processing of '%s' element", name);
+			return;
+		}
 		mt->consumer->lg_id = id;
 		LIST_INSERT_HEAD(&mt->geom->lg_consumer, mt->consumer,
 		    lg_consumer);
@@ -121,6 +125,10 @@
 	}
 	if (!strcmp(name, "provider") && mt->provider == NULL) {
 		mt->provider = calloc(1, sizeof *mt->provider);
+		if (mt->provider == NULL) {
+			warn("Problem during processing of '%s' element", name);
+			return;
+		}
 		mt->provider->lg_id = id;
 		LIST_INSERT_HEAD(&mt->geom->lg_provider, mt->provider,
 		    lg_provider);
--- patch ends here ---
>Release-Note:
>Audit-Trail:

From: "Poul-Henning Kamp" <phk@phk.freebsd.dk>
To: Dan Lukes <dan@obluda.cz>
Cc: FreeBSD-gnats-submit@FreeBSD.org
Subject: Re: bin/83464: [ PATCH ] Unhandled malloc failures within libgeom 
Date: Fri, 15 Jul 2005 11:31:04 +0200

 In message <200507141523.j6EFNTkl034020@kulesh.obluda.cz>, Dan Lukes writes:
 
 Looks sensible
 
 -- 
 Poul-Henning Kamp       | UNIX since Zilog Zeus 3.20
 phk@FreeBSD.ORG         | TCP/IP since RFC 956
 FreeBSD committer       | BSD since 4.3-tahoe    
 Never attribute to malice what can adequately be explained by incompetence.

From: Dan Lukes <dan@obluda.cz>
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: bin/83464: [ PATCH ] Unhandled malloc failures within libgeom
Date: Fri, 15 Jul 2005 18:32:22 +0200

 This is a multi-part message in MIME format.
 --------------070408060806070200010105
 Content-Type: text/plain; charset=ISO-8859-2; format=flowed
 Content-Transfer-Encoding: 7bit
 
 
 	Well, so rewritten patch follows.
 
 1. get_geomxml() is rewritten
 2. The recent gctl_check_alloc() assign pointer to constant string when 
 dynamic allocation of error message failed - but gctl_free try to free 
 the req->error even if not allocated dynamically. Corrected.
 3. realloc() within gctl_new_arg can cause memory leak. Changed to 
 reallocf()
 4. ap->name=strdup(name) within gctl_ro_param() and gctl_rw_param() not 
 checked for failures. Corrected.
 5. several malloc()/calloc()/strdup() used within StartElement() and 
 EndElement() not checked for failures. As those functions have no way to 
 return eror, I use the warn() then return. The XML parsing should fail 
 later due syntax error because element in question has not been processed.
 
 	WARNS can be raised to 6
 
 						Dan
 
 
 --------------070408060806070200010105
 Content-Type: text/plain;
  name="patch"
 Content-Transfer-Encoding: 7bit
 Content-Disposition: inline;
  filename="patch"
 
 --- lib/libgeom/geom_getxml.c.ORIG	Mon Feb 10 01:11:43 2003
 +++ lib/libgeom/geom_getxml.c	Fri Jul 15 17:22:18 2005
 @@ -39,28 +39,21 @@
  geom_getxml()
  {
  	char *p;
 -	size_t l;
 -	int i;
 +	size_t l = 0;
 +	int mib[3];
 +	size_t sizep = sizeof(mib)/sizeof(*mib);
  
 -	l = 1024 * 1024;	/* Start big, realloc back */
 -	p = malloc(l);
 -	if (p) {
 -		i = sysctlbyname("kern.geom.confxml", p, &l, NULL, 0);
 -		if (i == 0) {
 -			p = realloc(p, strlen(p) + 1);
 -			return (p);
 -		}
 +	if (sysctlnametomib("kern.geom.confxml", mib, &sizep) != 0)
 +		return (NULL);
 +	if (sysctl(mib, sizep, NULL, &l, NULL, 0) != 0)
 +		return (NULL);
 +	l+=4096;
 +	if ((p = malloc(l)) == NULL)
 +		return (NULL);
 +	if (sysctl(mib, sizep, p, &l, NULL, 0) != 0) {
  		free(p);
 -	}
 -	l = 0;
 -	i = sysctlbyname("kern.geom.confxml", p, &l, NULL, 0);
 -	if (i != 0)
  		return (NULL);
 -	p = malloc(l + 4096);
 -	i = sysctlbyname("kern.geom.confxml", p, &l, NULL, 0);
 -	if (i == 0) {
 -		p = realloc(p, strlen(p) + 1);
 -		return (p);
  	}
 -	return (NULL);
 +
 +	return (reallocf(p, strlen(p) + 1));
  }
 --- lib/libgeom/geom_ctl.c.ORIG	Mon Jun  2 20:54:50 2003
 +++ lib/libgeom/geom_ctl.c	Fri Jul 15 18:01:44 2005
 @@ -45,6 +45,8 @@
  #define GCTL_TABLE 1
  #include <libgeom.h>
  
 +char nomemmsg[] = "Could not allocate memory";
 +
  void
  gctl_dump(struct gctl_req *req, FILE *f)
  {
 @@ -109,7 +111,7 @@
  		return;
  	gctl_set_error(req, "Could not allocate memory");
  	if (req->error == NULL)
 -		req->error = "Could not allocate memory";
 +		req->error = nomemmsg;
  }
  
  /*
 @@ -134,7 +136,7 @@
  	struct gctl_req_arg *ap;
  
  	req->narg++;
 -	req->arg = realloc(req->arg, sizeof *ap * req->narg);
 +	req->arg = reallocf(req->arg, sizeof *ap * req->narg);
  	gctl_check_alloc(req, req->arg);
  	if (req->arg == NULL) {
  		req->narg = 0;
 @@ -149,14 +151,20 @@
  gctl_ro_param(struct gctl_req *req, const char *name, int len, const void* value)
  {
  	struct gctl_req_arg *ap;
 +	char *ap_name;
  
  	if (req == NULL || req->error != NULL)
  		return;
 +	ap_name = strdup(name);
 +	gctl_check_alloc(req, ap_name);
 +	if (ap_name == NULL)
 +		return;
  	ap = gctl_new_arg(req);
 -	if (ap == NULL)
 +	if (ap == NULL) {
 +		free(ap_name);
  		return;
 -	ap->name = strdup(name);
 -	gctl_check_alloc(req, ap->name);
 +	}
 +	ap->name = ap_name;
  	ap->nlen = strlen(ap->name) + 1;
  	ap->value = __DECONST(void *, value);
  	ap->flag = GCTL_PARAM_RD;
 @@ -172,14 +180,20 @@
  gctl_rw_param(struct gctl_req *req, const char *name, int len, void* value)
  {
  	struct gctl_req_arg *ap;
 +	char *ap_name;
  
  	if (req == NULL || req->error != NULL)
  		return;
 +	ap_name = strdup(name);
 +	gctl_check_alloc(req, ap_name);
 +	if (ap_name == NULL)
 +		return;
  	ap = gctl_new_arg(req);
 -	if (ap == NULL)
 +	if (ap == NULL) {
 +		free(ap_name);
  		return;
 -	ap->name = strdup(name);
 -	gctl_check_alloc(req, ap->name);
 +	}
 +	ap->name = ap_name;
  	ap->nlen = strlen(ap->name) + 1;
  	ap->value = value;
  	ap->flag = GCTL_PARAM_RW;
 @@ -201,12 +215,11 @@
  
  	req->version = GCTL_VERSION;
  	req->lerror = BUFSIZ;		/* XXX: arbitrary number */
 -	req->error = malloc(req->lerror);
 +	req->error = calloc(1, req->lerror);
  	if (req->error == NULL) {
  		gctl_check_alloc(req, req->error);
  		return (req->error);
  	}
 -	memset(req->error, 0, req->lerror);
  	req->lerror--;
  	fd = open(_PATH_DEV PATH_GEOM_CTL, O_RDONLY);
  	if (fd < 0)
 @@ -232,7 +245,7 @@
  			free(req->arg[i].name);
  	}
  	free(req->arg);
 -	if (req->error != NULL)
 +	if (req->error != NULL && req->error != nomemmsg)
  		free(req->error);
  	free(req);
  }
 --- lib/libgeom/Makefile.ORIG	Thu Jul 14 16:34:19 2005
 +++ lib/libgeom/Makefile	Fri Jul 15 17:44:37 2005
 @@ -10,7 +10,7 @@
  
  CFLAGS += -I${.CURDIR}
  
 -WARNS?=	3
 +WARNS?=	6
  
  DPADD=	${LIBBSDXML} ${LIBSBUF}
  LDADD=	-lbsdxml -lsbuf
 --- lib/libgeom/geom_xml2tree.c.ORIG	Tue May 24 12:10:38 2005
 +++ lib/libgeom/geom_xml2tree.c	Fri Jul 15 18:13:14 2005
 @@ -84,6 +84,10 @@
  	}
  	if (!strcmp(name, "class") && mt->class == NULL) {
  		mt->class = calloc(1, sizeof *mt->class);
 +		if (mt->class == NULL) {
 +			warn("Problem during processing of '%s' element", name);
 +			return;
 +		}
  		mt->class->lg_id = id;
  		LIST_INSERT_HEAD(&mt->mesh->lg_class, mt->class, lg_class);
  		LIST_INIT(&mt->class->lg_geom);
 @@ -92,6 +96,10 @@
  	}
  	if (!strcmp(name, "geom") && mt->geom == NULL) {
  		mt->geom = calloc(1, sizeof *mt->geom);
 +		if (mt->geom == NULL) {
 +			warn("Problem during processing of '%s' element", name);
 +			return;
 +		}
  		mt->geom->lg_id = id;
  		LIST_INSERT_HEAD(&mt->class->lg_geom, mt->geom, lg_geom);
  		LIST_INIT(&mt->geom->lg_provider);
 @@ -105,6 +113,10 @@
  	}
  	if (!strcmp(name, "consumer") && mt->consumer == NULL) {
  		mt->consumer = calloc(1, sizeof *mt->consumer);
 +		if (mt->consumer == NULL) {
 +			warn("Problem during processing of '%s' element", name);
 +			return;
 +		}
  		mt->consumer->lg_id = id;
  		LIST_INSERT_HEAD(&mt->geom->lg_consumer, mt->consumer,
  		    lg_consumer);
 @@ -121,6 +133,10 @@
  	}
  	if (!strcmp(name, "provider") && mt->provider == NULL) {
  		mt->provider = calloc(1, sizeof *mt->provider);
 +		if (mt->provider == NULL) {
 +			warn("Problem during processing of '%s' element", name);
 +			return;
 +		}
  		mt->provider->lg_id = id;
  		LIST_INSERT_HEAD(&mt->geom->lg_provider, mt->provider,
  		    lg_provider);
 @@ -162,6 +178,10 @@
  	mt = userData;
  	sbuf_finish(mt->sbuf[mt->level]);
  	p = strdup(sbuf_data(mt->sbuf[mt->level]));
 +	if (p == NULL) {
 +		warn("Problem during processing of '%s' element", name);
 +		return;
 +	}
  	sbuf_delete(mt->sbuf[mt->level]);
  	mt->sbuf[mt->level] = NULL;
  	mt->level--;
 @@ -212,8 +232,16 @@
  	}
  
  	if (mt->config != NULL) {
 -		gc = calloc(sizeof *gc, 1);
 +		gc = calloc(1, sizeof *gc);
 +		if (gc == NULL) {
 +			warn("Problem during processing of '%s' element", name);
 +			return;
 +		}
  		gc->lg_name = strdup(name);
 +		if (gc->lg_name == NULL) {
 +			warn("Problem during processing of '%s' element", name);
 +			return;
 +		}
  		gc->lg_val = p;
  		LIST_INSERT_HEAD(mt->config, gc, lg_config);
  		return;
 
 --------------070408060806070200010105--
Responsible-Changed-From-To: freebsd-bugs->freebsd-geom 
Responsible-Changed-By: ceri 
Responsible-Changed-When: Sun Oct 8 19:16:08 UTC 2006 
Responsible-Changed-Why:  
libgeom problem; patches look good. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=83464 
Responsible-Changed-From-To: freebsd-geom->lulf 
Responsible-Changed-By: lulf 
Responsible-Changed-When: Wed Jun 18 16:38:32 UTC 2008 
Responsible-Changed-Why:  
Reviewing and testing patch. 

http://www.freebsd.org/cgi/query-pr.cgi?pr=83464 
State-Changed-From-To: open->closed 
State-Changed-By: lulf 
State-Changed-When: Tue Jul 8 17:36:16 UTC 2008 
State-Changed-Why:  
- Patch have been committed with modifications. Thanks! 

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

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/83464: commit references a PR
Date: Tue,  8 Jul 2008 17:35:18 +0000 (UTC)

 lulf        2008-07-08 17:34:50 UTC
 
   FreeBSD src repository
 
   Modified files:
     lib/libgeom          geom_ctl.c geom_getxml.c geom_xml2tree.c 
   Log:
   SVN rev 180369 on 2008-07-08 17:34:50Z by lulf
   
   - Simplify the procedure of retrieving XML-data from the kernel.
   - Fix a number of potential memory leaks in libgeom related to doing realloc
     without freeing old pointer if things go wrong.
   - Fix a number of places in libgeom where malloc and calloc return values
     were not checked.
   - Check malloc return value and provide sufficient warning messages when XML
     parsing fails.
   
   PR:             kern/83464
   Submitted by:   Dan Lukes <dan - at - obluda.cz>
   Approved by:    kib (mentor)
   
   Revision  Changes    Path
   1.5       +16 -6     src/lib/libgeom/geom_ctl.c
   1.3       +13 -19    src/lib/libgeom/geom_getxml.c
   1.6       +36 -1     src/lib/libgeom/geom_xml2tree.c
 _______________________________________________
 cvs-all@freebsd.org mailing list
 http://lists.freebsd.org/mailman/listinfo/cvs-all
 To unsubscribe, send any mail to "cvs-all-unsubscribe@freebsd.org"
 
>Unformatted:
