From nobody@FreeBSD.org  Thu Jun 28 21:43:53 2007
Return-Path: <nobody@FreeBSD.org>
Received: from mx1.freebsd.org (mx1.freebsd.org [69.147.83.52])
	by hub.freebsd.org (Postfix) with ESMTP id BE0D616A400
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 28 Jun 2007 21:43:53 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (www.freebsd.org [69.147.83.33])
	by mx1.freebsd.org (Postfix) with ESMTP id 9698513C480
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 28 Jun 2007 21:43:53 +0000 (UTC)
	(envelope-from nobody@FreeBSD.org)
Received: from www.freebsd.org (localhost [127.0.0.1])
	by www.freebsd.org (8.13.1/8.13.1) with ESMTP id l5SLhrvv065122
	for <freebsd-gnats-submit@FreeBSD.org>; Thu, 28 Jun 2007 21:43:53 GMT
	(envelope-from nobody@www.freebsd.org)
Received: (from nobody@localhost)
	by www.freebsd.org (8.13.1/8.13.1/Submit) id l5SLhrY9065121;
	Thu, 28 Jun 2007 21:43:53 GMT
	(envelope-from nobody)
Message-Id: <200706282143.l5SLhrY9065121@www.freebsd.org>
Date: Thu, 28 Jun 2007 21:43:53 GMT
From: David Sanderson <dsanderson@panasas.com>
To: freebsd-gnats-submit@FreeBSD.org
Subject: Disk_Names() returns a vector that is unsafe to free
X-Send-Pr-Version: www-3.0

>Number:         114110
>Category:       kern
>Synopsis:       [libdisk] [patch] Disk_Names() returns a vector that is unsafe to free
>Confidential:   no
>Severity:       non-critical
>Priority:       medium
>Responsible:    antoine
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          sw-bug
>Submitter-Id:   current-users
>Arrival-Date:   Thu Jun 28 21:50:01 GMT 2007
>Closed-Date:    Mon Mar 17 19:13:47 UTC 2008
>Last-Modified:  Mon Mar 17 19:13:47 UTC 2008
>Originator:     David Sanderson
>Release:        FreeBSD 6.2
>Organization:
Panasas, Inc.
>Environment:
FreeBSD perf-x4 6.2-RELEASE FreeBSD 6.2-RELEASE #0: Fri Jan 12 08:43:30 UTC 2007     root@portnoy.cse.buffalo.edu:/usr/obj/usr/src/sys/SMP  amd64

>Description:
The documentation for the Disk_Names() function in libdisk(3) states:

     Disk_Names() returns `char**' with all disk's names (wd0, wd1 ...).  You
     must free each pointer, as well as the array by hand.

However, looking at the code, in FreeBSD 6 this routine returns a vector that
can be freed, but only one of the pointers in that vector can be freed, because
they all point to space in a single malloced buffer, char *disklist.  Since the pointers in the vector are sorted by the strings they point to, there is no way for the caller to know which is safe to free, and it is certainly wrong to free them all.

It would be best for Disk_Names() to return a vector according to its docs.
>How-To-Repeat:

>Fix:
I'll contribute a sample new version that returns a vector that is safe to free according to the docs.

Patch attached with submission follows:

char **
Disk_Names()
{
	static char **disks;
	int error;
	size_t listsize;
	char *disklist;
        char *disklistp;
        size_t ndisks;
        size_t i;

	error = sysctlbyname("kern.disks", NULL, &listsize, NULL, 0);
	if (error) {
		warn("kern.disks sysctl not available");
		return NULL;
	}

	if (listsize == 0)
		return (NULL);

	disklist = (char *)malloc(listsize + 1);
	if (disklist == NULL) {
		return NULL;
	}
	memset(disklist, 0, listsize + 1);
	error = sysctlbyname("kern.disks", disklist, &listsize, NULL, 0);
	if (error || disklist[0] == 0) {
		free(disklist);
		return NULL;
	}
	for (disklistp = disklist, ndisks = 0; disklistp;) {
		char *disk = strsep(&disklistp, " ");
		if (disk) {
			/* We restore the space for a second pass through the names. */
			if (disklistp) {
				disklistp[-1] = ' ';
			}
			ndisks++;
		}
	}
	disks = malloc(sizeof *disks * (1 + ndisks));
	if (disks == NULL) {
		free(disklist);
		return NULL;
        }
	memset(disks,0,sizeof *disks * (1 + ndisks));
	for (disklistp = disklist, i = 0; i < ndisks; i++) {
		disks[i] = strdup(strsep(&disklistp, " "));
		if (disks[i] == NULL) {
			size_t j;
			for (j = 0; j < i; j++) {
				free(disks[j]);
			}
			free(disklist);
			free(disks);
			return NULL;
		}
	}
        free(disklist);
	qsort(disks, ndisks, sizeof(char*), qstrcmp);
	return disks;
}


>Release-Note:
>Audit-Trail:

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/114110: commit references a PR
Date: Fri, 15 Feb 2008 21:19:25 +0000 (UTC)

 antoine     2008-02-15 21:19:15 UTC
 
   FreeBSD src repository
 
   Modified files:
     lib/libdisk          disk.c 
   Log:
   - Make Disk_Names() behave as documented in libdisk(3): return an array
   of disk names, where you must free each pointer, as well as the array
   by hand. [1]
   - Destaticize "disks" in Disk_Names, it has no reasons to be static.
   
   PR:             kern/96077 [1]
   PR:             kern/114110 [1]
   MFC after:      1 month
   Approved by:    rwatson (mentor)
   
   Revision  Changes    Path
   1.128     +14 -5     src/lib/libdisk/disk.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"
 
State-Changed-From-To: open->patched 
State-Changed-By: antoine 
State-Changed-When: Fri Feb 15 21:24:38 UTC 2008 
State-Changed-Why:  
Patched in revision 1.128 of src/lib/libdisk/disk.c 


Responsible-Changed-From-To: freebsd-bugs->antoine 
Responsible-Changed-By: antoine 
Responsible-Changed-When: Fri Feb 15 21:24:38 UTC 2008 
Responsible-Changed-Why:  
Patched in revision 1.128 of src/lib/libdisk/disk.c 

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

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/114110: commit references a PR
Date: Mon, 17 Mar 2008 19:05:42 +0000 (UTC)

 antoine     2008-03-17 19:05:36 UTC
 
   FreeBSD src repository
 
   Modified files:        (Branch: RELENG_7)
     lib/libdisk          disk.c 
   Log:
   MFC to RELENG_7
     - Make Disk_Names() behave as documented in libdisk(3): return an array
     of disk names, where you must free each pointer, as well as the array
     by hand. [1]
     - Destaticize "disks" in Disk_Names, it has no reasons to be static.
   
     PR:             kern/96077 [1]
     PR:             kern/114110 [1]
     MFC after:      1 month
     Approved by:    rwatson (mentor)
   
   Revision   Changes    Path
   1.127.2.1  +14 -5     src/lib/libdisk/disk.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"
 

From: dfilter@FreeBSD.ORG (dfilter service)
To: bug-followup@FreeBSD.org
Cc:  
Subject: Re: kern/114110: commit references a PR
Date: Mon, 17 Mar 2008 19:08:39 +0000 (UTC)

 antoine     2008-03-17 19:08:33 UTC
 
   FreeBSD src repository
 
   Modified files:        (Branch: RELENG_6)
     lib/libdisk          disk.c 
   Log:
   MFC to RELENG_6
     - Make Disk_Names() behave as documented in libdisk(3): return an array
     of disk names, where you must free each pointer, as well as the array
     by hand. [1]
     - Destaticize "disks" in Disk_Names, it has no reasons to be static.
   
     PR:             kern/96077 [1]
     PR:             kern/114110 [1]
     MFC after:      1 month
     Approved by:    rwatson (mentor)
   
   Revision   Changes    Path
   1.125.2.2  +14 -5     src/lib/libdisk/disk.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"
 
State-Changed-From-To: patched->closed 
State-Changed-By: antoine 
State-Changed-When: Mon Mar 17 19:13:25 UTC 2008 
State-Changed-Why:  
Close: fixed in HEAD, RELENG_7 and RELENG_6. 
Thanks for the report. 

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